summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
Diffstat (limited to 'indra')
-rw-r--r--indra/CMakeLists.txt22
-rw-r--r--indra/cmake/00-Common.cmake65
-rw-r--r--indra/cmake/APR.cmake16
-rw-r--r--indra/cmake/BerkeleyDB.cmake8
-rw-r--r--indra/cmake/Boost.cmake51
-rw-r--r--indra/cmake/CARes.cmake5
-rw-r--r--indra/cmake/CMakeLists.txt6
-rw-r--r--indra/cmake/CURL.cmake6
-rw-r--r--indra/cmake/Copy3rdPartyLibs.cmake225
-rw-r--r--indra/cmake/DBusGlib.cmake2
-rw-r--r--indra/cmake/DirectX.cmake2
-rw-r--r--indra/cmake/ELFIO.cmake19
-rwxr-xr-x[-rw-r--r--]indra/cmake/FMOD.cmake43
-rw-r--r--indra/cmake/FindAutobuild.cmake41
-rw-r--r--indra/cmake/FindFMOD.cmake2
-rw-r--r--indra/cmake/FindJsonCpp.cmake5
-rw-r--r--indra/cmake/FindLLQtWebkit.cmake62
-rw-r--r--indra/cmake/FindNDOF.cmake39
-rw-r--r--indra/cmake/FindTut.cmake31
-rw-r--r--indra/cmake/FindZLIB.cmake46
-rw-r--r--indra/cmake/FreeType.cmake2
-rw-r--r--indra/cmake/GLOD.cmake9
-rw-r--r--indra/cmake/GStreamer010Plugin.cmake6
-rw-r--r--indra/cmake/GetPrerequisites_2_8.cmake1572
-rw-r--r--indra/cmake/GoogleMock.cmake5
-rw-r--r--indra/cmake/GooglePerfTools.cmake15
-rw-r--r--indra/cmake/JPEG.cmake5
-rw-r--r--indra/cmake/JsonCpp.cmake10
-rw-r--r--indra/cmake/LLAddBuildTest.cmake21
-rw-r--r--indra/cmake/LLCommon.cmake9
-rw-r--r--indra/cmake/LLConvexDecomposition.cmake12
-rw-r--r--indra/cmake/LLKDU.cmake22
-rw-r--r--indra/cmake/LLPlugin.cmake8
-rw-r--r--indra/cmake/LLPrimitive.cmake28
-rw-r--r--indra/cmake/LLTestCommand.cmake1
-rw-r--r--indra/cmake/LLWindow.cmake2
-rw-r--r--indra/cmake/Linking.cmake51
-rw-r--r--indra/cmake/MonoEmbed.cmake4
-rw-r--r--indra/cmake/MySQL.cmake6
-rw-r--r--indra/cmake/NDOF.cmake34
-rw-r--r--indra/cmake/OPENAL.cmake16
-rw-r--r--indra/cmake/OpenGL.cmake5
-rw-r--r--indra/cmake/OpenSSL.cmake4
-rw-r--r--indra/cmake/PNG.cmake12
-rw-r--r--indra/cmake/Prebuilt.cmake75
-rw-r--r--indra/cmake/Pth.cmake21
-rw-r--r--indra/cmake/PulseAudio.cmake2
-rw-r--r--indra/cmake/Python.cmake2
-rw-r--r--indra/cmake/QuickTimePlugin.cmake2
-rw-r--r--indra/cmake/TemplateCheck.cmake6
-rw-r--r--indra/cmake/Tut.cmake10
-rw-r--r--indra/cmake/UI.cmake4
-rw-r--r--indra/cmake/Variables.cmake72
-rw-r--r--indra/cmake/ViewerMiscLibs.cmake2
-rw-r--r--indra/cmake/WebKitLibPlugin.cmake94
-rw-r--r--indra/cmake/XmlRpcEpi.cmake5
-rwxr-xr-x[-rw-r--r--]indra/cmake/run_build_test.py4
-rw-r--r--indra/copy_win_scripts/start-client.py24
-rwxr-xr-xindra/develop.py862
-rw-r--r--indra/integration_tests/CMakeLists.txt7
-rw-r--r--indra/integration_tests/llimage_libtest/CMakeLists.txt125
-rw-r--r--indra/integration_tests/llimage_libtest/llimage_libtest.cpp559
-rw-r--r--indra/integration_tests/llimage_libtest/llimage_libtest.h29
-rw-r--r--indra/integration_tests/llui_libtest/CMakeLists.txt10
-rw-r--r--indra/integration_tests/llui_libtest/llui_libtest.cpp5
-rwxr-xr-xindra/lib/python/indra/util/llperformance.py26
-rw-r--r--indra/lib/python/indra/util/llversion.py57
-rwxr-xr-xindra/lib/python/indra/util/simperf_proc_interface.py2
-rw-r--r--indra/lib/python/indra/util/test_win32_manifest.py73
-rw-r--r--indra/linux_updater/linux_updater.cpp202
-rw-r--r--indra/llaudio/CMakeLists.txt6
-rw-r--r--indra/llaudio/llaudiodecodemgr.cpp8
-rw-r--r--indra/llaudio/llaudioengine.cpp10
-rw-r--r--indra/llaudio/llaudioengine_openal.cpp2
-rw-r--r--indra/llaudio/llaudioengine_openal.h2
-rw-r--r--indra/llaudio/llvorbisencode.cpp7
-rw-r--r--indra/llaudio/llvorbisencode.h1
-rw-r--r--indra/llcharacter/CMakeLists.txt19
-rw-r--r--indra/llcharacter/llanimationstates.cpp278
-rw-r--r--indra/llcharacter/llbvhloader.cpp10
-rw-r--r--indra/llcharacter/lljoint.cpp38
-rw-r--r--indra/llcharacter/lljoint.h24
-rw-r--r--indra/llcharacter/llkeyframemotion.cpp2
-rw-r--r--indra/llcommon/CMakeLists.txt20
-rw-r--r--indra/llcommon/indra_constants.h19
-rw-r--r--indra/llcommon/llapp.cpp39
-rw-r--r--indra/llcommon/llapp.h6
-rw-r--r--indra/llcommon/llapr.cpp22
-rw-r--r--indra/llcommon/llapr.h5
-rw-r--r--indra/llcommon/llassettype.cpp3
-rw-r--r--indra/llcommon/llassettype.h6
-rw-r--r--indra/llcommon/llavatarconstants.h8
-rw-r--r--indra/llcommon/llavatarname.cpp12
-rw-r--r--indra/llcommon/llavatarname.h2
-rw-r--r--indra/llcommon/lldarray.h2
-rw-r--r--indra/llcommon/lldefs.h8
-rw-r--r--indra/llcommon/lleventdispatcher.cpp566
-rw-r--r--indra/llcommon/lleventdispatcher.h393
-rw-r--r--indra/llcommon/llevents.cpp17
-rw-r--r--indra/llcommon/llevents.h14
-rw-r--r--indra/llcommon/llfasttimer.h135
-rw-r--r--indra/llcommon/llfasttimer_class.cpp173
-rw-r--r--indra/llcommon/llfasttimer_class.h10
-rw-r--r--indra/llcommon/llfile.cpp16
-rw-r--r--indra/llcommon/llfile.h2
-rw-r--r--indra/llcommon/llfoldertype.cpp3
-rw-r--r--indra/llcommon/llfoldertype.h6
-rw-r--r--indra/llcommon/llinstancetracker.cpp17
-rw-r--r--indra/llcommon/llinstancetracker.h30
-rw-r--r--indra/llcommon/lllslconstants.h2
-rw-r--r--indra/llcommon/llmd5.h2
-rw-r--r--indra/llcommon/llmemory.cpp197
-rw-r--r--indra/llcommon/llmemory.h135
-rw-r--r--indra/llcommon/llmemtype.cpp1
-rw-r--r--indra/llcommon/llmetricperformancetester.cpp336
-rw-r--r--indra/llcommon/llmetricperformancetester.h215
-rw-r--r--indra/llcommon/llprocesslauncher.cpp38
-rw-r--r--indra/llcommon/llprocesslauncher.h2
-rw-r--r--indra/llcommon/llqueuedthread.h2
-rw-r--r--indra/llcommon/llrefcount.cpp110
-rw-r--r--indra/llcommon/llrefcount.h20
-rw-r--r--indra/llcommon/llsdserialize.cpp183
-rw-r--r--indra/llcommon/llsdserialize.h4
-rw-r--r--indra/llcommon/llsdutil.cpp27
-rw-r--r--indra/llcommon/llsdutil.h285
-rw-r--r--indra/llcommon/llsys.cpp82
-rw-r--r--indra/llcommon/llsys.h3
-rw-r--r--indra/llcommon/llthread.cpp96
-rw-r--r--indra/llcommon/llthread.h22
-rw-r--r--indra/llcommon/llthreadsafequeue.cpp109
-rw-r--r--indra/llcommon/llthreadsafequeue.h205
-rw-r--r--indra/llcommon/llversionviewer.h6
-rw-r--r--indra/llcommon/stdenums.h3
-rw-r--r--indra/llcommon/tests/lldependencies_test.cpp12
-rw-r--r--indra/llcommon/tests/llerror_test.cpp16
-rw-r--r--indra/llcommon/tests/lleventdispatcher_test.cpp1324
-rw-r--r--indra/llcommon/tests/llsdserialize_test.cpp2
-rw-r--r--indra/llimage/CMakeLists.txt14
-rw-r--r--indra/llimage/llimage.cpp43
-rw-r--r--indra/llimage/llimage.h21
-rw-r--r--indra/llimage/llimagedimensionsinfo.cpp99
-rw-r--r--indra/llimage/llimagedimensionsinfo.h3
-rw-r--r--indra/llimage/llimagej2c.cpp345
-rw-r--r--indra/llimage/llimagej2c.h51
-rw-r--r--indra/llimage/llimageworker.cpp6
-rw-r--r--indra/llimage/llimageworker.h2
-rw-r--r--indra/llimage/llpngwrapper.cpp18
-rw-r--r--indra/llimage/llpngwrapper.h3
-rw-r--r--indra/llimage/tests/llimageworker_test.cpp18
-rw-r--r--indra/llimagej2coj/llimagej2coj.cpp17
-rw-r--r--indra/llimagej2coj/llimagej2coj.h8
-rw-r--r--indra/llinventory/CMakeLists.txt25
-rw-r--r--indra/llinventory/llinventory.cpp2
-rw-r--r--indra/llinventory/llinventorytype.cpp79
-rw-r--r--indra/llinventory/llinventorytype.h3
-rw-r--r--indra/llinventory/llnotecard.cpp2
-rw-r--r--indra/llinventory/llparcel.cpp15
-rw-r--r--indra/llinventory/llparcel.h7
-rw-r--r--indra/llkdu/CMakeLists.txt65
-rw-r--r--indra/llkdu/llimagej2ckdu.cpp1156
-rw-r--r--indra/llkdu/llimagej2ckdu.h95
-rw-r--r--indra/llkdu/llkdumem.cpp196
-rw-r--r--indra/llkdu/llkdumem.h145
-rw-r--r--indra/llkdu/tests/llimagej2ckdu_test.cpp249
-rw-r--r--indra/llmath/CMakeLists.txt14
-rw-r--r--indra/llmath/llbbox.cpp22
-rw-r--r--indra/llmath/llbbox.h4
-rw-r--r--indra/llmath/llcamera.cpp276
-rw-r--r--indra/llmath/llcamera.h39
-rw-r--r--indra/llmath/llmath.h85
-rw-r--r--indra/llmath/llmatrix3a.cpp134
-rw-r--r--indra/llmath/llmatrix3a.h128
-rw-r--r--indra/llmath/llmatrix3a.inl119
-rw-r--r--indra/llmath/llmatrix4a.h143
-rw-r--r--indra/llmath/lloctree.h327
-rw-r--r--indra/llmath/llplane.h44
-rw-r--r--indra/llmath/llquantize.h6
-rw-r--r--indra/llmath/llquaternion.cpp3
-rw-r--r--indra/llmath/llquaternion.h6
-rw-r--r--indra/llmath/llquaternion2.h105
-rw-r--r--indra/llmath/llquaternion2.inl102
-rw-r--r--indra/llmath/llsimdmath.h93
-rw-r--r--indra/llmath/llsimdtypes.h124
-rw-r--r--indra/llmath/llsimdtypes.inl157
-rw-r--r--indra/llmath/lltreenode.h3
-rw-r--r--indra/llmath/llvector4a.cpp222
-rw-r--r--indra/llmath/llvector4a.h324
-rw-r--r--indra/llmath/llvector4a.inl593
-rw-r--r--indra/llmath/llvector4logical.h124
-rw-r--r--indra/llmath/llvolume.cpp2835
-rw-r--r--indra/llmath/llvolume.h190
-rw-r--r--indra/llmath/llvolumemgr.cpp15
-rw-r--r--indra/llmath/llvolumemgr.h1
-rw-r--r--indra/llmath/llvolumeoctree.cpp256
-rw-r--r--indra/llmath/llvolumeoctree.h134
-rw-r--r--indra/llmath/m4math.cpp138
-rw-r--r--indra/llmath/m4math.h34
-rw-r--r--indra/llmath/tests/llbbox_test.cpp2
-rw-r--r--indra/llmath/tests/llquaternion_test.cpp2
-rw-r--r--indra/llmath/tests/m3math_test.cpp27
-rw-r--r--indra/llmath/tests/v2math_test.cpp6
-rw-r--r--indra/llmath/tests/v3color_test.cpp6
-rw-r--r--indra/llmath/tests/v3dmath_test.cpp4
-rw-r--r--indra/llmath/tests/v3math_test.cpp8
-rw-r--r--indra/llmath/tests/v4color_test.cpp4
-rw-r--r--indra/llmath/tests/v4coloru_test.cpp2
-rw-r--r--indra/llmath/tests/v4math_test.cpp6
-rw-r--r--indra/llmath/v2math.cpp17
-rw-r--r--indra/llmath/v2math.h11
-rw-r--r--indra/llmath/v3color.h10
-rw-r--r--indra/llmath/v3dmath.h10
-rw-r--r--indra/llmath/v3math.cpp37
-rw-r--r--indra/llmath/v3math.h41
-rw-r--r--indra/llmath/v4color.h26
-rw-r--r--indra/llmath/v4coloru.h4
-rw-r--r--indra/llmath/v4math.h8
-rw-r--r--indra/llmath/xform.h4
-rw-r--r--indra/llmessage/CMakeLists.txt2
-rw-r--r--indra/llmessage/llassetstorage.cpp29
-rw-r--r--indra/llmessage/llavatarnamecache.cpp285
-rw-r--r--indra/llmessage/llavatarnamecache.h3
-rw-r--r--indra/llmessage/llcachename.cpp54
-rw-r--r--indra/llmessage/llcircuit.cpp3
-rw-r--r--indra/llmessage/llcircuit.h4
-rw-r--r--indra/llmessage/llcurl.cpp203
-rw-r--r--indra/llmessage/llcurl.h3
-rw-r--r--indra/llmessage/llhttpassetstorage.cpp8
-rw-r--r--indra/llmessage/llregionflags.h18
-rw-r--r--indra/llmessage/llsdmessagebuilder.cpp1
-rw-r--r--indra/llmessage/lltemplatemessagebuilder.cpp1
-rw-r--r--indra/llmessage/lltemplatemessagereader.cpp1
-rw-r--r--indra/llmessage/lltransfermanager.cpp2
-rw-r--r--indra/llmessage/lltransfersourceasset.cpp1
-rw-r--r--indra/llmessage/llurlrequest.cpp6
-rw-r--r--indra/llmessage/message.cpp8
-rw-r--r--indra/llmessage/message_prehash.cpp2684
-rw-r--r--indra/llmessage/message_prehash.h2684
-rw-r--r--indra/llmessage/tests/commtest.h20
-rw-r--r--indra/llmessage/tests/llhost_test.cpp3
-rw-r--r--indra/llmessage/tests/llsdmessage_test.cpp1
-rw-r--r--indra/llmessage/tests/test_llsdmessage_peer.py28
-rw-r--r--indra/llmessage/tests/testrunner.py83
-rw-r--r--indra/llplugin/CMakeLists.txt28
-rw-r--r--indra/llplugin/llpluginclassmedia.cpp80
-rw-r--r--indra/llplugin/llpluginclassmedia.h28
-rw-r--r--indra/llplugin/llpluginclassmediaowner.h9
-rw-r--r--indra/llplugin/llplugininstance.cpp20
-rw-r--r--indra/llplugin/llplugininstance.h2
-rw-r--r--indra/llplugin/llpluginprocesschild.cpp3
-rw-r--r--indra/llplugin/llpluginprocesschild.h1
-rw-r--r--indra/llplugin/llpluginprocessparent.cpp5
-rw-r--r--indra/llplugin/llpluginprocessparent.h2
-rw-r--r--indra/llprimitive/CMakeLists.txt20
-rw-r--r--indra/llprimitive/llmodel.cpp2292
-rw-r--r--indra/llprimitive/llmodel.h255
-rw-r--r--indra/llprimitive/llprimitive.cpp21
-rw-r--r--indra/llprimitive/llprimitive.h7
-rw-r--r--indra/llprimitive/lltextureentry.cpp24
-rw-r--r--indra/llprimitive/llvolumemessage.cpp6
-rw-r--r--indra/llprimitive/llvolumemessage.h6
-rw-r--r--indra/llrender/llfontfreetype.cpp2
-rw-r--r--indra/llrender/llfontgl.cpp1
-rw-r--r--indra/llrender/llgl.cpp326
-rw-r--r--indra/llrender/llgl.h88
-rw-r--r--indra/llrender/llglheaders.h133
-rw-r--r--indra/llrender/llglslshader.cpp41
-rw-r--r--indra/llrender/llglslshader.h3
-rw-r--r--indra/llrender/llglstates.h32
-rw-r--r--indra/llrender/llimagegl.cpp17
-rw-r--r--indra/llrender/llrender.cpp195
-rw-r--r--indra/llrender/llrender.h39
-rw-r--r--indra/llrender/llrendertarget.cpp264
-rw-r--r--indra/llrender/llrendertarget.h24
-rw-r--r--indra/llrender/llshadermgr.cpp81
-rw-r--r--indra/llrender/llvertexbuffer.cpp562
-rw-r--r--indra/llrender/llvertexbuffer.h85
-rw-r--r--indra/llui/CMakeLists.txt21
-rw-r--r--indra/llui/llaccordionctrltab.cpp58
-rw-r--r--indra/llui/llbutton.cpp8
-rw-r--r--indra/llui/llbutton.h7
-rw-r--r--indra/llui/llcheckboxctrl.cpp57
-rw-r--r--indra/llui/llcombobox.cpp45
-rw-r--r--indra/llui/llcombobox.h9
-rw-r--r--indra/llui/lldockcontrol.cpp31
-rw-r--r--indra/llui/llflatlistview.cpp3
-rw-r--r--indra/llui/llflatlistview.h3
-rw-r--r--indra/llui/llfloater.cpp85
-rw-r--r--indra/llui/llfloater.h11
-rw-r--r--indra/llui/llfloaterreg.h6
-rw-r--r--indra/llui/llfloaterreglistener.cpp17
-rw-r--r--indra/llui/llfloaterreglistener.h1
-rw-r--r--indra/llui/llfocusmgr.cpp33
-rw-r--r--indra/llui/llfocusmgr.h11
-rw-r--r--indra/llui/llhandle.h8
-rw-r--r--indra/llui/lliconctrl.cpp5
-rw-r--r--indra/llui/lliconctrl.h7
-rw-r--r--indra/llui/lllayoutstack.cpp81
-rw-r--r--indra/llui/lllayoutstack.h27
-rw-r--r--indra/llui/lllineeditor.cpp25
-rw-r--r--indra/llui/lllineeditor.h7
-rw-r--r--indra/llui/llloadingindicator.cpp67
-rw-r--r--indra/llui/llloadingindicator.h31
-rw-r--r--indra/llui/llmenubutton.cpp151
-rw-r--r--indra/llui/llmenubutton.h34
-rw-r--r--indra/llui/llmenugl.cpp268
-rw-r--r--indra/llui/llmenugl.h19
-rw-r--r--indra/llui/llmultislider.cpp1
-rw-r--r--indra/llui/llnotifications.cpp328
-rw-r--r--indra/llui/llnotifications.h27
-rw-r--r--indra/llui/llnotificationtemplate.h29
-rw-r--r--indra/llui/llnotificationvisibilityrule.h104
-rw-r--r--indra/llui/llpanel.cpp6
-rw-r--r--indra/llui/llpanel.h1
-rw-r--r--indra/llui/llprogressbar.cpp7
-rw-r--r--indra/llui/llprogressbar.h9
-rw-r--r--indra/llui/llradiogroup.cpp46
-rw-r--r--indra/llui/llradiogroup.h12
-rw-r--r--indra/llui/llscrollcontainer.cpp5
-rw-r--r--indra/llui/llscrolllistcolumn.cpp9
-rw-r--r--indra/llui/llscrolllistctrl.cpp45
-rw-r--r--indra/llui/llscrolllistctrl.h2
-rw-r--r--indra/llui/llsdparam.cpp27
-rw-r--r--indra/llui/llsdparam.h2
-rw-r--r--indra/llui/llslider.h1
-rw-r--r--indra/llui/llstyle.cpp2
-rw-r--r--indra/llui/llstyle.h5
-rw-r--r--indra/llui/lltextbase.cpp193
-rw-r--r--indra/llui/lltextbase.h4
-rw-r--r--indra/llui/lltexteditor.cpp16
-rw-r--r--indra/llui/lltexteditor.h1
-rw-r--r--indra/llui/lltoggleablemenu.cpp18
-rw-r--r--indra/llui/lltoggleablemenu.h5
-rw-r--r--indra/llui/lltransutil.cpp5
-rw-r--r--indra/llui/llui.cpp175
-rw-r--r--indra/llui/llui.h113
-rw-r--r--indra/llui/lluicolortable.cpp6
-rw-r--r--indra/llui/lluictrl.cpp39
-rw-r--r--indra/llui/lluictrl.h18
-rw-r--r--indra/llui/lluictrlfactory.cpp24
-rw-r--r--indra/llui/lluiimage.cpp12
-rw-r--r--indra/llui/lluiimage.h17
-rw-r--r--indra/llui/lluistring.h9
-rw-r--r--indra/llui/llurlentry.cpp169
-rw-r--r--indra/llui/llurlentry.h55
-rw-r--r--indra/llui/llurlregistry.cpp1
-rw-r--r--indra/llui/llview.cpp45
-rw-r--r--indra/llui/llview.h39
-rw-r--r--indra/llui/llviewborder.cpp1
-rw-r--r--indra/llui/llwindowshade.cpp328
-rw-r--r--indra/llui/llwindowshade.h70
-rw-r--r--indra/llui/tests/llurlentry_stub.cpp54
-rw-r--r--indra/llui/tests/llurlentry_test.cpp174
-rw-r--r--indra/llui/tests/llurlmatch_test.cpp54
-rw-r--r--indra/llvfs/CMakeLists.txt35
-rw-r--r--indra/llvfs/lldir.cpp31
-rw-r--r--indra/llvfs/lldir.h3
-rw-r--r--indra/llvfs/lldir_linux.cpp114
-rw-r--r--indra/llvfs/lldir_linux.h12
-rw-r--r--indra/llvfs/lldir_mac.cpp107
-rw-r--r--indra/llvfs/lldir_mac.h8
-rw-r--r--indra/llvfs/lldir_solaris.cpp108
-rw-r--r--indra/llvfs/lldir_solaris.h10
-rw-r--r--indra/llvfs/lldir_win32.cpp166
-rw-r--r--indra/llvfs/lldir_win32.h8
-rw-r--r--indra/llvfs/lldiriterator.cpp203
-rw-r--r--indra/llvfs/lldiriterator.h87
-rw-r--r--indra/llvfs/llvfile.cpp4
-rw-r--r--indra/llvfs/llvfs.cpp10
-rw-r--r--indra/llvfs/tests/lldir_test.cpp163
-rw-r--r--indra/llwindow/CMakeLists.txt10
-rw-r--r--indra/llwindow/llkeyboard.h2
-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/llwindowmacosx.cpp160
-rw-r--r--indra/llwindow/llwindowmacosx.h3
-rw-r--r--indra/llwindow/llwindowwin32.cpp31
-rw-r--r--indra/llxml/CMakeLists.txt36
-rw-r--r--indra/llxml/llcontrol.cpp51
-rw-r--r--indra/llxml/llcontrol.h2
-rw-r--r--indra/llxml/llxmlnode.cpp24
-rw-r--r--indra/llxml/llxmlnode.h3
-rw-r--r--indra/llxuixml/llinitparam.cpp113
-rw-r--r--indra/llxuixml/llinitparam.h1188
-rw-r--r--indra/llxuixml/llregistry.h5
-rw-r--r--indra/llxuixml/lltrans.cpp56
-rw-r--r--indra/llxuixml/lltrans.h14
-rw-r--r--indra/llxuixml/llxuiparser.cpp63
-rw-r--r--indra/llxuixml/llxuiparser.h9
-rw-r--r--indra/lscript/lscript_compile/indra.l5
-rw-r--r--indra/mac_updater/CMakeLists.txt7
-rw-r--r--indra/mac_updater/mac_updater.cpp113
-rw-r--r--indra/media_plugins/example/media_plugin_example.cpp733
-rw-r--r--indra/media_plugins/webkit/CMakeLists.txt5
-rw-r--r--indra/media_plugins/webkit/media_plugin_webkit.cpp93
-rw-r--r--indra/media_plugins/winmmshim/CMakeLists.txt6
-rw-r--r--indra/media_plugins/winmmshim/forwarding_api.cpp173
-rw-r--r--indra/media_plugins/winmmshim/forwarding_api.h1
-rw-r--r--indra/media_plugins/winmmshim/winmm_shim.cpp22
-rw-r--r--indra/newview/CMakeLists.txt206
-rw-r--r--indra/newview/English.lproj/InfoPlist.strings4
-rw-r--r--indra/newview/Info-SecondLife.plist2
-rw-r--r--indra/newview/app_settings/CA.pem6460
-rw-r--r--indra/newview/app_settings/cmd_line.xml30
-rw-r--r--indra/newview/app_settings/high_graphics.xml19
-rw-r--r--indra/newview/app_settings/ignorable_dialogs.xml34
-rw-r--r--indra/newview/app_settings/keys.ini357
-rw-r--r--indra/newview/app_settings/keys.xml350
-rw-r--r--indra/newview/app_settings/lindenlab.pem97
-rw-r--r--indra/newview/app_settings/llsd.xsd131
-rw-r--r--indra/newview/app_settings/low_graphics.xml23
-rw-r--r--indra/newview/app_settings/mid_graphics.xml19
-rw-r--r--indra/newview/app_settings/settings.xml1787
-rw-r--r--indra/newview/app_settings/settings_crash_behavior.xml2
-rw-r--r--indra/newview/app_settings/settings_files.xml212
-rw-r--r--indra/newview/app_settings/settings_minimal.xml463
-rw-r--r--indra/newview/app_settings/settings_per_account.xml34
-rw-r--r--indra/newview/app_settings/shaders/class1/avatar/avatarF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/avatar/avatarSkinV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/avatar/avatarV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/avatar/eyeballF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/avatar/eyeballV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/avatar/objectSkinV.glsl30
-rw-r--r--indra/newview/app_settings/shaders/class1/avatar/pickAvatarF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/avatar/pickAvatarV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl14
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/alphaSkinnedV.glsl107
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl57
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/attachmentShadowF.glsl18
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/attachmentShadowV.glsl27
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/avatarAlphaF.glsl68
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/avatarAlphaV.glsl66
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/avatarF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/avatarShadowF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/avatarShadowV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/avatarV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl37
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/blurLightV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/bumpSkinnedV.glsl37
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/bumpV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/diffuseSkinnedV.glsl33
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/giF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/giV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl4
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/impostorV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/luminanceF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/luminanceV.glsl3
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/multiPointLightV.glsl (renamed from indra/newview/app_settings/shaders/class2/deferred/blurLightV.glsl)13
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/pointLightV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/postDeferredF.glsl140
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/postDeferredNoDoFF.glsl24
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/postDeferredV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/postgiF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/postgiV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/shadowF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/shadowV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl12
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/softenLightV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/sunLightF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOF.glsl78
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/sunLightV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/terrainF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/terrainV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/treeF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/treeV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/waterF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/waterV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/effects/glowExtractF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/effects/glowExtractV.glsl1
-rw-r--r--indra/newview/app_settings/shaders/class1/effects/glowF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/effects/glowV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/environment/terrainF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/environment/terrainV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/environment/terrainWaterF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/environment/underWaterF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/environment/waterF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/environment/waterFogF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/environment/waterV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/interface/highlightF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/interface/highlightV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/lighting/lightF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/lighting/lightFullbrightF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyWaterF.glsl17
-rw-r--r--indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/lighting/lightFuncSpecularV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/lighting/lightFuncV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/lighting/lightShinyF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/lighting/lightShinyWaterF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/lighting/lightSpecularV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/lighting/lightV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/lighting/lightWaterF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/lighting/sumLightsSpecularV.glsl3
-rw-r--r--indra/newview/app_settings/shaders/class1/lighting/sumLightsV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/objects/fullbrightF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/objects/fullbrightShinyF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/objects/fullbrightShinySkinnedV.glsl39
-rw-r--r--indra/newview/app_settings/shaders/class1/objects/fullbrightShinyV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/objects/fullbrightShinyWaterF.glsl15
-rw-r--r--indra/newview/app_settings/shaders/class1/objects/fullbrightSkinnedV.glsl37
-rw-r--r--indra/newview/app_settings/shaders/class1/objects/fullbrightV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/objects/fullbrightWaterF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/objects/shinyF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/objects/shinySimpleSkinnedV.glsl39
-rw-r--r--indra/newview/app_settings/shaders/class1/objects/shinyV.glsl4
-rw-r--r--indra/newview/app_settings/shaders/class1/objects/shinyWaterF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/objects/simpleF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/objects/simpleSkinnedV.glsl39
-rw-r--r--indra/newview/app_settings/shaders/class1/objects/simpleV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/objects/simpleWaterF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/windlight/atmosphericsF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/windlight/atmosphericsHelpersV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/windlight/atmosphericsV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/windlight/gammaF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/windlight/transportF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class2/avatar/eyeballV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl16
-rw-r--r--indra/newview/app_settings/shaders/class2/deferred/alphaSkinnedV.glsl110
-rw-r--r--indra/newview/app_settings/shaders/class2/deferred/alphaV.glsl56
-rw-r--r--indra/newview/app_settings/shaders/class2/deferred/avatarAlphaF.glsl98
-rw-r--r--indra/newview/app_settings/shaders/class2/deferred/avatarAlphaV.glsl55
-rw-r--r--indra/newview/app_settings/shaders/class2/deferred/blurLightF.glsl81
-rw-r--r--indra/newview/app_settings/shaders/class2/deferred/edgeF.glsl4
-rw-r--r--indra/newview/app_settings/shaders/class2/deferred/edgeV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class2/deferred/postDeferredF.glsl59
-rw-r--r--indra/newview/app_settings/shaders/class2/deferred/postDeferredV.glsl17
-rw-r--r--indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class2/deferred/softenLightV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl5
-rw-r--r--indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl80
-rw-r--r--indra/newview/app_settings/shaders/class2/deferred/sunLightV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class2/effects/blurF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class2/effects/blurV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class2/effects/colorFilterF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class2/effects/drawQuadV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class2/effects/extractF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class2/effects/nightVisionF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class2/effects/simpleF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class2/environment/terrainF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class2/environment/terrainV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class2/environment/terrainWaterF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class2/environment/underWaterF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class2/environment/waterF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class2/environment/waterFogF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class2/lighting/lightF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class2/lighting/lightFullbrightF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class2/lighting/lightFullbrightShinyF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class2/lighting/lightFullbrightShinyWaterF.glsl31
-rw-r--r--indra/newview/app_settings/shaders/class2/lighting/lightFullbrightWaterF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class2/lighting/lightShinyF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class2/lighting/lightShinyWaterF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class2/lighting/lightSpecularV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class2/lighting/lightV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class2/lighting/lightWaterF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class2/lighting/sumLightsSpecularV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class2/lighting/sumLightsV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class2/objects/shinyV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class2/windlight/atmosphericsF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class2/windlight/atmosphericsHelpersV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class2/windlight/atmosphericsV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class2/windlight/atmosphericsVarsF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class2/windlight/atmosphericsVarsV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class2/windlight/cloudsF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class2/windlight/cloudsV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class2/windlight/gammaF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class2/windlight/skyF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class2/windlight/skyV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class2/windlight/transportF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class3/avatar/avatarV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class3/deferred/giDownsampleF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class3/deferred/giDownsampleV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class3/deferred/giF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class3/deferred/giFinalF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class3/deferred/giFinalV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class3/deferred/giV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class3/deferred/luminanceF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class3/deferred/luminanceV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class3/deferred/postDeferredF.glsl4
-rw-r--r--indra/newview/app_settings/shaders/class3/deferred/postDeferredV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class3/deferred/postgiF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class3/deferred/postgiV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class3/deferred/softenLightV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class3/deferred/treeF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class3/lighting/sumLightsSpecularV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class3/lighting/sumLightsV.glsl2
-rw-r--r--indra/newview/app_settings/shaders/shader_hierarchy.txt (renamed from indra/newview/app_settings/shaders/shader_heirarchy.txt)0
-rw-r--r--indra/newview/app_settings/ultra_graphics.xml19
-rw-r--r--indra/newview/app_settings/windlight/postprocesseffects.xml1
-rw-r--r--indra/newview/character/avatar_lad.xml650
-rw-r--r--indra/newview/featuretable.txt48
-rw-r--r--indra/newview/featuretable_linux.txt38
-rw-r--r--indra/newview/featuretable_mac.txt90
-rw-r--r--indra/newview/featuretable_xp.txt37
-rw-r--r--indra/newview/generate_breakpad_symbols.py63
-rw-r--r--indra/newview/gpu_table.txt805
-rw-r--r--indra/newview/groupchatlistener.cpp59
-rw-r--r--indra/newview/groupchatlistener.h23
-rw-r--r--indra/newview/installers/windows/installer_template.nsi20
-rw-r--r--indra/newview/installers/windows/lang_en-us.nsibin7162 -> 7542 bytes
-rw-r--r--indra/newview/licenses-mac.txt510
-rw-r--r--indra/newview/licenses-win32.txt69
-rwxr-xr-xindra/newview/linux_tools/wrapper.sh34
-rw-r--r--indra/newview/llagent.cpp148
-rw-r--r--indra/newview/llagent.h31
-rw-r--r--indra/newview/llagentcamera.cpp41
-rw-r--r--indra/newview/llagentlistener.cpp64
-rw-r--r--indra/newview/llagentlistener.h3
-rw-r--r--indra/newview/llagentpilot.cpp195
-rw-r--r--indra/newview/llagentpilot.h47
-rw-r--r--indra/newview/llagentwearables.cpp5
-rw-r--r--indra/newview/llagentwearables.h2
-rw-r--r--indra/newview/llappearancemgr.cpp139
-rw-r--r--indra/newview/llappearancemgr.h9
-rw-r--r--indra/newview/llappviewer.cpp1175
-rw-r--r--indra/newview/llappviewer.h27
-rw-r--r--indra/newview/llappviewerlinux.cpp8
-rw-r--r--indra/newview/llappviewermacosx.cpp2
-rw-r--r--indra/newview/llappviewerwin32.cpp12
-rw-r--r--indra/newview/llassetuploadresponders.cpp766
-rw-r--r--indra/newview/llassetuploadresponders.h53
-rw-r--r--indra/newview/llavataractions.cpp51
-rw-r--r--indra/newview/llavataractions.h2
-rw-r--r--indra/newview/llavatarlist.cpp35
-rw-r--r--indra/newview/llavatarlist.h2
-rw-r--r--indra/newview/llavatarlistitem.cpp11
-rw-r--r--indra/newview/llavatarlistitem.h4
-rw-r--r--indra/newview/llavatarpropertiesprocessor.cpp25
-rw-r--r--indra/newview/llbottomtray.cpp717
-rw-r--r--indra/newview/llbottomtray.h119
-rw-r--r--indra/newview/llbreastmotion.cpp396
-rw-r--r--indra/newview/llbreastmotion.h154
-rw-r--r--indra/newview/llbrowsernotification.cpp14
-rw-r--r--indra/newview/llbuycurrencyhtml.cpp4
-rw-r--r--indra/newview/llcallbacklist.cpp65
-rw-r--r--indra/newview/llcallbacklist.h9
-rw-r--r--indra/newview/llcallfloater.cpp21
-rw-r--r--indra/newview/llcallfloater.h1
-rw-r--r--indra/newview/llcapabilityprovider.h2
-rw-r--r--indra/newview/llchathistory.cpp94
-rw-r--r--indra/newview/llchathistory.h2
-rw-r--r--indra/newview/llchatitemscontainerctrl.cpp54
-rw-r--r--indra/newview/llchiclet.cpp15
-rw-r--r--indra/newview/llcolorswatch.cpp52
-rw-r--r--indra/newview/llcolorswatch.h4
-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/llcommandlineparser.cpp11
-rw-r--r--indra/newview/llcurrencyuimanager.cpp4
-rw-r--r--indra/newview/lldateutil.cpp4
-rw-r--r--indra/newview/lldebugview.cpp13
-rw-r--r--indra/newview/lldirpicker.cpp40
-rw-r--r--indra/newview/lldirpicker.h1
-rw-r--r--indra/newview/lldrawable.cpp221
-rw-r--r--indra/newview/lldrawable.h92
-rw-r--r--indra/newview/lldrawpool.cpp6
-rw-r--r--indra/newview/lldrawpool.h12
-rw-r--r--indra/newview/lldrawpoolalpha.cpp105
-rw-r--r--indra/newview/lldrawpoolavatar.cpp1027
-rw-r--r--indra/newview/lldrawpoolavatar.h110
-rw-r--r--indra/newview/lldrawpoolbump.cpp144
-rw-r--r--indra/newview/lldrawpoolbump.h11
-rw-r--r--indra/newview/lldrawpoolclouds.cpp3
-rw-r--r--indra/newview/lldrawpoolclouds.h1
-rw-r--r--indra/newview/lldrawpoolground.cpp6
-rw-r--r--indra/newview/lldrawpoolground.h1
-rw-r--r--indra/newview/lldrawpoolsky.cpp13
-rw-r--r--indra/newview/lldrawpoolsky.h1
-rw-r--r--indra/newview/lldrawpoolterrain.cpp21
-rw-r--r--indra/newview/lldrawpoolterrain.h1
-rw-r--r--indra/newview/lldrawpooltree.cpp77
-rw-r--r--indra/newview/lldrawpooltree.h1
-rw-r--r--indra/newview/lldrawpoolwater.cpp136
-rw-r--r--indra/newview/lldrawpoolwater.h5
-rw-r--r--indra/newview/lldrawpoolwlsky.cpp4
-rw-r--r--indra/newview/lldriverparam.h2
-rw-r--r--indra/newview/lldynamictexture.cpp10
-rw-r--r--indra/newview/lleventnotifier.h1
-rw-r--r--indra/newview/llexpandabletextbox.cpp33
-rw-r--r--indra/newview/llexpandabletextbox.h6
-rw-r--r--indra/newview/llexternaleditor.cpp208
-rw-r--r--indra/newview/llexternaleditor.h105
-rw-r--r--indra/newview/llface.cpp1281
-rw-r--r--indra/newview/llface.h52
-rw-r--r--indra/newview/llfasttimerview.cpp483
-rw-r--r--indra/newview/llfasttimerview.h4
-rw-r--r--indra/newview/llfavoritesbar.cpp51
-rw-r--r--indra/newview/llfavoritesbar.h5
-rw-r--r--indra/newview/llfeaturemanager.cpp53
-rw-r--r--indra/newview/llfilepicker.cpp170
-rw-r--r--indra/newview/llfilepicker.h10
-rw-r--r--indra/newview/llfirstuse.cpp20
-rw-r--r--indra/newview/llfirstuse.h4
-rw-r--r--indra/newview/llflexibleobject.cpp16
-rw-r--r--indra/newview/llflexibleobject.h2
-rw-r--r--indra/newview/llfloaterabout.cpp6
-rw-r--r--indra/newview/llfloateranimpreview.cpp2
-rw-r--r--indra/newview/llfloaterauction.cpp4
-rw-r--r--indra/newview/llfloaterbeacons.cpp2
-rw-r--r--indra/newview/llfloaterbump.cpp2
-rw-r--r--indra/newview/llfloaterbuycurrency.cpp6
-rw-r--r--indra/newview/llfloaterbuycurrencyhtml.cpp4
-rw-r--r--indra/newview/llfloaterbuyland.cpp14
-rw-r--r--indra/newview/llfloatercamera.cpp22
-rw-r--r--indra/newview/llfloaterchat.cpp5
-rw-r--r--indra/newview/llfloatercolorpicker.cpp19
-rw-r--r--indra/newview/llfloatercolorpicker.h1
-rw-r--r--indra/newview/llfloaterevent.cpp5
-rw-r--r--indra/newview/llfloaterevent.h1
-rw-r--r--indra/newview/llfloatergodtools.cpp18
-rw-r--r--indra/newview/llfloatergroups.cpp5
-rw-r--r--indra/newview/llfloaterhardwaresettings.cpp5
-rw-r--r--indra/newview/llfloaterhelpbrowser.cpp8
-rw-r--r--indra/newview/llfloaterimagepreview.cpp139
-rw-r--r--indra/newview/llfloaterland.cpp6
-rw-r--r--indra/newview/llfloaterland.h5
-rw-r--r--indra/newview/llfloatermap.cpp86
-rw-r--r--indra/newview/llfloatermap.h5
-rw-r--r--indra/newview/llfloatermediabrowser.cpp28
-rw-r--r--indra/newview/llfloatermodelpreview.cpp5017
-rw-r--r--indra/newview/llfloatermodelpreview.h420
-rw-r--r--indra/newview/llfloatermodelwizard.cpp679
-rw-r--r--indra/newview/llfloatermodelwizard.h113
-rw-r--r--indra/newview/llfloaternotificationsconsole.cpp1
-rw-r--r--indra/newview/llfloaterpostcard.cpp19
-rw-r--r--indra/newview/llfloaterpreference.cpp359
-rw-r--r--indra/newview/llfloaterpreference.h36
-rw-r--r--indra/newview/llfloaterregiondebugconsole.cpp224
-rw-r--r--indra/newview/llfloaterregiondebugconsole.h62
-rw-r--r--indra/newview/llfloaterregioninfo.cpp81
-rw-r--r--indra/newview/llfloaterregioninfo.h5
-rw-r--r--indra/newview/llfloatersearch.cpp9
-rw-r--r--indra/newview/llfloatersettingsdebug.cpp2
-rw-r--r--indra/newview/llfloatersidetraytab.cpp7
-rw-r--r--indra/newview/llfloatersidetraytab.h2
-rw-r--r--indra/newview/llfloatersnapshot.cpp44
-rw-r--r--indra/newview/llfloatersounddevices.cpp90
-rw-r--r--indra/newview/llfloatersounddevices.h49
-rw-r--r--indra/newview/llfloatertools.cpp170
-rw-r--r--indra/newview/llfloatertools.h2
-rw-r--r--indra/newview/llfloatertopobjects.cpp29
-rw-r--r--indra/newview/llfloatertopobjects.h5
-rw-r--r--indra/newview/llfloateruipreview.cpp241
-rw-r--r--indra/newview/llfloaterwebcontent.cpp402
-rw-r--r--indra/newview/llfloaterwebcontent.h82
-rw-r--r--indra/newview/llfloaterworldmap.cpp402
-rw-r--r--indra/newview/llfloaterworldmap.h5
-rw-r--r--indra/newview/llfolderview.cpp77
-rw-r--r--indra/newview/llfolderview.h4
-rw-r--r--indra/newview/llfolderviewitem.cpp2
-rw-r--r--indra/newview/llfolderviewitem.h1
-rw-r--r--indra/newview/llfriendcard.cpp115
-rw-r--r--indra/newview/llfriendcard.h13
-rw-r--r--indra/newview/llgesturemgr.cpp156
-rw-r--r--indra/newview/llgesturemgr.h19
-rw-r--r--indra/newview/llgiveinventory.cpp7
-rw-r--r--indra/newview/llglsandbox.cpp94
-rw-r--r--indra/newview/llgroupactions.cpp15
-rw-r--r--indra/newview/llgroupactions.h2
-rw-r--r--indra/newview/llgroupmgr.cpp1
-rw-r--r--indra/newview/llhints.cpp35
-rw-r--r--indra/newview/llhudeffectblob.cpp90
-rw-r--r--indra/newview/llhudeffectblob.h52
-rw-r--r--indra/newview/llhudeffectlookat.cpp9
-rw-r--r--indra/newview/llhudeffectpointat.cpp4
-rw-r--r--indra/newview/llhudicon.cpp47
-rw-r--r--indra/newview/llhudicon.h1
-rw-r--r--indra/newview/llhudmanager.cpp7
-rw-r--r--indra/newview/llhudnametag.cpp31
-rw-r--r--indra/newview/llhudobject.cpp25
-rw-r--r--indra/newview/llhudobject.h4
-rw-r--r--indra/newview/llhudtext.cpp28
-rw-r--r--indra/newview/llhudtext.h3
-rw-r--r--indra/newview/llimfloater.cpp20
-rw-r--r--indra/newview/llimfloater.h2
-rw-r--r--indra/newview/llimview.cpp218
-rw-r--r--indra/newview/llimview.h23
-rw-r--r--indra/newview/llinspectavatar.cpp93
-rw-r--r--indra/newview/llinspectobject.cpp3
-rw-r--r--indra/newview/llinspecttoast.cpp11
-rw-r--r--indra/newview/llinventorybridge.cpp232
-rw-r--r--indra/newview/llinventorybridge.h35
-rw-r--r--indra/newview/llinventoryfilter.cpp28
-rw-r--r--indra/newview/llinventoryfilter.h11
-rw-r--r--indra/newview/llinventoryfunctions.cpp15
-rw-r--r--indra/newview/llinventoryicon.cpp9
-rw-r--r--indra/newview/llinventoryicon.h5
-rw-r--r--indra/newview/llinventoryitemslist.h1
-rw-r--r--indra/newview/llinventorylistitem.cpp3
-rw-r--r--indra/newview/llinventorymodel.cpp31
-rw-r--r--indra/newview/llinventorymodel.h5
-rw-r--r--indra/newview/llinventorymodelbackgroundfetch.cpp12
-rw-r--r--indra/newview/llinventoryobserver.cpp15
-rw-r--r--indra/newview/llinventoryobserver.h1
-rw-r--r--indra/newview/llinventorypanel.cpp92
-rw-r--r--indra/newview/llinventorypanel.h3
-rw-r--r--indra/newview/lllistcontextmenu.cpp28
-rw-r--r--indra/newview/lllistcontextmenu.h3
-rw-r--r--indra/newview/lllocationhistory.h1
-rw-r--r--indra/newview/lllocationinputctrl.cpp5
-rw-r--r--indra/newview/lllogchat.cpp89
-rw-r--r--indra/newview/lllogchat.h4
-rw-r--r--indra/newview/lllogininstance.cpp549
-rw-r--r--indra/newview/lllogininstance.h13
-rw-r--r--indra/newview/llmainlooprepeater.cpp88
-rw-r--r--indra/newview/llmainlooprepeater.h65
-rw-r--r--indra/newview/llmaniprotate.cpp38
-rw-r--r--indra/newview/llmanipscale.cpp41
-rw-r--r--indra/newview/llmanipscale.h3
-rw-r--r--indra/newview/llmaniptranslate.cpp2
-rw-r--r--indra/newview/llmediactrl.cpp401
-rw-r--r--indra/newview/llmediactrl.h21
-rw-r--r--indra/newview/llmemoryview.cpp53
-rw-r--r--indra/newview/llmemoryview.h1
-rw-r--r--indra/newview/llmeshrepository.cpp3807
-rw-r--r--indra/newview/llmeshrepository.h551
-rw-r--r--indra/newview/llmetricperformancetester.cpp252
-rw-r--r--indra/newview/llmetricperformancetester.h153
-rw-r--r--indra/newview/llmoveview.cpp36
-rw-r--r--indra/newview/llmutelist.cpp25
-rw-r--r--indra/newview/llnamelistctrl.cpp24
-rw-r--r--indra/newview/llnamelistctrl.h18
-rw-r--r--indra/newview/llnavigationbar.cpp25
-rw-r--r--indra/newview/llnearbychat.cpp19
-rw-r--r--indra/newview/llnearbychat.h1
-rw-r--r--indra/newview/llnearbychatbar.cpp55
-rw-r--r--indra/newview/llnearbychatbar.h7
-rw-r--r--indra/newview/llnearbychathandler.cpp89
-rw-r--r--indra/newview/llnetmap.cpp161
-rw-r--r--indra/newview/llnetmap.h20
-rw-r--r--indra/newview/llnotificationhandlerutil.cpp18
-rw-r--r--indra/newview/llnotificationscripthandler.cpp2
-rw-r--r--indra/newview/lloutfitslist.cpp69
-rw-r--r--indra/newview/lloutfitslist.h4
-rw-r--r--indra/newview/lloutputmonitorctrl.h1
-rw-r--r--indra/newview/llpanelappearancetab.h2
-rw-r--r--indra/newview/llpanelavatar.cpp100
-rw-r--r--indra/newview/llpanelavatar.h8
-rw-r--r--indra/newview/llpaneleditwearable.cpp2319
-rw-r--r--indra/newview/llpaneleditwearable.h11
-rw-r--r--indra/newview/llpanelface.cpp11
-rw-r--r--indra/newview/llpanelgroupgeneral.cpp4
-rw-r--r--indra/newview/llpanelgroupnotices.cpp1
-rw-r--r--indra/newview/llpanelgrouproles.cpp133
-rw-r--r--indra/newview/llpanelgrouproles.h8
-rw-r--r--indra/newview/llpanellandaudio.cpp15
-rw-r--r--indra/newview/llpanellandmarkinfo.cpp6
-rw-r--r--indra/newview/llpanellandmarks.cpp108
-rw-r--r--indra/newview/llpanellandmarks.h15
-rw-r--r--indra/newview/llpanellandmedia.cpp27
-rw-r--r--indra/newview/llpanellogin.cpp454
-rw-r--r--indra/newview/llpanellogin.h6
-rw-r--r--indra/newview/llpanelmaininventory.cpp164
-rw-r--r--indra/newview/llpanelmaininventory.h8
-rw-r--r--indra/newview/llpanelme.cpp48
-rw-r--r--indra/newview/llpanelme.h1
-rw-r--r--indra/newview/llpanelnearbymedia.cpp29
-rw-r--r--indra/newview/llpanelobject.cpp71
-rw-r--r--indra/newview/llpanelobject.h5
-rw-r--r--indra/newview/llpanelobjectinventory.cpp136
-rw-r--r--indra/newview/llpaneloutfitedit.cpp74
-rw-r--r--indra/newview/llpaneloutfitedit.h12
-rw-r--r--indra/newview/llpaneloutfitsinventory.cpp20
-rw-r--r--indra/newview/llpaneloutfitsinventory.h1
-rw-r--r--indra/newview/llpanelpeople.cpp156
-rw-r--r--indra/newview/llpanelpeople.h12
-rw-r--r--indra/newview/llpanelpick.cpp3
-rw-r--r--indra/newview/llpanelpicks.cpp236
-rw-r--r--indra/newview/llpanelpicks.h5
-rw-r--r--indra/newview/llpanelplaceinfo.cpp4
-rw-r--r--indra/newview/llpanelplaces.cpp49
-rw-r--r--indra/newview/llpanelplaces.h4
-rw-r--r--indra/newview/llpanelprimmediacontrols.cpp126
-rw-r--r--indra/newview/llpanelprimmediacontrols.h16
-rw-r--r--indra/newview/llpanelprofile.cpp217
-rw-r--r--indra/newview/llpanelprofile.h32
-rw-r--r--indra/newview/llpanelteleporthistory.cpp39
-rw-r--r--indra/newview/llpanelteleporthistory.h3
-rw-r--r--indra/newview/llpaneltopinfobar.cpp9
-rw-r--r--indra/newview/llpanelvoicedevicesettings.cpp55
-rw-r--r--indra/newview/llpanelvoicedevicesettings.h3
-rw-r--r--indra/newview/llpanelvolume.cpp134
-rw-r--r--indra/newview/llpanelvolume.h15
-rw-r--r--indra/newview/llpanelwearing.cpp31
-rw-r--r--indra/newview/llpanelwearing.h2
-rw-r--r--indra/newview/llparticipantlist.cpp99
-rw-r--r--indra/newview/llparticipantlist.h431
-rw-r--r--indra/newview/llphysicsmotion.cpp732
-rw-r--r--indra/newview/llphysicsmotion.h118
-rw-r--r--indra/newview/llphysicsshapebuilderutil.cpp210
-rw-r--r--indra/newview/llphysicsshapebuilderutil.h138
-rw-r--r--indra/newview/llplacesinventorypanel.cpp18
-rw-r--r--indra/newview/llplacesinventorypanel.h6
-rw-r--r--indra/newview/llpolymesh.cpp1708
-rw-r--r--indra/newview/llpolymesh.h12
-rw-r--r--indra/newview/llpolymorph.cpp70
-rw-r--r--indra/newview/llpolymorph.h1
-rw-r--r--indra/newview/llpopupview.cpp73
-rw-r--r--indra/newview/llpopupview.h2
-rw-r--r--indra/newview/llpreview.cpp3
-rw-r--r--indra/newview/llpreviewgesture.cpp3
-rw-r--r--indra/newview/llpreviewscript.cpp313
-rw-r--r--indra/newview/llpreviewscript.h44
-rw-r--r--indra/newview/llpreviewtexture.cpp103
-rw-r--r--indra/newview/llprogressview.cpp6
-rw-r--r--indra/newview/llrecentpeople.cpp58
-rw-r--r--indra/newview/llrecentpeople.h33
-rw-r--r--indra/newview/llremoteparcelrequest.cpp72
-rw-r--r--indra/newview/llremoteparcelrequest.h2
-rw-r--r--indra/newview/llrootview.h22
-rw-r--r--indra/newview/llsceneview.cpp429
-rw-r--r--indra/newview/llsceneview.h48
-rw-r--r--indra/newview/llscreenchannel.cpp72
-rw-r--r--indra/newview/llscreenchannel.h11
-rw-r--r--indra/newview/llscriptfloater.cpp46
-rw-r--r--indra/newview/llscriptfloater.h7
-rw-r--r--indra/newview/llscrollingpanelparam.cpp62
-rw-r--r--indra/newview/llscrollingpanelparam.h11
-rw-r--r--indra/newview/llscrollingpanelparambase.cpp112
-rw-r--r--indra/newview/llscrollingpanelparambase.h62
-rw-r--r--indra/newview/llsearchcombobox.cpp3
-rw-r--r--indra/newview/llselectmgr.cpp649
-rw-r--r--indra/newview/llselectmgr.h29
-rw-r--r--indra/newview/llshareavatarhandler.cpp67
-rw-r--r--indra/newview/llsidepanelappearance.cpp54
-rw-r--r--indra/newview/llsidepanelappearance.h6
-rw-r--r--indra/newview/llsidepaneliteminfo.cpp29
-rw-r--r--indra/newview/llsidepaneliteminfo.h3
-rw-r--r--indra/newview/llsidepaneltaskinfo.cpp12
-rw-r--r--indra/newview/llsidetray.cpp299
-rw-r--r--indra/newview/llsidetray.h60
-rw-r--r--indra/newview/llsidetraylistener.cpp179
-rw-r--r--indra/newview/llsidetraylistener.h53
-rw-r--r--indra/newview/llsimplestat.h152
-rw-r--r--indra/newview/llspatialpartition.cpp1695
-rw-r--r--indra/newview/llspatialpartition.h114
-rw-r--r--indra/newview/llspeakbutton.cpp29
-rw-r--r--indra/newview/llspeakbutton.h5
-rw-r--r--indra/newview/llspeakers.cpp2
-rw-r--r--indra/newview/llspeakingindicatormanager.cpp5
-rw-r--r--indra/newview/llsprite.cpp9
-rw-r--r--indra/newview/llstartup.cpp246
-rw-r--r--indra/newview/llstartup.h1
-rw-r--r--indra/newview/llstatusbar.cpp18
-rw-r--r--indra/newview/llstatusbar.h2
-rw-r--r--indra/newview/llsurface.cpp10
-rw-r--r--indra/newview/llsurfacepatch.cpp6
-rw-r--r--indra/newview/llsyswellwindow.cpp2
-rw-r--r--indra/newview/lltexturecache.cpp46
-rw-r--r--indra/newview/lltexturectrl.cpp30
-rw-r--r--indra/newview/lltexturefetch.cpp694
-rw-r--r--indra/newview/lltexturefetch.h92
-rw-r--r--indra/newview/lltexturestats.cpp2
-rw-r--r--indra/newview/lltextureview.cpp8
-rw-r--r--indra/newview/lltoast.cpp165
-rw-r--r--indra/newview/lltoast.h50
-rw-r--r--indra/newview/lltoastalertpanel.cpp5
-rw-r--r--indra/newview/lltoastgroupnotifypanel.cpp3
-rw-r--r--indra/newview/lltoastnotifypanel.cpp27
-rw-r--r--indra/newview/lltoastscripttextbox.cpp121
-rw-r--r--indra/newview/lltoastscripttextbox.h59
-rw-r--r--indra/newview/lltool.cpp8
-rw-r--r--indra/newview/lltooldraganddrop.cpp300
-rw-r--r--indra/newview/lltooldraganddrop.h12
-rw-r--r--indra/newview/lltoolmorph.cpp4
-rw-r--r--indra/newview/lltoolmorph.h2
-rw-r--r--indra/newview/lltoolpie.cpp487
-rw-r--r--indra/newview/lltoolpie.h31
-rw-r--r--indra/newview/lltracker.cpp4
-rw-r--r--indra/newview/lltracker.h2
-rw-r--r--indra/newview/lltransientfloatermgr.cpp7
-rw-r--r--indra/newview/lltranslate.cpp62
-rw-r--r--indra/newview/lltranslate.h48
-rw-r--r--indra/newview/lluilistener.cpp28
-rw-r--r--indra/newview/lluilistener.h1
-rw-r--r--indra/newview/llurldispatcher.cpp27
-rw-r--r--indra/newview/llurldispatcher.h3
-rw-r--r--indra/newview/llurldispatcherlistener.cpp2
-rw-r--r--indra/newview/llversioninfo.cpp37
-rw-r--r--indra/newview/llversioninfo.h7
-rw-r--r--indra/newview/llviewerassetstats.cpp612
-rw-r--r--indra/newview/llviewerassetstats.h328
-rw-r--r--indra/newview/llviewerassetstorage.cpp129
-rw-r--r--indra/newview/llviewerassetstorage.h11
-rw-r--r--indra/newview/llviewerassettype.cpp2
-rw-r--r--indra/newview/llviewercamera.cpp21
-rw-r--r--indra/newview/llviewerchat.cpp68
-rw-r--r--indra/newview/llviewerchat.h10
-rw-r--r--indra/newview/llviewercontrol.cpp111
-rw-r--r--indra/newview/llviewercontrol.h2
-rw-r--r--indra/newview/llviewerdisplay.cpp111
-rw-r--r--indra/newview/llviewerdisplay.h1
-rw-r--r--indra/newview/llviewerfloaterreg.cpp37
-rw-r--r--indra/newview/llviewerfoldertype.cpp3
-rw-r--r--indra/newview/llviewerinventory.cpp152
-rw-r--r--indra/newview/llviewerinventory.h1
-rw-r--r--indra/newview/llviewerjoint.cpp2
-rw-r--r--indra/newview/llviewerjointmesh.cpp320
-rw-r--r--indra/newview/llviewerjointmesh_sse.cpp6
-rw-r--r--indra/newview/llviewerjointmesh_sse2.cpp6
-rw-r--r--indra/newview/llviewerjointmesh_vec.cpp2
-rw-r--r--indra/newview/llviewerjoystick.cpp2
-rw-r--r--indra/newview/llviewerkeyboard.cpp183
-rw-r--r--indra/newview/llviewerkeyboard.h38
-rw-r--r--indra/newview/llviewermedia.cpp216
-rw-r--r--indra/newview/llviewermedia.h16
-rw-r--r--indra/newview/llviewermediafocus.cpp12
-rw-r--r--indra/newview/llviewermenu.cpp500
-rw-r--r--indra/newview/llviewermenu.h2
-rw-r--r--indra/newview/llviewermenufile.cpp559
-rw-r--r--indra/newview/llviewermenufile.h135
-rw-r--r--indra/newview/llviewermessage.cpp200
-rw-r--r--indra/newview/llviewermessage.h1
-rw-r--r--indra/newview/llviewernetwork.cpp4
-rw-r--r--indra/newview/llviewerobject.cpp591
-rw-r--r--indra/newview/llviewerobject.h114
-rw-r--r--indra/newview/llviewerobjectlist.cpp623
-rw-r--r--indra/newview/llviewerobjectlist.h32
-rw-r--r--indra/newview/llviewerparcelmedia.cpp18
-rw-r--r--indra/newview/llviewerparcelmgr.cpp17
-rw-r--r--indra/newview/llviewerparceloverlay.cpp33
-rw-r--r--indra/newview/llviewerparceloverlay.h7
-rw-r--r--indra/newview/llviewerpartsim.cpp4
-rw-r--r--indra/newview/llviewerprecompiledheaders.h11
-rw-r--r--indra/newview/llviewerregion.cpp428
-rw-r--r--indra/newview/llviewerregion.h110
-rw-r--r--indra/newview/llviewershadermgr.cpp353
-rw-r--r--indra/newview/llviewershadermgr.h17
-rw-r--r--indra/newview/llviewerstats.cpp11
-rw-r--r--indra/newview/llviewerstats.h33
-rw-r--r--indra/newview/llviewerstatsrecorder.cpp258
-rw-r--r--indra/newview/llviewerstatsrecorder.h97
-rw-r--r--indra/newview/llviewertexteditor.cpp24
-rw-r--r--indra/newview/llviewertexture.cpp288
-rw-r--r--indra/newview/llviewertexture.h11
-rw-r--r--indra/newview/llviewertexturelist.cpp294
-rw-r--r--indra/newview/llviewertexturelist.h21
-rw-r--r--indra/newview/llviewerthrottle.cpp2
-rw-r--r--indra/newview/llviewerwindow.cpp696
-rw-r--r--indra/newview/llviewerwindow.h28
-rw-r--r--indra/newview/llviewerwindowlistener.cpp8
-rw-r--r--indra/newview/llvoavatar.cpp564
-rw-r--r--indra/newview/llvoavatar.h39
-rw-r--r--indra/newview/llvoavatarself.cpp59
-rw-r--r--indra/newview/llvoavatarself.h6
-rw-r--r--indra/newview/llvocache.cpp413
-rw-r--r--indra/newview/llvocache.h18
-rw-r--r--indra/newview/llvograss.cpp15
-rw-r--r--indra/newview/llvoground.cpp9
-rw-r--r--indra/newview/llvoicecallhandler.cpp69
-rw-r--r--indra/newview/llvoicechannel.cpp34
-rw-r--r--indra/newview/llvoicechannel.h7
-rw-r--r--indra/newview/llvoiceclient.cpp138
-rw-r--r--indra/newview/llvoiceclient.h34
-rw-r--r--indra/newview/llvoicevivox.cpp188
-rw-r--r--indra/newview/llvoicevivox.h32
-rw-r--r--indra/newview/llvopartgroup.cpp14
-rw-r--r--indra/newview/llvopartgroup.h2
-rw-r--r--indra/newview/llvosky.cpp83
-rw-r--r--indra/newview/llvosky.h44
-rw-r--r--indra/newview/llvosurfacepatch.cpp99
-rw-r--r--indra/newview/llvosurfacepatch.h2
-rw-r--r--indra/newview/llvotextbubble.cpp33
-rw-r--r--indra/newview/llvotree.cpp44
-rw-r--r--indra/newview/llvotree.h2
-rw-r--r--indra/newview/llvovolume.cpp972
-rw-r--r--indra/newview/llvovolume.h54
-rw-r--r--indra/newview/llvowater.cpp66
-rw-r--r--indra/newview/llvowater.h16
-rw-r--r--indra/newview/llvowlsky.cpp2
-rw-r--r--indra/newview/llwaterparammanager.cpp44
-rw-r--r--indra/newview/llwaterparammanager.h6
-rw-r--r--indra/newview/llwearableitemslist.cpp9
-rw-r--r--indra/newview/llwearableitemslist.h1
-rw-r--r--indra/newview/llwearabletype.cpp83
-rw-r--r--indra/newview/llwearabletype.h5
-rw-r--r--indra/newview/llweb.cpp32
-rw-r--r--indra/newview/llweb.h5
-rw-r--r--indra/newview/llwlparammanager.cpp11
-rw-r--r--indra/newview/llworld.cpp105
-rw-r--r--indra/newview/llworld.h3
-rw-r--r--indra/newview/llworldmapview.cpp8
-rw-r--r--indra/newview/llworldmipmap.cpp3
-rw-r--r--indra/newview/llxmlrpclistener.cpp7
-rw-r--r--indra/newview/pipeline.cpp2335
-rw-r--r--indra/newview/pipeline.h49
-rw-r--r--indra/newview/res/resource.h1
-rw-r--r--indra/newview/res/toolbuy.curbin4286 -> 4286 bytes
-rw-r--r--indra/newview/res/toolopen.curbin4286 -> 4286 bytes
-rw-r--r--indra/newview/res/toolsit.curbin4286 -> 4286 bytes
-rw-r--r--indra/newview/res/viewerRes.rc4
-rw-r--r--indra/newview/skins/default/colors.xml43
-rw-r--r--indra/newview/skins/default/textures/arrow_keys.pngbin0 -> 6558 bytes
-rw-r--r--indra/newview/skins/default/textures/bottomtray/ChatBarHandle.pngbin0 -> 2808 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Edit_Wrench.pngbin3713 -> 3000 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Inv_Mesh.pngbin0 -> 3263 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Inv_Physics.pngbin0 -> 539 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Web_Profile_Off.pngbin0 -> 2961 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/check_mark.pngbin0 -> 3166 bytes
-rw-r--r--indra/newview/skins/default/textures/model_wizard/divider_line.pngbin0 -> 2815 bytes
-rw-r--r--indra/newview/skins/default/textures/model_wizard/progress_bar_bg.pngbin0 -> 3180 bytes
-rw-r--r--indra/newview/skins/default/textures/model_wizard/progress_light.pngbin0 -> 2979 bytes
-rw-r--r--indra/newview/skins/default/textures/textures.xml41
-rw-r--r--indra/newview/skins/default/textures/widgets/BreadCrumbBtn_Left_Disabled.pngbin0 -> 3576 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/BreadCrumbBtn_Left_Off.pngbin0 -> 4309 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/BreadCrumbBtn_Left_Over.pngbin0 -> 4272 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/BreadCrumbBtn_Left_Press.pngbin0 -> 4278 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/BreadCrumbBtn_Middle_Disabled.pngbin0 -> 3425 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/BreadCrumbBtn_Middle_Off.pngbin0 -> 4151 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/BreadCrumbBtn_Middle_Over.pngbin0 -> 4137 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/BreadCrumbBtn_Middle_Press.pngbin0 -> 4200 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/BreadCrumbBtn_Right_Disabled.pngbin0 -> 3169 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/BreadCrumbBtn_Right_Off.pngbin0 -> 3845 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/BreadCrumbBtn_Right_Over.pngbin0 -> 3867 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/BreadCrumbBtn_Right_Press.pngbin0 -> 3915 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/ProgressBar.pngbin220 -> 316 bytes
-rw-r--r--indra/newview/skins/default/textures/world/CameraDragDot.pngbin0 -> 3101 bytes
-rw-r--r--indra/newview/skins/default/xui/en/floater_about.xml7
-rw-r--r--indra/newview/skins/default/xui/en/floater_import_collada.xml42
-rw-r--r--indra/newview/skins/default/xui/en/floater_inventory_view_finder.xml29
-rw-r--r--indra/newview/skins/default/xui/en/floater_model_preview.xml547
-rw-r--r--indra/newview/skins/default/xui/en/floater_model_wizard.xml1039
-rw-r--r--indra/newview/skins/default/xui/en/floater_postcard.xml1
-rw-r--r--indra/newview/skins/default/xui/en/floater_price_for_listing.xml81
-rw-r--r--indra/newview/skins/default/xui/en/floater_script_debug_panel.xml1
-rw-r--r--indra/newview/skins/default/xui/en/floater_sound_devices.xml21
-rw-r--r--indra/newview/skins/default/xui/en/floater_tools.xml223
-rw-r--r--indra/newview/skins/default/xui/en/menu_inventory_add.xml14
-rw-r--r--indra/newview/skins/default/xui/en/menu_model_import_gear_default.xml79
-rw-r--r--indra/newview/skins/default/xui/en/menu_viewer.xml121
-rw-r--r--indra/newview/skins/default/xui/en/notifications.xml26
-rw-r--r--indra/newview/skins/default/xui/en/panel_place_profile.xml2
-rw-r--r--indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml28
-rw-r--r--indra/newview/skins/default/xui/en/panel_region_general.xml15
-rw-r--r--indra/newview/skins/default/xui/en/panel_sound_devices.xml8
-rw-r--r--indra/newview/skins/default/xui/en/strings.xml79
-rw-r--r--indra/newview/skins/minimal/colors.xml6
-rw-r--r--indra/newview/skins/minimal/textures/arrow_keys.pngbin0 -> 6558 bytes
-rw-r--r--indra/newview/skins/minimal/textures/bottomtray/Speak_Btn_Off.pngbin0 -> 993 bytes
-rw-r--r--indra/newview/skins/minimal/textures/bottomtray/Speak_Btn_Selected_Press.pngbin0 -> 1217 bytes
-rw-r--r--indra/newview/skins/minimal/textures/bottomtray/button_separator.pngbin0 -> 153 bytes
-rw-r--r--indra/newview/skins/minimal/textures/bottomtray/close_off.pngbin0 -> 3184 bytes
-rw-r--r--indra/newview/skins/minimal/textures/bottomtray/close_over.pngbin0 -> 3173 bytes
-rw-r--r--indra/newview/skins/minimal/textures/bottomtray/close_press.pngbin0 -> 3259 bytes
-rw-r--r--indra/newview/skins/minimal/textures/click_to_move.pngbin0 -> 8188 bytes
-rw-r--r--indra/newview/skins/minimal/textures/textures.xml11
-rw-r--r--indra/newview/skins/minimal/xui/en/main_view.xml15
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_attachment_other.xml8
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_avatar_other.xml8
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_inspect_avatar_gear.xml9
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_people_nearby.xml10
-rw-r--r--indra/newview/skins/minimal/xui/en/notification_visibility.xml4
-rw-r--r--indra/newview/skins/minimal/xui/en/panel_adhoc_control_panel.xml35
-rw-r--r--indra/newview/skins/minimal/xui/en/panel_bottomtray.xml122
-rw-r--r--indra/newview/skins/minimal/xui/en/panel_im_control_panel.xml33
-rw-r--r--indra/newview/skins/minimal/xui/en/panel_people.xml21
-rw-r--r--indra/newview/tests/gpus_results.txt1595
-rw-r--r--indra/newview/tests/gpus_seen.txt1593
-rw-r--r--indra/newview/tests/llcapabilitylistener_test.cpp3
-rw-r--r--indra/newview/tests/lllogininstance_test.cpp56
-rw-r--r--indra/newview/tests/llremoteparcelrequest_test.cpp134
-rw-r--r--indra/newview/tests/llsimplestat_test.cpp580
-rw-r--r--indra/newview/tests/llversioninfo_test.cpp114
-rw-r--r--indra/newview/tests/llviewerassetstats_test.cpp984
-rw-r--r--indra/newview/tests/llviewerhelputil_test.cpp15
-rw-r--r--indra/newview/tests/llworldmap_test.cpp42
-rw-r--r--indra/newview/tests/llworldmipmap_test.cpp27
-rw-r--r--indra/newview/tests/llxmlrpclistener_test.cpp11
-rw-r--r--indra/newview/tests/test_llxmlrpc_peer.py23
-rw-r--r--indra/newview/viewer_manifest.py301
-rw-r--r--indra/test/CMakeLists.txt1
-rw-r--r--indra/test/test_llmanifest.py2
-rw-r--r--indra/test_apps/llplugintest/CMakeLists.txt17
-rw-r--r--indra/test_apps/llplugintest/llmediaplugintest.cpp31
-rw-r--r--indra/tools/vstool/VSTool.csproj5
-rwxr-xr-xindra/tools/vstool/VSTool.exebin24576 -> 24576 bytes
-rw-r--r--indra/tools/vstool/VSTool.sln4
-rw-r--r--indra/tools/vstool/main.cs10
-rw-r--r--indra/viewer_components/CMakeLists.txt2
-rw-r--r--indra/viewer_components/login/CMakeLists.txt9
-rw-r--r--indra/viewer_components/updater/CMakeLists.txt82
-rw-r--r--indra/viewer_components/updater/llupdatechecker.cpp194
-rw-r--r--indra/viewer_components/updater/llupdatechecker.h82
-rw-r--r--indra/viewer_components/updater/llupdatedownloader.cpp517
-rw-r--r--indra/viewer_components/updater/llupdatedownloader.h94
-rw-r--r--indra/viewer_components/updater/llupdateinstaller.cpp100
-rw-r--r--indra/viewer_components/updater/llupdateinstaller.h58
-rw-r--r--indra/viewer_components/updater/llupdaterservice.cpp621
-rw-r--r--indra/viewer_components/updater/llupdaterservice.h108
-rw-r--r--indra/viewer_components/updater/scripts/darwin/update_install10
-rw-r--r--indra/viewer_components/updater/scripts/linux/update_install10
-rw-r--r--indra/viewer_components/updater/scripts/windows/update_install.bat3
-rw-r--r--indra/viewer_components/updater/tests/llupdaterservice_test.cpp194
-rw-r--r--indra/win_crash_logger/llcrashloggerwindows.cpp1
1209 files changed, 91141 insertions, 28964 deletions
diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt
index 8d4969a49e..d1042d6e86 100644
--- a/indra/CMakeLists.txt
+++ b/indra/CMakeLists.txt
@@ -22,7 +22,10 @@ set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
include(Variables)
if (DARWIN)
- cmake_minimum_required(VERSION 2.6.2 FATAL_ERROR)
+ # 2.6.4 fixes a Mac bug in get_target_property(... "SLPlugin" LOCATION):
+ # before that version it returns "pathname/SLPlugin", whereas the correct
+ # answer is "pathname/SLPlugin.app/Contents/MacOS/SLPlugin".
+ cmake_minimum_required(VERSION 2.6.4 FATAL_ERROR)
endif (DARWIN)
if (NOT CMAKE_BUILD_TYPE)
@@ -32,14 +35,17 @@ endif (NOT CMAKE_BUILD_TYPE)
# For the library installation process;
# see cmake/Prebuild.cmake for the counterpart code.
-file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/temp)
-file(WRITE ${CMAKE_BINARY_DIR}/temp/sentinel_installed "0")
+if ("${CMAKE_SOURCE_DIR}/../autobuild.xml" IS_NEWER_THAN "${CMAKE_BINARY_DIR}/temp/sentinel_installed")
+ file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/temp)
+ file(WRITE ${CMAKE_BINARY_DIR}/temp/sentinel_installed "0")
+endif ("${CMAKE_SOURCE_DIR}/../autobuild.xml" IS_NEWER_THAN "${CMAKE_BINARY_DIR}/temp/sentinel_installed")
add_subdirectory(cmake)
add_subdirectory(${LIBS_OPEN_PREFIX}llaudio)
add_subdirectory(${LIBS_OPEN_PREFIX}llcharacter)
add_subdirectory(${LIBS_OPEN_PREFIX}llcommon)
add_subdirectory(${LIBS_OPEN_PREFIX}llimage)
+add_subdirectory(${LIBS_OPEN_PREFIX}llkdu)
add_subdirectory(${LIBS_OPEN_PREFIX}llimagej2coj)
add_subdirectory(${LIBS_OPEN_PREFIX}llinventory)
add_subdirectory(${LIBS_OPEN_PREFIX}llmath)
@@ -50,10 +56,6 @@ add_subdirectory(${LIBS_OPEN_PREFIX}llvfs)
add_subdirectory(${LIBS_OPEN_PREFIX}llwindow)
add_subdirectory(${LIBS_OPEN_PREFIX}llxml)
-if (EXISTS ${LIBS_CLOSED_DIR}llkdu)
- add_subdirectory(${LIBS_CLOSED_PREFIX}llkdu)
-endif (EXISTS ${LIBS_CLOSED_DIR}llkdu)
-
add_subdirectory(${LIBS_OPEN_PREFIX}lscript)
if (WINDOWS AND EXISTS ${LIBS_CLOSED_DIR}copy_win_scripts)
@@ -72,9 +74,9 @@ if (VIEWER)
add_subdirectory(${LIBS_OPEN_PREFIX}media_plugins)
# llplugin testbed code (is this the right way to include it?)
- if (NOT LINUX)
+ if (LL_TESTS AND NOT LINUX)
add_subdirectory(${VIEWER_PREFIX}test_apps/llplugintest)
- endif (NOT LINUX)
+ endif (LL_TESTS AND NOT LINUX)
if (LINUX)
add_subdirectory(${VIEWER_PREFIX}linux_crash_logger)
@@ -103,7 +105,7 @@ if (VIEWER)
endif (VIEWER)
# Linux builds the viewer and server in 2 separate projects
-# In order for ./develop.py build server to work on linux,
+# In order for build server to work on linux,
# the viewer project needs a server target.
# This is not true for mac and windows.
if (LINUX)
diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake
index a114d6e778..2c974fb4ff 100644
--- a/indra/cmake/00-Common.cmake
+++ b/indra/cmake/00-Common.cmake
@@ -4,27 +4,28 @@
include(Variables)
-
# Portable compilation flags.
-
-if (EXISTS ${CMAKE_SOURCE_DIR}/llphysics)
- # The release build should only offer to send crash reports if we're
- # building from a Linden internal source tree.
- set(release_crash_reports 1)
-else (EXISTS ${CMAKE_SOURCE_DIR}/llphysics)
- set(release_crash_reports 0)
-endif (EXISTS ${CMAKE_SOURCE_DIR}/llphysics)
-
set(CMAKE_CXX_FLAGS_DEBUG "-D_DEBUG -DLL_DEBUG=1")
set(CMAKE_CXX_FLAGS_RELEASE
- "-DLL_RELEASE=1 -DLL_RELEASE_FOR_DOWNLOAD=1 -D_SECURE_SCL=0 -DLL_SEND_CRASH_REPORTS=${release_crash_reports} -DNDEBUG")
+ "-DLL_RELEASE=1 -DLL_RELEASE_FOR_DOWNLOAD=1 -DNDEBUG")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO
- "-DLL_RELEASE=1 -D_SECURE_SCL=0 -DLL_SEND_CRASH_REPORTS=0 -DNDEBUG -DLL_RELEASE_WITH_DEBUG_INFO=1")
+ "-DLL_RELEASE=1 -DNDEBUG -DLL_RELEASE_WITH_DEBUG_INFO=1")
+# Configure crash reporting
+set(RELEASE_CRASH_REPORTING OFF CACHE BOOL "Enable use of crash reporting in release builds")
+set(NON_RELEASE_CRASH_REPORTING OFF CACHE BOOL "Enable use of crash reporting in developer builds")
-# Don't bother with a MinSizeRel build.
+if(RELEASE_CRASH_REPORTING)
+ set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DLL_SEND_CRASH_REPORTS=1")
+endif()
+
+if(NON_RELEASE_CRASH_REPORTING)
+ set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -DLL_SEND_CRASH_REPORTS=1")
+ set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DLL_SEND_CRASH_REPORTS=1")
+endif()
+# Don't bother with a MinSizeRel build.
set(CMAKE_CONFIGURATION_TYPES "RelWithDebInfo;Release;Debug" CACHE STRING
"Supported build types." FORCE)
@@ -35,13 +36,20 @@ if (WINDOWS)
# Don't build DLLs.
set(BUILD_SHARED_LIBS OFF)
- set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /Od /Zi /MDd /MP"
+ # for "backwards compatibility", cmake sneaks in the Zm1000 option which royally
+ # screws incredibuild. this hack disables it.
+ # for details see: http://connect.microsoft.com/VisualStudio/feedback/details/368107/clxx-fatal-error-c1027-inconsistent-values-for-ym-between-creation-and-use-of-precompiled-headers
+ # http://www.ogre3d.org/forums/viewtopic.php?f=2&t=60015
+ # http://www.cmake.org/pipermail/cmake/2009-September/032143.html
+ string(REPLACE "/Zm1000" " " CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
+
+ set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /Od /Zi /MDd /MP -D_SCL_SECURE_NO_WARNINGS=1"
CACHE STRING "C++ compiler debug options" FORCE)
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO
- "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Od /Zi /MD /MP"
+ "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Od /Zi /MD /MP /Ob2 -D_SECURE_STL=0"
CACHE STRING "C++ compiler release-with-debug options" FORCE)
set(CMAKE_CXX_FLAGS_RELEASE
- "${CMAKE_CXX_FLAGS_RELEASE} ${LL_CXX_FLAGS} /O2 /Zi /MD /MP"
+ "${CMAKE_CXX_FLAGS_RELEASE} ${LL_CXX_FLAGS} /O2 /Zi /MD /MP /Ob2 -D_SECURE_STL=0 -D_HAS_ITERATOR_DEBUGGING=0"
CACHE STRING "C++ compiler release options" FORCE)
set(CMAKE_CXX_STANDARD_LIBRARIES "")
@@ -49,27 +57,20 @@ if (WINDOWS)
add_definitions(
/DLL_WINDOWS=1
+ /DDOM_DYNAMIC
/DUNICODE
/D_UNICODE
/GS
/TP
- /W3
+ /W2
/c
/Zc:forScope
/nologo
/Oy-
- )
-
- if(MSVC80 OR MSVC90)
- set(CMAKE_CXX_FLAGS_RELEASE
- "${CMAKE_CXX_FLAGS_RELEASE} -D_SECURE_STL=0 -D_HAS_ITERATOR_DEBUGGING=0"
- CACHE STRING "C++ compiler release options" FORCE)
-
- add_definitions(
/Zc:wchar_t-
+ /arch:SSE2
)
- endif (MSVC80 OR MSVC90)
-
+
# Are we using the crummy Visual Studio KDU build workaround?
if (NOT VS_DISABLE_FATAL_WARNINGS)
add_definitions(/WX)
@@ -142,6 +143,8 @@ if (LINUX)
-fno-strict-aliasing
-fsigned-char
-g
+ -msse2
+ -mfpmath=sse
-pthread
)
@@ -161,10 +164,6 @@ if (LINUX)
link_directories(/usr/lib/mysql4/mysql)
endif (EXISTS /usr/lib/mysql4/mysql)
- add_definitions(
- -msse2
- -mfpmath=sse
- )
endif (SERVER)
if (VIEWER)
@@ -172,6 +171,8 @@ if (LINUX)
add_definitions(-fvisibility=hidden)
# don't catch SIGCHLD in our base application class for the viewer - some of our 3rd party libs may need their *own* SIGCHLD handler to work. Sigh! The viewer doesn't need to catch SIGCHLD anyway.
add_definitions(-DLL_IGNORE_SIGCHLD)
+ add_definitions(-march=pentium4 -mfpmath=sse)
+ #add_definitions(-ftree-vectorize) # THIS CRASHES GCC 3.1-3.2
if (NOT STANDALONE)
# this stops us requiring a really recent glibc at runtime
add_definitions(-fno-stack-protector)
@@ -211,7 +212,7 @@ if (LINUX OR DARWIN)
set(GCC_WARNINGS "${GCC_WARNINGS} -Werror")
endif (NOT GCC_DISABLE_FATAL_WARNINGS)
- set(GCC_CXX_WARNINGS "${GCC_WARNINGS} -Wno-reorder -Wno-non-virtual-dtor -Woverloaded-virtual")
+ set(GCC_CXX_WARNINGS "${GCC_WARNINGS} -Wno-reorder -Wno-non-virtual-dtor")
set(CMAKE_C_FLAGS "${GCC_WARNINGS} ${CMAKE_C_FLAGS}")
set(CMAKE_CXX_FLAGS "${GCC_CXX_WARNINGS} ${CMAKE_CXX_FLAGS}")
diff --git a/indra/cmake/APR.cmake b/indra/cmake/APR.cmake
index 180504d286..daafa00fe2 100644
--- a/indra/cmake/APR.cmake
+++ b/indra/cmake/APR.cmake
@@ -32,27 +32,21 @@ else (STANDALONE)
)
elseif (DARWIN)
if (LLCOMMON_LINK_SHARED)
- set(APR_selector "0.3.7.dylib")
- set(APRUTIL_selector "0.3.8.dylib")
+ set(APR_selector "0.dylib")
+ set(APRUTIL_selector "0.dylib")
else (LLCOMMON_LINK_SHARED)
set(APR_selector "a")
set(APRUTIL_selector "a")
endif (LLCOMMON_LINK_SHARED)
- set(APR_LIBRARIES
- debug ${ARCH_PREBUILT_DIRS_DEBUG}/libapr-1.${APR_selector}
- optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libapr-1.${APR_selector}
- )
- set(APRUTIL_LIBRARIES
- debug ${ARCH_PREBUILT_DIRS_DEBUG}/libaprutil-1.${APRUTIL_selector}
- optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libaprutil-1.${APRUTIL_selector}
- )
+ set(APR_LIBRARIES libapr-1.${APR_selector})
+ set(APRUTIL_LIBRARIES libaprutil-1.${APRUTIL_selector})
set(APRICONV_LIBRARIES iconv)
else (WINDOWS)
set(APR_LIBRARIES apr-1)
set(APRUTIL_LIBRARIES aprutil-1)
set(APRICONV_LIBRARIES iconv)
endif (WINDOWS)
- set(APR_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/apr-1)
+ set(APR_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/apr-1)
if (LINUX)
if (VIEWER)
diff --git a/indra/cmake/BerkeleyDB.cmake b/indra/cmake/BerkeleyDB.cmake
index d98e79179d..57b53f46ff 100644
--- a/indra/cmake/BerkeleyDB.cmake
+++ b/indra/cmake/BerkeleyDB.cmake
@@ -6,6 +6,12 @@ set(DB_FIND_REQUIRED ON)
if (STANDALONE)
include(FindBerkeleyDB)
else (STANDALONE)
- set(DB_LIBRARIES db-4.2)
+ if (LINUX)
+ # Need to add dependency pthread explicitely to support ld.gold.
+ use_prebuilt_binary(db)
+ set(DB_LIBRARIES db-5.1 pthread)
+ else (LINUX)
+ set(DB_LIBRARIES db-4.2)
+ endif (LINUX)
set(DB_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include)
endif (STANDALONE)
diff --git a/indra/cmake/Boost.cmake b/indra/cmake/Boost.cmake
index 7ce57a5572..2135f0584c 100644
--- a/indra/cmake/Boost.cmake
+++ b/indra/cmake/Boost.cmake
@@ -10,23 +10,15 @@ if (STANDALONE)
set(BOOST_PROGRAM_OPTIONS_LIBRARY boost_program_options-mt)
set(BOOST_REGEX_LIBRARY boost_regex-mt)
set(BOOST_SIGNALS_LIBRARY boost_signals-mt)
+ set(BOOST_SYSTEM_LIBRARY boost_system-mt)
+ set(BOOST_FILESYSTEM_LIBRARY boost_filesystem-mt)
else (STANDALONE)
use_prebuilt_binary(boost)
set(Boost_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include)
if (WINDOWS)
- set(BOOST_VERSION 1_39)
- if (MSVC71)
- set(BOOST_PROGRAM_OPTIONS_LIBRARY
- optimized libboost_program_options-vc71-mt-s-${BOOST_VERSION}
- debug libboost_program_options-vc71-mt-sgd-${BOOST_VERSION})
- set(BOOST_REGEX_LIBRARY
- optimized libboost_regex-vc71-mt-s-${BOOST_VERSION}
- debug libboost_regex-vc71-mt-sgd-${BOOST_VERSION})
- set(BOOST_SIGNALS_LIBRARY
- optimized libboost_signals-vc71-mt-s-${BOOST_VERSION}
- debug libboost_signals-vc71-mt-sgd-${BOOST_VERSION})
- else (MSVC71)
+ set(BOOST_VERSION 1_45)
+ if(MSVC80)
set(BOOST_PROGRAM_OPTIONS_LIBRARY
optimized libboost_program_options-vc80-mt-${BOOST_VERSION}
debug libboost_program_options-vc80-mt-gd-${BOOST_VERSION})
@@ -36,14 +28,31 @@ else (STANDALONE)
set(BOOST_SIGNALS_LIBRARY
optimized libboost_signals-vc80-mt-${BOOST_VERSION}
debug libboost_signals-vc80-mt-gd-${BOOST_VERSION})
- endif (MSVC71)
- elseif (DARWIN)
- set(BOOST_PROGRAM_OPTIONS_LIBRARY boost_program_options-xgcc40-mt)
- set(BOOST_REGEX_LIBRARY boost_regex-xgcc40-mt)
- set(BOOST_SIGNALS_LIBRARY boost_signals-xgcc40-mt)
- elseif (LINUX)
- set(BOOST_PROGRAM_OPTIONS_LIBRARY boost_program_options-gcc41-mt)
- set(BOOST_REGEX_LIBRARY boost_regex-gcc41-mt)
- set(BOOST_SIGNALS_LIBRARY boost_signals-gcc41-mt)
+ set(BOOST_SYSTEM_LIBRARY
+ optimized libboost_system-vc80-mt-${BOOST_VERSION}
+ debug libboost_system-vc80-mt-gd-${BOOST_VERSION})
+ set(BOOST_FILESYSTEM_LIBRARY
+ optimized libboost_filesystem-vc80-mt-${BOOST_VERSION}
+ debug libboost_filesystem-vc80-mt-gd-${BOOST_VERSION})
+ else(MSVC80)
+ # MSVC 10.0 config
+ set(BOOST_PROGRAM_OPTIONS_LIBRARY
+ optimized libboost_program_options-vc100-mt-${BOOST_VERSION}
+ debug libboost_program_options-vc100-mt-gd-${BOOST_VERSION})
+ set(BOOST_REGEX_LIBRARY
+ optimized libboost_regex-vc100-mt-${BOOST_VERSION}
+ debug libboost_regex-vc100-mt-gd-${BOOST_VERSION})
+ set(BOOST_SYSTEM_LIBRARY
+ optimized libboost_system-vc100-mt-${BOOST_VERSION}
+ debug libboost_system-vc100-mt-gd-${BOOST_VERSION})
+ set(BOOST_FILESYSTEM_LIBRARY
+ optimized libboost_filesystem-vc100-mt-${BOOST_VERSION}
+ debug libboost_filesystem-vc100-mt-gd-${BOOST_VERSION})
+ endif (MSVC80)
+ elseif (DARWIN OR LINUX)
+ set(BOOST_PROGRAM_OPTIONS_LIBRARY boost_program_options)
+ set(BOOST_REGEX_LIBRARY boost_regex)
+ set(BOOST_SYSTEM_LIBRARY boost_system)
+ set(BOOST_FILESYSTEM_LIBRARY boost_filesystem)
endif (WINDOWS)
endif (STANDALONE)
diff --git a/indra/cmake/CARes.cmake b/indra/cmake/CARes.cmake
index 1850b706ac..b0dac5b12f 100644
--- a/indra/cmake/CARes.cmake
+++ b/indra/cmake/CARes.cmake
@@ -13,10 +13,7 @@ else (STANDALONE)
if (WINDOWS)
set(CARES_LIBRARIES areslib)
elseif (DARWIN)
- set(CARES_LIBRARIES
- optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libcares.a
- debug ${ARCH_PREBUILT_DIRS_DEBUG}/libcares.a
- )
+ set(CARES_LIBRARIES cares)
else (WINDOWS)
set(CARES_LIBRARIES cares)
endif (WINDOWS)
diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt
index 6470836286..279d577a27 100644
--- a/indra/cmake/CMakeLists.txt
+++ b/indra/cmake/CMakeLists.txt
@@ -20,7 +20,6 @@ set(cmake_SOURCE_FILES
CSharpMacros.cmake
DBusGlib.cmake
DirectX.cmake
- ELFIO.cmake
EXPAT.cmake
FindAPR.cmake
FindBerkeleyDB.cmake
@@ -29,12 +28,13 @@ set(cmake_SOURCE_FILES
FindFMOD.cmake
FindGooglePerfTools.cmake
FindMono.cmake
- FindMT.cmake
FindMySQL.cmake
FindOpenJPEG.cmake
FindXmlRpcEpi.cmake
+ FindZLIB.cmake
FMOD.cmake
FreeType.cmake
+ GLOD.cmake
GStreamer010Plugin.cmake
GooglePerfTools.cmake
JPEG.cmake
@@ -42,6 +42,7 @@ set(cmake_SOURCE_FILES
LLAudio.cmake
LLCharacter.cmake
LLCommon.cmake
+ LLConvexDecomposition.cmake
LLCrashLogger.cmake
LLDatabase.cmake
LLImage.cmake
@@ -84,7 +85,6 @@ source_group("Shared Rules" FILES ${cmake_SOURCE_FILES})
set(master_SOURCE_FILES
../CMakeLists.txt
- ../develop.py
)
if (SERVER)
diff --git a/indra/cmake/CURL.cmake b/indra/cmake/CURL.cmake
index 6e5fed4d52..9aba08e573 100644
--- a/indra/cmake/CURL.cmake
+++ b/indra/cmake/CURL.cmake
@@ -10,10 +10,10 @@ else (STANDALONE)
use_prebuilt_binary(curl)
if (WINDOWS)
set(CURL_LIBRARIES
- debug libcurld
- optimized libcurl)
+ debug libcurld.lib
+ optimized libcurl.lib)
else (WINDOWS)
- set(CURL_LIBRARIES curl)
+ set(CURL_LIBRARIES libcurl.a)
endif (WINDOWS)
set(CURL_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include)
endif (STANDALONE)
diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake
index e852cf463c..d9efc8f40d 100644
--- a/indra/cmake/Copy3rdPartyLibs.cmake
+++ b/indra/cmake/Copy3rdPartyLibs.cmake
@@ -5,6 +5,7 @@
# VisualStudio.
include(CMakeCopyIfDifferent)
+include(Linking)
###################################################################
# set up platform specific lists of files that need to be copied
@@ -16,7 +17,7 @@ if(WINDOWS)
#*******************************
# VIVOX - *NOTE: no debug version
- set(vivox_src_dir "${CMAKE_SOURCE_DIR}/newview/vivox-runtime/i686-win32")
+ set(vivox_src_dir "${ARCH_PREBUILT_DIRS_RELEASE}")
set(vivox_files
SLVoice.exe
libsndfile-1.dll
@@ -30,24 +31,28 @@ if(WINDOWS)
#*******************************
# Misc shared libs
- # *TODO - update this to use LIBS_PREBUILT_DIR and LL_ARCH_DIR variables
- # or ARCH_PREBUILT_DIRS
- set(debug_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/debug")
+ set(debug_src_dir "${ARCH_PREBUILT_DIRS_DEBUG}")
set(debug_files
openjpegd.dll
libapr-1.dll
libaprutil-1.dll
libapriconv-1.dll
+ ssleay32.dll
+ libeay32.dll
+ libcollada14dom22-d.dll
+ glod.dll
)
- # *TODO - update this to use LIBS_PREBUILT_DIR and LL_ARCH_DIR variables
- # or ARCH_PREBUILT_DIRS
- set(release_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/release")
+ set(release_src_dir "${ARCH_PREBUILT_DIRS_RELEASE}")
set(release_files
openjpeg.dll
libapr-1.dll
libaprutil-1.dll
libapriconv-1.dll
+ ssleay32.dll
+ libeay32.dll
+ libcollada14dom22.dll
+ glod.dll
)
if(USE_GOOGLE_PERFTOOLS)
@@ -60,28 +65,13 @@ if(WINDOWS)
set(release_files ${release_files} fmod.dll)
endif (FMOD)
- #*******************************
- # LLKDU
- set(internal_llkdu_path "${CMAKE_SOURCE_DIR}/llkdu")
- if(NOT EXISTS ${internal_llkdu_path})
- if (EXISTS "${debug_src_dir}/llkdu.dll")
- set(debug_llkdu_src "${debug_src_dir}/llkdu.dll")
- set(debug_llkdu_dst "${SHARED_LIB_STAGING_DIR_DEBUG}/llkdu.dll")
- endif (EXISTS "${debug_src_dir}/llkdu.dll")
-
- if (EXISTS "${release_src_dir}/llkdu.dll")
- set(release_llkdu_src "${release_src_dir}/llkdu.dll")
- set(release_llkdu_dst "${SHARED_LIB_STAGING_DIR_RELEASE}/llkdu.dll")
- set(relwithdebinfo_llkdu_dst "${SHARED_LIB_STAGING_DIR_RELWITHDEBINFO}/llkdu.dll")
- endif (EXISTS "${release_src_dir}/llkdu.dll")
- endif (NOT EXISTS ${internal_llkdu_path})
-
#*******************************
# Copy MS C runtime dlls, required for packaging.
# *TODO - Adapt this to support VC9
if (MSVC80)
FIND_PATH(debug_msvc8_redist_path msvcr80d.dll
PATHS
+ ${MSVC_DEBUG_REDIST_PATH}
[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0\\Setup\\VC;ProductDir]/redist/Debug_NonRedist/x86/Microsoft.VC80.DebugCRT
NO_DEFAULT_PATH
NO_DEFAULT_PATH
@@ -106,6 +96,7 @@ if (MSVC80)
FIND_PATH(release_msvc8_redist_path msvcr80.dll
PATHS
+ ${MSVC_REDIST_PATH}
[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0\\Setup\\VC;ProductDir]/redist/x86/Microsoft.VC80.CRT
NO_DEFAULT_PATH
NO_DEFAULT_PATH
@@ -135,6 +126,64 @@ if (MSVC80)
set(third_party_targets ${third_party_targets} ${out_targets})
endif (EXISTS ${release_msvc8_redist_path})
+elseif (MSVC_VERSION EQUAL 1600) # VisualStudio 2010
+ FIND_PATH(debug_msvc10_redist_path msvcr100d.dll
+ PATHS
+ ${MSVC_DEBUG_REDIST_PATH}
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\10.0\\Setup\\VC;ProductDir]/redist/Debug_NonRedist/x86/Microsoft.VC100.DebugCRT
+ [HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Windows;Directory]/SysWOW64
+ [HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Windows;Directory]/System32
+ NO_DEFAULT_PATH
+ )
+
+ if(EXISTS ${debug_msvc10_redist_path})
+ set(debug_msvc10_files
+ msvcr100d.dll
+ msvcp100d.dll
+ )
+
+ copy_if_different(
+ ${debug_msvc10_redist_path}
+ "${SHARED_LIB_STAGING_DIR_DEBUG}"
+ out_targets
+ ${debug_msvc10_files}
+ )
+ set(third_party_targets ${third_party_targets} ${out_targets})
+
+ endif ()
+
+ FIND_PATH(release_msvc10_redist_path msvcr100.dll
+ PATHS
+ ${MSVC_REDIST_PATH}
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\10.0\\Setup\\VC;ProductDir]/redist/x86/Microsoft.VC100.CRT
+ [HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Windows;Directory]/SysWOW64
+ [HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Windows;Directory]/System32
+ NO_DEFAULT_PATH
+ )
+
+ if(EXISTS ${release_msvc10_redist_path})
+ set(release_msvc10_files
+ msvcr100.dll
+ msvcp100.dll
+ )
+
+ copy_if_different(
+ ${release_msvc10_redist_path}
+ "${SHARED_LIB_STAGING_DIR_RELEASE}"
+ out_targets
+ ${release_msvc10_files}
+ )
+ set(third_party_targets ${third_party_targets} ${out_targets})
+
+ copy_if_different(
+ ${release_msvc10_redist_path}
+ "${SHARED_LIB_STAGING_DIR_RELWITHDEBINFO}"
+ out_targets
+ ${release_msvc10_files}
+ )
+ set(third_party_targets ${third_party_targets} ${out_targets})
+
+ endif ()
endif (MSVC80)
elseif(DARWIN)
@@ -142,7 +191,7 @@ elseif(DARWIN)
set(SHARED_LIB_STAGING_DIR_RELWITHDEBINFO "${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/Resources")
set(SHARED_LIB_STAGING_DIR_RELEASE "${SHARED_LIB_STAGING_DIR}/Release/Resources")
- set(vivox_src_dir "${CMAKE_SOURCE_DIR}/newview/vivox-runtime/universal-darwin")
+ set(vivox_src_dir "${ARCH_PREBUILT_DIRS_RELEASE}")
set(vivox_files
SLVoice
libsndfile.dylib
@@ -151,44 +200,28 @@ elseif(DARWIN)
libvivoxplatform.dylib
libvivoxsdk.dylib
)
- # *TODO - update this to use LIBS_PREBUILT_DIR and LL_ARCH_DIR variables
- # or ARCH_PREBUILT_DIRS
- set(debug_src_dir "${CMAKE_SOURCE_DIR}/../libraries/universal-darwin/lib_debug")
+ set(debug_src_dir "${ARCH_PREBUILT_DIRS_DEBUG}")
set(debug_files
)
- # *TODO - update this to use LIBS_PREBUILT_DIR and LL_ARCH_DIR variables
- # or ARCH_PREBUILT_DIRS
- set(release_src_dir "${CMAKE_SOURCE_DIR}/../libraries/universal-darwin/lib_release")
+ set(release_src_dir "${ARCH_PREBUILT_DIRS_RELEASE}")
set(release_files
- libapr-1.0.3.7.dylib
+ libapr-1.0.dylib
libapr-1.dylib
- libaprutil-1.0.3.8.dylib
+ libaprutil-1.0.dylib
libaprutil-1.dylib
- libexpat.0.5.0.dylib
+ libexpat.1.5.2.dylib
libexpat.dylib
- libllqtwebkit.dylib
+ libGLOD.dylib
+ libllqtwebkit.dylib
+ libminizip.a
libndofdev.dylib
libexception_handler.dylib
+ libcollada14dom.dylib
)
# fmod is statically linked on darwin
set(fmod_files "")
- #*******************************
- # LLKDU
- set(internal_llkdu_path "${CMAKE_SOURCE_DIR}/llkdu")
- if(NOT EXISTS ${internal_llkdu_path})
- if (EXISTS "${debug_src_dir}/libllkdu.dylib")
- set(debug_llkdu_src "${debug_src_dir}/libllkdu.dylib")
- set(debug_llkdu_dst "${SHARED_LIB_STAGING_DIR_DEBUG}/libllkdu.dylib")
- endif (EXISTS "${debug_src_dir}/libllkdu.dylib")
-
- if (EXISTS "${release_src_dir}/libllkdu.dylib")
- set(release_llkdu_src "${release_src_dir}/libllkdu.dylib")
- set(release_llkdu_dst "${SHARED_LIB_STAGING_DIR_RELEASE}/libllkdu.dylib")
- set(relwithdebinfo_llkdu_dst "${SHARED_LIB_STAGING_DIR_RELWITHDEBINFO}/libllkdu.dylib")
- endif (EXISTS "${release_src_dir}/libllkdu.dylib")
- endif (NOT EXISTS ${internal_llkdu_path})
elseif(LINUX)
# linux is weird, multiple side by side configurations aren't supported
# and we don't seem to have any debug shared libs built yet anyways...
@@ -196,7 +229,7 @@ elseif(LINUX)
set(SHARED_LIB_STAGING_DIR_RELWITHDEBINFO "${SHARED_LIB_STAGING_DIR}")
set(SHARED_LIB_STAGING_DIR_RELEASE "${SHARED_LIB_STAGING_DIR}")
- set(vivox_src_dir "${CMAKE_SOURCE_DIR}/newview/vivox-runtime/i686-linux")
+ set(vivox_src_dir "${ARCH_PREBUILT_DIRS_RELEASE}")
set(vivox_files
libsndfile.so.1
libortp.so
@@ -207,56 +240,45 @@ elseif(LINUX)
)
# *TODO - update this to use LIBS_PREBUILT_DIR and LL_ARCH_DIR variables
# or ARCH_PREBUILT_DIRS
- set(debug_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-linux/lib_debug")
+ set(debug_src_dir "${ARCH_PREBUILT_DIRS_DEBUG}")
set(debug_files
)
# *TODO - update this to use LIBS_PREBUILT_DIR and LL_ARCH_DIR variables
# or ARCH_PREBUILT_DIRS
- set(release_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-linux/lib_release_client")
+ set(release_src_dir "${ARCH_PREBUILT_DIRS_RELEASE}")
# *FIX - figure out what to do with duplicate libalut.so here -brad
set(release_files
libapr-1.so.0
libaprutil-1.so.0
libatk-1.0.so
libbreakpad_client.so.0
- libcrypto.so.0.9.7
- libdb-4.2.so
+ libcollada14dom.so
+ libcrypto.so.1.0.0
+ libdb-5.1.so
libexpat.so
libexpat.so.1
+ libglod.so
libgmock_main.so
libgmock.so.0
libgmodule-2.0.so
libgobject-2.0.so
libgtest_main.so
libgtest.so.0
+ libminizip.so
libopenal.so
libopenjpeg.so
libssl.so
- libstacktrace.so
- libtcmalloc.so
- libuuid.so.1
- libssl.so.0.9.7
+ libtcmalloc_minimal.so
+ libuuid.so.16
+ libuuid.so.16.0.22
+ libssl.so.1.0.0
+ libfontconfig.so.1.4.4
)
if (FMOD)
set(release_files ${release_files} "libfmod-3.75.so")
endif (FMOD)
- #*******************************
- # LLKDU
- set(internal_llkdu_path "${CMAKE_SOURCE_DIR}/llkdu")
- if(NOT EXISTS ${internal_llkdu_path})
- if (EXISTS "${debug_src_dir}/libllkdu.so")
- set(debug_llkdu_src "${debug_src_dir}/libllkdu.so")
- set(debug_llkdu_dst "${SHARED_LIB_STAGING_DIR_DEBUG}/libllkdu.so")
- endif (EXISTS "${debug_src_dir}/libllkdu.so")
-
- if (EXISTS "${release_src_dir}/libllkdu.so")
- set(release_llkdu_src "${release_src_dir}/libllkdu.so")
- set(release_llkdu_dst "${SHARED_LIB_STAGING_DIR_RELEASE}/libllkdu.so")
- set(relwithdebinfo_llkdu_dst "${SHARED_LIB_STAGING_DIR_RELWITHDEBINFO}/libllkdu.so")
- endif (EXISTS "${release_src_dir}/libllkdu.so")
- endif(NOT EXISTS ${internal_llkdu_path})
else(WINDOWS)
message(STATUS "WARNING: unrecognized platform for staging 3rd party libs, skipping...")
set(vivox_src_dir "${CMAKE_SOURCE_DIR}/newview/vivox-runtime/i686-linux")
@@ -334,40 +356,29 @@ copy_if_different(
)
set(third_party_targets ${third_party_targets} ${out_targets})
-#*******************************
-# LLKDU
-set(internal_llkdu_path "${CMAKE_SOURCE_DIR}/llkdu")
-if(NOT EXISTS ${internal_llkdu_path})
- if (EXISTS "${debug_llkdu_src}")
- ADD_CUSTOM_COMMAND(
- OUTPUT ${debug_llkdu_dst}
- COMMAND ${CMAKE_COMMAND} -E copy_if_different ${debug_llkdu_src} ${debug_llkdu_dst}
- DEPENDS ${debug_llkdu_src}
- COMMENT "Copying llkdu.dll ${SHARED_LIB_STAGING_DIR_DEBUG}"
- )
- set(third_party_targets ${third_party_targets} $} ${debug_llkdu_dst})
- endif (EXISTS "${debug_llkdu_src}")
-
- if (EXISTS "${release_llkdu_src}")
- ADD_CUSTOM_COMMAND(
- OUTPUT ${release_llkdu_dst}
- COMMAND ${CMAKE_COMMAND} -E copy_if_different ${release_llkdu_src} ${release_llkdu_dst}
- DEPENDS ${release_llkdu_src}
- COMMENT "Copying llkdu.dll ${SHARED_LIB_STAGING_DIR_RELEASE}"
- )
- set(third_party_targets ${third_party_targets} ${release_llkdu_dst})
-
- ADD_CUSTOM_COMMAND(
- OUTPUT ${relwithdebinfo_llkdu_dst}
- COMMAND ${CMAKE_COMMAND} -E copy_if_different ${release_llkdu_src} ${relwithdebinfo_llkdu_dst}
- DEPENDS ${release_llkdu_src}
- COMMENT "Copying llkdu.dll ${SHARED_LIB_STAGING_DIR_RELWITHDEBINFO}"
- )
- set(third_party_targets ${third_party_targets} ${relwithdebinfo_llkdu_dst})
- endif (EXISTS "${release_llkdu_src}")
-
-endif (NOT EXISTS ${internal_llkdu_path})
-
+if (FMOD_SDK_DIR)
+ copy_if_different(
+ ${FMOD_SDK_DIR}
+ "${CMAKE_CURRENT_BINARY_DIR}/Debug"
+ out_targets
+ ${fmod_files}
+ )
+ set(all_targets ${all_targets} ${out_targets})
+ copy_if_different(
+ ${FMOD_SDK_DIR}
+ "${CMAKE_CURRENT_BINARY_DIR}/Release"
+ out_targets
+ ${fmod_files}
+ )
+ set(all_targets ${all_targets} ${out_targets})
+ copy_if_different(
+ ${FMOD_SDK_DIR}
+ "${CMAKE_CURRENT_BINARY_DIR}/RelWithDbgInfo"
+ out_targets
+ ${fmod_files}
+ )
+ set(all_targets ${all_targets} ${out_targets})
+endif (FMOD_SDK_DIR)
if(NOT STANDALONE)
add_custom_target(
diff --git a/indra/cmake/DBusGlib.cmake b/indra/cmake/DBusGlib.cmake
index cfc4ccd404..83c08d3350 100644
--- a/indra/cmake/DBusGlib.cmake
+++ b/indra/cmake/DBusGlib.cmake
@@ -10,7 +10,7 @@ elseif (LINUX)
use_prebuilt_binary(dbusglib)
set(DBUSGLIB_FOUND ON FORCE BOOL)
set(DBUSGLIB_INCLUDE_DIRS
- ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/glib-2.0
+ ${LIBS_PREBUILT_DIR}/include/dbus
)
# We don't need to explicitly link against dbus-glib itself, because
# the viewer probes for the system's copy at runtime.
diff --git a/indra/cmake/DirectX.cmake b/indra/cmake/DirectX.cmake
index 29724ee2fc..b2a18805d4 100644
--- a/indra/cmake/DirectX.cmake
+++ b/indra/cmake/DirectX.cmake
@@ -3,6 +3,7 @@
if (VIEWER AND WINDOWS)
find_path(DIRECTX_INCLUDE_DIR dxdiag.h
"$ENV{DXSDK_DIR}/Include"
+ "$ENV{PROGRAMFILES}/Microsoft DirectX SDK (August 2009)/Include"
"$ENV{PROGRAMFILES}/Microsoft DirectX SDK (March 2009)/Include"
"$ENV{PROGRAMFILES}/Microsoft DirectX SDK (August 2008)/Include"
"$ENV{PROGRAMFILES}/Microsoft DirectX SDK (June 2008)/Include"
@@ -24,6 +25,7 @@ if (VIEWER AND WINDOWS)
find_path(DIRECTX_LIBRARY_DIR dxguid.lib
"$ENV{DXSDK_DIR}/Lib/x86"
+ "$ENV{PROGRAMFILES}/Microsoft DirectX SDK (August 2009)/Lib/x86"
"$ENV{PROGRAMFILES}/Microsoft DirectX SDK (March 2009)/Lib/x86"
"$ENV{PROGRAMFILES}/Microsoft DirectX SDK (August 2008)/Lib/x86"
"$ENV{PROGRAMFILES}/Microsoft DirectX SDK (June 2008)/Lib/x86"
diff --git a/indra/cmake/ELFIO.cmake b/indra/cmake/ELFIO.cmake
deleted file mode 100644
index e51993b0f7..0000000000
--- a/indra/cmake/ELFIO.cmake
+++ /dev/null
@@ -1,19 +0,0 @@
-# -*- cmake -*-
-include(Prebuilt)
-
-set(ELFIO_FIND_QUIETLY ON)
-
-if (STANDALONE)
- include(FindELFIO)
-elseif (LINUX)
- use_prebuilt_binary(elfio)
- set(ELFIO_LIBRARIES ELFIO)
- set(ELFIO_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include)
- set(ELFIO_FOUND "YES")
-endif (STANDALONE)
-
-if (ELFIO_FOUND)
- add_definitions(-DLL_ELFBIN=1)
-else (ELFIO_FOUND)
- set(ELFIO_INCLUDE_DIR "")
-endif (ELFIO_FOUND)
diff --git a/indra/cmake/FMOD.cmake b/indra/cmake/FMOD.cmake
index 96434e38fa..cb5124812d 100644..100755
--- a/indra/cmake/FMOD.cmake
+++ b/indra/cmake/FMOD.cmake
@@ -1,24 +1,39 @@
# -*- cmake -*-
-set(FMOD ON CACHE BOOL "Use FMOD sound library.")
+# FMOD can be set when launching the make using the argument -DFMOD:BOOL=ON
+# When building using proprietary binaries though (i.e. having access to LL private servers),
+# we always build with FMOD.
+# Open source devs should use the -DFMOD:BOOL=ON then if they want to build with FMOD, whether
+# they are using STANDALONE or not.
+if (INSTALL_PROPRIETARY)
+ set(FMOD ON CACHE BOOL "Use FMOD sound library.")
+endif (INSTALL_PROPRIETARY)
if (FMOD)
if (STANDALONE)
+ # In that case, we use the version of the library installed on the system
set(FMOD_FIND_REQUIRED ON)
include(FindFMOD)
else (STANDALONE)
- include(Prebuilt)
- use_prebuilt_binary(fmod)
-
- if (WINDOWS)
- set(FMOD_LIBRARY fmod)
- elseif (DARWIN)
- set(FMOD_LIBRARY fmod)
- elseif (LINUX)
- set(FMOD_LIBRARY fmod-3.75)
- endif (WINDOWS)
-
- SET(FMOD_LIBRARIES ${FMOD_LIBRARY})
- set(FMOD_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include)
+ if (FMOD_LIBRARY AND FMOD_INCLUDE_DIR)
+ # If the path have been specified in the arguments, use that
+ set(FMOD_LIBRARIES ${FMOD_LIBRARY})
+ MESSAGE(STATUS "Using FMOD path: ${FMOD_LIBRARIES}, ${FMOD_INCLUDE_DIR}")
+ else (FMOD_LIBRARY AND FMOD_INCLUDE_DIR)
+ # If not, we're going to try to get the package listed in autobuild.xml
+ # Note: if you're not using INSTALL_PROPRIETARY, the package URL should be local (file:/// URL)
+ # as accessing the private LL location will fail if you don't have the credential
+ include(Prebuilt)
+ use_prebuilt_binary(fmod)
+ if (WINDOWS)
+ set(FMOD_LIBRARY fmod)
+ elseif (DARWIN)
+ set(FMOD_LIBRARY fmod)
+ elseif (LINUX)
+ set(FMOD_LIBRARY fmod-3.75)
+ endif (WINDOWS)
+ set(FMOD_LIBRARIES ${FMOD_LIBRARY})
+ set(FMOD_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include)
+ endif (FMOD_LIBRARY AND FMOD_INCLUDE_DIR)
endif (STANDALONE)
endif (FMOD)
diff --git a/indra/cmake/FindAutobuild.cmake b/indra/cmake/FindAutobuild.cmake
new file mode 100644
index 0000000000..45db2b6ed0
--- /dev/null
+++ b/indra/cmake/FindAutobuild.cmake
@@ -0,0 +1,41 @@
+# -*- cmake -*-
+#
+# Find the autobuild tool
+#
+# Output variables:
+#
+# AUTOBUILD_EXECUTABLE - path to autobuild or pautobuild executable
+
+# *TODO - if cmake was executed by autobuild, autobuild will have set the AUTOBUILD env var
+# update this to check for that case
+
+IF (NOT AUTOBUILD_EXECUTABLE)
+ IF(WIN32)
+ SET(AUTOBUILD_EXE_NAMES autobuild.cmd autobuild.exe)
+ ELSE(WIN32)
+ SET(AUTOBUILD_EXE_NAMES autobuild)
+ ENDIF(WIN32)
+
+ SET(AUTOBUILD_EXECUTABLE)
+ FIND_PROGRAM(
+ AUTOBUILD_EXECUTABLE
+ NAMES ${AUTOBUILD_EXE_NAMES}
+ PATHS
+ ENV PATH
+ ${CMAKE_SOURCE_DIR}/..
+ ${CMAKE_SOURCE_DIR}/../..
+ ${CMAKE_SOURCE_DIR}/../../..
+ PATH_SUFFIXES "/autobuild/bin/"
+ )
+
+ IF (AUTOBUILD_EXECUTABLE)
+ GET_FILENAME_COMPONENT(_autobuild_name ${AUTOBUILD_EXECUTABLE} NAME_WE)
+ MESSAGE(STATUS "Using autobuild at: ${AUTOBUILD_EXECUTABLE}")
+ ELSE (AUTOBUILD_EXECUTABLE)
+ IF (AUTOBUILD_FIND_REQUIRED)
+ MESSAGE(FATAL_ERROR "Could not find autobuild executable")
+ ENDIF (AUTOBUILD_FIND_REQUIRED)
+ ENDIF (AUTOBUILD_EXECUTABLE)
+
+ MARK_AS_ADVANCED(AUTOBUILD_EXECUTABLE)
+ENDIF (NOT AUTOBUILD_EXECUTABLE)
diff --git a/indra/cmake/FindFMOD.cmake b/indra/cmake/FindFMOD.cmake
index e60b386027..1ebbc8c96e 100644
--- a/indra/cmake/FindFMOD.cmake
+++ b/indra/cmake/FindFMOD.cmake
@@ -11,7 +11,7 @@
FIND_PATH(FMOD_INCLUDE_DIR fmod.h PATH_SUFFIXES fmod)
-SET(FMOD_NAMES ${FMOD_NAMES} fmod fmodvc fmod-3.75)
+SET(FMOD_NAMES ${FMOD_NAMES} fmod fmodvc fmodex fmod-3.75)
FIND_LIBRARY(FMOD_LIBRARY
NAMES ${FMOD_NAMES}
PATH_SUFFIXES fmod
diff --git a/indra/cmake/FindJsonCpp.cmake b/indra/cmake/FindJsonCpp.cmake
index 9d16f2aaab..cf84b309c1 100644
--- a/indra/cmake/FindJsonCpp.cmake
+++ b/indra/cmake/FindJsonCpp.cmake
@@ -21,7 +21,12 @@ EXEC_PROGRAM(${CMAKE_CXX_COMPILER}
OUTPUT_STRIP_TRAILING_WHITESPACE
)
+# Try to find a library that was compiled with the same compiler version as we currently use.
SET(JSONCPP_NAMES ${JSONCPP_NAMES} libjson_linux-gcc-${_gcc_COMPILER_VERSION}_libmt.so)
+IF (STANDALONE)
+ # On standalone, assume that the system installed library was compiled with the used compiler.
+ SET(JSONCPP_NAMES ${JSONCPP_NAMES} libjson.so)
+ENDIF (STANDALONE)
FIND_LIBRARY(JSONCPP_LIBRARY
NAMES ${JSONCPP_NAMES}
PATHS /usr/lib /usr/local/lib
diff --git a/indra/cmake/FindLLQtWebkit.cmake b/indra/cmake/FindLLQtWebkit.cmake
new file mode 100644
index 0000000000..4bf5f5cb73
--- /dev/null
+++ b/indra/cmake/FindLLQtWebkit.cmake
@@ -0,0 +1,62 @@
+# -*- cmake -*-
+
+# - Find llqtwebkit
+# Find the llqtwebkit includes and library
+# This module defines
+# LLQTWEBKIT_INCLUDE_DIR, where to find llqtwebkit.h, etc.
+# LLQTWEBKIT_LIBRARY, the llqtwebkit library with full path.
+# LLQTWEBKIT_FOUND, If false, do not try to use llqtwebkit.
+# also defined, but not for general use are
+# LLQTWEBKIT_LIBRARIES, the libraries needed to use llqtwebkit.
+# LLQTWEBKIT_LIBRARY_DIRS, where to find the llqtwebkit library.
+# LLQTWEBKIT_DEFINITIONS - You should add_definitions(${LLQTWEBKIT_DEFINITIONS})
+# before compiling code that includes llqtwebkit library files.
+
+# Try to use pkg-config first.
+# This allows to have two different libllqtwebkit packages installed:
+# one for viewer 2.x and one for viewer 1.x.
+include(FindPkgConfig)
+if (PKG_CONFIG_FOUND)
+ if (LLQtWebkit_FIND_REQUIRED AND LLQtWebkit_FIND_VERSION)
+ set(_PACKAGE_ARGS libllqtwebkit>=${LLQtWebkit_FIND_VERSION} REQUIRED)
+ else (LLQtWebkit_FIND_REQUIRED AND LLQtWebkit_FIND_VERSION)
+ set(_PACKAGE_ARGS libllqtwebkit)
+ endif (LLQtWebkit_FIND_REQUIRED AND LLQtWebkit_FIND_VERSION)
+ if (NOT "${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION}" VERSION_LESS "2.8.2")
+ # As virtually nobody will have a pkg-config file for this, do this check always quiet.
+ # Unfortunately cmake 2.8.2 or higher is required for pkg_check_modules to have a 'QUIET'.
+ set(_PACKAGE_ARGS ${_PACKAGE_ARGS} QUIET)
+ endif ()
+ pkg_check_modules(LLQTWEBKIT ${_PACKAGE_ARGS})
+endif (PKG_CONFIG_FOUND)
+set(LLQTWEBKIT_DEFINITIONS ${LLQTWEBKIT_CFLAGS_OTHER})
+
+find_path(LLQTWEBKIT_INCLUDE_DIR llqtwebkit.h NO_SYSTEM_ENVIRONMENT_PATH HINTS ${LLQTWEBKIT_INCLUDE_DIRS})
+
+find_library(LLQTWEBKIT_LIBRARY NAMES llqtwebkit NO_SYSTEM_ENVIRONMENT_PATH HINTS ${LLQTWEBKIT_LIBRARY_DIRS})
+
+if (NOT PKG_CONFIG_FOUND OR NOT LLQTWEBKIT_FOUND) # If pkg-config couldn't find it, pretend we don't have pkg-config.
+ set(LLQTWEBKIT_LIBRARIES llqtwebkit)
+ get_filename_component(LLQTWEBKIT_LIBRARY_DIRS ${LLQTWEBKIT_LIBRARY} PATH)
+endif (NOT PKG_CONFIG_FOUND OR NOT LLQTWEBKIT_FOUND)
+
+# Handle the QUIETLY and REQUIRED arguments and set LLQTWEBKIT_FOUND
+# to TRUE if all listed variables are TRUE.
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(
+ LLQTWEBKIT
+ DEFAULT_MSG
+ LLQTWEBKIT_LIBRARY
+ LLQTWEBKIT_INCLUDE_DIR
+ LLQTWEBKIT_LIBRARIES
+ LLQTWEBKIT_LIBRARY_DIRS
+ )
+
+mark_as_advanced(
+ LLQTWEBKIT_LIBRARY
+ LLQTWEBKIT_INCLUDE_DIR
+ LLQTWEBKIT_LIBRARIES
+ LLQTWEBKIT_LIBRARY_DIRS
+ LLQTWEBKIT_DEFINITIONS
+ )
+
diff --git a/indra/cmake/FindNDOF.cmake b/indra/cmake/FindNDOF.cmake
new file mode 100644
index 0000000000..6dcf590a53
--- /dev/null
+++ b/indra/cmake/FindNDOF.cmake
@@ -0,0 +1,39 @@
+# -*- cmake -*-
+
+# - Find NDOF
+# Find the NDOF includes and library
+# This module defines
+# NDOF_INCLUDE_DIR, where to find ndofdev_external.h, etc.
+# NDOF_LIBRARY, the library needed to use NDOF.
+# NDOF_FOUND, If false, do not try to use NDOF.
+
+find_path(NDOF_INCLUDE_DIR ndofdev_external.h
+ PATH_SUFFIXES ndofdev
+ )
+
+set(NDOF_NAMES ${NDOF_NAMES} ndofdev libndofdev)
+find_library(NDOF_LIBRARY
+ NAMES ${NDOF_NAMES}
+ )
+
+if (NDOF_LIBRARY AND NDOF_INCLUDE_DIR)
+ set(NDOF_FOUND "YES")
+else (NDOF_LIBRARY AND NDOF_INCLUDE_DIR)
+ set(NDOF_FOUND "NO")
+endif (NDOF_LIBRARY AND NDOF_INCLUDE_DIR)
+
+
+if (NDOF_FOUND)
+ if (NOT NDOF_FIND_QUIETLY)
+ message(STATUS "Found NDOF: Library in '${NDOF_LIBRARY}' and header in '${NDOF_INCLUDE_DIR}' ")
+ endif (NOT NDOF_FIND_QUIETLY)
+else (NDOF_FOUND)
+ if (NDOF_FIND_REQUIRED)
+ message(FATAL_ERROR " * * *\nCould not find NDOF library!\nIf you don't need Space Navigator Joystick support you can skip this test by configuring with -DNDOF:BOOL=OFF\n * * *")
+ endif (NDOF_FIND_REQUIRED)
+endif (NDOF_FOUND)
+
+mark_as_advanced(
+ NDOF_LIBRARY
+ NDOF_INCLUDE_DIR
+ )
diff --git a/indra/cmake/FindTut.cmake b/indra/cmake/FindTut.cmake
deleted file mode 100644
index b5d58f6396..0000000000
--- a/indra/cmake/FindTut.cmake
+++ /dev/null
@@ -1,31 +0,0 @@
-# -*- cmake -*-
-
-# - Find Tut
-# Find the Tut unit test framework includes and library
-# This module defines
-# TUT_INCLUDE_DIR, where to find tut.h, etc.
-# TUT_FOUND, If false, do not try to use Tut.
-
-find_path(TUT_INCLUDE_DIR tut.h
- /usr/local/include/
- /usr/include
- )
-
-if (TUT_INCLUDE_DIR)
- set(TUT_FOUND "YES")
-else (TUT_INCLUDE_DIR)
- set(TUT_FOUND "NO")
-endif (TUT_INCLUDE_DIR)
-
-if (TUT_FOUND)
- if (NOT TUT_FIND_QUIETLY)
- message(STATUS "Found Tut: ${TUT_INCLUDE_DIR}")
- set(TUT_FIND_QUIETLY TRUE) # Only alert us the first time
- endif (NOT TUT_FIND_QUIETLY)
-else (TUT_FOUND)
- if (TUT_FIND_REQUIRED)
- message(FATAL_ERROR "Could not find Tut")
- endif (TUT_FIND_REQUIRED)
-endif (TUT_FOUND)
-
-mark_as_advanced(TUT_INCLUDE_DIR)
diff --git a/indra/cmake/FindZLIB.cmake b/indra/cmake/FindZLIB.cmake
new file mode 100644
index 0000000000..6d630f1ba9
--- /dev/null
+++ b/indra/cmake/FindZLIB.cmake
@@ -0,0 +1,46 @@
+# -*- cmake -*-
+
+# - Find zlib
+# Find the ZLIB includes and library
+# This module defines
+# ZLIB_INCLUDE_DIRS, where to find zlib.h, etc.
+# ZLIB_LIBRARIES, the libraries needed to use zlib.
+# ZLIB_FOUND, If false, do not try to use zlib.
+#
+# This FindZLIB is about 43 times as fast the one provided with cmake (2.8.x),
+# because it doesn't look up the version of zlib, resulting in a dramatic
+# speed up for configure (from 4 minutes 22 seconds to 6 seconds).
+#
+# Note: Since this file is only used for standalone, the windows
+# specific parts were left out.
+
+FIND_PATH(ZLIB_INCLUDE_DIR zlib.h
+ NO_SYSTEM_ENVIRONMENT_PATH
+ )
+
+FIND_LIBRARY(ZLIB_LIBRARY z)
+
+if (ZLIB_LIBRARY AND ZLIB_INCLUDE_DIR)
+ SET(ZLIB_INCLUDE_DIRS ${ZLIB_INCLUDE_DIR})
+ SET(ZLIB_LIBRARIES ${ZLIB_LIBRARY})
+ SET(ZLIB_FOUND "YES")
+else (ZLIB_LIBRARY AND ZLIB_INCLUDE_DIR)
+ SET(ZLIB_FOUND "NO")
+endif (ZLIB_LIBRARY AND ZLIB_INCLUDE_DIR)
+
+if (ZLIB_FOUND)
+ if (NOT ZLIB_FIND_QUIETLY)
+ message(STATUS "Found ZLIB: ${ZLIB_LIBRARIES}")
+ SET(ZLIB_FIND_QUIETLY TRUE)
+ endif (NOT ZLIB_FIND_QUIETLY)
+else (ZLIB_FOUND)
+ if (ZLIB_FIND_REQUIRED)
+ message(FATAL_ERROR "Could not find ZLIB library")
+ endif (ZLIB_FIND_REQUIRED)
+endif (ZLIB_FOUND)
+
+mark_as_advanced(
+ ZLIB_LIBRARY
+ ZLIB_INCLUDE_DIR
+ )
+
diff --git a/indra/cmake/FreeType.cmake b/indra/cmake/FreeType.cmake
index 5f1aa26e89..43a9d282d0 100644
--- a/indra/cmake/FreeType.cmake
+++ b/indra/cmake/FreeType.cmake
@@ -9,7 +9,7 @@ else (STANDALONE)
use_prebuilt_binary(freetype)
if (LINUX)
set(FREETYPE_INCLUDE_DIRS
- ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include)
+ ${LIBS_PREBUILT_DIR}/include)
else (LINUX)
set(FREETYPE_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include)
endif (LINUX)
diff --git a/indra/cmake/GLOD.cmake b/indra/cmake/GLOD.cmake
new file mode 100644
index 0000000000..77221d55ed
--- /dev/null
+++ b/indra/cmake/GLOD.cmake
@@ -0,0 +1,9 @@
+# -*- cmake -*-
+include(Prebuilt)
+
+if (NOT STANDALONE)
+ use_prebuilt_binary(GLOD)
+endif (NOT STANDALONE)
+
+set(GLOD_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include)
+set(GLOD_LIBRARIES glod)
diff --git a/indra/cmake/GStreamer010Plugin.cmake b/indra/cmake/GStreamer010Plugin.cmake
index 0ca432da18..d2d0699bcd 100644
--- a/indra/cmake/GStreamer010Plugin.cmake
+++ b/indra/cmake/GStreamer010Plugin.cmake
@@ -13,9 +13,9 @@ elseif (LINUX)
set(GSTREAMER010_FOUND ON FORCE BOOL)
set(GSTREAMER010_PLUGINS_BASE_FOUND ON FORCE BOOL)
set(GSTREAMER010_INCLUDE_DIRS
- ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/gstreamer-0.10
- ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/glib-2.0
- ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/libxml2
+ ${LIBS_PREBUILT_DIR}/include/gstreamer-0.10
+ ${LIBS_PREBUILT_DIR}/include/glib-2.0
+ ${LIBS_PREBUILT_DIR}/include/libxml2
)
# We don't need to explicitly link against gstreamer itself, because
# LLMediaImplGStreamer probes for the system's copy at runtime.
diff --git a/indra/cmake/GetPrerequisites_2_8.cmake b/indra/cmake/GetPrerequisites_2_8.cmake
index 5a24842c89..05ec1539ba 100644
--- a/indra/cmake/GetPrerequisites_2_8.cmake
+++ b/indra/cmake/GetPrerequisites_2_8.cmake
@@ -1,786 +1,786 @@
-# GetPrerequisites.cmake
-#
-# This script provides functions to list the .dll, .dylib or .so files that an
-# executable or shared library file depends on. (Its prerequisites.)
-#
-# It uses various tools to obtain the list of required shared library files:
-# dumpbin (Windows)
-# ldd (Linux/Unix)
-# otool (Mac OSX)
-#
-# The following functions are provided by this script:
-# gp_append_unique
-# is_file_executable
-# gp_item_default_embedded_path
-# (projects can override with gp_item_default_embedded_path_override)
-# gp_resolve_item
-# (projects can override with gp_resolve_item_override)
-# gp_resolved_file_type
-# gp_file_type
-# get_prerequisites
-# list_prerequisites
-# list_prerequisites_by_glob
-#
-# Requires CMake 2.6 or greater because it uses function, break, return and
-# PARENT_SCOPE.
-
-#=============================================================================
-# Copyright 2008-2009 Kitware, Inc.
-#
-# Distributed under the OSI-approved BSD License (the "License");
-# see accompanying file Copyright.txt for details.
-#
-# This software is distributed WITHOUT ANY WARRANTY; without even the
-# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-# See the License for more information.
-#=============================================================================
-# (To distributed this file outside of CMake, substitute the full
-# License text for the above reference.)
-
-# gp_append_unique list_var value
-#
-# Append value to the list variable ${list_var} only if the value is not
-# already in the list.
-#
-function(gp_append_unique list_var value)
- set(contains 0)
-
- foreach(item ${${list_var}})
- if("${item}" STREQUAL "${value}")
- set(contains 1)
- break()
- endif("${item}" STREQUAL "${value}")
- endforeach(item)
-
- if(NOT contains)
- set(${list_var} ${${list_var}} "${value}" PARENT_SCOPE)
- endif(NOT contains)
-endfunction(gp_append_unique)
-
-
-# is_file_executable file result_var
-#
-# Return 1 in ${result_var} if ${file} is a binary executable.
-#
-# Return 0 in ${result_var} otherwise.
-#
-function(is_file_executable file result_var)
- #
- # A file is not executable until proven otherwise:
- #
- set(${result_var} 0 PARENT_SCOPE)
-
- get_filename_component(file_full "${file}" ABSOLUTE)
- string(TOLOWER "${file_full}" file_full_lower)
-
- # If file name ends in .exe on Windows, *assume* executable:
- #
- if(WIN32)
- if("${file_full_lower}" MATCHES "\\.exe$")
- set(${result_var} 1 PARENT_SCOPE)
- return()
- endif("${file_full_lower}" MATCHES "\\.exe$")
-
- # A clause could be added here that uses output or return value of dumpbin
- # to determine ${result_var}. In 99%+? practical cases, the exe name
- # match will be sufficient...
- #
- endif(WIN32)
-
- # Use the information returned from the Unix shell command "file" to
- # determine if ${file_full} should be considered an executable file...
- #
- # If the file command's output contains "executable" and does *not* contain
- # "text" then it is likely an executable suitable for prerequisite analysis
- # via the get_prerequisites macro.
- #
- if(UNIX)
- if(NOT file_cmd)
- find_program(file_cmd "file")
- endif(NOT file_cmd)
-
- if(file_cmd)
- execute_process(COMMAND "${file_cmd}" "${file_full}"
- OUTPUT_VARIABLE file_ov
- OUTPUT_STRIP_TRAILING_WHITESPACE
- )
-
- # Replace the name of the file in the output with a placeholder token
- # (the string " _file_full_ ") so that just in case the path name of
- # the file contains the word "text" or "executable" we are not fooled
- # into thinking "the wrong thing" because the file name matches the
- # other 'file' command output we are looking for...
- #
- string(REPLACE "${file_full}" " _file_full_ " file_ov "${file_ov}")
- string(TOLOWER "${file_ov}" file_ov)
-
- #message(STATUS "file_ov='${file_ov}'")
- if("${file_ov}" MATCHES "executable")
- #message(STATUS "executable!")
- if("${file_ov}" MATCHES "text")
- #message(STATUS "but text, so *not* a binary executable!")
- else("${file_ov}" MATCHES "text")
- set(${result_var} 1 PARENT_SCOPE)
- return()
- endif("${file_ov}" MATCHES "text")
- endif("${file_ov}" MATCHES "executable")
- else(file_cmd)
- message(STATUS "warning: No 'file' command, skipping execute_process...")
- endif(file_cmd)
- endif(UNIX)
-endfunction(is_file_executable)
-
-
-# gp_item_default_embedded_path item default_embedded_path_var
-#
-# Return the path that others should refer to the item by when the item
-# is embedded inside a bundle.
-#
-# Override on a per-project basis by providing a project-specific
-# gp_item_default_embedded_path_override function.
-#
-function(gp_item_default_embedded_path item default_embedded_path_var)
-
- # On Windows and Linux, "embed" prerequisites in the same directory
- # as the executable by default:
- #
- set(path "@executable_path")
- set(overridden 0)
-
- # On the Mac, relative to the executable depending on the type
- # of the thing we are embedding:
- #
- if(APPLE)
- #
- # The assumption here is that all executables in the bundle will be
- # in same-level-directories inside the bundle. The parent directory
- # of an executable inside the bundle should be MacOS or a sibling of
- # MacOS and all embedded paths returned from here will begin with
- # "@executable_path/../" and will work from all executables in all
- # such same-level-directories inside the bundle.
- #
-
- # By default, embed things right next to the main bundle executable:
- #
- set(path "@executable_path/../../Contents/MacOS")
-
- # Embed .dylibs right next to the main bundle executable:
- #
- if(item MATCHES "\\.dylib$")
- set(path "@executable_path/../MacOS")
- set(overridden 1)
- endif(item MATCHES "\\.dylib$")
-
- # Embed frameworks in the embedded "Frameworks" directory (sibling of MacOS):
- #
- if(NOT overridden)
- if(item MATCHES "[^/]+\\.framework/")
- set(path "@executable_path/../Frameworks")
- set(overridden 1)
- endif(item MATCHES "[^/]+\\.framework/")
- endif(NOT overridden)
- endif()
-
- # Provide a hook so that projects can override the default embedded location
- # of any given library by whatever logic they choose:
- #
- if(COMMAND gp_item_default_embedded_path_override)
- gp_item_default_embedded_path_override("${item}" path)
- endif(COMMAND gp_item_default_embedded_path_override)
-
- set(${default_embedded_path_var} "${path}" PARENT_SCOPE)
-endfunction(gp_item_default_embedded_path)
-
-
-# gp_resolve_item context item exepath dirs resolved_item_var
-#
-# Resolve an item into an existing full path file.
-#
-# Override on a per-project basis by providing a project-specific
-# gp_resolve_item_override function.
-#
-function(gp_resolve_item context item exepath dirs resolved_item_var)
- set(resolved 0)
- set(resolved_item "${item}")
-
- # Is it already resolved?
- #
- if(EXISTS "${resolved_item}")
- set(resolved 1)
- endif(EXISTS "${resolved_item}")
-
- if(NOT resolved)
- if(item MATCHES "@executable_path")
- #
- # @executable_path references are assumed relative to exepath
- #
- string(REPLACE "@executable_path" "${exepath}" ri "${item}")
- get_filename_component(ri "${ri}" ABSOLUTE)
-
- if(EXISTS "${ri}")
- #message(STATUS "info: embedded item exists (${ri})")
- set(resolved 1)
- set(resolved_item "${ri}")
- else(EXISTS "${ri}")
- message(STATUS "warning: embedded item does not exist '${ri}'")
- endif(EXISTS "${ri}")
- endif(item MATCHES "@executable_path")
- endif(NOT resolved)
-
- if(NOT resolved)
- if(item MATCHES "@loader_path")
- #
- # @loader_path references are assumed relative to the
- # PATH of the given "context" (presumably another library)
- #
- get_filename_component(contextpath "${context}" PATH)
- string(REPLACE "@loader_path" "${contextpath}" ri "${item}")
- get_filename_component(ri "${ri}" ABSOLUTE)
-
- if(EXISTS "${ri}")
- #message(STATUS "info: embedded item exists (${ri})")
- set(resolved 1)
- set(resolved_item "${ri}")
- else(EXISTS "${ri}")
- message(STATUS "warning: embedded item does not exist '${ri}'")
- endif(EXISTS "${ri}")
- endif(item MATCHES "@loader_path")
- endif(NOT resolved)
-
- if(NOT resolved)
- set(ri "ri-NOTFOUND")
- find_file(ri "${item}" ${exepath} ${dirs} NO_DEFAULT_PATH)
- find_file(ri "${item}" ${exepath} ${dirs} /usr/lib)
- if(ri)
- #message(STATUS "info: 'find_file' in exepath/dirs (${ri})")
- set(resolved 1)
- set(resolved_item "${ri}")
- set(ri "ri-NOTFOUND")
- endif(ri)
- endif(NOT resolved)
-
- if(NOT resolved)
- if(item MATCHES "[^/]+\\.framework/")
- set(fw "fw-NOTFOUND")
- find_file(fw "${item}"
- "~/Library/Frameworks"
- "/Library/Frameworks"
- "/System/Library/Frameworks"
- )
- if(fw)
- #message(STATUS "info: 'find_file' found framework (${fw})")
- set(resolved 1)
- set(resolved_item "${fw}")
- set(fw "fw-NOTFOUND")
- endif(fw)
- endif(item MATCHES "[^/]+\\.framework/")
- endif(NOT resolved)
-
- # Using find_program on Windows will find dll files that are in the PATH.
- # (Converting simple file names into full path names if found.)
- #
- if(WIN32)
- if(NOT resolved)
- set(ri "ri-NOTFOUND")
- find_program(ri "${item}" PATHS "${exepath};${dirs}" NO_DEFAULT_PATH)
- find_program(ri "${item}" PATHS "${exepath};${dirs}")
- if(ri)
- #message(STATUS "info: 'find_program' in exepath/dirs (${ri})")
- set(resolved 1)
- set(resolved_item "${ri}")
- set(ri "ri-NOTFOUND")
- endif(ri)
- endif(NOT resolved)
- endif(WIN32)
-
- # Provide a hook so that projects can override item resolution
- # by whatever logic they choose:
- #
- if(COMMAND gp_resolve_item_override)
- gp_resolve_item_override("${context}" "${item}" "${exepath}" "${dirs}" resolved_item resolved)
- endif(COMMAND gp_resolve_item_override)
-
- if(NOT resolved)
- message(STATUS "
-warning: cannot resolve item '${item}'
-
- possible problems:
- need more directories?
- need to use InstallRequiredSystemLibraries?
- run in install tree instead of build tree?
-")
-# message(STATUS "
-#******************************************************************************
-#warning: cannot resolve item '${item}'
-#
-# possible problems:
-# need more directories?
-# need to use InstallRequiredSystemLibraries?
-# run in install tree instead of build tree?
-#
-# context='${context}'
-# item='${item}'
-# exepath='${exepath}'
-# dirs='${dirs}'
-# resolved_item_var='${resolved_item_var}'
-#******************************************************************************
-#")
- endif(NOT resolved)
-
- set(${resolved_item_var} "${resolved_item}" PARENT_SCOPE)
-endfunction(gp_resolve_item)
-
-
-# gp_resolved_file_type original_file file exepath dirs type_var
-#
-# Return the type of ${file} with respect to ${original_file}. String
-# describing type of prerequisite is returned in variable named ${type_var}.
-#
-# Use ${exepath} and ${dirs} if necessary to resolve non-absolute ${file}
-# values -- but only for non-embedded items.
-#
-# Possible types are:
-# system
-# local
-# embedded
-# other
-#
-function(gp_resolved_file_type original_file file exepath dirs type_var)
- #message(STATUS "**")
-
- if(NOT IS_ABSOLUTE "${original_file}")
- message(STATUS "warning: gp_resolved_file_type expects absolute full path for first arg original_file")
- endif()
-
- set(is_embedded 0)
- set(is_local 0)
- set(is_system 0)
-
- set(resolved_file "${file}")
-
- if("${file}" MATCHES "^@(executable|loader)_path")
- set(is_embedded 1)
- endif()
-
- if(NOT is_embedded)
- if(NOT IS_ABSOLUTE "${file}")
- gp_resolve_item("${original_file}" "${file}" "${exepath}" "${dirs}" resolved_file)
- endif()
-
- string(TOLOWER "${original_file}" original_lower)
- string(TOLOWER "${resolved_file}" lower)
-
- if(UNIX)
- if(resolved_file MATCHES "^(/lib/|/lib32/|/lib64/|/usr/lib/|/usr/lib32/|/usr/lib64/|/usr/X11R6/)")
- set(is_system 1)
- endif()
- endif()
-
- if(APPLE)
- if(resolved_file MATCHES "^(/System/Library/|/usr/lib/)")
- set(is_system 1)
- endif()
- endif()
-
- if(WIN32)
- string(TOLOWER "$ENV{SystemRoot}" sysroot)
- string(REGEX REPLACE "\\\\" "/" sysroot "${sysroot}")
-
- string(TOLOWER "$ENV{windir}" windir)
- string(REGEX REPLACE "\\\\" "/" windir "${windir}")
-
- if(lower MATCHES "^(${sysroot}/system|${windir}/system|${sysroot}/syswow|${windir}/syswow|(.*/)*msvc[^/]+dll)")
- set(is_system 1)
- endif()
- endif()
-
- if(NOT is_system)
- get_filename_component(original_path "${original_lower}" PATH)
- get_filename_component(path "${lower}" PATH)
- if("${original_path}" STREQUAL "${path}")
- set(is_local 1)
- endif()
- endif()
- endif()
-
- # Return type string based on computed booleans:
- #
- set(type "other")
-
- if(is_system)
- set(type "system")
- elseif(is_embedded)
- set(type "embedded")
- elseif(is_local)
- set(type "local")
- endif()
-
- #message(STATUS "gp_resolved_file_type: '${file}' '${resolved_file}'")
- #message(STATUS " type: '${type}'")
-
- if(NOT is_embedded)
- if(NOT IS_ABSOLUTE "${resolved_file}")
- if(lower MATCHES "^msvc[^/]+dll" AND is_system)
- message(STATUS "info: non-absolute msvc file '${file}' returning type '${type}'")
- else()
- message(STATUS "warning: gp_resolved_file_type non-absolute file '${file}' returning type '${type}' -- possibly incorrect")
- endif()
- endif()
- endif()
-
- set(${type_var} "${type}" PARENT_SCOPE)
-
- #message(STATUS "**")
-endfunction()
-
-
-# gp_file_type original_file file type_var
-#
-# Return the type of ${file} with respect to ${original_file}. String
-# describing type of prerequisite is returned in variable named ${type_var}.
-#
-# Possible types are:
-# system
-# local
-# embedded
-# other
-#
-function(gp_file_type original_file file type_var)
- if(NOT IS_ABSOLUTE "${original_file}")
- message(STATUS "warning: gp_file_type expects absolute full path for first arg original_file")
- endif()
-
- get_filename_component(exepath "${original_file}" PATH)
-
- set(type "")
- gp_resolved_file_type("${original_file}" "${file}" "${exepath}" "" type)
-
- set(${type_var} "${type}" PARENT_SCOPE)
-endfunction(gp_file_type)
-
-
-# get_prerequisites target prerequisites_var exclude_system recurse dirs
-#
-# Get the list of shared library files required by ${target}. The list in
-# the variable named ${prerequisites_var} should be empty on first entry to
-# this function. On exit, ${prerequisites_var} will contain the list of
-# required shared library files.
-#
-# target is the full path to an executable file
-#
-# prerequisites_var is the name of a CMake variable to contain the results
-#
-# exclude_system is 0 or 1: 0 to include "system" prerequisites , 1 to
-# exclude them
-#
-# recurse is 0 or 1: 0 for direct prerequisites only, 1 for all prerequisites
-# recursively
-#
-# exepath is the path to the top level executable used for @executable_path
-# replacment on the Mac
-#
-# dirs is a list of paths where libraries might be found: these paths are
-# searched first when a target without any path info is given. Then standard
-# system locations are also searched: PATH, Framework locations, /usr/lib...
-#
-function(get_prerequisites target prerequisites_var exclude_system recurse exepath dirs)
- set(verbose 0)
- set(eol_char "E")
-
- if(NOT IS_ABSOLUTE "${target}")
- message("warning: target '${target}' is not absolute...")
- endif(NOT IS_ABSOLUTE "${target}")
-
- if(NOT EXISTS "${target}")
- message("warning: target '${target}' does not exist...")
- endif(NOT EXISTS "${target}")
-
- # <setup-gp_tool-vars>
- #
- # Try to choose the right tool by default. Caller can set gp_tool prior to
- # calling this function to force using a different tool.
- #
- if("${gp_tool}" STREQUAL "")
- set(gp_tool "ldd")
- if(APPLE)
- set(gp_tool "otool")
- endif(APPLE)
- if(WIN32)
- set(gp_tool "dumpbin")
- endif(WIN32)
- endif("${gp_tool}" STREQUAL "")
-
- set(gp_tool_known 0)
-
- if("${gp_tool}" STREQUAL "ldd")
- set(gp_cmd_args "")
- set(gp_regex "^[\t ]*[^\t ]+ => ([^\t ]+).*${eol_char}$")
- set(gp_regex_cmp_count 1)
- set(gp_tool_known 1)
- endif("${gp_tool}" STREQUAL "ldd")
-
- if("${gp_tool}" STREQUAL "otool")
- set(gp_cmd_args "-L")
- set(gp_regex "^\t([^\t]+) \\(compatibility version ([0-9]+.[0-9]+.[0-9]+), current version ([0-9]+.[0-9]+.[0-9]+)\\)${eol_char}$")
- set(gp_regex_cmp_count 3)
- set(gp_tool_known 1)
- endif("${gp_tool}" STREQUAL "otool")
-
- if("${gp_tool}" STREQUAL "dumpbin")
- set(gp_cmd_args "/dependents")
- set(gp_regex "^ ([^ ].*[Dd][Ll][Ll])${eol_char}$")
- set(gp_regex_cmp_count 1)
- set(gp_tool_known 1)
- set(ENV{VS_UNICODE_OUTPUT} "") # Block extra output from inside VS IDE.
- endif("${gp_tool}" STREQUAL "dumpbin")
-
- if(NOT gp_tool_known)
- message(STATUS "warning: gp_tool='${gp_tool}' is an unknown tool...")
- message(STATUS "CMake function get_prerequisites needs more code to handle '${gp_tool}'")
- message(STATUS "Valid gp_tool values are dumpbin, ldd and otool.")
- return()
- endif(NOT gp_tool_known)
-
- set(gp_cmd_paths ${gp_cmd_paths}
- "C:/Program Files/Microsoft Visual Studio 9.0/VC/bin"
- "C:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/bin"
- "C:/Program Files/Microsoft Visual Studio 8/VC/BIN"
- "C:/Program Files (x86)/Microsoft Visual Studio 8/VC/BIN"
- "C:/Program Files/Microsoft Visual Studio .NET 2003/VC7/BIN"
- "C:/Program Files (x86)/Microsoft Visual Studio .NET 2003/VC7/BIN"
- "/usr/local/bin"
- "/usr/bin"
- )
-
- find_program(gp_cmd ${gp_tool} PATHS ${gp_cmd_paths})
-
- if(NOT gp_cmd)
- message(STATUS "warning: could not find '${gp_tool}' - cannot analyze prerequisites...")
- return()
- endif(NOT gp_cmd)
-
- if("${gp_tool}" STREQUAL "dumpbin")
- # When running dumpbin, it also needs the "Common7/IDE" directory in the
- # PATH. It will already be in the PATH if being run from a Visual Studio
- # command prompt. Add it to the PATH here in case we are running from a
- # different command prompt.
- #
- get_filename_component(gp_cmd_dir "${gp_cmd}" PATH)
- get_filename_component(gp_cmd_dlls_dir "${gp_cmd_dir}/../../Common7/IDE" ABSOLUTE)
- if(EXISTS "${gp_cmd_dlls_dir}")
- # only add to the path if it is not already in the path
- if(NOT "$ENV{PATH}" MATCHES "${gp_cmd_dlls_dir}")
- set(ENV{PATH} "$ENV{PATH};${gp_cmd_dlls_dir}")
- endif(NOT "$ENV{PATH}" MATCHES "${gp_cmd_dlls_dir}")
- endif(EXISTS "${gp_cmd_dlls_dir}")
- endif("${gp_tool}" STREQUAL "dumpbin")
- #
- # </setup-gp_tool-vars>
-
- if("${gp_tool}" STREQUAL "ldd")
- set(old_ld_env "$ENV{LD_LIBRARY_PATH}")
- foreach(dir ${exepath} ${dirs})
- set(ENV{LD_LIBRARY_PATH} "${dir}:$ENV{LD_LIBRARY_PATH}")
- endforeach(dir)
- endif("${gp_tool}" STREQUAL "ldd")
-
-
- # Track new prerequisites at each new level of recursion. Start with an
- # empty list at each level:
- #
- set(unseen_prereqs)
-
- # Run gp_cmd on the target:
- #
- execute_process(
- COMMAND ${gp_cmd} ${gp_cmd_args} ${target}
- OUTPUT_VARIABLE gp_cmd_ov
- )
-
- if("${gp_tool}" STREQUAL "ldd")
- set(ENV{LD_LIBRARY_PATH} "${old_ld_env}")
- endif("${gp_tool}" STREQUAL "ldd")
-
- if(verbose)
- message(STATUS "<RawOutput cmd='${gp_cmd} ${gp_cmd_args} ${target}'>")
- message(STATUS "gp_cmd_ov='${gp_cmd_ov}'")
- message(STATUS "</RawOutput>")
- endif(verbose)
-
- get_filename_component(target_dir "${target}" PATH)
-
- # Convert to a list of lines:
- #
- string(REGEX REPLACE ";" "\\\\;" candidates "${gp_cmd_ov}")
- string(REGEX REPLACE "\n" "${eol_char};" candidates "${candidates}")
-
- # Analyze each line for file names that match the regular expression:
- #
- foreach(candidate ${candidates})
- if("${candidate}" MATCHES "${gp_regex}")
- # Extract information from each candidate:
- string(REGEX REPLACE "${gp_regex}" "\\1" raw_item "${candidate}")
-
- if(gp_regex_cmp_count GREATER 1)
- string(REGEX REPLACE "${gp_regex}" "\\2" raw_compat_version "${candidate}")
- string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\1" compat_major_version "${raw_compat_version}")
- string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\2" compat_minor_version "${raw_compat_version}")
- string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\3" compat_patch_version "${raw_compat_version}")
- endif(gp_regex_cmp_count GREATER 1)
-
- if(gp_regex_cmp_count GREATER 2)
- string(REGEX REPLACE "${gp_regex}" "\\3" raw_current_version "${candidate}")
- string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\1" current_major_version "${raw_current_version}")
- string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\2" current_minor_version "${raw_current_version}")
- string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\3" current_patch_version "${raw_current_version}")
- endif(gp_regex_cmp_count GREATER 2)
-
- # Use the raw_item as the list entries returned by this function. Use the
- # gp_resolve_item function to resolve it to an actual full path file if
- # necessary.
- #
- set(item "${raw_item}")
-
- # Add each item unless it is excluded:
- #
- set(add_item 1)
-
- if(${exclude_system})
- set(type "")
- gp_resolved_file_type("${target}" "${item}" "${exepath}" "${dirs}" type)
- if("${type}" STREQUAL "system")
- set(add_item 0)
- endif("${type}" STREQUAL "system")
- endif(${exclude_system})
-
- if(add_item)
- list(LENGTH ${prerequisites_var} list_length_before_append)
- gp_append_unique(${prerequisites_var} "${item}")
- list(LENGTH ${prerequisites_var} list_length_after_append)
-
- if(${recurse})
- # If item was really added, this is the first time we have seen it.
- # Add it to unseen_prereqs so that we can recursively add *its*
- # prerequisites...
- #
- # But first: resolve its name to an absolute full path name such
- # that the analysis tools can simply accept it as input.
- #
- if(NOT list_length_before_append EQUAL list_length_after_append)
- gp_resolve_item("${target}" "${item}" "${exepath}" "${dirs}" resolved_item)
- set(unseen_prereqs ${unseen_prereqs} "${resolved_item}")
- endif(NOT list_length_before_append EQUAL list_length_after_append)
- endif(${recurse})
- endif(add_item)
- else("${candidate}" MATCHES "${gp_regex}")
- if(verbose)
- message(STATUS "ignoring non-matching line: '${candidate}'")
- endif(verbose)
- endif("${candidate}" MATCHES "${gp_regex}")
- endforeach(candidate)
-
- list(LENGTH ${prerequisites_var} prerequisites_var_length)
- if(prerequisites_var_length GREATER 0)
- list(SORT ${prerequisites_var})
- endif(prerequisites_var_length GREATER 0)
- if(${recurse})
- set(more_inputs ${unseen_prereqs})
- foreach(input ${more_inputs})
- get_prerequisites("${input}" ${prerequisites_var} ${exclude_system} ${recurse} "${exepath}" "${dirs}")
- endforeach(input)
- endif(${recurse})
-
- set(${prerequisites_var} ${${prerequisites_var}} PARENT_SCOPE)
-endfunction(get_prerequisites)
-
-
-# list_prerequisites target all exclude_system verbose
-#
-# ARGV0 (target) is the full path to an executable file
-#
-# optional ARGV1 (all) is 0 or 1: 0 for direct prerequisites only,
-# 1 for all prerequisites recursively
-#
-# optional ARGV2 (exclude_system) is 0 or 1: 0 to include "system"
-# prerequisites , 1 to exclude them
-#
-# optional ARGV3 (verbose) is 0 or 1: 0 to print only full path
-# names of prerequisites, 1 to print extra information
-#
-function(list_prerequisites target)
- if("${ARGV1}" STREQUAL "")
- set(all 1)
- else("${ARGV1}" STREQUAL "")
- set(all "${ARGV1}")
- endif("${ARGV1}" STREQUAL "")
-
- if("${ARGV2}" STREQUAL "")
- set(exclude_system 0)
- else("${ARGV2}" STREQUAL "")
- set(exclude_system "${ARGV2}")
- endif("${ARGV2}" STREQUAL "")
-
- if("${ARGV3}" STREQUAL "")
- set(verbose 0)
- else("${ARGV3}" STREQUAL "")
- set(verbose "${ARGV3}")
- endif("${ARGV3}" STREQUAL "")
-
- set(count 0)
- set(count_str "")
- set(print_count "${verbose}")
- set(print_prerequisite_type "${verbose}")
- set(print_target "${verbose}")
- set(type_str "")
-
- get_filename_component(exepath "${target}" PATH)
-
- set(prereqs "")
- get_prerequisites("${target}" prereqs ${exclude_system} ${all} "${exepath}" "")
-
- if(print_target)
- message(STATUS "File '${target}' depends on:")
- endif(print_target)
-
- foreach(d ${prereqs})
- math(EXPR count "${count} + 1")
-
- if(print_count)
- set(count_str "${count}. ")
- endif(print_count)
-
- if(print_prerequisite_type)
- gp_file_type("${target}" "${d}" type)
- set(type_str " (${type})")
- endif(print_prerequisite_type)
-
- message(STATUS "${count_str}${d}${type_str}")
- endforeach(d)
-endfunction(list_prerequisites)
-
-
-# list_prerequisites_by_glob glob_arg glob_exp
-#
-# glob_arg is GLOB or GLOB_RECURSE
-#
-# glob_exp is a globbing expression used with "file(GLOB" to retrieve a list
-# of matching files. If a matching file is executable, its prerequisites are
-# listed.
-#
-# Any additional (optional) arguments provided are passed along as the
-# optional arguments to the list_prerequisites calls.
-#
-function(list_prerequisites_by_glob glob_arg glob_exp)
- message(STATUS "=============================================================================")
- message(STATUS "List prerequisites of executables matching ${glob_arg} '${glob_exp}'")
- message(STATUS "")
- file(${glob_arg} file_list ${glob_exp})
- foreach(f ${file_list})
- is_file_executable("${f}" is_f_executable)
- if(is_f_executable)
- message(STATUS "=============================================================================")
- list_prerequisites("${f}" ${ARGN})
- message(STATUS "")
- endif(is_f_executable)
- endforeach(f)
-endfunction(list_prerequisites_by_glob)
+# GetPrerequisites.cmake
+#
+# This script provides functions to list the .dll, .dylib or .so files that an
+# executable or shared library file depends on. (Its prerequisites.)
+#
+# It uses various tools to obtain the list of required shared library files:
+# dumpbin (Windows)
+# ldd (Linux/Unix)
+# otool (Mac OSX)
+#
+# The following functions are provided by this script:
+# gp_append_unique
+# is_file_executable
+# gp_item_default_embedded_path
+# (projects can override with gp_item_default_embedded_path_override)
+# gp_resolve_item
+# (projects can override with gp_resolve_item_override)
+# gp_resolved_file_type
+# gp_file_type
+# get_prerequisites
+# list_prerequisites
+# list_prerequisites_by_glob
+#
+# Requires CMake 2.6 or greater because it uses function, break, return and
+# PARENT_SCOPE.
+
+#=============================================================================
+# Copyright 2008-2009 Kitware, Inc.
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distributed this file outside of CMake, substitute the full
+# License text for the above reference.)
+
+# gp_append_unique list_var value
+#
+# Append value to the list variable ${list_var} only if the value is not
+# already in the list.
+#
+function(gp_append_unique list_var value)
+ set(contains 0)
+
+ foreach(item ${${list_var}})
+ if("${item}" STREQUAL "${value}")
+ set(contains 1)
+ break()
+ endif("${item}" STREQUAL "${value}")
+ endforeach(item)
+
+ if(NOT contains)
+ set(${list_var} ${${list_var}} "${value}" PARENT_SCOPE)
+ endif(NOT contains)
+endfunction(gp_append_unique)
+
+
+# is_file_executable file result_var
+#
+# Return 1 in ${result_var} if ${file} is a binary executable.
+#
+# Return 0 in ${result_var} otherwise.
+#
+function(is_file_executable file result_var)
+ #
+ # A file is not executable until proven otherwise:
+ #
+ set(${result_var} 0 PARENT_SCOPE)
+
+ get_filename_component(file_full "${file}" ABSOLUTE)
+ string(TOLOWER "${file_full}" file_full_lower)
+
+ # If file name ends in .exe on Windows, *assume* executable:
+ #
+ if(WIN32)
+ if("${file_full_lower}" MATCHES "\\.exe$")
+ set(${result_var} 1 PARENT_SCOPE)
+ return()
+ endif("${file_full_lower}" MATCHES "\\.exe$")
+
+ # A clause could be added here that uses output or return value of dumpbin
+ # to determine ${result_var}. In 99%+? practical cases, the exe name
+ # match will be sufficient...
+ #
+ endif(WIN32)
+
+ # Use the information returned from the Unix shell command "file" to
+ # determine if ${file_full} should be considered an executable file...
+ #
+ # If the file command's output contains "executable" and does *not* contain
+ # "text" then it is likely an executable suitable for prerequisite analysis
+ # via the get_prerequisites macro.
+ #
+ if(UNIX)
+ if(NOT file_cmd)
+ find_program(file_cmd "file")
+ endif(NOT file_cmd)
+
+ if(file_cmd)
+ execute_process(COMMAND "${file_cmd}" "${file_full}"
+ OUTPUT_VARIABLE file_ov
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+
+ # Replace the name of the file in the output with a placeholder token
+ # (the string " _file_full_ ") so that just in case the path name of
+ # the file contains the word "text" or "executable" we are not fooled
+ # into thinking "the wrong thing" because the file name matches the
+ # other 'file' command output we are looking for...
+ #
+ string(REPLACE "${file_full}" " _file_full_ " file_ov "${file_ov}")
+ string(TOLOWER "${file_ov}" file_ov)
+
+ #message(STATUS "file_ov='${file_ov}'")
+ if("${file_ov}" MATCHES "executable")
+ #message(STATUS "executable!")
+ if("${file_ov}" MATCHES "text")
+ #message(STATUS "but text, so *not* a binary executable!")
+ else("${file_ov}" MATCHES "text")
+ set(${result_var} 1 PARENT_SCOPE)
+ return()
+ endif("${file_ov}" MATCHES "text")
+ endif("${file_ov}" MATCHES "executable")
+ else(file_cmd)
+ message(STATUS "warning: No 'file' command, skipping execute_process...")
+ endif(file_cmd)
+ endif(UNIX)
+endfunction(is_file_executable)
+
+
+# gp_item_default_embedded_path item default_embedded_path_var
+#
+# Return the path that others should refer to the item by when the item
+# is embedded inside a bundle.
+#
+# Override on a per-project basis by providing a project-specific
+# gp_item_default_embedded_path_override function.
+#
+function(gp_item_default_embedded_path item default_embedded_path_var)
+
+ # On Windows and Linux, "embed" prerequisites in the same directory
+ # as the executable by default:
+ #
+ set(path "@executable_path")
+ set(overridden 0)
+
+ # On the Mac, relative to the executable depending on the type
+ # of the thing we are embedding:
+ #
+ if(APPLE)
+ #
+ # The assumption here is that all executables in the bundle will be
+ # in same-level-directories inside the bundle. The parent directory
+ # of an executable inside the bundle should be MacOS or a sibling of
+ # MacOS and all embedded paths returned from here will begin with
+ # "@executable_path/../" and will work from all executables in all
+ # such same-level-directories inside the bundle.
+ #
+
+ # By default, embed things right next to the main bundle executable:
+ #
+ set(path "@executable_path/../../Contents/MacOS")
+
+ # Embed .dylibs right next to the main bundle executable:
+ #
+ if(item MATCHES "\\.dylib$")
+ set(path "@executable_path/../MacOS")
+ set(overridden 1)
+ endif(item MATCHES "\\.dylib$")
+
+ # Embed frameworks in the embedded "Frameworks" directory (sibling of MacOS):
+ #
+ if(NOT overridden)
+ if(item MATCHES "[^/]+\\.framework/")
+ set(path "@executable_path/../Frameworks")
+ set(overridden 1)
+ endif(item MATCHES "[^/]+\\.framework/")
+ endif(NOT overridden)
+ endif()
+
+ # Provide a hook so that projects can override the default embedded location
+ # of any given library by whatever logic they choose:
+ #
+ if(COMMAND gp_item_default_embedded_path_override)
+ gp_item_default_embedded_path_override("${item}" path)
+ endif(COMMAND gp_item_default_embedded_path_override)
+
+ set(${default_embedded_path_var} "${path}" PARENT_SCOPE)
+endfunction(gp_item_default_embedded_path)
+
+
+# gp_resolve_item context item exepath dirs resolved_item_var
+#
+# Resolve an item into an existing full path file.
+#
+# Override on a per-project basis by providing a project-specific
+# gp_resolve_item_override function.
+#
+function(gp_resolve_item context item exepath dirs resolved_item_var)
+ set(resolved 0)
+ set(resolved_item "${item}")
+
+ # Is it already resolved?
+ #
+ if(EXISTS "${resolved_item}")
+ set(resolved 1)
+ endif(EXISTS "${resolved_item}")
+
+ if(NOT resolved)
+ if(item MATCHES "@executable_path")
+ #
+ # @executable_path references are assumed relative to exepath
+ #
+ string(REPLACE "@executable_path" "${exepath}" ri "${item}")
+ get_filename_component(ri "${ri}" ABSOLUTE)
+
+ if(EXISTS "${ri}")
+ #message(STATUS "info: embedded item exists (${ri})")
+ set(resolved 1)
+ set(resolved_item "${ri}")
+ else(EXISTS "${ri}")
+ message(STATUS "warning: embedded item does not exist '${ri}'")
+ endif(EXISTS "${ri}")
+ endif(item MATCHES "@executable_path")
+ endif(NOT resolved)
+
+ if(NOT resolved)
+ if(item MATCHES "@loader_path")
+ #
+ # @loader_path references are assumed relative to the
+ # PATH of the given "context" (presumably another library)
+ #
+ get_filename_component(contextpath "${context}" PATH)
+ string(REPLACE "@loader_path" "${contextpath}" ri "${item}")
+ get_filename_component(ri "${ri}" ABSOLUTE)
+
+ if(EXISTS "${ri}")
+ #message(STATUS "info: embedded item exists (${ri})")
+ set(resolved 1)
+ set(resolved_item "${ri}")
+ else(EXISTS "${ri}")
+ message(STATUS "warning: embedded item does not exist '${ri}'")
+ endif(EXISTS "${ri}")
+ endif(item MATCHES "@loader_path")
+ endif(NOT resolved)
+
+ if(NOT resolved)
+ set(ri "ri-NOTFOUND")
+ find_file(ri "${item}" ${exepath} ${dirs} NO_DEFAULT_PATH)
+ find_file(ri "${item}" ${exepath} ${dirs} /usr/lib)
+ if(ri)
+ #message(STATUS "info: 'find_file' in exepath/dirs (${ri})")
+ set(resolved 1)
+ set(resolved_item "${ri}")
+ set(ri "ri-NOTFOUND")
+ endif(ri)
+ endif(NOT resolved)
+
+ if(NOT resolved)
+ if(item MATCHES "[^/]+\\.framework/")
+ set(fw "fw-NOTFOUND")
+ find_file(fw "${item}"
+ "~/Library/Frameworks"
+ "/Library/Frameworks"
+ "/System/Library/Frameworks"
+ )
+ if(fw)
+ #message(STATUS "info: 'find_file' found framework (${fw})")
+ set(resolved 1)
+ set(resolved_item "${fw}")
+ set(fw "fw-NOTFOUND")
+ endif(fw)
+ endif(item MATCHES "[^/]+\\.framework/")
+ endif(NOT resolved)
+
+ # Using find_program on Windows will find dll files that are in the PATH.
+ # (Converting simple file names into full path names if found.)
+ #
+ if(WIN32)
+ if(NOT resolved)
+ set(ri "ri-NOTFOUND")
+ find_program(ri "${item}" PATHS "${exepath};${dirs}" NO_DEFAULT_PATH)
+ find_program(ri "${item}" PATHS "${exepath};${dirs}")
+ if(ri)
+ #message(STATUS "info: 'find_program' in exepath/dirs (${ri})")
+ set(resolved 1)
+ set(resolved_item "${ri}")
+ set(ri "ri-NOTFOUND")
+ endif(ri)
+ endif(NOT resolved)
+ endif(WIN32)
+
+ # Provide a hook so that projects can override item resolution
+ # by whatever logic they choose:
+ #
+ if(COMMAND gp_resolve_item_override)
+ gp_resolve_item_override("${context}" "${item}" "${exepath}" "${dirs}" resolved_item resolved)
+ endif(COMMAND gp_resolve_item_override)
+
+ if(NOT resolved)
+ message(STATUS "
+warning: cannot resolve item '${item}'
+
+ possible problems:
+ need more directories?
+ need to use InstallRequiredSystemLibraries?
+ run in install tree instead of build tree?
+")
+# message(STATUS "
+#******************************************************************************
+#warning: cannot resolve item '${item}'
+#
+# possible problems:
+# need more directories?
+# need to use InstallRequiredSystemLibraries?
+# run in install tree instead of build tree?
+#
+# context='${context}'
+# item='${item}'
+# exepath='${exepath}'
+# dirs='${dirs}'
+# resolved_item_var='${resolved_item_var}'
+#******************************************************************************
+#")
+ endif(NOT resolved)
+
+ set(${resolved_item_var} "${resolved_item}" PARENT_SCOPE)
+endfunction(gp_resolve_item)
+
+
+# gp_resolved_file_type original_file file exepath dirs type_var
+#
+# Return the type of ${file} with respect to ${original_file}. String
+# describing type of prerequisite is returned in variable named ${type_var}.
+#
+# Use ${exepath} and ${dirs} if necessary to resolve non-absolute ${file}
+# values -- but only for non-embedded items.
+#
+# Possible types are:
+# system
+# local
+# embedded
+# other
+#
+function(gp_resolved_file_type original_file file exepath dirs type_var)
+ #message(STATUS "**")
+
+ if(NOT IS_ABSOLUTE "${original_file}")
+ message(STATUS "warning: gp_resolved_file_type expects absolute full path for first arg original_file")
+ endif()
+
+ set(is_embedded 0)
+ set(is_local 0)
+ set(is_system 0)
+
+ set(resolved_file "${file}")
+
+ if("${file}" MATCHES "^@(executable|loader)_path")
+ set(is_embedded 1)
+ endif()
+
+ if(NOT is_embedded)
+ if(NOT IS_ABSOLUTE "${file}")
+ gp_resolve_item("${original_file}" "${file}" "${exepath}" "${dirs}" resolved_file)
+ endif()
+
+ string(TOLOWER "${original_file}" original_lower)
+ string(TOLOWER "${resolved_file}" lower)
+
+ if(UNIX)
+ if(resolved_file MATCHES "^(/lib/|/lib32/|/lib64/|/usr/lib/|/usr/lib32/|/usr/lib64/|/usr/X11R6/)")
+ set(is_system 1)
+ endif()
+ endif()
+
+ if(APPLE)
+ if(resolved_file MATCHES "^(/System/Library/|/usr/lib/)")
+ set(is_system 1)
+ endif()
+ endif()
+
+ if(WIN32)
+ string(TOLOWER "$ENV{SystemRoot}" sysroot)
+ string(REGEX REPLACE "\\\\" "/" sysroot "${sysroot}")
+
+ string(TOLOWER "$ENV{windir}" windir)
+ string(REGEX REPLACE "\\\\" "/" windir "${windir}")
+
+ if(lower MATCHES "^(${sysroot}/system|${windir}/system|${sysroot}/syswow|${windir}/syswow|(.*/)*msvc[^/]+dll)")
+ set(is_system 1)
+ endif()
+ endif()
+
+ if(NOT is_system)
+ get_filename_component(original_path "${original_lower}" PATH)
+ get_filename_component(path "${lower}" PATH)
+ if("${original_path}" STREQUAL "${path}")
+ set(is_local 1)
+ endif()
+ endif()
+ endif()
+
+ # Return type string based on computed booleans:
+ #
+ set(type "other")
+
+ if(is_system)
+ set(type "system")
+ elseif(is_embedded)
+ set(type "embedded")
+ elseif(is_local)
+ set(type "local")
+ endif()
+
+ #message(STATUS "gp_resolved_file_type: '${file}' '${resolved_file}'")
+ #message(STATUS " type: '${type}'")
+
+ if(NOT is_embedded)
+ if(NOT IS_ABSOLUTE "${resolved_file}")
+ if(lower MATCHES "^msvc[^/]+dll" AND is_system)
+ message(STATUS "info: non-absolute msvc file '${file}' returning type '${type}'")
+ else()
+ message(STATUS "warning: gp_resolved_file_type non-absolute file '${file}' returning type '${type}' -- possibly incorrect")
+ endif()
+ endif()
+ endif()
+
+ set(${type_var} "${type}" PARENT_SCOPE)
+
+ #message(STATUS "**")
+endfunction()
+
+
+# gp_file_type original_file file type_var
+#
+# Return the type of ${file} with respect to ${original_file}. String
+# describing type of prerequisite is returned in variable named ${type_var}.
+#
+# Possible types are:
+# system
+# local
+# embedded
+# other
+#
+function(gp_file_type original_file file type_var)
+ if(NOT IS_ABSOLUTE "${original_file}")
+ message(STATUS "warning: gp_file_type expects absolute full path for first arg original_file")
+ endif()
+
+ get_filename_component(exepath "${original_file}" PATH)
+
+ set(type "")
+ gp_resolved_file_type("${original_file}" "${file}" "${exepath}" "" type)
+
+ set(${type_var} "${type}" PARENT_SCOPE)
+endfunction(gp_file_type)
+
+
+# get_prerequisites target prerequisites_var exclude_system recurse dirs
+#
+# Get the list of shared library files required by ${target}. The list in
+# the variable named ${prerequisites_var} should be empty on first entry to
+# this function. On exit, ${prerequisites_var} will contain the list of
+# required shared library files.
+#
+# target is the full path to an executable file
+#
+# prerequisites_var is the name of a CMake variable to contain the results
+#
+# exclude_system is 0 or 1: 0 to include "system" prerequisites , 1 to
+# exclude them
+#
+# recurse is 0 or 1: 0 for direct prerequisites only, 1 for all prerequisites
+# recursively
+#
+# exepath is the path to the top level executable used for @executable_path
+# replacment on the Mac
+#
+# dirs is a list of paths where libraries might be found: these paths are
+# searched first when a target without any path info is given. Then standard
+# system locations are also searched: PATH, Framework locations, /usr/lib...
+#
+function(get_prerequisites target prerequisites_var exclude_system recurse exepath dirs)
+ set(verbose 0)
+ set(eol_char "E")
+
+ if(NOT IS_ABSOLUTE "${target}")
+ message("warning: target '${target}' is not absolute...")
+ endif(NOT IS_ABSOLUTE "${target}")
+
+ if(NOT EXISTS "${target}")
+ message("warning: target '${target}' does not exist...")
+ endif(NOT EXISTS "${target}")
+
+ # <setup-gp_tool-vars>
+ #
+ # Try to choose the right tool by default. Caller can set gp_tool prior to
+ # calling this function to force using a different tool.
+ #
+ if("${gp_tool}" STREQUAL "")
+ set(gp_tool "ldd")
+ if(APPLE)
+ set(gp_tool "otool")
+ endif(APPLE)
+ if(WIN32)
+ set(gp_tool "dumpbin")
+ endif(WIN32)
+ endif("${gp_tool}" STREQUAL "")
+
+ set(gp_tool_known 0)
+
+ if("${gp_tool}" STREQUAL "ldd")
+ set(gp_cmd_args "")
+ set(gp_regex "^[\t ]*[^\t ]+ => ([^\t ]+).*${eol_char}$")
+ set(gp_regex_cmp_count 1)
+ set(gp_tool_known 1)
+ endif("${gp_tool}" STREQUAL "ldd")
+
+ if("${gp_tool}" STREQUAL "otool")
+ set(gp_cmd_args "-L")
+ set(gp_regex "^\t([^\t]+) \\(compatibility version ([0-9]+.[0-9]+.[0-9]+), current version ([0-9]+.[0-9]+.[0-9]+)\\)${eol_char}$")
+ set(gp_regex_cmp_count 3)
+ set(gp_tool_known 1)
+ endif("${gp_tool}" STREQUAL "otool")
+
+ if("${gp_tool}" STREQUAL "dumpbin")
+ set(gp_cmd_args "/dependents")
+ set(gp_regex "^ ([^ ].*[Dd][Ll][Ll])${eol_char}$")
+ set(gp_regex_cmp_count 1)
+ set(gp_tool_known 1)
+ set(ENV{VS_UNICODE_OUTPUT} "") # Block extra output from inside VS IDE.
+ endif("${gp_tool}" STREQUAL "dumpbin")
+
+ if(NOT gp_tool_known)
+ message(STATUS "warning: gp_tool='${gp_tool}' is an unknown tool...")
+ message(STATUS "CMake function get_prerequisites needs more code to handle '${gp_tool}'")
+ message(STATUS "Valid gp_tool values are dumpbin, ldd and otool.")
+ return()
+ endif(NOT gp_tool_known)
+
+ set(gp_cmd_paths ${gp_cmd_paths}
+ "C:/Program Files/Microsoft Visual Studio 9.0/VC/bin"
+ "C:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/bin"
+ "C:/Program Files/Microsoft Visual Studio 8/VC/BIN"
+ "C:/Program Files (x86)/Microsoft Visual Studio 8/VC/BIN"
+ "C:/Program Files/Microsoft Visual Studio .NET 2003/VC7/BIN"
+ "C:/Program Files (x86)/Microsoft Visual Studio .NET 2003/VC7/BIN"
+ "/usr/local/bin"
+ "/usr/bin"
+ )
+
+ find_program(gp_cmd ${gp_tool} PATHS ${gp_cmd_paths})
+
+ if(NOT gp_cmd)
+ message(STATUS "warning: could not find '${gp_tool}' - cannot analyze prerequisites...")
+ return()
+ endif(NOT gp_cmd)
+
+ if("${gp_tool}" STREQUAL "dumpbin")
+ # When running dumpbin, it also needs the "Common7/IDE" directory in the
+ # PATH. It will already be in the PATH if being run from a Visual Studio
+ # command prompt. Add it to the PATH here in case we are running from a
+ # different command prompt.
+ #
+ get_filename_component(gp_cmd_dir "${gp_cmd}" PATH)
+ get_filename_component(gp_cmd_dlls_dir "${gp_cmd_dir}/../../Common7/IDE" ABSOLUTE)
+ if(EXISTS "${gp_cmd_dlls_dir}")
+ # only add to the path if it is not already in the path
+ if(NOT "$ENV{PATH}" MATCHES "${gp_cmd_dlls_dir}")
+ set(ENV{PATH} "$ENV{PATH};${gp_cmd_dlls_dir}")
+ endif(NOT "$ENV{PATH}" MATCHES "${gp_cmd_dlls_dir}")
+ endif(EXISTS "${gp_cmd_dlls_dir}")
+ endif("${gp_tool}" STREQUAL "dumpbin")
+ #
+ # </setup-gp_tool-vars>
+
+ if("${gp_tool}" STREQUAL "ldd")
+ set(old_ld_env "$ENV{LD_LIBRARY_PATH}")
+ foreach(dir ${exepath} ${dirs})
+ set(ENV{LD_LIBRARY_PATH} "${dir}:$ENV{LD_LIBRARY_PATH}")
+ endforeach(dir)
+ endif("${gp_tool}" STREQUAL "ldd")
+
+
+ # Track new prerequisites at each new level of recursion. Start with an
+ # empty list at each level:
+ #
+ set(unseen_prereqs)
+
+ # Run gp_cmd on the target:
+ #
+ execute_process(
+ COMMAND ${gp_cmd} ${gp_cmd_args} ${target}
+ OUTPUT_VARIABLE gp_cmd_ov
+ )
+
+ if("${gp_tool}" STREQUAL "ldd")
+ set(ENV{LD_LIBRARY_PATH} "${old_ld_env}")
+ endif("${gp_tool}" STREQUAL "ldd")
+
+ if(verbose)
+ message(STATUS "<RawOutput cmd='${gp_cmd} ${gp_cmd_args} ${target}'>")
+ message(STATUS "gp_cmd_ov='${gp_cmd_ov}'")
+ message(STATUS "</RawOutput>")
+ endif(verbose)
+
+ get_filename_component(target_dir "${target}" PATH)
+
+ # Convert to a list of lines:
+ #
+ string(REGEX REPLACE ";" "\\\\;" candidates "${gp_cmd_ov}")
+ string(REGEX REPLACE "\n" "${eol_char};" candidates "${candidates}")
+
+ # Analyze each line for file names that match the regular expression:
+ #
+ foreach(candidate ${candidates})
+ if("${candidate}" MATCHES "${gp_regex}")
+ # Extract information from each candidate:
+ string(REGEX REPLACE "${gp_regex}" "\\1" raw_item "${candidate}")
+
+ if(gp_regex_cmp_count GREATER 1)
+ string(REGEX REPLACE "${gp_regex}" "\\2" raw_compat_version "${candidate}")
+ string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\1" compat_major_version "${raw_compat_version}")
+ string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\2" compat_minor_version "${raw_compat_version}")
+ string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\3" compat_patch_version "${raw_compat_version}")
+ endif(gp_regex_cmp_count GREATER 1)
+
+ if(gp_regex_cmp_count GREATER 2)
+ string(REGEX REPLACE "${gp_regex}" "\\3" raw_current_version "${candidate}")
+ string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\1" current_major_version "${raw_current_version}")
+ string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\2" current_minor_version "${raw_current_version}")
+ string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\3" current_patch_version "${raw_current_version}")
+ endif(gp_regex_cmp_count GREATER 2)
+
+ # Use the raw_item as the list entries returned by this function. Use the
+ # gp_resolve_item function to resolve it to an actual full path file if
+ # necessary.
+ #
+ set(item "${raw_item}")
+
+ # Add each item unless it is excluded:
+ #
+ set(add_item 1)
+
+ if(${exclude_system})
+ set(type "")
+ gp_resolved_file_type("${target}" "${item}" "${exepath}" "${dirs}" type)
+ if("${type}" STREQUAL "system")
+ set(add_item 0)
+ endif("${type}" STREQUAL "system")
+ endif(${exclude_system})
+
+ if(add_item)
+ list(LENGTH ${prerequisites_var} list_length_before_append)
+ gp_append_unique(${prerequisites_var} "${item}")
+ list(LENGTH ${prerequisites_var} list_length_after_append)
+
+ if(${recurse})
+ # If item was really added, this is the first time we have seen it.
+ # Add it to unseen_prereqs so that we can recursively add *its*
+ # prerequisites...
+ #
+ # But first: resolve its name to an absolute full path name such
+ # that the analysis tools can simply accept it as input.
+ #
+ if(NOT list_length_before_append EQUAL list_length_after_append)
+ gp_resolve_item("${target}" "${item}" "${exepath}" "${dirs}" resolved_item)
+ set(unseen_prereqs ${unseen_prereqs} "${resolved_item}")
+ endif(NOT list_length_before_append EQUAL list_length_after_append)
+ endif(${recurse})
+ endif(add_item)
+ else("${candidate}" MATCHES "${gp_regex}")
+ if(verbose)
+ message(STATUS "ignoring non-matching line: '${candidate}'")
+ endif(verbose)
+ endif("${candidate}" MATCHES "${gp_regex}")
+ endforeach(candidate)
+
+ list(LENGTH ${prerequisites_var} prerequisites_var_length)
+ if(prerequisites_var_length GREATER 0)
+ list(SORT ${prerequisites_var})
+ endif(prerequisites_var_length GREATER 0)
+ if(${recurse})
+ set(more_inputs ${unseen_prereqs})
+ foreach(input ${more_inputs})
+ get_prerequisites("${input}" ${prerequisites_var} ${exclude_system} ${recurse} "${exepath}" "${dirs}")
+ endforeach(input)
+ endif(${recurse})
+
+ set(${prerequisites_var} ${${prerequisites_var}} PARENT_SCOPE)
+endfunction(get_prerequisites)
+
+
+# list_prerequisites target all exclude_system verbose
+#
+# ARGV0 (target) is the full path to an executable file
+#
+# optional ARGV1 (all) is 0 or 1: 0 for direct prerequisites only,
+# 1 for all prerequisites recursively
+#
+# optional ARGV2 (exclude_system) is 0 or 1: 0 to include "system"
+# prerequisites , 1 to exclude them
+#
+# optional ARGV3 (verbose) is 0 or 1: 0 to print only full path
+# names of prerequisites, 1 to print extra information
+#
+function(list_prerequisites target)
+ if("${ARGV1}" STREQUAL "")
+ set(all 1)
+ else("${ARGV1}" STREQUAL "")
+ set(all "${ARGV1}")
+ endif("${ARGV1}" STREQUAL "")
+
+ if("${ARGV2}" STREQUAL "")
+ set(exclude_system 0)
+ else("${ARGV2}" STREQUAL "")
+ set(exclude_system "${ARGV2}")
+ endif("${ARGV2}" STREQUAL "")
+
+ if("${ARGV3}" STREQUAL "")
+ set(verbose 0)
+ else("${ARGV3}" STREQUAL "")
+ set(verbose "${ARGV3}")
+ endif("${ARGV3}" STREQUAL "")
+
+ set(count 0)
+ set(count_str "")
+ set(print_count "${verbose}")
+ set(print_prerequisite_type "${verbose}")
+ set(print_target "${verbose}")
+ set(type_str "")
+
+ get_filename_component(exepath "${target}" PATH)
+
+ set(prereqs "")
+ get_prerequisites("${target}" prereqs ${exclude_system} ${all} "${exepath}" "")
+
+ if(print_target)
+ message(STATUS "File '${target}' depends on:")
+ endif(print_target)
+
+ foreach(d ${prereqs})
+ math(EXPR count "${count} + 1")
+
+ if(print_count)
+ set(count_str "${count}. ")
+ endif(print_count)
+
+ if(print_prerequisite_type)
+ gp_file_type("${target}" "${d}" type)
+ set(type_str " (${type})")
+ endif(print_prerequisite_type)
+
+ message(STATUS "${count_str}${d}${type_str}")
+ endforeach(d)
+endfunction(list_prerequisites)
+
+
+# list_prerequisites_by_glob glob_arg glob_exp
+#
+# glob_arg is GLOB or GLOB_RECURSE
+#
+# glob_exp is a globbing expression used with "file(GLOB" to retrieve a list
+# of matching files. If a matching file is executable, its prerequisites are
+# listed.
+#
+# Any additional (optional) arguments provided are passed along as the
+# optional arguments to the list_prerequisites calls.
+#
+function(list_prerequisites_by_glob glob_arg glob_exp)
+ message(STATUS "=============================================================================")
+ message(STATUS "List prerequisites of executables matching ${glob_arg} '${glob_exp}'")
+ message(STATUS "")
+ file(${glob_arg} file_list ${glob_exp})
+ foreach(f ${file_list})
+ is_file_executable("${f}" is_f_executable)
+ if(is_f_executable)
+ message(STATUS "=============================================================================")
+ list_prerequisites("${f}" ${ARGN})
+ message(STATUS "")
+ endif(is_f_executable)
+ endforeach(f)
+endfunction(list_prerequisites_by_glob)
diff --git a/indra/cmake/GoogleMock.cmake b/indra/cmake/GoogleMock.cmake
index ca5a8034ba..06d6d847a0 100644
--- a/indra/cmake/GoogleMock.cmake
+++ b/indra/cmake/GoogleMock.cmake
@@ -8,9 +8,10 @@ set(GOOGLEMOCK_INCLUDE_DIRS
${LIBS_PREBUILT_DIR}/include)
if (LINUX)
+ # VWR-24366: gmock is underlinked, it needs gtest.
set(GOOGLEMOCK_LIBRARIES
- gmock
- gtest)
+ gmock -Wl,--no-as-needed
+ gtest -Wl,--as-needed)
elseif(WINDOWS)
set(GOOGLEMOCK_LIBRARIES
gmock)
diff --git a/indra/cmake/GooglePerfTools.cmake b/indra/cmake/GooglePerfTools.cmake
index 946fc6b375..8740e36753 100644
--- a/indra/cmake/GooglePerfTools.cmake
+++ b/indra/cmake/GooglePerfTools.cmake
@@ -4,20 +4,20 @@ include(Prebuilt)
if (STANDALONE)
include(FindGooglePerfTools)
else (STANDALONE)
- use_prebuilt_binary(google)
if (WINDOWS)
- use_prebuilt_binary(google-perftools)
+ use_prebuilt_binary(tcmalloc)
set(TCMALLOC_LIBRARIES
debug libtcmalloc_minimal-debug
optimized libtcmalloc_minimal)
set(GOOGLE_PERFTOOLS_FOUND "YES")
endif (WINDOWS)
if (LINUX)
- set(TCMALLOC_LIBRARIES tcmalloc)
- set(STACKTRACE_LIBRARIES stacktrace)
+ use_prebuilt_binary(tcmalloc)
+ set(TCMALLOC_LIBRARIES
+ tcmalloc)
set(PROFILER_LIBRARIES profiler)
set(GOOGLE_PERFTOOLS_INCLUDE_DIR
- ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include)
+ ${LIBS_PREBUILT_DIR}/include)
set(GOOGLE_PERFTOOLS_FOUND "YES")
endif (LINUX)
endif (STANDALONE)
@@ -29,12 +29,11 @@ if (GOOGLE_PERFTOOLS_FOUND)
endif (GOOGLE_PERFTOOLS_FOUND)
if (WINDOWS)
- # *TODO -reenable this once we get server usage sorted out
- #set(USE_GOOGLE_PERFTOOLS ON)
+ set(USE_GOOGLE_PERFTOOLS ON)
endif (WINDOWS)
if (USE_GOOGLE_PERFTOOLS)
- set(TCMALLOC_FLAG -DLL_USE_TCMALLOC=1)
+ set(TCMALLOC_FLAG -ULL_USE_TCMALLOC=1)
include_directories(${GOOGLE_PERFTOOLS_INCLUDE_DIR})
set(GOOGLE_PERFTOOLS_LIBRARIES ${TCMALLOC_LIBRARIES} ${STACKTRACE_LIBRARIES} ${PROFILER_LIBRARIES})
else (USE_GOOGLE_PERFTOOLS)
diff --git a/indra/cmake/JPEG.cmake b/indra/cmake/JPEG.cmake
index 9514d59f64..4f99efd602 100644
--- a/indra/cmake/JPEG.cmake
+++ b/indra/cmake/JPEG.cmake
@@ -12,10 +12,7 @@ else (STANDALONE)
if (LINUX)
set(JPEG_LIBRARIES jpeg)
elseif (DARWIN)
- set(JPEG_LIBRARIES
- optimized ${ARCH_PREBUILT_DIRS_RELEASE}/liblljpeg.a
- debug ${ARCH_PREBUILT_DIRS_DEBUG}/liblljpeg.a
- )
+ set(JPEG_LIBRARIES jpeg)
elseif (WINDOWS)
set(JPEG_LIBRARIES jpeglib)
endif (LINUX)
diff --git a/indra/cmake/JsonCpp.cmake b/indra/cmake/JsonCpp.cmake
index 7dd565be7c..499b00fb44 100644
--- a/indra/cmake/JsonCpp.cmake
+++ b/indra/cmake/JsonCpp.cmake
@@ -11,12 +11,12 @@ else (STANDALONE)
use_prebuilt_binary(jsoncpp)
if (WINDOWS)
set(JSONCPP_LIBRARIES
- debug json_vc80d
- optimized json_vc80)
+ debug json_vc100debug_libmt.lib
+ optimized json_vc100_libmt)
elseif (DARWIN)
- set(JSONCPP_LIBRARIES json_mac-universal-gcc_libmt)
+ set(JSONCPP_LIBRARIES libjson_linux-gcc-4.0.1_libmt.a)
elseif (LINUX)
- set(JSONCPP_LIBRARIES jsoncpp)
+ set(JSONCPP_LIBRARIES libjson_linux-gcc-4.1.3_libmt.a)
endif (WINDOWS)
- set(JSONCPP_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include/jsoncpp)
+ set(JSONCPP_INCLUDE_DIRS "${LIBS_PREBUILT_DIR}/include/jsoncpp" "${LIBS_PREBUILT_DIR}/include/json")
endif (STANDALONE)
diff --git a/indra/cmake/LLAddBuildTest.cmake b/indra/cmake/LLAddBuildTest.cmake
index 79c3bb7da2..08feab6e36 100644
--- a/indra/cmake/LLAddBuildTest.cmake
+++ b/indra/cmake/LLAddBuildTest.cmake
@@ -1,6 +1,7 @@
# -*- cmake -*-
include(LLTestCommand)
include(GoogleMock)
+include(Tut)
MACRO(LL_ADD_PROJECT_UNIT_TESTS project sources)
# Given a project name and a list of sourcefiles (with optional properties on each),
@@ -57,11 +58,6 @@ INCLUDE(GoogleMock)
${CMAKE_SOURCE_DIR}/test/test.h
)
- # Use the default flags
- if (LINUX)
- SET(CMAKE_EXE_LINKER_FLAGS "")
- endif (LINUX)
-
# start the source test executable definitions
SET(${project}_TEST_OUTPUT "")
FOREACH (source ${sources})
@@ -99,7 +95,7 @@ INCLUDE(GoogleMock)
IF(${name}_test_additional_INCLUDE_DIRS MATCHES NOTFOUND)
SET(${name}_test_additional_INCLUDE_DIRS "")
ENDIF(${name}_test_additional_INCLUDE_DIRS MATCHES NOTFOUND)
- INCLUDE_DIRECTORIES(${alltest_INCLUDE_DIRS} ${name}_test_additional_INCLUDE_DIRS )
+ INCLUDE_DIRECTORIES(${alltest_INCLUDE_DIRS} ${${name}_test_additional_INCLUDE_DIRS} )
IF(LL_TEST_VERBOSE)
MESSAGE("LL_ADD_PROJECT_UNIT_TESTS ${name}_test_additional_INCLUDE_DIRS ${${name}_test_additional_INCLUDE_DIRS}")
ENDIF(LL_TEST_VERBOSE)
@@ -129,7 +125,15 @@ INCLUDE(GoogleMock)
ENDIF(LL_TEST_VERBOSE)
# Add to project
TARGET_LINK_LIBRARIES(PROJECT_${project}_TEST_${name} ${alltest_LIBRARIES} ${alltest_DEP_TARGETS} ${${name}_test_additional_PROJECTS} ${${name}_test_additional_LIBRARIES} )
-
+ # Compile-time Definitions
+ GET_SOURCE_FILE_PROPERTY(${name}_test_additional_CFLAGS ${source} LL_TEST_ADDITIONAL_CFLAGS)
+ IF(NOT ${name}_test_additional_CFLAGS MATCHES NOTFOUND)
+ SET_TARGET_PROPERTIES(PROJECT_${project}_TEST_${name} PROPERTIES COMPILE_FLAGS ${${name}_test_additional_CFLAGS} )
+ IF(LL_TEST_VERBOSE)
+ MESSAGE("LL_ADD_PROJECT_UNIT_TESTS ${name}_test_additional_CFLAGS ${${name}_test_additional_CFLAGS}")
+ ENDIF(LL_TEST_VERBOSE)
+ ENDIF(NOT ${name}_test_additional_CFLAGS MATCHES NOTFOUND)
+
#
# Setup test targets
#
@@ -197,6 +201,9 @@ FUNCTION(LL_ADD_INTEGRATION_TEST
endif(TEST_DEBUG)
ADD_EXECUTABLE(INTEGRATION_TEST_${testname} ${source_files})
SET_TARGET_PROPERTIES(INTEGRATION_TEST_${testname} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${EXE_STAGING_DIR}")
+ if(STANDALONE)
+ SET_TARGET_PROPERTIES(INTEGRATION_TEST_${testname} PROPERTIES COMPILE_FLAGS -I"${TUT_INCLUDE_DIR}")
+ endif(STANDALONE)
# Add link deps to the executable
if(TEST_DEBUG)
diff --git a/indra/cmake/LLCommon.cmake b/indra/cmake/LLCommon.cmake
index d1ab264a41..17e211cb99 100644
--- a/indra/cmake/LLCommon.cmake
+++ b/indra/cmake/LLCommon.cmake
@@ -13,7 +13,14 @@ set(LLCOMMON_INCLUDE_DIRS
${Boost_INCLUDE_DIRS}
)
-set(LLCOMMON_LIBRARIES llcommon)
+if (LINUX)
+ # In order to support using ld.gold on linux, we need to explicitely
+ # specify all libraries that llcommon uses.
+ # llcommon uses `clock_gettime' which is provided by librt on linux.
+ set(LLCOMMON_LIBRARIES llcommon rt)
+else (LINUX)
+ set(LLCOMMON_LIBRARIES llcommon)
+endif (LINUX)
add_definitions(${TCMALLOC_FLAG})
diff --git a/indra/cmake/LLConvexDecomposition.cmake b/indra/cmake/LLConvexDecomposition.cmake
new file mode 100644
index 0000000000..8e44504782
--- /dev/null
+++ b/indra/cmake/LLConvexDecomposition.cmake
@@ -0,0 +1,12 @@
+# -*- cmake -*-
+include(Prebuilt)
+
+set(LLCONVEXDECOMP_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include)
+
+if (INSTALL_PROPRIETARY AND NOT STANDALONE)
+ use_prebuilt_binary(llconvexdecomposition)
+ set(LLCONVEXDECOMP_LIBRARY llconvexdecomposition)
+else (INSTALL_PROPRIETARY AND NOT STANDALONE)
+ use_prebuilt_binary(llconvexdecompositionstub)
+ set(LLCONVEXDECOMP_LIBRARY llconvexdecompositionstub)
+endif (INSTALL_PROPRIETARY AND NOT STANDALONE)
diff --git a/indra/cmake/LLKDU.cmake b/indra/cmake/LLKDU.cmake
index 27c8ada686..e478b01f84 100644
--- a/indra/cmake/LLKDU.cmake
+++ b/indra/cmake/LLKDU.cmake
@@ -1,7 +1,21 @@
# -*- cmake -*-
-include(Prebuilt)
-if (INSTALL_PROPRIETARY AND NOT STANDALONE)
+# USE_KDU can be set when launching cmake as an option using the argument -DUSE_KDU:BOOL=ON
+# When building using proprietary binaries though (i.e. having access to LL private servers),
+# we always build with KDU
+if (INSTALL_PROPRIETARY)
+ set(USE_KDU ON CACHE BOOL "Use Kakadu library.")
+endif (INSTALL_PROPRIETARY)
+
+if (USE_KDU)
+ include(Prebuilt)
use_prebuilt_binary(kdu)
- set(LLKDU_LIBRARY llkdu)
-endif (INSTALL_PROPRIETARY AND NOT STANDALONE)
+ if (WINDOWS)
+ set(KDU_LIBRARY kdu.lib)
+ else (WINDOWS)
+ set(KDU_LIBRARY libkdu.a)
+ endif (WINDOWS)
+ set(KDU_INCLUDE_DIR ${AUTOBUILD_INSTALL_DIR}/include/kdu)
+ set(LLKDU_INCLUDE_DIRS ${LIBS_OPEN_DIR}/llkdu)
+ set(LLKDU_LIBRARIES llkdu)
+endif (USE_KDU)
diff --git a/indra/cmake/LLPlugin.cmake b/indra/cmake/LLPlugin.cmake
index 9722f16c3c..7ee404b9bd 100644
--- a/indra/cmake/LLPlugin.cmake
+++ b/indra/cmake/LLPlugin.cmake
@@ -5,4 +5,10 @@ set(LLPLUGIN_INCLUDE_DIRS
${LIBS_OPEN_DIR}/llplugin
)
-set(LLPLUGIN_LIBRARIES llplugin)
+if (LINUX)
+ # In order to support using ld.gold on linux, we need to explicitely
+ # specify all libraries that llplugin uses.
+ set(LLPLUGIN_LIBRARIES llplugin pthread)
+else (LINUX)
+ set(LLPLUGIN_LIBRARIES llplugin)
+endif (LINUX)
diff --git a/indra/cmake/LLPrimitive.cmake b/indra/cmake/LLPrimitive.cmake
index d397b78f1c..e68d16ed08 100644
--- a/indra/cmake/LLPrimitive.cmake
+++ b/indra/cmake/LLPrimitive.cmake
@@ -1,7 +1,33 @@
# -*- cmake -*-
+# these should be moved to their own cmake file
+include(Prebuilt)
+use_prebuilt_binary(colladadom)
+use_prebuilt_binary(pcre)
+use_prebuilt_binary(libxml)
+
set(LLPRIMITIVE_INCLUDE_DIRS
${LIBS_OPEN_DIR}/llprimitive
)
+if (WINDOWS)
+ set(LLPRIMITIVE_LIBRARIES
+ debug llprimitive
+ optimized llprimitive
+ debug libcollada14dom22-d
+ optimized libcollada14dom22
+ debug libboost_filesystem-vc100-mt-gd-1_45
+ optimized libboost_filesystem-vc100-mt-1_45
+ debug libboost_system-vc100-mt-gd-1_45
+ optimized libboost_system-vc100-mt-1_45
+ )
+else (WINDOWS)
+ set(LLPRIMITIVE_LIBRARIES
+ llprimitive
+ collada14dom
+ minizip
+ xml2
+ pcrecpp
+ pcre
+ )
+endif (WINDOWS)
-set(LLPRIMITIVE_LIBRARIES llprimitive)
diff --git a/indra/cmake/LLTestCommand.cmake b/indra/cmake/LLTestCommand.cmake
index 554559edbd..b5a0580a90 100644
--- a/indra/cmake/LLTestCommand.cmake
+++ b/indra/cmake/LLTestCommand.cmake
@@ -1,3 +1,4 @@
+include(Python)
MACRO(LL_TEST_COMMAND OUTVAR LD_LIBRARY_PATH)
# nat wonders how Kitware can use the term 'function' for a construct that
# cannot return a value. And yet, variables you set inside a FUNCTION are
diff --git a/indra/cmake/LLWindow.cmake b/indra/cmake/LLWindow.cmake
index a5b9cf47a4..b4bb9a078a 100644
--- a/indra/cmake/LLWindow.cmake
+++ b/indra/cmake/LLWindow.cmake
@@ -18,7 +18,7 @@ else (STANDALONE)
use_prebuilt_binary(SDL)
set (SDL_FOUND TRUE)
set (SDL_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/i686-linux)
- set (SDL_LIBRARY SDL)
+ set (SDL_LIBRARY SDL directfb fusion direct)
endif (LINUX AND VIEWER)
endif (STANDALONE)
diff --git a/indra/cmake/Linking.cmake b/indra/cmake/Linking.cmake
index bca99caf2a..07db6ab257 100644
--- a/indra/cmake/Linking.cmake
+++ b/indra/cmake/Linking.cmake
@@ -1,32 +1,43 @@
# -*- cmake -*-
+include(Variables)
+
+
if (NOT STANDALONE)
+ set(ARCH_PREBUILT_DIRS ${AUTOBUILD_INSTALL_DIR}/lib)
+ set(ARCH_PREBUILT_DIRS_RELEASE ${AUTOBUILD_INSTALL_DIR}/lib/release)
+ set(ARCH_PREBUILT_DIRS_DEBUG ${AUTOBUILD_INSTALL_DIR}/lib/debug)
if (WINDOWS)
- set(ARCH_PREBUILT_DIRS ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/lib)
- set(ARCH_PREBUILT_DIRS_RELEASE ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/lib/release)
- set(ARCH_PREBUILT_DIRS_DEBUG ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/lib/debug)
- set(SHARED_LIB_STAGING_DIR ${CMAKE_BINARY_DIR}/sharedlibs CACHE FILEPATH "Location of staged DLLs")
- set(EXE_STAGING_DIR ${CMAKE_BINARY_DIR}/sharedlibs CACHE FILEPATH "Location of staged executables")
+ set(SHARED_LIB_STAGING_DIR ${CMAKE_BINARY_DIR}/sharedlibs)
+ set(EXE_STAGING_DIR ${CMAKE_BINARY_DIR}/sharedlibs)
elseif (LINUX)
- if (VIEWER)
- set(ARCH_PREBUILT_DIRS ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/lib_release_client)
- else (VIEWER)
- set(ARCH_PREBUILT_DIRS ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/lib_release)
- endif (VIEWER)
- set(ARCH_PREBUILT_DIRS_RELEASE ${ARCH_PREBUILT_DIRS})
- set(ARCH_PREBUILT_DIRS_DEBUG ${ARCH_PREBUILT_DIRS})
- set(SHARED_LIB_STAGING_DIR ${CMAKE_BINARY_DIR}/sharedlibs/lib CACHE FILEPATH "Location of staged .sos")
- set(EXE_STAGING_DIR ${CMAKE_BINARY_DIR}/sharedlibs/bin CACHE FILEPATH "Location of staged executables")
+ set(SHARED_LIB_STAGING_DIR ${CMAKE_BINARY_DIR}/sharedlibs/lib)
+ set(EXE_STAGING_DIR ${CMAKE_BINARY_DIR}/sharedlibs/bin)
elseif (DARWIN)
- set(ARCH_PREBUILT_DIRS_RELEASE ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/lib_release)
- set(ARCH_PREBUILT_DIRS ${ARCH_PREBUILT_DIRS_RELEASE})
- set(ARCH_PREBUILT_DIRS_DEBUG ${ARCH_PREBUILT_DIRS_RELEASE})
- set(SHARED_LIB_STAGING_DIR ${CMAKE_BINARY_DIR}/sharedlibs CACHE FILEPATH "Location of staged DLLs")
- set(EXE_STAGING_DIR "${CMAKE_BINARY_DIR}/sharedlibs/\$(CONFIGURATION)" CACHE FILEPATH "Location of staged executables")
+ set(SHARED_LIB_STAGING_DIR ${CMAKE_BINARY_DIR}/sharedlibs)
+ set(EXE_STAGING_DIR "${CMAKE_BINARY_DIR}/sharedlibs/\$(CONFIGURATION)")
endif (WINDOWS)
endif (NOT STANDALONE)
-link_directories(${ARCH_PREBUILT_DIRS})
+# Autobuild packages must provide 'release' versions of libraries, but may provide versions for
+# specific build types. AUTOBUILD_LIBS_INSTALL_DIRS lists first the build type directory and then
+# the 'release' directory (as a default fallback).
+# *NOTE - we have to take special care to use CMAKE_CFG_INTDIR on IDE generators (like mac and
+# windows) and CMAKE_BUILD_TYPE on Makefile based generators (like linux). The reason for this is
+# that CMAKE_BUILD_TYPE is essentially meaningless at configuration time for IDE generators and
+# CMAKE_CFG_INTDIR is meaningless at build time for Makefile generators
+if(WINDOWS OR DARWIN)
+ # the cmake xcode and VS generators implicitly append ${CMAKE_CFG_INTDIR} to the library paths for us
+ # fortunately both windows and darwin are case insensitive filesystems so this works.
+ set(AUTOBUILD_LIBS_INSTALL_DIRS "${AUTOBUILD_INSTALL_DIR}/lib/")
+else(WINDOWS OR DARWIN)
+ # else block is for linux and any other makefile based generators
+ string(TOLOWER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE_LOWER)
+ set(AUTOBUILD_LIBS_INSTALL_DIRS ${AUTOBUILD_INSTALL_DIR}/lib/${CMAKE_BUILD_TYPE_LOWER})
+endif(WINDOWS OR DARWIN)
+
+list(APPEND AUTOBUILD_LIBS_INSTALL_DIRS ${ARCH_PREBUILT_DIRS_RELEASE})
+link_directories(${AUTOBUILD_LIBS_INSTALL_DIRS})
if (LINUX)
set(DL_LIBRARY dl)
diff --git a/indra/cmake/MonoEmbed.cmake b/indra/cmake/MonoEmbed.cmake
index 0f1f23309c..30890aed21 100644
--- a/indra/cmake/MonoEmbed.cmake
+++ b/indra/cmake/MonoEmbed.cmake
@@ -37,9 +37,9 @@ IF (DARWIN)
ELSE (DARWIN)
- SET(MONO_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include)
+ SET(MONO_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include)
SET(GLIB_2_0_PLATFORM_INCLUDE_DIR
- ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/glib-2.0)
+ ${LIBS_PREBUILT_DIR}/include/glib-2.0)
SET(GLIB_2_0_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/glib-2.0)
INCLUDE_DIRECTORIES(
diff --git a/indra/cmake/MySQL.cmake b/indra/cmake/MySQL.cmake
index e591fbc3d8..218482449d 100644
--- a/indra/cmake/MySQL.cmake
+++ b/indra/cmake/MySQL.cmake
@@ -7,7 +7,7 @@ use_prebuilt_binary(mysql)
if (LINUX)
if (WORD_SIZE EQUAL 32 OR DEBIAN_VERSION STREQUAL "3.1")
set(MYSQL_LIBRARIES mysqlclient)
- set(MYSQL_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include)
+ set(MYSQL_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include)
else (WORD_SIZE EQUAL 32 OR DEBIAN_VERSION STREQUAL "3.1")
# Use the native MySQL library on a 64-bit system.
set(MYSQL_FIND_QUIETLY ON)
@@ -16,9 +16,9 @@ if (LINUX)
endif (WORD_SIZE EQUAL 32 OR DEBIAN_VERSION STREQUAL "3.1")
elseif (WINDOWS)
set(MYSQL_LIBRARIES mysqlclient)
- set(MYSQL_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include)
+ set(MYSQL_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include)
elseif (DARWIN)
- set(MYSQL_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include)
+ set(MYSQL_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include)
set(MYSQL_LIBRARIES
optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libmysqlclient.a
debug ${ARCH_PREBUILT_DIRS_DEBUG}/libmysqlclient.a
diff --git a/indra/cmake/NDOF.cmake b/indra/cmake/NDOF.cmake
index dad74e99b1..7a463d1190 100644
--- a/indra/cmake/NDOF.cmake
+++ b/indra/cmake/NDOF.cmake
@@ -1,14 +1,32 @@
# -*- cmake -*-
include(Prebuilt)
-use_prebuilt_binary(ndofdev)
+set(NDOF ON CACHE BOOL "Use NDOF space navigator joystick library.")
-if (WINDOWS OR DARWIN OR LINUX)
+if (NDOF)
+ if (STANDALONE)
+ set(NDOF_FIND_REQUIRED ON)
+ include(FindNDOF)
+ else (STANDALONE)
+ use_prebuilt_binary(ndofdev)
+
+ if (WINDOWS)
+ set(NDOF_LIBRARY libndofdev)
+ elseif (DARWIN OR LINUX)
+ set(NDOF_LIBRARY ndofdev)
+ endif (WINDOWS)
+
+ set(NDOF_INCLUDE_DIR ${ARCH_PREBUILT_DIRS}/include/ndofdev)
+ set(NDOF_FOUND 1)
+ endif (STANDALONE)
+endif (NDOF)
+
+if (NDOF_FOUND)
add_definitions(-DLIB_NDOF=1)
-endif (WINDOWS OR DARWIN OR LINUX)
+ include_directories(${NDOF_INCLUDE_DIR})
+else (NDOF_FOUND)
+ message(STATUS "Building without N-DoF joystick support")
+ set(NDOF_INCLUDE_DIR "")
+ set(NDOF_LIBRARY "")
+endif (NDOF_FOUND)
-if (WINDOWS)
- set(NDOF_LIBRARY libndofdev)
-elseif (DARWIN OR LINUX)
- set(NDOF_LIBRARY ndofdev)
-endif (WINDOWS)
diff --git a/indra/cmake/OPENAL.cmake b/indra/cmake/OPENAL.cmake
index d01c680ed1..a3e1fb924e 100644
--- a/indra/cmake/OPENAL.cmake
+++ b/indra/cmake/OPENAL.cmake
@@ -9,18 +9,26 @@ else (LINUX)
endif (LINUX)
if (OPENAL)
+ set(OPENAL_LIB_INCLUDE_DIRS "${LIBS_PREBUILT_DIR}/include/AL")
if (STANDALONE)
include(FindPkgConfig)
include(FindOpenAL)
pkg_check_modules(OPENAL_LIB REQUIRED openal)
pkg_check_modules(FREEALUT_LIB REQUIRED freealut)
else (STANDALONE)
- use_prebuilt_binary(openal-soft)
+ use_prebuilt_binary(openal_soft)
endif (STANDALONE)
- set(OPENAL_LIBRARIES
- openal
- alut
+ if(WINDOWS)
+ set(OPENAL_LIBRARIES
+ OpenAL32
+ alut
)
+ else()
+ set(OPENAL_LIBRARIES
+ openal
+ alut
+ )
+ endif()
endif (OPENAL)
if (OPENAL)
diff --git a/indra/cmake/OpenGL.cmake b/indra/cmake/OpenGL.cmake
index 6a2b6811af..0a3dd976b4 100644
--- a/indra/cmake/OpenGL.cmake
+++ b/indra/cmake/OpenGL.cmake
@@ -2,8 +2,7 @@
include(Prebuilt)
if (NOT STANDALONE)
- use_prebuilt_binary(GL)
- # possible glh_linear should have its own .cmake file instead
+ use_prebuilt_binary(glext)
use_prebuilt_binary(glh_linear)
- set(GLEXT_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include)
+ set(GLEXT_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include)
endif (NOT STANDALONE)
diff --git a/indra/cmake/OpenSSL.cmake b/indra/cmake/OpenSSL.cmake
index 81584c09ea..5982ee9a49 100644
--- a/indra/cmake/OpenSSL.cmake
+++ b/indra/cmake/OpenSSL.cmake
@@ -13,11 +13,11 @@ else (STANDALONE)
else (WINDOWS)
set(OPENSSL_LIBRARIES ssl)
endif (WINDOWS)
- set(OPENSSL_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include)
+ set(OPENSSL_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include)
endif (STANDALONE)
if (LINUX)
set(CRYPTO_LIBRARIES crypto)
elseif (DARWIN)
- set(CRYPTO_LIBRARIES llcrypto)
+ set(CRYPTO_LIBRARIES crypto)
endif (LINUX)
diff --git a/indra/cmake/PNG.cmake b/indra/cmake/PNG.cmake
index f6522d9e2f..913c575672 100644
--- a/indra/cmake/PNG.cmake
+++ b/indra/cmake/PNG.cmake
@@ -8,6 +8,14 @@ if (STANDALONE)
include(FindPNG)
else (STANDALONE)
use_prebuilt_binary(libpng)
- set(PNG_LIBRARIES png12)
- set(PNG_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include/libpng12)
+ if (WINDOWS)
+ set(PNG_LIBRARIES libpng15)
+ set(PNG_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include/libpng15)
+ elseif(DARWIN)
+ set(PNG_LIBRARIES png15)
+ set(PNG_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include/libpng15)
+ else()
+ set(PNG_LIBRARIES png15)
+ set(PNG_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include/libpng15)
+ endif()
endif (STANDALONE)
diff --git a/indra/cmake/Prebuilt.cmake b/indra/cmake/Prebuilt.cmake
index a91519278c..dbb4dfc46c 100644
--- a/indra/cmake/Prebuilt.cmake
+++ b/indra/cmake/Prebuilt.cmake
@@ -1,44 +1,53 @@
# -*- cmake -*-
-include(Python)
-include(FindSCP)
+include(FindAutobuild)
+if(INSTALL_PROPRIETARY)
+ include(FindSCP)
+endif(INSTALL_PROPRIETARY)
+# The use_prebuilt_binary macro handles automated installation of package
+# dependencies using autobuild. The goal is that 'autobuild install' should
+# only be run when we know we need to install a new package. This should be
+# the case in a clean checkout, or if autobuild.xml has been updated since the
+# last run (encapsulated by the file ${CMAKE_BINARY_DIR}/temp/sentinel_installed),
+# or if a previous attempt to install the package has failed (the exit status
+# of previous attempts is serialized in the file
+# ${CMAKE_BINARY_DIR}/temp/${_binary}_installed)
macro (use_prebuilt_binary _binary)
- if (NOT STANDALONE)
- if(${CMAKE_BINARY_DIR}/temp/sentinel_installed IS_NEWER_THAN ${CMAKE_BINARY_DIR}/temp/${_binary}_installed)
- if(INSTALL_PROPRIETARY)
- include(FindSCP)
- if(DEBUG_PREBUILT)
- message("cd ${SCRIPTS_DIR} && ${PYTHON_EXECUTABLE} install.py --install-dir=${CMAKE_SOURCE_DIR}/.. --scp=${SCP_EXECUTABLE} ${_binary}")
- endif(DEBUG_PREBUILT)
- execute_process(COMMAND ${PYTHON_EXECUTABLE}
- install.py
- --install-dir=${CMAKE_SOURCE_DIR}/..
- --scp=${SCP_EXECUTABLE}
- ${_binary}
- WORKING_DIRECTORY ${SCRIPTS_DIR}
- RESULT_VARIABLE ${_binary}_installed
- )
- else(INSTALL_PROPRIETARY)
- if(DEBUG_PREBUILT)
- message("cd ${SCRIPTS_DIR} && ${PYTHON_EXECUTABLE} install.py --install-dir=${CMAKE_SOURCE_DIR}/.. ${_binary}")
- endif(DEBUG_PREBUILT)
- execute_process(COMMAND ${PYTHON_EXECUTABLE}
- install.py
- --install-dir=${CMAKE_SOURCE_DIR}/..
- ${_binary}
- WORKING_DIRECTORY ${SCRIPTS_DIR}
- RESULT_VARIABLE ${_binary}_installed
- )
- endif(INSTALL_PROPRIETARY)
+ if (NOT DEFINED STANDALONE_${_binary})
+ set(STANDALONE_${_binary} ${STANDALONE})
+ endif (NOT DEFINED STANDALONE_${_binary})
+
+ if (NOT STANDALONE_${_binary})
+ if("${${_binary}_installed}" STREQUAL "" AND EXISTS "${CMAKE_BINARY_DIR}/temp/${_binary}_installed")
+ file(READ ${CMAKE_BINARY_DIR}/temp/${_binary}_installed "${_binary}_installed")
+ if(DEBUG_PREBUILT)
+ message(STATUS "${_binary}_installed: \"${${_binary}_installed}\"")
+ endif(DEBUG_PREBUILT)
+ endif("${${_binary}_installed}" STREQUAL "" AND EXISTS "${CMAKE_BINARY_DIR}/temp/${_binary}_installed")
+
+ if(${CMAKE_BINARY_DIR}/temp/sentinel_installed IS_NEWER_THAN ${CMAKE_BINARY_DIR}/temp/${_binary}_installed OR NOT ${${_binary}_installed} EQUAL 0)
+ if(DEBUG_PREBUILT)
+ message("cd ${CMAKE_SOURCE_DIR} && ${AUTOBUILD_EXECUTABLE} install
+ --install-dir=${AUTOBUILD_INSTALL_DIR}
+ --skip-license-check
+ ${_binary} ")
+ endif(DEBUG_PREBUILT)
+ execute_process(COMMAND "${AUTOBUILD_EXECUTABLE}"
+ install
+ --install-dir=${AUTOBUILD_INSTALL_DIR}
+ --skip-license-check
+ ${_binary}
+ WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
+ RESULT_VARIABLE ${_binary}_installed
+ )
file(WRITE ${CMAKE_BINARY_DIR}/temp/${_binary}_installed "${${_binary}_installed}")
- else(${CMAKE_BINARY_DIR}/temp/sentinel_installed IS_NEWER_THAN ${CMAKE_BINARY_DIR}/temp/${_binary}_installed)
- set(${_binary}_installed 0)
- endif(${CMAKE_BINARY_DIR}/temp/sentinel_installed IS_NEWER_THAN ${CMAKE_BINARY_DIR}/temp/${_binary}_installed)
+ endif(${CMAKE_BINARY_DIR}/temp/sentinel_installed IS_NEWER_THAN ${CMAKE_BINARY_DIR}/temp/${_binary}_installed OR NOT ${${_binary}_installed} EQUAL 0)
+
if(NOT ${_binary}_installed EQUAL 0)
message(FATAL_ERROR
"Failed to download or unpack prebuilt '${_binary}'."
" Process returned ${${_binary}_installed}.")
endif (NOT ${_binary}_installed EQUAL 0)
- endif (NOT STANDALONE)
+ endif (NOT STANDALONE_${_binary})
endmacro (use_prebuilt_binary _binary)
diff --git a/indra/cmake/Pth.cmake b/indra/cmake/Pth.cmake
deleted file mode 100644
index a28f6ec696..0000000000
--- a/indra/cmake/Pth.cmake
+++ /dev/null
@@ -1,21 +0,0 @@
-# -*- cmake -*-
-include(Prebuilt)
-
-set(PTH_FIND_QUIETLY ON)
-set(PTH_FIND_REQUIRED ON)
-
-if (STANDALONE)
-# ?? How would I construct FindPTH.cmake? This file was cloned from
-# CURL.cmake, which uses include(FindCURL), but there's no FindCURL.cmake?
-# include(FindPTH)
-else (STANDALONE)
- # This library is only needed to support Boost.Coroutine, and only on Mac.
- if (DARWIN)
- use_prebuilt_binary(pth)
- set(PTH_LIBRARIES pth)
- set(PTH_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include)
- else (DARWIN)
- set(PTH_LIBRARIES)
- set(PTH_INCLUDE_DIRS)
- endif (DARWIN)
-endif (STANDALONE)
diff --git a/indra/cmake/PulseAudio.cmake b/indra/cmake/PulseAudio.cmake
index e918de0198..360a971058 100644
--- a/indra/cmake/PulseAudio.cmake
+++ b/indra/cmake/PulseAudio.cmake
@@ -1,7 +1,7 @@
# -*- cmake -*-
include(Prebuilt)
-set(PULSEAUDIO ON CACHE BOOL "Build with PulseAudio support, if available.")
+set(PULSEAUDIO OFF CACHE BOOL "Build with PulseAudio support, if available.")
if (PULSEAUDIO)
if (STANDALONE)
diff --git a/indra/cmake/Python.cmake b/indra/cmake/Python.cmake
index 0901c1b7a2..748c8c2bec 100644
--- a/indra/cmake/Python.cmake
+++ b/indra/cmake/Python.cmake
@@ -9,10 +9,12 @@ if (WINDOWS)
NAMES python25.exe python23.exe python.exe
NO_DEFAULT_PATH # added so that cmake does not find cygwin python
PATHS
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.7\\InstallPath]
[HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.6\\InstallPath]
[HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.5\\InstallPath]
[HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.4\\InstallPath]
[HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.3\\InstallPath]
+ [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\2.7\\InstallPath]
[HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\2.6\\InstallPath]
[HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\2.5\\InstallPath]
[HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\2.4\\InstallPath]
diff --git a/indra/cmake/QuickTimePlugin.cmake b/indra/cmake/QuickTimePlugin.cmake
index 02f432e3c1..012f4e20d8 100644
--- a/indra/cmake/QuickTimePlugin.cmake
+++ b/indra/cmake/QuickTimePlugin.cmake
@@ -33,7 +33,7 @@ elseif (WINDOWS)
endif (DEBUG_QUICKTIME_LIBRARY AND RELEASE_QUICKTIME_LIBRARY)
include_directories(
- ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/quicktime
+ ${LIBS_PREBUILT_DIR}/include/quicktime
"${QUICKTIME_SDK_DIR}\\CIncludes"
)
endif (DARWIN)
diff --git a/indra/cmake/TemplateCheck.cmake b/indra/cmake/TemplateCheck.cmake
index fa4e387dd5..2fada2eda9 100644
--- a/indra/cmake/TemplateCheck.cmake
+++ b/indra/cmake/TemplateCheck.cmake
@@ -5,10 +5,10 @@ include(Python)
macro (check_message_template _target)
add_custom_command(
TARGET ${_target}
- POST_BUILD
+ PRE_LINK
COMMAND ${PYTHON_EXECUTABLE}
ARGS ${SCRIPTS_DIR}/template_verifier.py
- --mode=development --cache_master
- COMMENT "Verifying message template"
+ --mode=development --cache_master --master_url=${TEMPLATE_VERIFIER_MASTER_URL} ${TEMPLATE_VERIFIER_OPTIONS}
+ COMMENT "Verifying message template - See http://wiki.secondlife.com/wiki/Template_verifier.py"
)
endmacro (check_message_template)
diff --git a/indra/cmake/Tut.cmake b/indra/cmake/Tut.cmake
index 784560471d..7488e9dcb0 100644
--- a/indra/cmake/Tut.cmake
+++ b/indra/cmake/Tut.cmake
@@ -1,12 +1,6 @@
# -*- cmake -*-
include(Prebuilt)
-set(TUT_FIND_REQUIRED TRUE)
-set(TUT_FIND_QUIETLY TRUE)
-
-if (STANDALONE)
- include(FindTut)
- include_directories(${TUT_INCLUDE_DIR})
-else (STANDALONE)
+if (NOT STANDALONE)
use_prebuilt_binary(tut)
-endif (STANDALONE)
+endif(NOT STANDALONE)
diff --git a/indra/cmake/UI.cmake b/indra/cmake/UI.cmake
index f529f5b644..91e5258fb7 100644
--- a/indra/cmake/UI.cmake
+++ b/indra/cmake/UI.cmake
@@ -51,11 +51,11 @@ else (STANDALONE)
endif (LINUX)
include_directories (
- ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include
+ ${LIBS_PREBUILT_DIR}/include
${LIBS_PREBUILT_DIR}/include
)
foreach(include ${${LL_ARCH}_INCLUDES})
- include_directories(${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/${include})
+ include_directories(${LIBS_PREBUILT_DIR}/include/${include})
endforeach(include)
endif (STANDALONE)
diff --git a/indra/cmake/Variables.cmake b/indra/cmake/Variables.cmake
index 5dc0cabf03..cfccd29def 100644
--- a/indra/cmake/Variables.cmake
+++ b/indra/cmake/Variables.cmake
@@ -17,6 +17,10 @@
# Relative and absolute paths to subtrees.
+if(NOT DEFINED COMMON_CMAKE_DIR)
+ set(COMMON_CMAKE_DIR "${CMAKE_SOURCE_DIR}/cmake")
+endif(NOT DEFINED COMMON_CMAKE_DIR)
+
set(LIBS_CLOSED_PREFIX)
set(LIBS_OPEN_PREFIX)
set(LIBS_SERVER_PREFIX)
@@ -25,22 +29,41 @@ set(SERVER_PREFIX)
set(VIEWER_PREFIX)
set(INTEGRATION_TESTS_PREFIX)
set(LL_TESTS ON CACHE BOOL "Build and run unit and integration tests (disable for build timing runs to reduce variation")
+set(INCREMENTAL_LINK OFF CACHE BOOL "Use incremental linking on win32 builds (enable for faster links on some machines)")
+
+if(LIBS_CLOSED_DIR)
+ file(TO_CMAKE_PATH "${LIBS_CLOSED_DIR}" LIBS_CLOSED_DIR)
+else(LIBS_CLOSED_DIR)
+ set(LIBS_CLOSED_DIR ${CMAKE_SOURCE_DIR}/${LIBS_CLOSED_PREFIX})
+endif(LIBS_CLOSED_DIR)
+if(LIBS_COMMON_DIR)
+ file(TO_CMAKE_PATH "${LIBS_COMMON_DIR}" LIBS_COMMON_DIR)
+else(LIBS_COMMON_DIR)
+ set(LIBS_COMMON_DIR ${CMAKE_SOURCE_DIR}/${LIBS_OPEN_PREFIX})
+endif(LIBS_COMMON_DIR)
+set(LIBS_OPEN_DIR ${LIBS_COMMON_DIR})
-set(LIBS_CLOSED_DIR ${CMAKE_SOURCE_DIR}/${LIBS_CLOSED_PREFIX})
-set(LIBS_OPEN_DIR ${CMAKE_SOURCE_DIR}/${LIBS_OPEN_PREFIX})
set(LIBS_SERVER_DIR ${CMAKE_SOURCE_DIR}/${LIBS_SERVER_PREFIX})
set(SCRIPTS_DIR ${CMAKE_SOURCE_DIR}/${SCRIPTS_PREFIX})
set(SERVER_DIR ${CMAKE_SOURCE_DIR}/${SERVER_PREFIX})
set(VIEWER_DIR ${CMAKE_SOURCE_DIR}/${VIEWER_PREFIX})
-set(LIBS_PREBUILT_DIR ${CMAKE_SOURCE_DIR}/../libraries CACHE PATH
+set(AUTOBUILD_INSTALL_DIR ${CMAKE_BINARY_DIR}/packages)
+
+set(LIBS_PREBUILT_DIR ${AUTOBUILD_INSTALL_DIR} CACHE PATH
"Location of prebuilt libraries.")
if (EXISTS ${CMAKE_SOURCE_DIR}/Server.cmake)
# We use this as a marker that you can try to use the proprietary libraries.
set(INSTALL_PROPRIETARY ON CACHE BOOL "Install proprietary binaries")
endif (EXISTS ${CMAKE_SOURCE_DIR}/Server.cmake)
+set(TEMPLATE_VERIFIER_OPTIONS "" CACHE STRING "Options for scripts/template_verifier.py")
+set(TEMPLATE_VERIFIER_MASTER_URL "http://bitbucket.org/lindenlab/master-message-template/raw/tip/message_template.msg" CACHE STRING "Location of the master message template")
+if (NOT CMAKE_BUILD_TYPE)
+ set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING
+ "Build type. One of: Debug Release RelWithDebInfo" FORCE)
+endif (NOT CMAKE_BUILD_TYPE)
if (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
set(WINDOWS ON BOOL FORCE)
@@ -54,20 +77,19 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
set(LINUX ON BOOl FORCE)
# If someone has specified a word size, use that to determine the
- # architecture. Otherwise, let the compiler specify the word size.
- # Using uname will break under chroots and other cross arch compiles. RC
+ # architecture. Otherwise, let the architecture specify the word size.
if (WORD_SIZE EQUAL 32)
set(ARCH i686)
elseif (WORD_SIZE EQUAL 64)
set(ARCH x86_64)
else (WORD_SIZE EQUAL 32)
- if(CMAKE_SIZEOF_VOID_P MATCHES 4)
- set(ARCH i686)
- set(WORD_SIZE 32)
- else(CMAKE_SIZEOF_VOID_P MATCHES 4)
- set(ARCH x86_64)
+ execute_process(COMMAND uname -m COMMAND sed s/i.86/i686/
+ OUTPUT_VARIABLE ARCH OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if (ARCH STREQUAL x86_64)
set(WORD_SIZE 64)
- endif(CMAKE_SIZEOF_VOID_P MATCHES 4)
+ else (ARCH STREQUAL x86_64)
+ set(WORD_SIZE 32)
+ endif (ARCH STREQUAL x86_64)
endif (WORD_SIZE EQUAL 32)
set(LL_ARCH ${ARCH}_linux)
@@ -76,25 +98,12 @@ endif (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(DARWIN 1)
-
- # NOTE: If specifying a different SDK with CMAKE_OSX_SYSROOT at configure
- # time you should also specify CMAKE_OSX_DEPLOYMENT_TARGET explicitly,
- # otherwise CMAKE_OSX_SYSROOT will be overridden here. We can't just check
- # for it being unset, as it gets set to the system default :(
-
- # Default to building against the 10.4 SDK if no deployment target is
- # specified.
- if (NOT CMAKE_OSX_DEPLOYMENT_TARGET)
- # NOTE: setting -isysroot is NOT adequate: http://lists.apple.com/archives/Xcode-users/2007/Oct/msg00696.html
- # see http://public.kitware.com/Bug/view.php?id=9959 + poppy
- set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.5.sdk)
- set(CMAKE_OSX_DEPLOYMENT_TARGET 10.4)
- endif (NOT CMAKE_OSX_DEPLOYMENT_TARGET)
-
- # GCC 4.2 is incompatible with the MacOSX 10.4 SDK
- if (${CMAKE_OSX_SYSROOT} MATCHES "10.4u")
- set(CMAKE_XCODE_ATTRIBUTE_GCC_VERSION "4.0")
- endif (${CMAKE_OSX_SYSROOT} MATCHES "10.4u")
+
+ # To support a different SDK update these Xcode settings:
+ set(CMAKE_OSX_DEPLOYMENT_TARGET 10.5)
+ set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.5.sdk)
+ set(CMAKE_XCODE_ATTRIBUTE_GCC_VERSION "4.2")
+ set(CMAKE_XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT dwarf-with-dsym)
# NOTE: To attempt an i386/PPC Universal build, add this on the configure line:
# -DCMAKE_OSX_ARCHITECTURES:STRING='i386;ppc'
@@ -125,7 +134,9 @@ set(VIEWER ON CACHE BOOL "Build Second Life viewer.")
set(VIEWER_CHANNEL "LindenDeveloper" CACHE STRING "Viewer Channel Name")
set(VIEWER_LOGIN_CHANNEL ${VIEWER_CHANNEL} CACHE STRING "Fake login channel for A/B Testing")
+set(VERSION_BUILD "0" CACHE STRING "Revision number passed in from the outside")
set(STANDALONE OFF CACHE BOOL "Do not use Linden-supplied prebuilt libraries.")
+set(UNATTENDED OFF CACHE BOOL "Should be set to ON for building with VC Express editions.")
if (NOT STANDALONE AND EXISTS ${CMAKE_SOURCE_DIR}/llphysics)
set(SERVER ON CACHE BOOL "Build Second Life server software.")
@@ -144,3 +155,4 @@ endif (LINUX AND SERVER AND VIEWER)
set(USE_PRECOMPILED_HEADERS ON CACHE BOOL "Enable use of precompiled header directives where supported.")
source_group("CMake Rules" FILES CMakeLists.txt)
+
diff --git a/indra/cmake/ViewerMiscLibs.cmake b/indra/cmake/ViewerMiscLibs.cmake
index 32c4bc81df..df013b1665 100644
--- a/indra/cmake/ViewerMiscLibs.cmake
+++ b/indra/cmake/ViewerMiscLibs.cmake
@@ -3,7 +3,7 @@ include(Prebuilt)
if (NOT STANDALONE)
use_prebuilt_binary(libuuid)
- use_prebuilt_binary(vivox)
+ use_prebuilt_binary(slvoice)
use_prebuilt_binary(fontconfig)
endif(NOT STANDALONE)
diff --git a/indra/cmake/WebKitLibPlugin.cmake b/indra/cmake/WebKitLibPlugin.cmake
index 12ba1b1b35..7131445464 100644
--- a/indra/cmake/WebKitLibPlugin.cmake
+++ b/indra/cmake/WebKitLibPlugin.cmake
@@ -3,57 +3,83 @@ include(Linking)
include(Prebuilt)
if (STANDALONE)
- set(WEBKITLIBPLUGIN OFF CACHE BOOL
- "WEBKITLIBPLUGIN support for the llplugin/llmedia test apps.")
+ # The minimal version, 4.4.3, is rather arbitrary: it's the version in Debian/Lenny.
+ find_package(Qt4 4.4.3 COMPONENTS QtCore QtGui QtNetwork QtOpenGL QtWebKit REQUIRED)
+ include(${QT_USE_FILE})
+ set(QTDIR $ENV{QTDIR})
+ if (QTDIR AND NOT "${QT_BINARY_DIR}" STREQUAL "${QTDIR}/bin")
+ message(FATAL_ERROR "\"${QT_BINARY_DIR}\" is unequal \"${QTDIR}/bin\"; "
+ "Qt is found by looking for qmake in your PATH. "
+ "Please set your PATH such that 'qmake' is found in \$QTDIR/bin, "
+ "or unset QTDIR if the found Qt is correct.")
+ endif (QTDIR AND NOT "${QT_BINARY_DIR}" STREQUAL "${QTDIR}/bin")
+ find_package(LLQtWebkit REQUIRED QUIET)
+ # Add the plugins.
+ set(QT_PLUGIN_LIBRARIES)
+ foreach(qlibname qgif qjpeg)
+ find_library(QT_PLUGIN_${qlibname} ${qlibname} PATHS ${QT_PLUGINS_DIR}/imageformats NO_DEFAULT_PATH)
+ if (QT_PLUGIN_${qlibname})
+ list(APPEND QT_PLUGIN_LIBRARIES ${QT_PLUGIN_${qlibname}})
+ else (QT_PLUGIN_${qtlibname})
+ message(FATAL_ERROR "Could not find the Qt plugin ${qlibname} in \"${QT_PLUGINS_DIR}/imageformats\"!")
+ endif (QT_PLUGIN_${qlibname})
+ endforeach(qlibname)
+ # qjpeg depends on libjpeg
+ list(APPEND QT_PLUGIN_LIBRARIES jpeg)
+ set(WEBKITLIBPLUGIN OFF CACHE BOOL
+ "WEBKITLIBPLUGIN support for the llplugin/llmedia test apps.")
else (STANDALONE)
- use_prebuilt_binary(llqtwebkit)
- set(WEBKITLIBPLUGIN ON CACHE BOOL
- "WEBKITLIBPLUGIN support for the llplugin/llmedia test apps.")
+ use_prebuilt_binary(llqtwebkit)
+ set(WEBKITLIBPLUGIN ON CACHE BOOL
+ "WEBKITLIBPLUGIN support for the llplugin/llmedia test apps.")
endif (STANDALONE)
if (WINDOWS)
- set(WEBKIT_PLUGIN_LIBRARIES
- debug llqtwebkitd
- debug QtWebKitd4
- debug QtOpenGLd4
- debug QtNetworkd4
- debug QtGuid4
- debug QtCored4
- debug qtmaind
- optimized llqtwebkit
- optimized QtWebKit4
- optimized QtOpenGL4
- optimized QtNetwork4
- optimized QtGui4
- optimized QtCore4
- optimized qtmain
- )
+ set(WEBKIT_PLUGIN_LIBRARIES
+ debug llqtwebkitd
+ debug QtWebKitd4
+ debug QtOpenGLd4
+ debug QtNetworkd4
+ debug QtGuid4
+ debug QtCored4
+ debug qtmaind
+ optimized llqtwebkit
+ optimized QtWebKit4
+ optimized QtOpenGL4
+ optimized QtNetwork4
+ optimized QtGui4
+ optimized QtCore4
+ optimized qtmain
+ )
elseif (DARWIN)
- set(WEBKIT_PLUGIN_LIBRARIES
- optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libllqtwebkit.dylib
- debug ${ARCH_PREBUILT_DIRS_RELEASE}/libllqtwebkit.dylib
- )
+ set(WEBKIT_PLUGIN_LIBRARIES
+ optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libllqtwebkit.dylib
+ debug ${ARCH_PREBUILT_DIRS_RELEASE}/libllqtwebkit.dylib
+ )
elseif (LINUX)
- if (STANDALONE)
- set(WEBKIT_PLUGIN_LIBRARIES llqtwebkit)
- else (STANDALONE)
+ set(WEBKIT_PLUGIN_LIBRARIES ${LLQTWEBKIT_LIBRARY} ${QT_LIBRARIES} ${QT_PLUGIN_LIBRARIES})
set(WEBKIT_PLUGIN_LIBRARIES
llqtwebkit
-
- qgif
- qjpeg
-
+# qico
+# qpng
+# qtiff
+# qsvg
+# QtSvg
QtWebKit
QtOpenGL
QtNetwork
QtGui
QtCore
-
+ qgif
+ qjpeg
jpeg
fontconfig
X11
Xrender
GL
+
+# sqlite3
+# Xi
+# SM
)
- endif (STANDALONE)
endif (WINDOWS)
diff --git a/indra/cmake/XmlRpcEpi.cmake b/indra/cmake/XmlRpcEpi.cmake
index 107d1926ba..5bd4848245 100644
--- a/indra/cmake/XmlRpcEpi.cmake
+++ b/indra/cmake/XmlRpcEpi.cmake
@@ -9,7 +9,10 @@ if (STANDALONE)
else (STANDALONE)
use_prebuilt_binary(xmlrpc-epi)
if (WINDOWS)
- set(XMLRPCEPI_LIBRARIES xmlrpcepi)
+ set(XMLRPCEPI_LIBRARIES
+ debug xmlrpc-epid
+ optimized xmlrpc-epi
+ )
else (WINDOWS)
set(XMLRPCEPI_LIBRARIES xmlrpc-epi)
endif (WINDOWS)
diff --git a/indra/cmake/run_build_test.py b/indra/cmake/run_build_test.py
index 37aa75e364..ce2d1e0386 100644..100755
--- a/indra/cmake/run_build_test.py
+++ b/indra/cmake/run_build_test.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
"""\
@file run_build_test.py
@author Nat Goodspeed
@@ -109,6 +109,8 @@ def main(command, libpath=[], vars={}):
os.environ.update(dict([(str(key), str(value)) for key, value in vars.iteritems()]))
# Run the child process.
print "Running: %s" % " ".join(command)
+ # Make sure we see all relevant output *before* child-process output.
+ sys.stdout.flush()
return subprocess.call(command)
if __name__ == "__main__":
diff --git a/indra/copy_win_scripts/start-client.py b/indra/copy_win_scripts/start-client.py
index 5f7ff2f293..5699f5273f 100644
--- a/indra/copy_win_scripts/start-client.py
+++ b/indra/copy_win_scripts/start-client.py
@@ -1,4 +1,28 @@
#!/usr/bin/env python
+"""\
+@file start-client.py
+
+$LicenseInfo:firstyear=2010&license=viewerlgpl$
+Second Life Viewer Source Code
+Copyright (C) 2010-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$
+"""
import sys, getopt
import os
import llstart
diff --git a/indra/develop.py b/indra/develop.py
deleted file mode 100755
index 36c947327a..0000000000
--- a/indra/develop.py
+++ /dev/null
@@ -1,862 +0,0 @@
-#!/usr/bin/env python
-#
-# @file develop.py
-# @authors Bryan O'Sullivan, Mark Palange, Aaron Brashears
-# @brief Fire and forget script to appropriately configure cmake for SL.
-#
-# $LicenseInfo:firstyear=2007&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$
-
-
-import errno
-import getopt
-import os
-import random
-import re
-import shutil
-import socket
-import sys
-import commands
-import subprocess
-
-class CommandError(Exception):
- pass
-
-
-def mkdir(path):
- try:
- os.mkdir(path)
- return path
- except OSError, err:
- if err.errno != errno.EEXIST or not os.path.isdir(path):
- raise
-
-def getcwd():
- cwd = os.getcwd()
- if 'a' <= cwd[0] <= 'z' and cwd[1] == ':':
- # CMake wants DOS drive letters to be in uppercase. The above
- # condition never asserts on platforms whose full path names
- # always begin with a slash, so we don't need to test whether
- # we are running on Windows.
- cwd = cwd[0].upper() + cwd[1:]
- return cwd
-
-def quote(opts):
- return '"' + '" "'.join([ opt.replace('"', '') for opt in opts ]) + '"'
-
-class PlatformSetup(object):
- generator = None
- build_types = {}
- for t in ('Debug', 'Release', 'RelWithDebInfo'):
- build_types[t.lower()] = t
-
- build_type = build_types['relwithdebinfo']
- standalone = 'OFF'
- unattended = 'OFF'
- universal = 'OFF'
- project_name = 'SecondLife'
- distcc = True
- cmake_opts = []
- word_size = 32
- using_express = False
-
- def __init__(self):
- self.script_dir = os.path.realpath(
- os.path.dirname(__import__(__name__).__file__))
-
- def os(self):
- '''Return the name of the OS.'''
-
- raise NotImplemented('os')
-
- def arch(self):
- '''Return the CPU architecture.'''
-
- return None
-
- def platform(self):
- '''Return a stringified two-tuple of the OS name and CPU
- architecture.'''
-
- ret = self.os()
- if self.arch():
- ret += '-' + self.arch()
- return ret
-
- def build_dirs(self):
- '''Return the top-level directories in which builds occur.
-
- This can return more than one directory, e.g. if doing a
- 32-bit viewer and server build on Linux.'''
-
- return ['build-' + self.platform()]
-
- def cmake_commandline(self, src_dir, build_dir, opts, simple):
- '''Return the command line to run cmake with.'''
-
- args = dict(
- dir=src_dir,
- generator=self.generator,
- opts=quote(opts),
- standalone=self.standalone,
- unattended=self.unattended,
- word_size=self.word_size,
- type=self.build_type.upper(),
- )
- #if simple:
- # return 'cmake %(opts)s %(dir)r' % args
- return ('cmake -DCMAKE_BUILD_TYPE:STRING=%(type)s '
- '-DSTANDALONE:BOOL=%(standalone)s '
- '-DUNATTENDED:BOOL=%(unattended)s '
- '-DWORD_SIZE:STRING=%(word_size)s '
- '-G %(generator)r %(opts)s %(dir)r' % args)
-
- def run_cmake(self, args=[]):
- '''Run cmake.'''
-
- # do a sanity check to make sure we have a generator
- if not hasattr(self, 'generator'):
- raise "No generator available for '%s'" % (self.__name__,)
- cwd = getcwd()
- created = []
- try:
- for d in self.build_dirs():
- simple = True
- if mkdir(d):
- created.append(d)
- simple = False
- try:
- os.chdir(d)
- cmd = self.cmake_commandline(cwd, d, args, simple)
- print 'Running %r in %r' % (cmd, d)
- self.run(cmd, 'cmake')
- finally:
- os.chdir(cwd)
- except:
- # If we created a directory in which to run cmake and
- # something went wrong, the directory probably just
- # contains garbage, so delete it.
- os.chdir(cwd)
- for d in created:
- print 'Cleaning %r' % d
- shutil.rmtree(d)
- raise
-
- def parse_build_opts(self, arguments):
- opts, targets = getopt.getopt(arguments, 'o:', ['option='])
- build_opts = []
- for o, a in opts:
- if o in ('-o', '--option'):
- build_opts.append(a)
- return build_opts, targets
-
- def run_build(self, opts, targets):
- '''Build the default targets for this platform.'''
-
- raise NotImplemented('run_build')
-
- def cleanup(self):
- '''Delete all build directories.'''
-
- cleaned = 0
- for d in self.build_dirs():
- if os.path.isdir(d):
- print 'Cleaning %r' % d
- shutil.rmtree(d)
- cleaned += 1
- if not cleaned:
- print 'Nothing to clean up!'
-
- def is_internal_tree(self):
- '''Indicate whether we are building in an internal source tree.'''
-
- return os.path.isdir(os.path.join(self.script_dir, 'newsim'))
-
- def find_in_path(self, name, defval=None, basename=False):
- for ext in self.exe_suffixes:
- name_ext = name + ext
- if os.sep in name_ext:
- path = os.path.abspath(name_ext)
- if os.access(path, os.X_OK):
- return [basename and os.path.basename(path) or path]
- for p in os.getenv('PATH', self.search_path).split(os.pathsep):
- path = os.path.join(p, name_ext)
- if os.access(path, os.X_OK):
- return [basename and os.path.basename(path) or path]
- if defval:
- return [defval]
- return []
-
-
-class UnixSetup(PlatformSetup):
- '''Generic Unixy build instructions.'''
-
- search_path = '/usr/bin:/usr/local/bin'
- exe_suffixes = ('',)
-
- def __init__(self):
- super(UnixSetup, self).__init__()
- self.generator = 'Unix Makefiles'
-
- def os(self):
- return 'unix'
-
- def arch(self):
- cpu = os.uname()[-1]
- if cpu.endswith('386'):
- cpu = 'i386'
- elif cpu.endswith('86'):
- cpu = 'i686'
- elif cpu in ('athlon',):
- cpu = 'i686'
- elif cpu == 'Power Macintosh':
- cpu = 'ppc'
- elif cpu == 'x86_64' and self.word_size == 32:
- cpu = 'i686'
- return cpu
-
- def run(self, command, name=None):
- '''Run a program. If the program fails, raise an exception.'''
- sys.stdout.flush()
- ret = os.system(command)
- if ret:
- if name is None:
- name = command.split(None, 1)[0]
- if os.WIFEXITED(ret):
- st = os.WEXITSTATUS(ret)
- if st == 127:
- event = 'was not found'
- else:
- event = 'exited with status %d' % st
- elif os.WIFSIGNALED(ret):
- event = 'was killed by signal %d' % os.WTERMSIG(ret)
- else:
- event = 'died unexpectedly (!?) with 16-bit status %d' % ret
- raise CommandError('the command %r %s' %
- (name, event))
-
-
-class LinuxSetup(UnixSetup):
- def __init__(self):
- super(LinuxSetup, self).__init__()
- try:
- self.debian_sarge = open('/etc/debian_version').read().strip() == '3.1'
- except:
- self.debian_sarge = False
-
- def os(self):
- return 'linux'
-
- def build_dirs(self):
- # Only build the server code if we have it.
- platform_build = '%s-%s' % (self.platform(), self.build_type.lower())
-
- if self.arch() == 'i686' and self.is_internal_tree():
- return ['viewer-' + platform_build, 'server-' + platform_build]
- elif self.arch() == 'x86_64' and self.is_internal_tree():
- # the viewer does not build in 64bit -- kdu5 issues
- # we can either use openjpeg, or overhaul our viewer to handle kdu5 or higher
- # doug knows about kdu issues
- return ['server-' + platform_build]
- else:
- return ['viewer-' + platform_build]
-
- def cmake_commandline(self, src_dir, build_dir, opts, simple):
- args = dict(
- dir=src_dir,
- generator=self.generator,
- opts=quote(opts),
- standalone=self.standalone,
- unattended=self.unattended,
- type=self.build_type.upper(),
- project_name=self.project_name,
- word_size=self.word_size,
- )
- if not self.is_internal_tree():
- args.update({'cxx':'g++', 'server':'OFF', 'viewer':'ON'})
- else:
- if self.distcc:
- distcc = self.find_in_path('distcc')
- baseonly = True
- else:
- distcc = []
- baseonly = False
- if 'server' in build_dir:
- gcc = distcc + self.find_in_path(
- self.debian_sarge and 'g++-3.3' or 'g++-4.1',
- 'g++', baseonly)
- args.update({'cxx': ' '.join(gcc), 'server': 'ON',
- 'viewer': 'OFF'})
- else:
- gcc41 = distcc + self.find_in_path('g++-4.1', 'g++', baseonly)
- args.update({'cxx': ' '.join(gcc41),
- 'server': 'OFF',
- 'viewer': 'ON'})
- cmd = (('cmake -DCMAKE_BUILD_TYPE:STRING=%(type)s '
- '-G %(generator)r -DSERVER:BOOL=%(server)s '
- '-DVIEWER:BOOL=%(viewer)s -DSTANDALONE:BOOL=%(standalone)s '
- '-DUNATTENDED:BOOL=%(unattended)s '
- '-DWORD_SIZE:STRING=%(word_size)s '
- '-DROOT_PROJECT_NAME:STRING=%(project_name)s '
- '%(opts)s %(dir)r')
- % args)
- if 'CXX' not in os.environ:
- args.update({'cmd':cmd})
- cmd = ('CXX=%(cxx)r %(cmd)s' % args)
- return cmd
-
- def run_build(self, opts, targets):
- job_count = None
-
- for i in range(len(opts)):
- if opts[i].startswith('-j'):
- try:
- job_count = int(opts[i][2:])
- except ValueError:
- try:
- job_count = int(opts[i+1])
- except ValueError:
- job_count = True
-
- def get_cpu_count():
- count = 0
- for line in open('/proc/cpuinfo'):
- if re.match(r'processor\s*:', line):
- count += 1
- return count
-
- def localhost():
- count = get_cpu_count()
- return 'localhost/' + str(count), count
-
- def get_distcc_hosts():
- try:
- hosts = []
- name = os.getenv('DISTCC_DIR', '/etc/distcc') + '/hosts'
- for l in open(name):
- l = l[l.find('#')+1:].strip()
- if l: hosts.append(l)
- return hosts
- except IOError:
- return (os.getenv('DISTCC_HOSTS', '').split() or
- [localhost()[0]])
-
- def count_distcc_hosts():
- cpus = 0
- hosts = 0
- for host in get_distcc_hosts():
- m = re.match(r'.*/(\d+)', host)
- hosts += 1
- cpus += m and int(m.group(1)) or 1
- return hosts, cpus
-
- def mk_distcc_hosts(basename, range, num_cpus):
- '''Generate a list of LL-internal machines to build on.'''
- loc_entry, cpus = localhost()
- hosts = [loc_entry]
- dead = []
- stations = [s for s in xrange(range) if s not in dead]
- random.shuffle(stations)
- hosts += ['%s%d.lindenlab.com/%d,lzo' % (basename, s, num_cpus) for s in stations]
- cpus += 2 * len(stations)
- return ' '.join(hosts), cpus
-
- if job_count is None:
- hosts, job_count = count_distcc_hosts()
- hostname = socket.gethostname()
- if hosts == 1:
- if hostname.startswith('station'):
- hosts, job_count = mk_distcc_hosts('station', 36, 2)
- os.environ['DISTCC_HOSTS'] = hosts
- if hostname.startswith('eniac'):
- hosts, job_count = mk_distcc_hosts('eniac', 71, 2)
- os.environ['DISTCC_HOSTS'] = hosts
- if hostname.startswith('build'):
- max_jobs = 6
- else:
- max_jobs = 12
- if job_count > max_jobs:
- job_count = max_jobs;
- opts.extend(['-j', str(job_count)])
-
- if targets:
- targets = ' '.join(targets)
- else:
- targets = 'all'
-
- for d in self.build_dirs():
- cmd = 'make -C %r %s %s' % (d, ' '.join(opts), targets)
- print 'Running %r' % cmd
- self.run(cmd)
-
-
-class DarwinSetup(UnixSetup):
- def __init__(self):
- super(DarwinSetup, self).__init__()
- self.generator = 'Xcode'
-
- def os(self):
- return 'darwin'
-
- def arch(self):
- if self.universal == 'ON':
- return 'universal'
- else:
- return UnixSetup.arch(self)
-
- def cmake_commandline(self, src_dir, build_dir, opts, simple):
- args = dict(
- dir=src_dir,
- generator=self.generator,
- opts=quote(opts),
- standalone=self.standalone,
- word_size=self.word_size,
- unattended=self.unattended,
- project_name=self.project_name,
- universal=self.universal,
- type=self.build_type.upper(),
- )
- if self.universal == 'ON':
- args['universal'] = '-DCMAKE_OSX_ARCHITECTURES:STRING=\'i386;ppc\''
- #if simple:
- # return 'cmake %(opts)s %(dir)r' % args
- return ('cmake -G %(generator)r '
- '-DCMAKE_BUILD_TYPE:STRING=%(type)s '
- '-DSTANDALONE:BOOL=%(standalone)s '
- '-DUNATTENDED:BOOL=%(unattended)s '
- '-DWORD_SIZE:STRING=%(word_size)s '
- '-DROOT_PROJECT_NAME:STRING=%(project_name)s '
- '%(universal)s '
- '%(opts)s %(dir)r' % args)
-
- def run_build(self, opts, targets):
- cwd = getcwd()
- if targets:
- targets = ' '.join(['-target ' + repr(t) for t in targets])
- else:
- targets = ''
- cmd = ('xcodebuild -configuration %s %s %s | grep -v "^[[:space:]]*setenv" ; exit ${PIPESTATUS[0]}' %
- (self.build_type, ' '.join(opts), targets))
- for d in self.build_dirs():
- try:
- os.chdir(d)
- print 'Running %r in %r' % (cmd, d)
- self.run(cmd)
- finally:
- os.chdir(cwd)
-
-
-class WindowsSetup(PlatformSetup):
- gens = {
- 'vc71' : {
- 'gen' : r'Visual Studio 7 .NET 2003',
- 'ver' : r'7.1'
- },
- 'vc80' : {
- 'gen' : r'Visual Studio 8 2005',
- 'ver' : r'8.0'
- },
- 'vc90' : {
- 'gen' : r'Visual Studio 9 2008',
- 'ver' : r'9.0'
- }
- }
- gens['vs2003'] = gens['vc71']
- gens['vs2005'] = gens['vc80']
- gens['vs2008'] = gens['vc90']
-
- search_path = r'C:\windows'
- exe_suffixes = ('.exe', '.bat', '.com')
-
- def __init__(self):
- super(WindowsSetup, self).__init__()
- self._generator = None
- self.incredibuild = False
-
- def _get_generator(self):
- if self._generator is None:
- for version in 'vc80 vc90 vc71'.split():
- if self.find_visual_studio(version):
- self._generator = version
- print 'Building with ', self.gens[version]['gen']
- break
- else:
- print >> sys.stderr, 'Cannot find a Visual Studio installation, testing for express editions'
- for version in 'vc80 vc90 vc71'.split():
- if self.find_visual_studio_express(version):
- self._generator = version
- self.using_express = True
- print 'Building with ', self.gens[version]['gen'] , "Express edition"
- break
- else:
- print >> sys.stderr, 'Cannot find any Visual Studio installation'
- sys.exit(1)
- return self._generator
-
- def _set_generator(self, gen):
- self._generator = gen
-
- generator = property(_get_generator, _set_generator)
-
- def os(self):
- return 'win32'
-
- def build_dirs(self):
- return ['build-' + self.generator]
-
- def cmake_commandline(self, src_dir, build_dir, opts, simple):
- args = dict(
- dir=src_dir,
- generator=self.gens[self.generator.lower()]['gen'],
- opts=quote(opts),
- standalone=self.standalone,
- unattended=self.unattended,
- project_name=self.project_name,
- word_size=self.word_size,
- )
- #if simple:
- # return 'cmake %(opts)s "%(dir)s"' % args
- return ('cmake -G "%(generator)s" '
- '-DSTANDALONE:BOOL=%(standalone)s '
- '-DUNATTENDED:BOOL=%(unattended)s '
- '-DWORD_SIZE:STRING=%(word_size)s '
- '-DROOT_PROJECT_NAME:STRING=%(project_name)s '
- '%(opts)s "%(dir)s"' % args)
-
- def get_HKLM_registry_value(self, key_str, value_str):
- import _winreg
- reg = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE)
- key = _winreg.OpenKey(reg, key_str)
- value = _winreg.QueryValueEx(key, value_str)[0]
- print 'Found: %s' % value
- return value
-
- def find_visual_studio(self, gen=None):
- if gen is None:
- gen = self._generator
- gen = gen.lower()
- value_str = (r'EnvironmentDirectory')
- key_str = (r'SOFTWARE\Microsoft\VisualStudio\%s\Setup\VS' %
- self.gens[gen]['ver'])
- print ('Reading VS environment from HKEY_LOCAL_MACHINE\%s\%s' %
- (key_str, value_str))
- try:
- return self.get_HKLM_registry_value(key_str, value_str)
- except WindowsError, err:
- key_str = (r'SOFTWARE\Wow6432Node\Microsoft\VisualStudio\%s\Setup\VS' %
- self.gens[gen]['ver'])
-
- try:
- return self.get_HKLM_registry_value(key_str, value_str)
- except:
- print >> sys.stderr, "Didn't find ", self.gens[gen]['gen']
-
- return ''
-
- def find_visual_studio_express(self, gen=None):
- if gen is None:
- gen = self._generator
- gen = gen.lower()
- try:
- import _winreg
- key_str = (r'SOFTWARE\Microsoft\VCEXpress\%s\Setup\VC' %
- self.gens[gen]['ver'])
- value_str = (r'ProductDir')
- print ('Reading VS environment from HKEY_LOCAL_MACHINE\%s\%s' %
- (key_str, value_str))
- print key_str
-
- reg = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE)
- key = _winreg.OpenKey(reg, key_str)
- value = _winreg.QueryValueEx(key, value_str)[0]+"IDE"
- print 'Found: %s' % value
- return value
- except WindowsError, err:
- print >> sys.stderr, "Didn't find ", self.gens[gen]['gen']
- return ''
-
- def get_build_cmd(self):
- if self.incredibuild:
- config = self.build_type
- if self.gens[self.generator]['ver'] in [ r'8.0', r'9.0' ]:
- config = '\"%s|Win32\"' % config
-
- executable = 'buildconsole'
- cmd = "%(bin)s %(prj)s.sln /build /cfg=%(cfg)s" % {'prj': self.project_name, 'cfg': config, 'bin': executable}
- return (executable, cmd)
-
- environment = self.find_visual_studio()
- if environment == '':
- environment = self.find_visual_studio_express()
- if environment == '':
- print >> sys.stderr, "Something went very wrong during build stage, could not find a Visual Studio installation."
- else:
- build_dirs=self.build_dirs();
- print >> sys.stderr, "\nSolution generation complete, it can can now be found in:", build_dirs[0]
- print >> sys.stderr, "\nPlease see https://wiki.secondlife.com/wiki/Microsoft_Visual_Studio#Extra_steps_for_Visual_Studio_Express_editions for express specific information"
- exit(0)
-
- # devenv.com is CLI friendly, devenv.exe... not so much.
- executable = '%sdevenv.com' % (self.find_visual_studio(),)
- cmd = ('"%s" %s.sln /build %s' %
- (executable, self.project_name, self.build_type))
- return (executable, cmd)
-
- def run(self, command, name=None, retry_on=None, retries=1):
- '''Run a program. If the program fails, raise an exception.'''
- assert name is not None, 'On windows an executable path must be given in name. [DEV-44838]'
- if os.path.isfile(name):
- path = name
- else:
- path = self.find_in_path(name)[0]
- while retries:
- retries = retries - 1
- print "develop.py tries to run:", command
- ret = subprocess.call(command, executable=path)
- print "got ret", ret, "from", command
- if ret == 0:
- break
- else:
- error = 'exited with status %d' % ret
- if retry_on is not None and retry_on == ret:
- print "Retrying... the command %r %s" % (name, error)
- else:
- raise CommandError('the command %r %s' % (name, error))
-
- def run_cmake(self, args=[]):
- '''Override to add the vstool.exe call after running cmake.'''
- PlatformSetup.run_cmake(self, args)
- if self.unattended == 'OFF':
- if self.using_express == False:
- self.run_vstool()
-
- def run_vstool(self):
- for build_dir in self.build_dirs():
- stamp = os.path.join(build_dir, 'vstool.txt')
- try:
- prev_build = open(stamp).read().strip()
- except IOError:
- prev_build = ''
- if prev_build == self.build_type:
- # Only run vstool if the build type has changed.
- continue
- executable = os.path.join('tools','vstool','VSTool.exe')
- vstool_cmd = (executable +
- ' --solution ' +
- os.path.join(build_dir,'SecondLife.sln') +
- ' --config ' + self.build_type +
- ' --startup secondlife-bin')
- print 'Running %r in %r' % (vstool_cmd, getcwd())
- self.run(vstool_cmd, name=executable)
- print >> open(stamp, 'w'), self.build_type
-
- def run_build(self, opts, targets):
- for t in targets:
- assert t.strip(), 'Unexpected empty targets: ' + repr(targets)
- cwd = getcwd()
- executable, build_cmd = self.get_build_cmd()
-
- for d in self.build_dirs():
- try:
- os.chdir(d)
- if targets:
- for t in targets:
- cmd = '%s /project %s %s' % (build_cmd, t, ' '.join(opts))
- print 'Running %r in %r' % (cmd, d)
- self.run(cmd, name=executable, retry_on=4, retries=3)
- else:
- cmd = '%s %s' % (build_cmd, ' '.join(opts))
- print 'Running %r in %r' % (cmd, d)
- self.run(cmd, name=executable, retry_on=4, retries=3)
- finally:
- os.chdir(cwd)
-
-class CygwinSetup(WindowsSetup):
- def __init__(self):
- super(CygwinSetup, self).__init__()
- self.generator = 'vc80'
-
- def cmake_commandline(self, src_dir, build_dir, opts, simple):
- dos_dir = commands.getoutput("cygpath -w %s" % src_dir)
- args = dict(
- dir=dos_dir,
- generator=self.gens[self.generator.lower()]['gen'],
- opts=quote(opts),
- standalone=self.standalone,
- unattended=self.unattended,
- project_name=self.project_name,
- word_size=self.word_size,
- )
- #if simple:
- # return 'cmake %(opts)s "%(dir)s"' % args
- return ('cmake -G "%(generator)s" '
- '-DUNATTENDED:BOOl=%(unattended)s '
- '-DSTANDALONE:BOOL=%(standalone)s '
- '-DWORD_SIZE:STRING=%(word_size)s '
- '-DROOT_PROJECT_NAME:STRING=%(project_name)s '
- '%(opts)s "%(dir)s"' % args)
-
-setup_platform = {
- 'darwin': DarwinSetup,
- 'linux2': LinuxSetup,
- 'win32' : WindowsSetup,
- 'cygwin' : CygwinSetup
- }
-
-
-usage_msg = '''
-Usage: develop.py [options] [command [command-options]]
-
-Options:
- -h | --help print this help message
- --standalone build standalone, without Linden prebuild libraries
- --unattended build unattended, do not invoke any tools requiring
- a human response
- --universal build a universal binary on Mac OS X (unsupported)
- -t | --type=NAME build type ("Debug", "Release", or "RelWithDebInfo")
- -m32 | -m64 build architecture (32-bit or 64-bit)
- -N | --no-distcc disable use of distcc
- -G | --generator=NAME generator name
- Windows: VC71 or VS2003 (default), VC80 (VS2005) or
- VC90 (VS2008)
- Mac OS X: Xcode (default), Unix Makefiles
- Linux: Unix Makefiles (default), KDevelop3
- -p | --project=NAME set the root project name. (Doesn't effect makefiles)
-
-Commands:
- build configure and build default target
- clean delete all build directories, does not affect sources
- configure configure project by running cmake (default if none given)
- printbuilddirs print the build directory that will be used
-
-Command-options for "configure":
- We use cmake variables to change the build configuration.
- -DSERVER:BOOL=OFF Don't configure simulator/dataserver/etc
- -DVIEWER:BOOL=OFF Don't configure the viewer
- -DPACKAGE:BOOL=ON Create "package" target to make installers
- -DLOCALIZESETUP:BOOL=ON Create one win_setup target per supported language
-
-Examples:
- Set up a viewer-only project for your system:
- develop.py configure -DSERVER:BOOL=OFF
-
- Set up a Visual Studio 2005 project with "package" target:
- develop.py -G vc80 configure -DPACKAGE:BOOL=ON
-'''
-
-def main(arguments):
- setup = setup_platform[sys.platform]()
- try:
- opts, args = getopt.getopt(
- arguments,
- '?hNt:p:G:m:',
- ['help', 'standalone', 'no-distcc', 'unattended', 'universal', 'type=', 'incredibuild', 'generator=', 'project='])
- except getopt.GetoptError, err:
- print >> sys.stderr, 'Error:', err
- print >> sys.stderr, """
-Note: You must pass -D options to cmake after the "configure" command
-For example: develop.py configure -DSERVER:BOOL=OFF"""
- print >> sys.stderr, usage_msg.strip()
- sys.exit(1)
-
- for o, a in opts:
- if o in ('-?', '-h', '--help'):
- print usage_msg.strip()
- sys.exit(0)
- elif o in ('--standalone',):
- setup.standalone = 'ON'
- elif o in ('--unattended',):
- setup.unattended = 'ON'
- elif o in ('--universal',):
- setup.universal = 'ON'
- elif o in ('-m',):
- if a in ('32', '64'):
- setup.word_size = int(a)
- else:
- print >> sys.stderr, 'Error: unknown word size', repr(a)
- print >> sys.stderr, 'Supported word sizes: 32, 64'
- sys.exit(1)
- elif o in ('-t', '--type'):
- try:
- setup.build_type = setup.build_types[a.lower()]
- except KeyError:
- print >> sys.stderr, 'Error: unknown build type', repr(a)
- print >> sys.stderr, 'Supported build types:'
- types = setup.build_types.values()
- types.sort()
- for t in types:
- print ' ', t
- sys.exit(1)
- elif o in ('-G', '--generator'):
- setup.generator = a
- elif o in ('-N', '--no-distcc'):
- setup.distcc = False
- elif o in ('-p', '--project'):
- setup.project_name = a
- elif o in ('--incredibuild'):
- setup.incredibuild = True
- else:
- print >> sys.stderr, 'INTERNAL ERROR: unhandled option', repr(o)
- sys.exit(1)
- if not args:
- setup.run_cmake()
- return
- try:
- cmd = args.pop(0)
- if cmd in ('cmake', 'configure'):
- setup.run_cmake(args)
- elif cmd == 'build':
- if os.getenv('DISTCC_DIR') is None:
- distcc_dir = os.path.join(getcwd(), '.distcc')
- if not os.path.exists(distcc_dir):
- os.mkdir(distcc_dir)
- print "setting DISTCC_DIR to %s" % distcc_dir
- os.environ['DISTCC_DIR'] = distcc_dir
- else:
- print "DISTCC_DIR is set to %s" % os.getenv('DISTCC_DIR')
- for d in setup.build_dirs():
- if not os.path.exists(d):
- raise CommandError('run "develop.py cmake" first')
- setup.run_cmake()
- opts, targets = setup.parse_build_opts(args)
- setup.run_build(opts, targets)
- elif cmd == 'clean':
- if args:
- raise CommandError('clean takes no arguments')
- setup.cleanup()
- elif cmd == 'printbuilddirs':
- for d in setup.build_dirs():
- print >> sys.stdout, d
- else:
- print >> sys.stderr, 'Error: unknown subcommand', repr(cmd)
- print >> sys.stderr, "(run 'develop.py --help' for help)"
- sys.exit(1)
- except getopt.GetoptError, err:
- print >> sys.stderr, 'Error with %r subcommand: %s' % (cmd, err)
- sys.exit(1)
-
-
-if __name__ == '__main__':
- try:
- main(sys.argv[1:])
- except CommandError, err:
- print >> sys.stderr, 'Error:', err
- sys.exit(1)
diff --git a/indra/integration_tests/CMakeLists.txt b/indra/integration_tests/CMakeLists.txt
index 67e8fbf1f2..ced2b3dbcf 100644
--- a/indra/integration_tests/CMakeLists.txt
+++ b/indra/integration_tests/CMakeLists.txt
@@ -1,3 +1,8 @@
# -*- cmake -*-
-
add_subdirectory(llui_libtest)
+IF (LLIMAGE_LIBTEST)
+ MESSAGE(STATUS "Build llimage_libtest")
+ add_subdirectory(llimage_libtest)
+ELSE (LLIMAGE_LIBTEST)
+ MESSAGE(STATUS "Skip llimage_libtest")
+ENDIF (LLIMAGE_LIBTEST)
diff --git a/indra/integration_tests/llimage_libtest/CMakeLists.txt b/indra/integration_tests/llimage_libtest/CMakeLists.txt
new file mode 100644
index 0000000000..a687e60610
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/CMakeLists.txt
@@ -0,0 +1,125 @@
+# -*- cmake -*-
+
+# Integration tests of the llimage library (JPEG2000, PNG, jpeg, etc... images reading and writing)
+
+project (llimage_libtest)
+
+include(00-Common)
+include(LLCommon)
+include(LLImage)
+include(LLImageJ2COJ)
+include(LLKDU)
+include(LLVFS)
+
+include_directories(
+ ${LLCOMMON_INCLUDE_DIRS}
+ ${LLVFS_INCLUDE_DIRS}
+ ${LLIMAGE_INCLUDE_DIRS}
+ )
+
+set(llimage_libtest_SOURCE_FILES
+ llimage_libtest.cpp
+ )
+
+set(llimage_libtest_HEADER_FILES
+ CMakeLists.txt
+ llimage_libtest.h
+ )
+
+set_source_files_properties(${llimage_libtest_HEADER_FILES}
+ PROPERTIES HEADER_FILE_ONLY TRUE)
+
+list(APPEND llimage_libtest_SOURCE_FILES ${llimage_libtest_HEADER_FILES})
+
+add_executable(llimage_libtest
+ WIN32
+ MACOSX_BUNDLE
+ ${llimage_libtest_SOURCE_FILES}
+)
+
+set_target_properties(llimage_libtest
+ PROPERTIES
+ WIN32_EXECUTABLE
+ FALSE
+)
+
+# OS-specific libraries
+if (DARWIN)
+ include(CMakeFindFrameworks)
+ find_library(COREFOUNDATION_LIBRARY CoreFoundation)
+ set(OS_LIBRARIES ${COREFOUNDATION_LIBRARY})
+elseif (WINDOWS)
+ set(OS_LIBRARIES)
+elseif (LINUX)
+ set(OS_LIBRARIES)
+else (DARWIN)
+ message(FATAL_ERROR "Unknown platform")
+endif (DARWIN)
+
+# Libraries on which this application depends on
+# Sort by high-level to low-level
+target_link_libraries(llimage_libtest
+ ${LLCOMMON_LIBRARIES}
+ ${LLVFS_LIBRARIES}
+ ${LLIMAGE_LIBRARIES}
+ ${LLKDU_LIBRARIES}
+ ${KDU_LIBRARY}
+ ${LLIMAGEJ2COJ_LIBRARIES}
+ ${OS_LIBRARIES}
+ )
+
+if (DARWIN)
+ # Path inside the app bundle where we'll need to copy libraries
+ set(LLIMAGE_LIBTEST_DESTINATION_DIR
+ ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/llimage_libtest.app/Contents/Resources
+ )
+ # Create the Contents/Resources directory
+ add_custom_command(
+ TARGET llimage_libtest POST_BUILD
+ COMMAND ${CMAKE_COMMAND}
+ ARGS
+ -E
+ make_directory
+ ${LLIMAGE_LIBTEST_DESTINATION_DIR}
+ COMMENT "Creating Resources directory in app bundle."
+ )
+else (DARWIN)
+ set(LLIMAGE_LIBTEST_DESTINATION_DIR
+ ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/
+ )
+endif (DARWIN)
+
+get_target_property(BUILT_LLCOMMON llcommon LOCATION)
+add_custom_command(TARGET llimage_libtest POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy ${BUILT_LLCOMMON} ${LLIMAGE_LIBTEST_DESTINATION_DIR}
+ DEPENDS ${BUILT_LLCOMMON}
+)
+
+if (DARWIN)
+ # Copy the required libraries to the package app
+ add_custom_command(TARGET llimage_libtest POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/../build-darwin-i386/packages/lib/release/libapr-1.0.dylib ${LLIMAGE_LIBTEST_DESTINATION_DIR}
+ DEPENDS ${CMAKE_SOURCE_DIR}/../build-darwin-i386/packages/lib/release/libapr-1.0.dylib
+ )
+ add_custom_command(TARGET llimage_libtest POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/../build-darwin-i386/packages/lib/release/libaprutil-1.0.dylib ${LLIMAGE_LIBTEST_DESTINATION_DIR}
+ DEPENDS ${CMAKE_SOURCE_DIR}/../build-darwin-i386/packages/lib/release/libaprutil-1.0.dylib
+ )
+ add_custom_command(TARGET llimage_libtest POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/../build-darwin-i386/packages/lib/release/libexception_handler.dylib ${LLIMAGE_LIBTEST_DESTINATION_DIR}
+ DEPENDS ${CMAKE_SOURCE_DIR}/../build-darwin-i386/packages/lib/release/libexception_handler.dylib
+ )
+ add_custom_command(TARGET llimage_libtest POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/../build-darwin-i386/packages/lib/release/libexpat.1.5.2.dylib ${LLIMAGE_LIBTEST_DESTINATION_DIR}
+ DEPENDS ${CMAKE_SOURCE_DIR}/../build-darwin-i386/packages/lib/release/libexpat.1.5.2.dylib
+ )
+endif (DARWIN)
+
+if (WINDOWS)
+ # Check indra/test_apps/llplugintest/CMakeLists.txt for an example of what to copy over for Windows and how
+endif (WINDOWS)
+
+# Ensure people working on the viewer don't break this library
+# *NOTE: This could be removed, or only built by TeamCity, if the build
+# and link times become too long.
+add_dependencies(viewer llimage_libtest)
diff --git a/indra/integration_tests/llimage_libtest/llimage_libtest.cpp b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp
new file mode 100644
index 0000000000..976aae08bb
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp
@@ -0,0 +1,559 @@
+/**
+ * @file llimage_libtest.cpp
+ * @author Merov Linden
+ * @brief Integration test for the llimage library
+ *
+ * $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$
+ */
+#include "linden_common.h"
+#include "llpointer.h"
+#include "lltimer.h"
+
+#include "llimage_libtest.h"
+
+// Linden library includes
+#include "llimage.h"
+#include "llimagejpeg.h"
+#include "llimagepng.h"
+#include "llimagebmp.h"
+#include "llimagetga.h"
+#include "llimagej2c.h"
+#include "lldir.h"
+
+// system libraries
+#include <iostream>
+
+// doc string provided when invoking the program with --help
+static const char USAGE[] = "\n"
+"usage:\tllimage_libtest [options]\n"
+"\n"
+" -h, --help\n"
+" Print this help\n"
+" -i, --input <file1 .. file2>\n"
+" List of image files to load and convert. Patterns with wild cards can be used.\n"
+" -o, --output <file1 .. file2> OR <type>\n"
+" List of image files to create (assumes same order as for input files)\n"
+" OR 3 letters file type extension to convert each input file into.\n"
+" -r, --region <x0, y0, x1, y1>\n"
+" Crop region applied to the input files in pixels.\n"
+" Only used for j2c images. Default is no region cropping.\n"
+" -d, --discard_level <n>\n"
+" Discard level max used on input. 0 is highest resolution. Max discard level is 5.\n"
+" This allows the input image to be clamped in resolution when loading.\n"
+" Only valid for j2c images. Default is no discard.\n"
+" -p, --precincts <n>\n"
+" Dimension of precincts in pixels. Precincts are assumed square and identical for\n"
+" all levels. Note that this option also add PLT and tile markers to the codestream, \n"
+" and uses RPCL order. Power of 2 must be used.\n"
+" Only valid for output j2c images. Default is no precincts used.\n"
+" -b, --blocks <n>\n"
+" Dimension of coding blocks in pixels. Blocks are assumed square. Power of 2 must\n"
+" be used. Blocks must be smaller than precincts. Like precincts, this option adds\n"
+" PLT, tile markers and uses RPCL.\n"
+" Only valid for output j2c images. Default is 64.\n"
+" -l, --levels <n>\n"
+" Number of decomposition levels (aka discard levels) in the output image.\n"
+" The maximum number of levels authorized is 32.\n"
+" Only valid for output j2c images. Default is 5.\n"
+" -rev, --reversible\n"
+" Set the compression to be lossless (reversible in j2c parlance).\n"
+" Only valid for output j2c images.\n"
+" -log, --logmetrics <metric>\n"
+" Log performance data for <metric>. Results in <metric>.slp\n"
+" Note: so far, only ImageCompressionTester has been tested.\n"
+" -a, --analyzeperformance\n"
+" Create a report comparing <metric>_baseline.slp with current <metric>.slp\n"
+" Results in <metric>_report.csv\n"
+" -s, --image-stats\n"
+" Output stats for each input and output image.\n"
+"\n";
+
+// true when all image loading is done. Used by metric logging thread to know when to stop the thread.
+static bool sAllDone = false;
+
+// Create an empty formatted image instance of the correct type from the filename
+LLPointer<LLImageFormatted> create_image(const std::string &filename)
+{
+ std::string exten = gDirUtilp->getExtension(filename);
+ LLPointer<LLImageFormatted> image = LLImageFormatted::createFromExtension(exten);
+ return image;
+}
+
+void output_image_stats(LLPointer<LLImageFormatted> image, const std::string &filename)
+{
+ // Print out some statistical data on the image
+ std::cout << "Image stats for : " << filename << ", extension : " << image->getExtension() << std::endl;
+
+ std::cout << " with : " << (int)(image->getWidth()) << ", height : " << (int)(image->getHeight()) << std::endl;
+ std::cout << " comp : " << (int)(image->getComponents()) << ", levels : " << (int)(image->getDiscardLevel()) << std::endl;
+ std::cout << " head : " << (int)(image->calcHeaderSize()) << ", data : " << (int)(image->getDataSize()) << std::endl;
+
+ return;
+}
+
+// Load an image from file and return a raw (decompressed) instance of its data
+LLPointer<LLImageRaw> load_image(const std::string &src_filename, int discard_level, int* region, bool output_stats)
+{
+ LLPointer<LLImageFormatted> image = create_image(src_filename);
+
+ // This just loads the image file stream into a buffer. No decoding done.
+ if (!image->load(src_filename))
+ {
+ return NULL;
+ }
+
+ if( (image->getComponents() != 3) && (image->getComponents() != 4) )
+ {
+ std::cout << "Image files with less than 3 or more than 4 components are not supported\n";
+ return NULL;
+ }
+
+ if (output_stats)
+ {
+ output_image_stats(image, src_filename);
+ }
+
+ LLPointer<LLImageRaw> raw_image = new LLImageRaw;
+
+ // Set the image restriction on load in the case of a j2c image
+ if ((image->getCodec() == IMG_CODEC_J2C) && ((discard_level != -1) || (region != NULL)))
+ {
+ // That method doesn't exist (and likely, doesn't make sense) for any other image file format
+ // hence the required cryptic cast.
+ ((LLImageJ2C*)(image.get()))->initDecode(*raw_image, discard_level, region);
+ }
+
+ if (!image->decode(raw_image, 0.0f))
+ {
+ return NULL;
+ }
+
+ return raw_image;
+}
+
+// Save a raw image instance into a file
+bool save_image(const std::string &dest_filename, LLPointer<LLImageRaw> raw_image, int blocks_size, int precincts_size, int levels, bool reversible, bool output_stats)
+{
+ LLPointer<LLImageFormatted> image = create_image(dest_filename);
+
+ // Set the image codestream parameters on output in the case of a j2c image
+ if (image->getCodec() == IMG_CODEC_J2C)
+ {
+ // That method doesn't exist (and likely, doesn't make sense) for any other image file format
+ // hence the required cryptic cast.
+ if ((blocks_size != -1) || (precincts_size != -1) || (levels != 0))
+ {
+ ((LLImageJ2C*)(image.get()))->initEncode(*raw_image, blocks_size, precincts_size, levels);
+ }
+ ((LLImageJ2C*)(image.get()))->setReversible(reversible);
+ }
+
+ if (!image->encode(raw_image, 0.0f))
+ {
+ return false;
+ }
+
+ if (output_stats)
+ {
+ output_image_stats(image, dest_filename);
+ }
+
+ return image->save(dest_filename);
+}
+
+void store_input_file(std::list<std::string> &input_filenames, const std::string &path)
+{
+ // Break the incoming path in its components
+ std::string dir = gDirUtilp->getDirName(path);
+ std::string name = gDirUtilp->getBaseFileName(path);
+ std::string exten = gDirUtilp->getExtension(path);
+
+ // std::cout << "store_input_file : " << path << ", dir : " << dir << ", name : " << name << ", exten : " << exten << std::endl;
+
+ // If extension is not an image type or "*", exit
+ // Note: we don't support complex patterns for the extension like "j??"
+ // Note: on most shells, the pattern expansion is done by the shell so that pattern matching limitation is actually not a problem
+ if ((exten.compare("*") != 0) && (LLImageBase::getCodecFromExtension(exten) == IMG_CODEC_INVALID))
+ {
+ return;
+ }
+
+ if ((name.find('*') != -1) || ((name.find('?') != -1)))
+ {
+ // If file name is a pattern, iterate to get each file name and store
+ std::string next_name;
+ while (gDirUtilp->getNextFileInDir(dir,name,next_name))
+ {
+ std::string file_name = dir + gDirUtilp->getDirDelimiter() + next_name;
+ input_filenames.push_back(file_name);
+ }
+ }
+ else
+ {
+ // Verify that the file does exist before storing
+ if (gDirUtilp->fileExists(path))
+ {
+ input_filenames.push_back(path);
+ }
+ else
+ {
+ std::cout << "store_input_file : the file " << path << " could not be found" << std::endl;
+ }
+ }
+}
+
+void store_output_file(std::list<std::string> &output_filenames, std::list<std::string> &input_filenames, const std::string &path)
+{
+ // Break the incoming path in its components
+ std::string dir = gDirUtilp->getDirName(path);
+ std::string name = gDirUtilp->getBaseFileName(path);
+ std::string exten = gDirUtilp->getExtension(path);
+
+ // std::cout << "store_output_file : " << path << ", dir : " << dir << ", name : " << name << ", exten : " << exten << std::endl;
+
+ if (dir.empty() && exten.empty())
+ {
+ // If dir and exten are empty, we interpret the name as a file extension type name and will iterate through input list to populate the output list
+ exten = name;
+ // Make sure the extension is an image type
+ if (LLImageBase::getCodecFromExtension(exten) == IMG_CODEC_INVALID)
+ {
+ return;
+ }
+ std::string delim = gDirUtilp->getDirDelimiter();
+ std::list<std::string>::iterator in_file = input_filenames.begin();
+ std::list<std::string>::iterator end = input_filenames.end();
+ for (; in_file != end; ++in_file)
+ {
+ dir = gDirUtilp->getDirName(*in_file);
+ name = gDirUtilp->getBaseFileName(*in_file,true);
+ std::string file_name;
+ if (!dir.empty())
+ {
+ file_name = dir + delim + name + "." + exten;
+ }
+ else
+ {
+ file_name = name + "." + exten;
+ }
+ output_filenames.push_back(file_name);
+ }
+ }
+ else
+ {
+ // Make sure the extension is an image type
+ if (LLImageBase::getCodecFromExtension(exten) == IMG_CODEC_INVALID)
+ {
+ return;
+ }
+ // Store the path
+ output_filenames.push_back(path);
+ }
+}
+
+// Holds the metric gathering output in a thread safe way
+class LogThread : public LLThread
+{
+public:
+ std::string mFile;
+
+ LogThread(std::string& test_name) : LLThread("llimage_libtest log")
+ {
+ std::string file_name = test_name + std::string(".slp");
+ mFile = file_name;
+ }
+
+ void run()
+ {
+ std::ofstream os(mFile.c_str());
+
+ while (!sAllDone)
+ {
+ LLFastTimer::writeLog(os);
+ os.flush();
+ ms_sleep(32);
+ }
+ LLFastTimer::writeLog(os);
+ os.flush();
+ os.close();
+ }
+};
+
+int main(int argc, char** argv)
+{
+ // List of input and output files
+ std::list<std::string> input_filenames;
+ std::list<std::string> output_filenames;
+ // Other optional parsed arguments
+ bool analyze_performance = false;
+ bool image_stats = false;
+ int* region = NULL;
+ int discard_level = -1;
+ int precincts_size = -1;
+ int blocks_size = -1;
+ int levels = 0;
+ bool reversible = false;
+
+ // Init whatever is necessary
+ ll_init_apr();
+ LLImage::initClass();
+ LogThread* fast_timer_log_thread = NULL; // For performance and metric gathering
+
+ // Analyze command line arguments
+ for (int arg = 1; arg < argc; ++arg)
+ {
+ if (!strcmp(argv[arg], "--help") || !strcmp(argv[arg], "-h"))
+ {
+ // Send the usage to standard out
+ std::cout << USAGE << std::endl;
+ return 0;
+ }
+ else if ((!strcmp(argv[arg], "--input") || !strcmp(argv[arg], "-i")) && arg < argc-1)
+ {
+ std::string file_name = argv[arg+1];
+ while (file_name[0] != '-') // if arg starts with '-', we consider it's not a file name but some other argument
+ {
+ // std::cout << "input file name : " << file_name << std::endl;
+ store_input_file(input_filenames, file_name);
+ arg += 1; // Skip that arg now we know it's a file name
+ if ((arg + 1) == argc) // Break out of the loop if we reach the end of the arg list
+ break;
+ file_name = argv[arg+1]; // Next argument and loop over
+ }
+ }
+ else if ((!strcmp(argv[arg], "--output") || !strcmp(argv[arg], "-o")) && arg < argc-1)
+ {
+ std::string file_name = argv[arg+1];
+ while (file_name[0] != '-') // if arg starts with '-', we consider it's not a file name but some other argument
+ {
+ // std::cout << "output file name : " << file_name << std::endl;
+ store_output_file(output_filenames, input_filenames, file_name);
+ arg += 1; // Skip that arg now we know it's a file name
+ if ((arg + 1) == argc) // Break out of the loop if we reach the end of the arg list
+ break;
+ file_name = argv[arg+1]; // Next argument and loop over
+ }
+ }
+ else if ((!strcmp(argv[arg], "--region") || !strcmp(argv[arg], "-r")) && arg < argc-1)
+ {
+ std::string value_str = argv[arg+1];
+ int index = 0;
+ region = new int[4];
+ while (value_str[0] != '-') // if arg starts with '-', it's the next option
+ {
+ int value = atoi(value_str.c_str());
+ region[index++] = value;
+ arg += 1; // Definitely skip that arg now we know it's a number
+ if ((arg + 1) == argc) // Break out of the loop if we reach the end of the arg list
+ break;
+ if (index == 4) // Break out of the loop if we captured 4 values already
+ break;
+ value_str = argv[arg+1]; // Next argument and loop over
+ }
+ if (index != 4)
+ {
+ std::cout << "--region arguments invalid" << std::endl;
+ delete [] region;
+ region = NULL;
+ }
+ }
+ else if (!strcmp(argv[arg], "--discard_level") || !strcmp(argv[arg], "-d"))
+ {
+ std::string value_str;
+ if ((arg + 1) < argc)
+ {
+ value_str = argv[arg+1];
+ }
+ if (((arg + 1) >= argc) || (value_str[0] == '-'))
+ {
+ std::cout << "No valid --discard_level argument given, discard_level ignored" << std::endl;
+ }
+ else
+ {
+ discard_level = atoi(value_str.c_str());
+ // Clamp to the values accepted by the viewer
+ discard_level = llclamp(discard_level,0,5);
+ }
+ }
+ else if (!strcmp(argv[arg], "--precincts") || !strcmp(argv[arg], "-p"))
+ {
+ std::string value_str;
+ if ((arg + 1) < argc)
+ {
+ value_str = argv[arg+1];
+ }
+ if (((arg + 1) >= argc) || (value_str[0] == '-'))
+ {
+ std::cout << "No valid --precincts argument given, precincts ignored" << std::endl;
+ }
+ else
+ {
+ precincts_size = atoi(value_str.c_str());
+ }
+ }
+ else if (!strcmp(argv[arg], "--blocks") || !strcmp(argv[arg], "-b"))
+ {
+ std::string value_str;
+ if ((arg + 1) < argc)
+ {
+ value_str = argv[arg+1];
+ }
+ if (((arg + 1) >= argc) || (value_str[0] == '-'))
+ {
+ std::cout << "No valid --blocks argument given, blocks ignored" << std::endl;
+ }
+ else
+ {
+ blocks_size = atoi(value_str.c_str());
+ }
+ }
+ else if (!strcmp(argv[arg], "--levels") || !strcmp(argv[arg], "-l"))
+ {
+ std::string value_str;
+ if ((arg + 1) < argc)
+ {
+ value_str = argv[arg+1];
+ }
+ if (((arg + 1) >= argc) || (value_str[0] == '-'))
+ {
+ std::cout << "No valid --levels argument given, default (5) will be used" << std::endl;
+ }
+ else
+ {
+ levels = atoi(value_str.c_str());
+ }
+ }
+ else if (!strcmp(argv[arg], "--reversible") || !strcmp(argv[arg], "-rev"))
+ {
+ reversible = true;
+ }
+ else if (!strcmp(argv[arg], "--logmetrics") || !strcmp(argv[arg], "-log"))
+ {
+ // '--logmetrics' needs to be specified with a named test metric argument
+ // Note: for the moment, only ImageCompressionTester has been tested
+ std::string test_name;
+ if ((arg + 1) < argc)
+ {
+ test_name = argv[arg+1];
+ }
+ if (((arg + 1) >= argc) || (test_name[0] == '-'))
+ {
+ // We don't have an argument left in the arg list or the next argument is another option
+ std::cout << "No --logmetrics argument given, no perf data will be gathered" << std::endl;
+ }
+ else
+ {
+ LLFastTimer::sMetricLog = TRUE;
+ LLFastTimer::sLogName = test_name;
+ arg += 1; // Skip that arg now we know it's a valid test name
+ if ((arg + 1) == argc) // Break out of the loop if we reach the end of the arg list
+ break;
+ }
+ }
+ else if (!strcmp(argv[arg], "--analyzeperformance") || !strcmp(argv[arg], "-a"))
+ {
+ analyze_performance = true;
+ }
+ else if (!strcmp(argv[arg], "--image-stats") || !strcmp(argv[arg], "-s"))
+ {
+ image_stats = true;
+ }
+ }
+
+ // Check arguments consistency. Exit with proper message if inconsistent.
+ if (input_filenames.size() == 0)
+ {
+ std::cout << "No input file, nothing to do -> exit" << std::endl;
+ return 0;
+ }
+ if (analyze_performance && !LLFastTimer::sMetricLog)
+ {
+ std::cout << "Cannot create perf report if no perf gathered (i.e. use argument -log <perf> with -a) -> exit" << std::endl;
+ return 0;
+ }
+
+
+ // Create the logging thread if required
+ if (LLFastTimer::sMetricLog)
+ {
+ LLFastTimer::sLogLock = new LLMutex(NULL);
+ fast_timer_log_thread = new LogThread(LLFastTimer::sLogName);
+ fast_timer_log_thread->start();
+ }
+
+ // Perform action on each input file
+ std::list<std::string>::iterator in_file = input_filenames.begin();
+ std::list<std::string>::iterator out_file = output_filenames.begin();
+ std::list<std::string>::iterator in_end = input_filenames.end();
+ std::list<std::string>::iterator out_end = output_filenames.end();
+ for (; in_file != in_end; ++in_file, ++out_file)
+ {
+ // Load file
+ LLPointer<LLImageRaw> raw_image = load_image(*in_file, discard_level, region, image_stats);
+ if (!raw_image)
+ {
+ std::cout << "Error: Image " << *in_file << " could not be loaded" << std::endl;
+ continue;
+ }
+
+ // Save file
+ if (out_file != out_end)
+ {
+ if (!save_image(*out_file, raw_image, blocks_size, precincts_size, levels, reversible, image_stats))
+ {
+ std::cout << "Error: Image " << *out_file << " could not be saved" << std::endl;
+ }
+ else
+ {
+ std::cout << *in_file << " -> " << *out_file << std::endl;
+ }
+ }
+ }
+
+ // Output perf data if requested by user
+ if (analyze_performance)
+ {
+ std::string baseline_name = LLFastTimer::sLogName + "_baseline.slp";
+ std::string current_name = LLFastTimer::sLogName + ".slp";
+ std::string report_name = LLFastTimer::sLogName + "_report.csv";
+
+ std::cout << "Analyzing performance, check report in : " << report_name << std::endl;
+
+ LLMetricPerformanceTesterBasic::doAnalysisMetrics(baseline_name, current_name, report_name);
+ }
+
+ // Stop the perf gathering system if needed
+ if (LLFastTimer::sMetricLog)
+ {
+ LLMetricPerformanceTesterBasic::deleteTester(LLFastTimer::sLogName);
+ sAllDone = true;
+ }
+
+ // Cleanup and exit
+ LLImage::cleanupClass();
+ if (fast_timer_log_thread)
+ {
+ fast_timer_log_thread->shutdown();
+ }
+
+ return 0;
+}
diff --git a/indra/integration_tests/llimage_libtest/llimage_libtest.h b/indra/integration_tests/llimage_libtest/llimage_libtest.h
new file mode 100644
index 0000000000..63f3d46b50
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/llimage_libtest.h
@@ -0,0 +1,29 @@
+/**
+ * @file llimage_libtest.h
+ *
+ * $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 LLIMAGE_LIBTEST_H
+#define LLIMAGE_LIBTEST_H
+
+
+#endif
diff --git a/indra/integration_tests/llui_libtest/CMakeLists.txt b/indra/integration_tests/llui_libtest/CMakeLists.txt
index 452d37d3be..df47167154 100644
--- a/indra/integration_tests/llui_libtest/CMakeLists.txt
+++ b/indra/integration_tests/llui_libtest/CMakeLists.txt
@@ -10,6 +10,7 @@ include(00-Common)
include(LLCommon)
include(LLImage)
include(LLImageJ2COJ) # ugh, needed for images
+include(LLKDU)
include(LLMath)
include(LLMessage)
include(LLRender)
@@ -71,6 +72,11 @@ endif (DARWIN)
target_link_libraries(llui_libtest
llui
llmessage
+ ${LLRENDER_LIBRARIES}
+ ${LLIMAGE_LIBRARIES}
+ ${LLKDU_LIBRARIES}
+ ${KDU_LIBRARY}
+ ${LLIMAGEJ2COJ_LIBRARIES}
${OS_LIBRARIES}
${GOOGLE_PERFTOOLS_LIBRARIES}
)
@@ -85,14 +91,14 @@ if (WINDOWS)
# Copy over OpenJPEG.dll
# *NOTE: On Windows with VS2005, only the first comment prints
set(OPENJPEG_RELEASE
- "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/release/openjpeg.dll")
+ "${ARCH_PREBUILT_DIRS_RELEASE}/openjpeg.dll")
add_custom_command( TARGET llui_libtest POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${OPENJPEG_RELEASE} ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Copying OpenJPEG DLLs to binary directory"
)
set(OPENJPEG_DEBUG
- "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/debug/openjpegd.dll")
+ "${ARCH_PREBUILT_DIRS_DEBUG}/openjpegd.dll")
add_custom_command( TARGET llui_libtest POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${OPENJPEG_DEBUG} ${CMAKE_CURRENT_BINARY_DIR}
diff --git a/indra/integration_tests/llui_libtest/llui_libtest.cpp b/indra/integration_tests/llui_libtest/llui_libtest.cpp
index 1f15b73182..217e26c3ca 100644
--- a/indra/integration_tests/llui_libtest/llui_libtest.cpp
+++ b/indra/integration_tests/llui_libtest/llui_libtest.cpp
@@ -33,6 +33,7 @@
// linden library includes
#include "llcontrol.h" // LLControlGroup
#include "lldir.h"
+#include "lldiriterator.h"
#include "llerrorcontrol.h"
#include "llfloater.h"
#include "llfontfreetype.h"
@@ -174,7 +175,9 @@ void export_test_floaters()
std::string delim = gDirUtilp->getDirDelimiter();
std::string xui_dir = get_xui_dir() + "en" + delim;
std::string filename;
- while (gDirUtilp->getNextFileInDir(xui_dir, "floater_test_*.xml", filename, false))
+
+ LLDirIterator iter(xui_dir, "floater_test_*.xml");
+ while (iter.next(filename))
{
if (filename.find("_new.xml") != std::string::npos)
{
diff --git a/indra/lib/python/indra/util/llperformance.py b/indra/lib/python/indra/util/llperformance.py
index 7c52730b5e..57dd64de3f 100755
--- a/indra/lib/python/indra/util/llperformance.py
+++ b/indra/lib/python/indra/util/llperformance.py
@@ -1,4 +1,28 @@
-#!/usr/bin/python
+#!/usr/bin/env python
+"""\
+@file llperformance.py
+
+$LicenseInfo:firstyear=2010&license=viewerlgpl$
+Second Life Viewer Source Code
+Copyright (C) 2010-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$
+"""
# ------------------------------------------------
# Sim metrics utility functions.
diff --git a/indra/lib/python/indra/util/llversion.py b/indra/lib/python/indra/util/llversion.py
index 2718a85f41..ba6f567b60 100644
--- a/indra/lib/python/indra/util/llversion.py
+++ b/indra/lib/python/indra/util/llversion.py
@@ -1,7 +1,9 @@
-"""@file llversion.py
-@brief Utility for parsing llcommon/llversion${server}.h
- for the version string and channel string
- Utility that parses hg or svn info for branch and revision
+#!/usr/bin/env python
+"""\
+@file llversion.py
+@brief Parses llcommon/llversionserver.h and llcommon/llversionviewer.h
+ for the version string and channel string.
+ Parses hg info for branch and revision.
$LicenseInfo:firstyear=2006&license=mit$
@@ -27,7 +29,7 @@ THE SOFTWARE.
$/LicenseInfo$
"""
-import re, sys, os, commands
+import re, sys, os, subprocess
# Methods for gathering version information from
# llversionviewer.h and llversionserver.h
@@ -73,29 +75,13 @@ def get_viewer_channel():
def get_server_channel():
return get_channel('server')
-# Methods for gathering subversion information
-def get_svn_status_matching(regular_expression):
- # Get the subversion info from the working source tree
- status, output = commands.getstatusoutput('svn info %s' % get_src_root())
- m = regular_expression.search(output)
- if not m:
- print >> sys.stderr, "Failed to parse svn info output, result follows:"
- print >> sys.stderr, output
- raise Exception, "No matching svn status in "+src_root
- return m.group(1)
-
-def get_svn_branch():
- branch_re = re.compile('URL: (\S+)')
- return get_svn_status_matching(branch_re)
-
-def get_svn_revision():
- last_rev_re = re.compile('Last Changed Rev: (\d+)')
- return get_svn_status_matching(last_rev_re)
-
+# Methods for gathering hg information
def get_hg_repo():
- status, output = commands.getstatusoutput('hg showconfig paths.default')
+ child = subprocess.Popen(["hg","showconfig","paths.default"], stdout=subprocess.PIPE)
+ output, error = child.communicate()
+ status = child.returncode
if status:
- print >> sys.stderr, output
+ print >> sys.stderr, error
sys.exit(1)
if not output:
print >> sys.stderr, 'ERROR: cannot find repo we cloned from'
@@ -103,24 +89,19 @@ def get_hg_repo():
return output
def get_hg_changeset():
- # The right thing to do:
- # status, output = commands.getstatusoutput('hg id -i')
- # if status:
- # print >> sys.stderr, output
- # sys.exit(1)
-
- # The temporary hack:
- status, output = commands.getstatusoutput('hg parents --template "{rev}"')
+ # The right thing to do would be to use the *global* revision id:
+ # "hg id -i"
+ # For the moment though, we use the parent revision:
+ child = subprocess.Popen(["hg","parents","--template","{rev}"], stdout=subprocess.PIPE)
+ output, error = child.communicate()
+ status = child.returncode
if status:
- print >> sys.stderr, output
+ print >> sys.stderr, error
sys.exit(1)
lines = output.splitlines()
if len(lines) > 1:
print >> sys.stderr, 'ERROR: working directory has %d parents' % len(lines)
return lines[0]
-def using_svn():
- return os.path.isdir(os.path.join(get_src_root(), '.svn'))
-
def using_hg():
return os.path.isdir(os.path.join(get_src_root(), '.hg'))
diff --git a/indra/lib/python/indra/util/simperf_proc_interface.py b/indra/lib/python/indra/util/simperf_proc_interface.py
index da6304a274..de061f68cc 100755
--- a/indra/lib/python/indra/util/simperf_proc_interface.py
+++ b/indra/lib/python/indra/util/simperf_proc_interface.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
"""\
@file simperf_proc_interface.py
@brief Utility to extract log messages from *.<pid>.llsd files containing performance statistics.
diff --git a/indra/lib/python/indra/util/test_win32_manifest.py b/indra/lib/python/indra/util/test_win32_manifest.py
index 786521c068..0532cb0065 100644
--- a/indra/lib/python/indra/util/test_win32_manifest.py
+++ b/indra/lib/python/indra/util/test_win32_manifest.py
@@ -1,28 +1,29 @@
#!/usr/bin/env python
-# @file test_win32_manifest.py
-# @brief Test an assembly binding version and uniqueness in a windows dll or exe.
-#
-# $LicenseInfo:firstyear=2009&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$
-
+"""\
+@file test_win32_manifest.py
+@brief Test an assembly binding version and uniqueness in a windows dll or exe.
+
+$LicenseInfo:firstyear=2009&license=viewerlgpl$
+Second Life Viewer Source Code
+Copyright (C) 2009-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$
+"""
import sys, os
import tempfile
from xml.dom.minidom import parse
@@ -52,20 +53,22 @@ def get_HKLM_registry_value(key_str, value_str):
def find_vc_dir():
supported_versions = (r'8.0', r'9.0')
+ supported_products = (r'VisualStudio', r'VCExpress')
value_str = (r'ProductDir')
- for version in supported_versions:
- key_str = (r'SOFTWARE\Microsoft\VisualStudio\%s\Setup\VC' %
- version)
- try:
- return get_HKLM_registry_value(key_str, value_str)
- except WindowsError, err:
- x64_key_str = (r'SOFTWARE\Wow6432Node\Microsoft\VisualStudio\%s\Setup\VS' %
- version)
+ for product in supported_products:
+ for version in supported_versions:
+ key_str = (r'SOFTWARE\Microsoft\%s\%s\Setup\VC' %
+ (product, version))
try:
- return get_HKLM_registry_value(x64_key_str, value_str)
- except:
- print >> sys.stderr, "Didn't find MS VC version %s " % version
+ return get_HKLM_registry_value(key_str, value_str)
+ except WindowsError, err:
+ x64_key_str = (r'SOFTWARE\Wow6432Node\Microsoft\VisualStudio\%s\Setup\VS' %
+ version)
+ try:
+ return get_HKLM_registry_value(x64_key_str, value_str)
+ except:
+ print >> sys.stderr, "Didn't find MS %s version %s " % (product,version)
raise
diff --git a/indra/linux_updater/linux_updater.cpp b/indra/linux_updater/linux_updater.cpp
index be4d810860..eed00ac06e 100644
--- a/indra/linux_updater/linux_updater.cpp
+++ b/indra/linux_updater/linux_updater.cpp
@@ -33,6 +33,7 @@
#include "llerrorcontrol.h"
#include "llfile.h"
#include "lldir.h"
+#include "lldiriterator.h"
#include "llxmlnode.h"
#include "lltrans.h"
@@ -49,11 +50,14 @@ const guint ROTATE_IMAGE_TIMEOUT = 8000;
typedef struct _updater_app_state {
std::string app_name;
std::string url;
+ std::string file;
std::string image_dir;
std::string dest_dir;
std::string strings_dirs;
std::string strings_file;
+ LLDirIterator *image_dir_iter;
+
GtkWidget *window;
GtkWidget *progress_bar;
GtkWidget *image;
@@ -87,9 +91,16 @@ bool translate_init(std::string comma_delim_path_list,
std::vector<std::string> paths;
LLStringUtil::getTokens(comma_delim_path_list, paths, ","); // split over ','
+ for(std::vector<std::string>::iterator it = paths.begin(), end_it = paths.end();
+ it != end_it;
+ ++it)
+ {
+ (*it) = gDirUtilp->findSkinnedFilename(*it, base_xml_name);
+ }
+
// suck the translation xml files into memory
LLXMLNodePtr root;
- bool success = LLXMLNode::getLayeredXMLNode(base_xml_name, root, paths);
+ bool success = LLXMLNode::getLayeredXMLNode(root, paths);
if (!success)
{
// couldn't load string table XML
@@ -107,13 +118,13 @@ bool translate_init(std::string comma_delim_path_list,
void updater_app_ui_init(void);
void updater_app_quit(UpdaterAppState *app_state);
void parse_args_and_init(int argc, char **argv, UpdaterAppState *app_state);
-std::string next_image_filename(std::string& image_path);
+std::string next_image_filename(std::string& image_path, LLDirIterator& iter);
void display_error(GtkWidget *parent, std::string title, std::string message);
BOOL install_package(std::string package_file, std::string destination);
BOOL spawn_viewer(UpdaterAppState *app_state);
extern "C" {
- void on_window_closed(GtkWidget *sender, gpointer state);
+ void on_window_closed(GtkWidget *sender, GdkEvent *event, gpointer state);
gpointer worker_thread_cb(gpointer *data);
int download_progress_cb(gpointer data, double t, double d, double utotal, double ulnow);
gboolean rotate_image_cb(gpointer data);
@@ -173,7 +184,7 @@ void updater_app_ui_init(UpdaterAppState *app_state)
// load the first image
app_state->image = gtk_image_new_from_file
- (next_image_filename(app_state->image_dir).c_str());
+ (next_image_filename(app_state->image_dir, *app_state->image_dir_iter).c_str());
gtk_widget_set_size_request(app_state->image, 340, 310);
gtk_container_add(GTK_CONTAINER(frame), app_state->image);
@@ -204,7 +215,7 @@ gboolean rotate_image_cb(gpointer data)
llassert(data != NULL);
app_state = (UpdaterAppState *) data;
- filename = next_image_filename(app_state->image_dir);
+ filename = next_image_filename(app_state->image_dir, *app_state->image_dir_iter);
gdk_threads_enter();
gtk_image_set_from_file(GTK_IMAGE(app_state->image), filename.c_str());
@@ -213,14 +224,14 @@ gboolean rotate_image_cb(gpointer data)
return TRUE;
}
-std::string next_image_filename(std::string& image_path)
+std::string next_image_filename(std::string& image_path, LLDirIterator& iter)
{
std::string image_filename;
- gDirUtilp->getNextFileInDir(image_path, "/*.jpg", image_filename, true);
+ iter.next(image_filename);
return image_path + "/" + image_filename;
}
-void on_window_closed(GtkWidget *sender, gpointer data)
+void on_window_closed(GtkWidget *sender, GdkEvent* event, gpointer data)
{
UpdaterAppState *app_state;
@@ -266,85 +277,95 @@ gpointer worker_thread_cb(gpointer data)
CURLcode result;
FILE *package_file;
GError *error = NULL;
- char *tmp_filename = NULL;
int fd;
//g_return_val_if_fail (data != NULL, NULL);
app_state = (UpdaterAppState *) data;
try {
- // create temporary file to store the package.
- fd = g_file_open_tmp
- ("secondlife-update-XXXXXX", &tmp_filename, &error);
- if (error != NULL)
- {
- llerrs << "Unable to create temporary file: "
- << error->message
- << llendl;
- g_error_free(error);
- throw 0;
- }
-
- package_file = fdopen(fd, "wb");
- if (package_file == NULL)
+ if(!app_state->url.empty())
{
- llerrs << "Failed to create temporary file: "
- << tmp_filename
- << llendl;
+ char* tmp_local_filename = NULL;
+ // create temporary file to store the package.
+ fd = g_file_open_tmp
+ ("secondlife-update-XXXXXX", &tmp_local_filename, &error);
+ if (error != NULL)
+ {
+ llerrs << "Unable to create temporary file: "
+ << error->message
+ << llendl;
- gdk_threads_enter();
- display_error(app_state->window,
- LLTrans::getString("UpdaterFailDownloadTitle"),
- LLTrans::getString("UpdaterFailUpdateDescriptive"));
- gdk_threads_leave();
- throw 0;
- }
+ g_error_free(error);
+ throw 0;
+ }
+
+ if(tmp_local_filename != NULL)
+ {
+ app_state->file = tmp_local_filename;
+ g_free(tmp_local_filename);
+ }
- // initialize curl and start downloading the package
- llinfos << "Downloading package: " << app_state->url << llendl;
+ package_file = fdopen(fd, "wb");
+ if (package_file == NULL)
+ {
+ llerrs << "Failed to create temporary file: "
+ << app_state->file.c_str()
+ << llendl;
+
+ gdk_threads_enter();
+ display_error(app_state->window,
+ LLTrans::getString("UpdaterFailDownloadTitle"),
+ LLTrans::getString("UpdaterFailUpdateDescriptive"));
+ gdk_threads_leave();
+ throw 0;
+ }
- curl = curl_easy_init();
- if (curl == NULL)
- {
- llerrs << "Failed to initialize libcurl" << llendl;
+ // initialize curl and start downloading the package
+ llinfos << "Downloading package: " << app_state->url << llendl;
- gdk_threads_enter();
- display_error(app_state->window,
- LLTrans::getString("UpdaterFailDownloadTitle"),
- LLTrans::getString("UpdaterFailUpdateDescriptive"));
- gdk_threads_leave();
- throw 0;
- }
+ curl = curl_easy_init();
+ if (curl == NULL)
+ {
+ llerrs << "Failed to initialize libcurl" << llendl;
+
+ gdk_threads_enter();
+ display_error(app_state->window,
+ LLTrans::getString("UpdaterFailDownloadTitle"),
+ LLTrans::getString("UpdaterFailUpdateDescriptive"));
+ gdk_threads_leave();
+ throw 0;
+ }
- curl_easy_setopt(curl, CURLOPT_URL, app_state->url.c_str());
- curl_easy_setopt(curl, CURLOPT_NOSIGNAL, TRUE);
- curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, TRUE);
- curl_easy_setopt(curl, CURLOPT_WRITEDATA, package_file);
- curl_easy_setopt(curl, CURLOPT_NOPROGRESS, FALSE);
- curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION,
- &download_progress_cb);
- curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, app_state);
+ curl_easy_setopt(curl, CURLOPT_URL, app_state->url.c_str());
+ curl_easy_setopt(curl, CURLOPT_NOSIGNAL, TRUE);
+ curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, TRUE);
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, package_file);
+ curl_easy_setopt(curl, CURLOPT_NOPROGRESS, FALSE);
+ curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION,
+ &download_progress_cb);
+ curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, app_state);
- result = curl_easy_perform(curl);
- fclose(package_file);
- curl_easy_cleanup(curl);
+ result = curl_easy_perform(curl);
+ fclose(package_file);
+ curl_easy_cleanup(curl);
- if (result)
- {
- llerrs << "Failed to download update: "
- << app_state->url
- << llendl;
+ if (result)
+ {
+ llerrs << "Failed to download update: "
+ << app_state->url
+ << llendl;
- gdk_threads_enter();
- display_error(app_state->window,
- LLTrans::getString("UpdaterFailDownloadTitle"),
- LLTrans::getString("UpdaterFailUpdateDescriptive"));
- gdk_threads_leave();
+ gdk_threads_enter();
+ display_error(app_state->window,
+ LLTrans::getString("UpdaterFailDownloadTitle"),
+ LLTrans::getString("UpdaterFailUpdateDescriptive"));
+ gdk_threads_leave();
- throw 0;
+ throw 0;
+ }
}
-
+
// now pulse the progres bar back and forth while the package is
// being unpacked
gdk_threads_enter();
@@ -357,7 +378,7 @@ gpointer worker_thread_cb(gpointer data)
// *TODO: if the destination is not writable, terminate this
// thread and show file chooser?
- if (!install_package(tmp_filename, app_state->dest_dir))
+ if (!install_package(app_state->file.c_str(), app_state->dest_dir))
{
llwarns << "Failed to install package to destination: "
<< app_state->dest_dir
@@ -392,15 +413,6 @@ gpointer worker_thread_cb(gpointer data)
app_state->failure = TRUE;
}
- // FIXME: delete package file also if delete-event is raised on window
- if (tmp_filename != NULL)
- {
- if (gDirUtilp->fileExists(tmp_filename))
- {
- LLFile::remove(tmp_filename);
- }
- }
-
gdk_threads_enter();
updater_app_quit(app_state);
gdk_threads_leave();
@@ -712,7 +724,7 @@ BOOL spawn_viewer(UpdaterAppState *app_state)
void show_usage_and_exit()
{
- std::cout << "Usage: linux-updater --url URL --name NAME --dest PATH --stringsdir PATH1,PATH2 --stringsfile FILE"
+ std::cout << "Usage: linux-updater <--url URL | --file FILE> --name NAME --dest PATH --stringsdir PATH1,PATH2 --stringsfile FILE"
<< "[--image-dir PATH]"
<< std::endl;
exit(1);
@@ -728,6 +740,10 @@ void parse_args_and_init(int argc, char **argv, UpdaterAppState *app_state)
{
app_state->url = argv[i];
}
+ else if ((!strcmp(argv[i], "--file")) && (++i < argc))
+ {
+ app_state->file = argv[i];
+ }
else if ((!strcmp(argv[i], "--name")) && (++i < argc))
{
app_state->app_name = argv[i];
@@ -735,6 +751,7 @@ void parse_args_and_init(int argc, char **argv, UpdaterAppState *app_state)
else if ((!strcmp(argv[i], "--image-dir")) && (++i < argc))
{
app_state->image_dir = argv[i];
+ app_state->image_dir_iter = new LLDirIterator(argv[i], "/*.jpg");
}
else if ((!strcmp(argv[i], "--dest")) && (++i < argc))
{
@@ -756,7 +773,7 @@ void parse_args_and_init(int argc, char **argv, UpdaterAppState *app_state)
}
if (app_state->app_name.empty()
- || app_state->url.empty()
+ || (app_state->url.empty() && app_state->file.empty())
|| app_state->dest_dir.empty())
{
show_usage_and_exit();
@@ -771,10 +788,10 @@ void parse_args_and_init(int argc, char **argv, UpdaterAppState *app_state)
int main(int argc, char **argv)
{
- UpdaterAppState app_state;
+ UpdaterAppState* app_state = new UpdaterAppState;
GThread *worker_thread;
- parse_args_and_init(argc, argv, &app_state);
+ parse_args_and_init(argc, argv, app_state);
// Initialize logger, and rename old log file
gDirUtilp->initAppDirs("SecondLife");
@@ -797,17 +814,30 @@ int main(int argc, char **argv)
gtk_init(&argc, &argv);
// create UI
- updater_app_ui_init(&app_state);
+ updater_app_ui_init(app_state);
//llinfos << "SAMPLE TRANSLATION IS: " << LLTrans::getString("LoginInProgress") << llendl;
// create download thread
worker_thread = g_thread_create
- (GThreadFunc(worker_thread_cb), &app_state, FALSE, NULL);
+ (GThreadFunc(worker_thread_cb), app_state, FALSE, NULL);
gdk_threads_enter();
gtk_main();
gdk_threads_leave();
- return (app_state.failure == FALSE) ? 0 : 1;
+ // Delete the file only if created from url download.
+ if(!app_state->url.empty() && !app_state->file.empty())
+ {
+ if (gDirUtilp->fileExists(app_state->file))
+ {
+ LLFile::remove(app_state->file);
+ }
+ }
+
+ bool success = !app_state->failure;
+ delete app_state->image_dir_iter;
+ delete app_state;
+ return success ? 0 : 1;
}
+
diff --git a/indra/llaudio/CMakeLists.txt b/indra/llaudio/CMakeLists.txt
index e869b9717c..632e5d46e3 100644
--- a/indra/llaudio/CMakeLists.txt
+++ b/indra/llaudio/CMakeLists.txt
@@ -14,7 +14,6 @@ include(LLVFS)
include_directories(
${LLAUDIO_INCLUDE_DIRS}
- ${FMOD_INCLUDE_DIR}
${LLCOMMON_INCLUDE_DIRS}
${LLMATH_INCLUDE_DIRS}
${LLMESSAGE_INCLUDE_DIRS}
@@ -25,6 +24,7 @@ include_directories(
${VORBIS_INCLUDE_DIRS}
${OPENAL_LIB_INCLUDE_DIRS}
${FREEAULT_LIB_INCLUDE_DIRS}
+ ${FMOD_INCLUDE_DIR}
)
set(llaudio_SOURCE_FILES
@@ -45,6 +45,10 @@ set(llaudio_HEADER_FILES
)
if (FMOD)
+ include_directories(
+ ${FMOD_INCLUDE_DIR}
+ )
+
list(APPEND llaudio_SOURCE_FILES
llaudioengine_fmod.cpp
lllistener_fmod.cpp
diff --git a/indra/llaudio/llaudiodecodemgr.cpp b/indra/llaudio/llaudiodecodemgr.cpp
index 01dfd03c18..f0b44f97d2 100644
--- a/indra/llaudio/llaudiodecodemgr.cpp
+++ b/indra/llaudio/llaudiodecodemgr.cpp
@@ -680,4 +680,10 @@ BOOL LLAudioDecodeMgr::addDecodeRequest(const LLUUID &uuid)
return FALSE;
}
-
+#if LL_DARWIN || LL_LINUX
+// HACK: to fool the compiler into not emitting unused warnings.
+namespace {
+ const ov_callbacks callback_array[4] = {OV_CALLBACKS_DEFAULT, OV_CALLBACKS_NOCLOSE, OV_CALLBACKS_STREAMONLY,
+ OV_CALLBACKS_STREAMONLY_NOCLOSE};
+}
+#endif
diff --git a/indra/llaudio/llaudioengine.cpp b/indra/llaudio/llaudioengine.cpp
index 1cc03bddb8..5e540ad8c5 100644
--- a/indra/llaudio/llaudioengine.cpp
+++ b/indra/llaudio/llaudioengine.cpp
@@ -97,7 +97,11 @@ void LLAudioEngine::setDefaults()
}
mMasterGain = 1.f;
- mInternalGain = 0.f;
+ // Setting mInternalGain to an out of range value fixes the issue reported in STORM-830.
+ // There is an edge case in setMasterGain during startup which prevents setInternalGain from
+ // being called if the master volume setting and mInternalGain both equal 0, so using -1 forces
+ // the if statement in setMasterGain to execute when the viewer starts up.
+ mInternalGain = -1.f;
mNextWindUpdate = 0.f;
mStreamingAudioImpl = NULL;
@@ -1557,6 +1561,10 @@ bool LLAudioSource::hasPendingPreloads() const
LLAudioData *adp = iter->second;
// note: a bad UUID will forever be !hasDecodedData()
// but also !hasValidData(), hence the check for hasValidData()
+ if (!adp)
+ {
+ continue;
+ }
if (!adp->hasDecodedData() && adp->hasValidData())
{
// This source is still waiting for a preload
diff --git a/indra/llaudio/llaudioengine_openal.cpp b/indra/llaudio/llaudioengine_openal.cpp
index e352045291..34a057dcc0 100644
--- a/indra/llaudio/llaudioengine_openal.cpp
+++ b/indra/llaudio/llaudioengine_openal.cpp
@@ -32,6 +32,8 @@
#include "lllistener_openal.h"
+const float LLAudioEngine_OpenAL::WIND_BUFFER_SIZE_SEC = 0.05f;
+
LLAudioEngine_OpenAL::LLAudioEngine_OpenAL()
:
mWindGen(NULL),
diff --git a/indra/llaudio/llaudioengine_openal.h b/indra/llaudio/llaudioengine_openal.h
index 258febb1a8..6639d9dfe6 100644
--- a/indra/llaudio/llaudioengine_openal.h
+++ b/indra/llaudio/llaudioengine_openal.h
@@ -67,7 +67,7 @@ class LLAudioEngine_OpenAL : public LLAudioEngine
int mNumEmptyWindALBuffers;
static const int MAX_NUM_WIND_BUFFERS = 80;
- static const float WIND_BUFFER_SIZE_SEC = 0.05f; // 1/20th sec
+ static const float WIND_BUFFER_SIZE_SEC; // 1/20th sec
};
class LLAudioChannelOpenAL : public LLAudioChannel
diff --git a/indra/llaudio/llvorbisencode.cpp b/indra/llaudio/llvorbisencode.cpp
index 9f479189d7..0e0c80a456 100644
--- a/indra/llaudio/llvorbisencode.cpp
+++ b/indra/llaudio/llvorbisencode.cpp
@@ -120,6 +120,13 @@ S32 check_for_invalid_wav_formats(const std::string& in_fname, std::string& erro
+ ((U32) wav_header[5] << 8)
+ wav_header[4];
+ if (chunk_length > physical_file_size - file_pos - 4)
+ {
+ infile.close();
+ error_msg = "SoundFileInvalidChunkSize";
+ return(LLVORBISENC_CHUNK_SIZE_ERR);
+ }
+
// llinfos << "chunk found: '" << wav_header[0] << wav_header[1] << wav_header[2] << wav_header[3] << "'" << llendl;
if (!(strncmp((char *)&(wav_header[0]),"fmt ",4)))
diff --git a/indra/llaudio/llvorbisencode.h b/indra/llaudio/llvorbisencode.h
index d33aacf1ea..6b22a2cb59 100644
--- a/indra/llaudio/llvorbisencode.h
+++ b/indra/llaudio/llvorbisencode.h
@@ -38,6 +38,7 @@ const S32 LLVORBISENC_MULTICHANNEL_ERR = 7; // can't do stereo
const S32 LLVORBISENC_UNSUPPORTED_SAMPLE_RATE = 8; // unsupported sample rate
const S32 LLVORBISENC_UNSUPPORTED_WORD_SIZE = 9; // unsupported word size
const S32 LLVORBISENC_CLIP_TOO_LONG = 10; // source file is too long
+const S32 LLVORBISENC_CHUNK_SIZE_ERR = 11; // chunk size is wrong
const F32 LLVORBIS_CLIP_MAX_TIME = 10.0f;
const U8 LLVORBIS_CLIP_MAX_CHANNELS = 2;
diff --git a/indra/llcharacter/CMakeLists.txt b/indra/llcharacter/CMakeLists.txt
index 14841b5d3d..6eb154458d 100644
--- a/indra/llcharacter/CMakeLists.txt
+++ b/indra/llcharacter/CMakeLists.txt
@@ -77,12 +77,13 @@ list(APPEND llcharacter_SOURCE_FILES ${llcharacter_HEADER_FILES})
add_library (llcharacter ${llcharacter_SOURCE_FILES})
-if(LL_TESTS)
- # Add tests
- include(LLAddBuildTest)
- # UNIT TESTS
- SET(llcharacter_TEST_SOURCE_FILES
- lljoint.cpp
- )
- LL_ADD_PROJECT_UNIT_TESTS(llcharacter "${llcharacter_TEST_SOURCE_FILES}")
-endif(LL_TESTS)
+# Add tests
+if (LL_TESTS)
+ include(LLAddBuildTest)
+ # UNIT TESTS
+ SET(llcharacter_TEST_SOURCE_FILES
+ lljoint.cpp
+ )
+ LL_ADD_PROJECT_UNIT_TESTS(llcharacter "${llcharacter_TEST_SOURCE_FILES}")
+endif (LL_TESTS)
+
diff --git a/indra/llcharacter/llanimationstates.cpp b/indra/llcharacter/llanimationstates.cpp
index a30113a478..155226cf17 100644
--- a/indra/llcharacter/llanimationstates.cpp
+++ b/indra/llcharacter/llanimationstates.cpp
@@ -33,145 +33,145 @@
#include "llanimationstates.h"
#include "llstring.h"
-const LLUUID ANIM_AGENT_AFRAID = LLUUID("6b61c8e8-4747-0d75-12d7-e49ff207a4ca");
-const LLUUID ANIM_AGENT_AIM_BAZOOKA_R = LLUUID("b5b4a67d-0aee-30d2-72cd-77b333e932ef");
-const LLUUID ANIM_AGENT_AIM_BOW_L = LLUUID("46bb4359-de38-4ed8-6a22-f1f52fe8f506");
-const LLUUID ANIM_AGENT_AIM_HANDGUN_R = LLUUID("3147d815-6338-b932-f011-16b56d9ac18b");
-const LLUUID ANIM_AGENT_AIM_RIFLE_R = LLUUID("ea633413-8006-180a-c3ba-96dd1d756720");
-const LLUUID ANIM_AGENT_ANGRY = LLUUID("5747a48e-073e-c331-f6f3-7c2149613d3e");
-const LLUUID ANIM_AGENT_AWAY = LLUUID("fd037134-85d4-f241-72c6-4f42164fedee");
-const LLUUID ANIM_AGENT_BACKFLIP = LLUUID("c4ca6188-9127-4f31-0158-23c4e2f93304");
-const LLUUID ANIM_AGENT_BELLY_LAUGH = LLUUID("18b3a4b5-b463-bd48-e4b6-71eaac76c515");
-const LLUUID ANIM_AGENT_BLOW_KISS = LLUUID("db84829b-462c-ee83-1e27-9bbee66bd624");
-const LLUUID ANIM_AGENT_BORED = LLUUID("b906c4ba-703b-1940-32a3-0c7f7d791510");
-const LLUUID ANIM_AGENT_BOW = LLUUID("82e99230-c906-1403-4d9c-3889dd98daba");
-const LLUUID ANIM_AGENT_BRUSH = LLUUID("349a3801-54f9-bf2c-3bd0-1ac89772af01");
-const LLUUID ANIM_AGENT_BUSY = LLUUID("efcf670c-2d18-8128-973a-034ebc806b67");
-const LLUUID ANIM_AGENT_CLAP = LLUUID("9b0c1c4e-8ac7-7969-1494-28c874c4f668");
-const LLUUID ANIM_AGENT_COURTBOW = LLUUID("9ba1c942-08be-e43a-fb29-16ad440efc50");
-const LLUUID ANIM_AGENT_CROUCH = LLUUID("201f3fdf-cb1f-dbec-201f-7333e328ae7c");
-const LLUUID ANIM_AGENT_CROUCHWALK = LLUUID("47f5f6fb-22e5-ae44-f871-73aaaf4a6022");
-const LLUUID ANIM_AGENT_CRY = LLUUID("92624d3e-1068-f1aa-a5ec-8244585193ed");
-const LLUUID ANIM_AGENT_CUSTOMIZE = LLUUID("038fcec9-5ebd-8a8e-0e2e-6e71a0a1ac53");
-const LLUUID ANIM_AGENT_CUSTOMIZE_DONE = LLUUID("6883a61a-b27b-5914-a61e-dda118a9ee2c");
-const LLUUID ANIM_AGENT_DANCE1 = LLUUID("b68a3d7c-de9e-fc87-eec8-543d787e5b0d");
-const LLUUID ANIM_AGENT_DANCE2 = LLUUID("928cae18-e31d-76fd-9cc9-2f55160ff818");
-const LLUUID ANIM_AGENT_DANCE3 = LLUUID("30047778-10ea-1af7-6881-4db7a3a5a114");
-const LLUUID ANIM_AGENT_DANCE4 = LLUUID("951469f4-c7b2-c818-9dee-ad7eea8c30b7");
-const LLUUID ANIM_AGENT_DANCE5 = LLUUID("4bd69a1d-1114-a0b4-625f-84e0a5237155");
-const LLUUID ANIM_AGENT_DANCE6 = LLUUID("cd28b69b-9c95-bb78-3f94-8d605ff1bb12");
-const LLUUID ANIM_AGENT_DANCE7 = LLUUID("a54d8ee2-28bb-80a9-7f0c-7afbbe24a5d6");
-const LLUUID ANIM_AGENT_DANCE8 = LLUUID("b0dc417c-1f11-af36-2e80-7e7489fa7cdc");
-const LLUUID ANIM_AGENT_DEAD = LLUUID("57abaae6-1d17-7b1b-5f98-6d11a6411276");
-const LLUUID ANIM_AGENT_DRINK = LLUUID("0f86e355-dd31-a61c-fdb0-3a96b9aad05f");
-const LLUUID ANIM_AGENT_EMBARRASSED = LLUUID("514af488-9051-044a-b3fc-d4dbf76377c6");
-const LLUUID ANIM_AGENT_EXPRESS_AFRAID = LLUUID("aa2df84d-cf8f-7218-527b-424a52de766e");
-const LLUUID ANIM_AGENT_EXPRESS_ANGER = LLUUID("1a03b575-9634-b62a-5767-3a679e81f4de");
-const LLUUID ANIM_AGENT_EXPRESS_BORED = LLUUID("214aa6c1-ba6a-4578-f27c-ce7688f61d0d");
-const LLUUID ANIM_AGENT_EXPRESS_CRY = LLUUID("d535471b-85bf-3b4d-a542-93bea4f59d33");
-const LLUUID ANIM_AGENT_EXPRESS_DISDAIN = LLUUID("d4416ff1-09d3-300f-4183-1b68a19b9fc1");
-const LLUUID ANIM_AGENT_EXPRESS_EMBARRASSED = LLUUID("0b8c8211-d78c-33e8-fa28-c51a9594e424");
-const LLUUID ANIM_AGENT_EXPRESS_FROWN = LLUUID("fee3df48-fa3d-1015-1e26-a205810e3001");
-const LLUUID ANIM_AGENT_EXPRESS_KISS = LLUUID("1e8d90cc-a84e-e135-884c-7c82c8b03a14");
-const LLUUID ANIM_AGENT_EXPRESS_LAUGH = LLUUID("62570842-0950-96f8-341c-809e65110823");
-const LLUUID ANIM_AGENT_EXPRESS_OPEN_MOUTH = LLUUID("d63bc1f9-fc81-9625-a0c6-007176d82eb7");
-const LLUUID ANIM_AGENT_EXPRESS_REPULSED = LLUUID("f76cda94-41d4-a229-2872-e0296e58afe1");
-const LLUUID ANIM_AGENT_EXPRESS_SAD = LLUUID("eb6ebfb2-a4b3-a19c-d388-4dd5c03823f7");
-const LLUUID ANIM_AGENT_EXPRESS_SHRUG = LLUUID("a351b1bc-cc94-aac2-7bea-a7e6ebad15ef");
-const LLUUID ANIM_AGENT_EXPRESS_SMILE = LLUUID("b7c7c833-e3d3-c4e3-9fc0-131237446312");
-const LLUUID ANIM_AGENT_EXPRESS_SURPRISE = LLUUID("728646d9-cc79-08b2-32d6-937f0a835c24");
-const LLUUID ANIM_AGENT_EXPRESS_TONGUE_OUT = LLUUID("835965c6-7f2f-bda2-5deb-2478737f91bf");
-const LLUUID ANIM_AGENT_EXPRESS_TOOTHSMILE = LLUUID("b92ec1a5-e7ce-a76b-2b05-bcdb9311417e");
-const LLUUID ANIM_AGENT_EXPRESS_WINK = LLUUID("da020525-4d94-59d6-23d7-81fdebf33148");
-const LLUUID ANIM_AGENT_EXPRESS_WORRY = LLUUID("9c05e5c7-6f07-6ca4-ed5a-b230390c3950");
-const LLUUID ANIM_AGENT_FALLDOWN = LLUUID("666307d9-a860-572d-6fd4-c3ab8865c094");
-const LLUUID ANIM_AGENT_FEMALE_RUN_NEW = LLUUID("85995026-eade-5d78-d364-94a64512cb66");
-const LLUUID ANIM_AGENT_FEMALE_WALK = LLUUID("f5fc7433-043d-e819-8298-f519a119b688");
-const LLUUID ANIM_AGENT_FEMALE_WALK_NEW = LLUUID("d60c41d2-7c24-7074-d3fa-6101cea22a51");
-const LLUUID ANIM_AGENT_FINGER_WAG = LLUUID("c1bc7f36-3ba0-d844-f93c-93be945d644f");
-const LLUUID ANIM_AGENT_FIST_PUMP = LLUUID("7db00ccd-f380-f3ee-439d-61968ec69c8a");
-const LLUUID ANIM_AGENT_FLY = LLUUID("aec4610c-757f-bc4e-c092-c6e9caf18daf");
-const LLUUID ANIM_AGENT_FLYSLOW = LLUUID("2b5a38b2-5e00-3a97-a495-4c826bc443e6");
-const LLUUID ANIM_AGENT_HELLO = LLUUID("9b29cd61-c45b-5689-ded2-91756b8d76a9");
-const LLUUID ANIM_AGENT_HOLD_BAZOOKA_R = LLUUID("ef62d355-c815-4816-2474-b1acc21094a6");
-const LLUUID ANIM_AGENT_HOLD_BOW_L = LLUUID("8b102617-bcba-037b-86c1-b76219f90c88");
-const LLUUID ANIM_AGENT_HOLD_HANDGUN_R = LLUUID("efdc1727-8b8a-c800-4077-975fc27ee2f2");
-const LLUUID ANIM_AGENT_HOLD_RIFLE_R = LLUUID("3d94bad0-c55b-7dcc-8763-033c59405d33");
-const LLUUID ANIM_AGENT_HOLD_THROW_R = LLUUID("7570c7b5-1f22-56dd-56ef-a9168241bbb6");
-const LLUUID ANIM_AGENT_HOVER = LLUUID("4ae8016b-31b9-03bb-c401-b1ea941db41d");
-const LLUUID ANIM_AGENT_HOVER_DOWN = LLUUID("20f063ea-8306-2562-0b07-5c853b37b31e");
-const LLUUID ANIM_AGENT_HOVER_UP = LLUUID("62c5de58-cb33-5743-3d07-9e4cd4352864");
-const LLUUID ANIM_AGENT_IMPATIENT = LLUUID("5ea3991f-c293-392e-6860-91dfa01278a3");
-const LLUUID ANIM_AGENT_JUMP = LLUUID("2305bd75-1ca9-b03b-1faa-b176b8a8c49e");
-const LLUUID ANIM_AGENT_JUMP_FOR_JOY = LLUUID("709ea28e-1573-c023-8bf8-520c8bc637fa");
-const LLUUID ANIM_AGENT_KISS_MY_BUTT = LLUUID("19999406-3a3a-d58c-a2ac-d72e555dcf51");
-const LLUUID ANIM_AGENT_LAND = LLUUID("7a17b059-12b2-41b1-570a-186368b6aa6f");
-const LLUUID ANIM_AGENT_LAUGH_SHORT = LLUUID("ca5b3f14-3194-7a2b-c894-aa699b718d1f");
-const LLUUID ANIM_AGENT_MEDIUM_LAND = LLUUID("f4f00d6e-b9fe-9292-f4cb-0ae06ea58d57");
-const LLUUID ANIM_AGENT_MOTORCYCLE_SIT = LLUUID("08464f78-3a8e-2944-cba5-0c94aff3af29");
-const LLUUID ANIM_AGENT_MUSCLE_BEACH = LLUUID("315c3a41-a5f3-0ba4-27da-f893f769e69b");
-const LLUUID ANIM_AGENT_NO = LLUUID("5a977ed9-7f72-44e9-4c4c-6e913df8ae74");
-const LLUUID ANIM_AGENT_NO_UNHAPPY = LLUUID("d83fa0e5-97ed-7eb2-e798-7bd006215cb4");
-const LLUUID ANIM_AGENT_NYAH_NYAH = LLUUID("f061723d-0a18-754f-66ee-29a44795a32f");
-const LLUUID ANIM_AGENT_ONETWO_PUNCH = LLUUID("eefc79be-daae-a239-8c04-890f5d23654a");
-const LLUUID ANIM_AGENT_PEACE = LLUUID("b312b10e-65ab-a0a4-8b3c-1326ea8e3ed9");
-const LLUUID ANIM_AGENT_POINT_ME = LLUUID("17c024cc-eef2-f6a0-3527-9869876d7752");
-const LLUUID ANIM_AGENT_POINT_YOU = LLUUID("ec952cca-61ef-aa3b-2789-4d1344f016de");
-const LLUUID ANIM_AGENT_PRE_JUMP = LLUUID("7a4e87fe-de39-6fcb-6223-024b00893244");
-const LLUUID ANIM_AGENT_PUNCH_LEFT = LLUUID("f3300ad9-3462-1d07-2044-0fef80062da0");
-const LLUUID ANIM_AGENT_PUNCH_RIGHT = LLUUID("c8e42d32-7310-6906-c903-cab5d4a34656");
-const LLUUID ANIM_AGENT_REPULSED = LLUUID("36f81a92-f076-5893-dc4b-7c3795e487cf");
-const LLUUID ANIM_AGENT_ROUNDHOUSE_KICK = LLUUID("49aea43b-5ac3-8a44-b595-96100af0beda");
-const LLUUID ANIM_AGENT_RPS_COUNTDOWN = LLUUID("35db4f7e-28c2-6679-cea9-3ee108f7fc7f");
-const LLUUID ANIM_AGENT_RPS_PAPER = LLUUID("0836b67f-7f7b-f37b-c00a-460dc1521f5a");
-const LLUUID ANIM_AGENT_RPS_ROCK = LLUUID("42dd95d5-0bc6-6392-f650-777304946c0f");
-const LLUUID ANIM_AGENT_RPS_SCISSORS = LLUUID("16803a9f-5140-e042-4d7b-d28ba247c325");
-const LLUUID ANIM_AGENT_RUN = LLUUID("05ddbff8-aaa9-92a1-2b74-8fe77a29b445");
-const LLUUID ANIM_AGENT_RUN_NEW = LLUUID("1ab1b236-cd08-21e6-0cbc-0d923fc6eca2");
-const LLUUID ANIM_AGENT_SAD = LLUUID("0eb702e2-cc5a-9a88-56a5-661a55c0676a");
-const LLUUID ANIM_AGENT_SALUTE = LLUUID("cd7668a6-7011-d7e2-ead8-fc69eff1a104");
-const LLUUID ANIM_AGENT_SHOOT_BOW_L = LLUUID("e04d450d-fdb5-0432-fd68-818aaf5935f8");
-const LLUUID ANIM_AGENT_SHOUT = LLUUID("6bd01860-4ebd-127a-bb3d-d1427e8e0c42");
-const LLUUID ANIM_AGENT_SHRUG = LLUUID("70ea714f-3a97-d742-1b01-590a8fcd1db5");
-const LLUUID ANIM_AGENT_SIT = LLUUID("1a5fe8ac-a804-8a5d-7cbd-56bd83184568");
-const LLUUID ANIM_AGENT_SIT_FEMALE = LLUUID("b1709c8d-ecd3-54a1-4f28-d55ac0840782");
-const LLUUID ANIM_AGENT_SIT_GENERIC = LLUUID("245f3c54-f1c0-bf2e-811f-46d8eeb386e7");
-const LLUUID ANIM_AGENT_SIT_GROUND = LLUUID("1c7600d6-661f-b87b-efe2-d7421eb93c86");
-const LLUUID ANIM_AGENT_SIT_GROUND_CONSTRAINED = LLUUID("1a2bd58e-87ff-0df8-0b4c-53e047b0bb6e");
-const LLUUID ANIM_AGENT_SIT_TO_STAND = LLUUID("a8dee56f-2eae-9e7a-05a2-6fb92b97e21e");
-const LLUUID ANIM_AGENT_SLEEP = LLUUID("f2bed5f9-9d44-39af-b0cd-257b2a17fe40");
-const LLUUID ANIM_AGENT_SMOKE_IDLE = LLUUID("d2f2ee58-8ad1-06c9-d8d3-3827ba31567a");
-const LLUUID ANIM_AGENT_SMOKE_INHALE = LLUUID("6802d553-49da-0778-9f85-1599a2266526");
-const LLUUID ANIM_AGENT_SMOKE_THROW_DOWN = LLUUID("0a9fb970-8b44-9114-d3a9-bf69cfe804d6");
-const LLUUID ANIM_AGENT_SNAPSHOT = LLUUID("eae8905b-271a-99e2-4c0e-31106afd100c");
-const LLUUID ANIM_AGENT_STAND = LLUUID("2408fe9e-df1d-1d7d-f4ff-1384fa7b350f");
-const LLUUID ANIM_AGENT_STANDUP = LLUUID("3da1d753-028a-5446-24f3-9c9b856d9422");
-const LLUUID ANIM_AGENT_STAND_1 = LLUUID("15468e00-3400-bb66-cecc-646d7c14458e");
-const LLUUID ANIM_AGENT_STAND_2 = LLUUID("370f3a20-6ca6-9971-848c-9a01bc42ae3c");
-const LLUUID ANIM_AGENT_STAND_3 = LLUUID("42b46214-4b44-79ae-deb8-0df61424ff4b");
-const LLUUID ANIM_AGENT_STAND_4 = LLUUID("f22fed8b-a5ed-2c93-64d5-bdd8b93c889f");
-const LLUUID ANIM_AGENT_STRETCH = LLUUID("80700431-74ec-a008-14f8-77575e73693f");
-const LLUUID ANIM_AGENT_STRIDE = LLUUID("1cb562b0-ba21-2202-efb3-30f82cdf9595");
-const LLUUID ANIM_AGENT_SURF = LLUUID("41426836-7437-7e89-025d-0aa4d10f1d69");
-const LLUUID ANIM_AGENT_SURPRISE = LLUUID("313b9881-4302-73c0-c7d0-0e7a36b6c224");
-const LLUUID ANIM_AGENT_SWORD_STRIKE = LLUUID("85428680-6bf9-3e64-b489-6f81087c24bd");
-const LLUUID ANIM_AGENT_TALK = LLUUID("5c682a95-6da4-a463-0bf6-0f5b7be129d1");
-const LLUUID ANIM_AGENT_TANTRUM = LLUUID("11000694-3f41-adc2-606b-eee1d66f3724");
-const LLUUID ANIM_AGENT_THROW_R = LLUUID("aa134404-7dac-7aca-2cba-435f9db875ca");
-const LLUUID ANIM_AGENT_TRYON_SHIRT = LLUUID("83ff59fe-2346-f236-9009-4e3608af64c1");
-const LLUUID ANIM_AGENT_TURNLEFT = LLUUID("56e0ba0d-4a9f-7f27-6117-32f2ebbf6135");
-const LLUUID ANIM_AGENT_TURNRIGHT = LLUUID("2d6daa51-3192-6794-8e2e-a15f8338ec30");
-const LLUUID ANIM_AGENT_TYPE = LLUUID("c541c47f-e0c0-058b-ad1a-d6ae3a4584d9");
-const LLUUID ANIM_AGENT_WALK = LLUUID("6ed24bd8-91aa-4b12-ccc7-c97c857ab4e0");
-const LLUUID ANIM_AGENT_WALK_NEW = LLUUID("33339176-7ddc-9397-94a4-bf3403cbc8f5");
-const LLUUID ANIM_AGENT_WHISPER = LLUUID("7693f268-06c7-ea71-fa21-2b30d6533f8f");
-const LLUUID ANIM_AGENT_WHISTLE = LLUUID("b1ed7982-c68e-a982-7561-52a88a5298c0");
-const LLUUID ANIM_AGENT_WINK = LLUUID("869ecdad-a44b-671e-3266-56aef2e3ac2e");
-const LLUUID ANIM_AGENT_WINK_HOLLYWOOD = LLUUID("c0c4030f-c02b-49de-24ba-2331f43fe41c");
-const LLUUID ANIM_AGENT_WORRY = LLUUID("9f496bd2-589a-709f-16cc-69bf7df1d36c");
-const LLUUID ANIM_AGENT_YES = LLUUID("15dd911d-be82-2856-26db-27659b142875");
-const LLUUID ANIM_AGENT_YES_HAPPY = LLUUID("b8c8b2a3-9008-1771-3bfc-90924955ab2d");
-const LLUUID ANIM_AGENT_YOGA_FLOAT = LLUUID("42ecd00b-9947-a97c-400a-bbc9174c7aeb");
+LLUUID const ANIM_AGENT_AFRAID ("6b61c8e8-4747-0d75-12d7-e49ff207a4ca");
+LLUUID const ANIM_AGENT_AIM_BAZOOKA_R ("b5b4a67d-0aee-30d2-72cd-77b333e932ef");
+LLUUID const ANIM_AGENT_AIM_BOW_L ("46bb4359-de38-4ed8-6a22-f1f52fe8f506");
+LLUUID const ANIM_AGENT_AIM_HANDGUN_R ("3147d815-6338-b932-f011-16b56d9ac18b");
+LLUUID const ANIM_AGENT_AIM_RIFLE_R ("ea633413-8006-180a-c3ba-96dd1d756720");
+LLUUID const ANIM_AGENT_ANGRY ("5747a48e-073e-c331-f6f3-7c2149613d3e");
+LLUUID const ANIM_AGENT_AWAY ("fd037134-85d4-f241-72c6-4f42164fedee");
+LLUUID const ANIM_AGENT_BACKFLIP ("c4ca6188-9127-4f31-0158-23c4e2f93304");
+LLUUID const ANIM_AGENT_BELLY_LAUGH ("18b3a4b5-b463-bd48-e4b6-71eaac76c515");
+LLUUID const ANIM_AGENT_BLOW_KISS ("db84829b-462c-ee83-1e27-9bbee66bd624");
+LLUUID const ANIM_AGENT_BORED ("b906c4ba-703b-1940-32a3-0c7f7d791510");
+LLUUID const ANIM_AGENT_BOW ("82e99230-c906-1403-4d9c-3889dd98daba");
+LLUUID const ANIM_AGENT_BRUSH ("349a3801-54f9-bf2c-3bd0-1ac89772af01");
+LLUUID const ANIM_AGENT_BUSY ("efcf670c-2d18-8128-973a-034ebc806b67");
+LLUUID const ANIM_AGENT_CLAP ("9b0c1c4e-8ac7-7969-1494-28c874c4f668");
+LLUUID const ANIM_AGENT_COURTBOW ("9ba1c942-08be-e43a-fb29-16ad440efc50");
+LLUUID const ANIM_AGENT_CROUCH ("201f3fdf-cb1f-dbec-201f-7333e328ae7c");
+LLUUID const ANIM_AGENT_CROUCHWALK ("47f5f6fb-22e5-ae44-f871-73aaaf4a6022");
+LLUUID const ANIM_AGENT_CRY ("92624d3e-1068-f1aa-a5ec-8244585193ed");
+LLUUID const ANIM_AGENT_CUSTOMIZE ("038fcec9-5ebd-8a8e-0e2e-6e71a0a1ac53");
+LLUUID const ANIM_AGENT_CUSTOMIZE_DONE ("6883a61a-b27b-5914-a61e-dda118a9ee2c");
+LLUUID const ANIM_AGENT_DANCE1 ("b68a3d7c-de9e-fc87-eec8-543d787e5b0d");
+LLUUID const ANIM_AGENT_DANCE2 ("928cae18-e31d-76fd-9cc9-2f55160ff818");
+LLUUID const ANIM_AGENT_DANCE3 ("30047778-10ea-1af7-6881-4db7a3a5a114");
+LLUUID const ANIM_AGENT_DANCE4 ("951469f4-c7b2-c818-9dee-ad7eea8c30b7");
+LLUUID const ANIM_AGENT_DANCE5 ("4bd69a1d-1114-a0b4-625f-84e0a5237155");
+LLUUID const ANIM_AGENT_DANCE6 ("cd28b69b-9c95-bb78-3f94-8d605ff1bb12");
+LLUUID const ANIM_AGENT_DANCE7 ("a54d8ee2-28bb-80a9-7f0c-7afbbe24a5d6");
+LLUUID const ANIM_AGENT_DANCE8 ("b0dc417c-1f11-af36-2e80-7e7489fa7cdc");
+LLUUID const ANIM_AGENT_DEAD ("57abaae6-1d17-7b1b-5f98-6d11a6411276");
+LLUUID const ANIM_AGENT_DRINK ("0f86e355-dd31-a61c-fdb0-3a96b9aad05f");
+LLUUID const ANIM_AGENT_EMBARRASSED ("514af488-9051-044a-b3fc-d4dbf76377c6");
+LLUUID const ANIM_AGENT_EXPRESS_AFRAID ("aa2df84d-cf8f-7218-527b-424a52de766e");
+LLUUID const ANIM_AGENT_EXPRESS_ANGER ("1a03b575-9634-b62a-5767-3a679e81f4de");
+LLUUID const ANIM_AGENT_EXPRESS_BORED ("214aa6c1-ba6a-4578-f27c-ce7688f61d0d");
+LLUUID const ANIM_AGENT_EXPRESS_CRY ("d535471b-85bf-3b4d-a542-93bea4f59d33");
+LLUUID const ANIM_AGENT_EXPRESS_DISDAIN ("d4416ff1-09d3-300f-4183-1b68a19b9fc1");
+LLUUID const ANIM_AGENT_EXPRESS_EMBARRASSED ("0b8c8211-d78c-33e8-fa28-c51a9594e424");
+LLUUID const ANIM_AGENT_EXPRESS_FROWN ("fee3df48-fa3d-1015-1e26-a205810e3001");
+LLUUID const ANIM_AGENT_EXPRESS_KISS ("1e8d90cc-a84e-e135-884c-7c82c8b03a14");
+LLUUID const ANIM_AGENT_EXPRESS_LAUGH ("62570842-0950-96f8-341c-809e65110823");
+LLUUID const ANIM_AGENT_EXPRESS_OPEN_MOUTH ("d63bc1f9-fc81-9625-a0c6-007176d82eb7");
+LLUUID const ANIM_AGENT_EXPRESS_REPULSED ("f76cda94-41d4-a229-2872-e0296e58afe1");
+LLUUID const ANIM_AGENT_EXPRESS_SAD ("eb6ebfb2-a4b3-a19c-d388-4dd5c03823f7");
+LLUUID const ANIM_AGENT_EXPRESS_SHRUG ("a351b1bc-cc94-aac2-7bea-a7e6ebad15ef");
+LLUUID const ANIM_AGENT_EXPRESS_SMILE ("b7c7c833-e3d3-c4e3-9fc0-131237446312");
+LLUUID const ANIM_AGENT_EXPRESS_SURPRISE ("728646d9-cc79-08b2-32d6-937f0a835c24");
+LLUUID const ANIM_AGENT_EXPRESS_TONGUE_OUT ("835965c6-7f2f-bda2-5deb-2478737f91bf");
+LLUUID const ANIM_AGENT_EXPRESS_TOOTHSMILE ("b92ec1a5-e7ce-a76b-2b05-bcdb9311417e");
+LLUUID const ANIM_AGENT_EXPRESS_WINK ("da020525-4d94-59d6-23d7-81fdebf33148");
+LLUUID const ANIM_AGENT_EXPRESS_WORRY ("9c05e5c7-6f07-6ca4-ed5a-b230390c3950");
+LLUUID const ANIM_AGENT_FALLDOWN ("666307d9-a860-572d-6fd4-c3ab8865c094");
+LLUUID const ANIM_AGENT_FEMALE_RUN_NEW ("85995026-eade-5d78-d364-94a64512cb66");
+LLUUID const ANIM_AGENT_FEMALE_WALK ("f5fc7433-043d-e819-8298-f519a119b688");
+LLUUID const ANIM_AGENT_FEMALE_WALK_NEW ("d60c41d2-7c24-7074-d3fa-6101cea22a51");
+LLUUID const ANIM_AGENT_FINGER_WAG ("c1bc7f36-3ba0-d844-f93c-93be945d644f");
+LLUUID const ANIM_AGENT_FIST_PUMP ("7db00ccd-f380-f3ee-439d-61968ec69c8a");
+LLUUID const ANIM_AGENT_FLY ("aec4610c-757f-bc4e-c092-c6e9caf18daf");
+LLUUID const ANIM_AGENT_FLYSLOW ("2b5a38b2-5e00-3a97-a495-4c826bc443e6");
+LLUUID const ANIM_AGENT_HELLO ("9b29cd61-c45b-5689-ded2-91756b8d76a9");
+LLUUID const ANIM_AGENT_HOLD_BAZOOKA_R ("ef62d355-c815-4816-2474-b1acc21094a6");
+LLUUID const ANIM_AGENT_HOLD_BOW_L ("8b102617-bcba-037b-86c1-b76219f90c88");
+LLUUID const ANIM_AGENT_HOLD_HANDGUN_R ("efdc1727-8b8a-c800-4077-975fc27ee2f2");
+LLUUID const ANIM_AGENT_HOLD_RIFLE_R ("3d94bad0-c55b-7dcc-8763-033c59405d33");
+LLUUID const ANIM_AGENT_HOLD_THROW_R ("7570c7b5-1f22-56dd-56ef-a9168241bbb6");
+LLUUID const ANIM_AGENT_HOVER ("4ae8016b-31b9-03bb-c401-b1ea941db41d");
+LLUUID const ANIM_AGENT_HOVER_DOWN ("20f063ea-8306-2562-0b07-5c853b37b31e");
+LLUUID const ANIM_AGENT_HOVER_UP ("62c5de58-cb33-5743-3d07-9e4cd4352864");
+LLUUID const ANIM_AGENT_IMPATIENT ("5ea3991f-c293-392e-6860-91dfa01278a3");
+LLUUID const ANIM_AGENT_JUMP ("2305bd75-1ca9-b03b-1faa-b176b8a8c49e");
+LLUUID const ANIM_AGENT_JUMP_FOR_JOY ("709ea28e-1573-c023-8bf8-520c8bc637fa");
+LLUUID const ANIM_AGENT_KISS_MY_BUTT ("19999406-3a3a-d58c-a2ac-d72e555dcf51");
+LLUUID const ANIM_AGENT_LAND ("7a17b059-12b2-41b1-570a-186368b6aa6f");
+LLUUID const ANIM_AGENT_LAUGH_SHORT ("ca5b3f14-3194-7a2b-c894-aa699b718d1f");
+LLUUID const ANIM_AGENT_MEDIUM_LAND ("f4f00d6e-b9fe-9292-f4cb-0ae06ea58d57");
+LLUUID const ANIM_AGENT_MOTORCYCLE_SIT ("08464f78-3a8e-2944-cba5-0c94aff3af29");
+LLUUID const ANIM_AGENT_MUSCLE_BEACH ("315c3a41-a5f3-0ba4-27da-f893f769e69b");
+LLUUID const ANIM_AGENT_NO ("5a977ed9-7f72-44e9-4c4c-6e913df8ae74");
+LLUUID const ANIM_AGENT_NO_UNHAPPY ("d83fa0e5-97ed-7eb2-e798-7bd006215cb4");
+LLUUID const ANIM_AGENT_NYAH_NYAH ("f061723d-0a18-754f-66ee-29a44795a32f");
+LLUUID const ANIM_AGENT_ONETWO_PUNCH ("eefc79be-daae-a239-8c04-890f5d23654a");
+LLUUID const ANIM_AGENT_PEACE ("b312b10e-65ab-a0a4-8b3c-1326ea8e3ed9");
+LLUUID const ANIM_AGENT_POINT_ME ("17c024cc-eef2-f6a0-3527-9869876d7752");
+LLUUID const ANIM_AGENT_POINT_YOU ("ec952cca-61ef-aa3b-2789-4d1344f016de");
+LLUUID const ANIM_AGENT_PRE_JUMP ("7a4e87fe-de39-6fcb-6223-024b00893244");
+LLUUID const ANIM_AGENT_PUNCH_LEFT ("f3300ad9-3462-1d07-2044-0fef80062da0");
+LLUUID const ANIM_AGENT_PUNCH_RIGHT ("c8e42d32-7310-6906-c903-cab5d4a34656");
+LLUUID const ANIM_AGENT_REPULSED ("36f81a92-f076-5893-dc4b-7c3795e487cf");
+LLUUID const ANIM_AGENT_ROUNDHOUSE_KICK ("49aea43b-5ac3-8a44-b595-96100af0beda");
+LLUUID const ANIM_AGENT_RPS_COUNTDOWN ("35db4f7e-28c2-6679-cea9-3ee108f7fc7f");
+LLUUID const ANIM_AGENT_RPS_PAPER ("0836b67f-7f7b-f37b-c00a-460dc1521f5a");
+LLUUID const ANIM_AGENT_RPS_ROCK ("42dd95d5-0bc6-6392-f650-777304946c0f");
+LLUUID const ANIM_AGENT_RPS_SCISSORS ("16803a9f-5140-e042-4d7b-d28ba247c325");
+LLUUID const ANIM_AGENT_RUN ("05ddbff8-aaa9-92a1-2b74-8fe77a29b445");
+LLUUID const ANIM_AGENT_RUN_NEW ("1ab1b236-cd08-21e6-0cbc-0d923fc6eca2");
+LLUUID const ANIM_AGENT_SAD ("0eb702e2-cc5a-9a88-56a5-661a55c0676a");
+LLUUID const ANIM_AGENT_SALUTE ("cd7668a6-7011-d7e2-ead8-fc69eff1a104");
+LLUUID const ANIM_AGENT_SHOOT_BOW_L ("e04d450d-fdb5-0432-fd68-818aaf5935f8");
+LLUUID const ANIM_AGENT_SHOUT ("6bd01860-4ebd-127a-bb3d-d1427e8e0c42");
+LLUUID const ANIM_AGENT_SHRUG ("70ea714f-3a97-d742-1b01-590a8fcd1db5");
+LLUUID const ANIM_AGENT_SIT ("1a5fe8ac-a804-8a5d-7cbd-56bd83184568");
+LLUUID const ANIM_AGENT_SIT_FEMALE ("b1709c8d-ecd3-54a1-4f28-d55ac0840782");
+LLUUID const ANIM_AGENT_SIT_GENERIC ("245f3c54-f1c0-bf2e-811f-46d8eeb386e7");
+LLUUID const ANIM_AGENT_SIT_GROUND ("1c7600d6-661f-b87b-efe2-d7421eb93c86");
+LLUUID const ANIM_AGENT_SIT_GROUND_CONSTRAINED("1a2bd58e-87ff-0df8-0b4c-53e047b0bb6e");
+LLUUID const ANIM_AGENT_SIT_TO_STAND ("a8dee56f-2eae-9e7a-05a2-6fb92b97e21e");
+LLUUID const ANIM_AGENT_SLEEP ("f2bed5f9-9d44-39af-b0cd-257b2a17fe40");
+LLUUID const ANIM_AGENT_SMOKE_IDLE ("d2f2ee58-8ad1-06c9-d8d3-3827ba31567a");
+LLUUID const ANIM_AGENT_SMOKE_INHALE ("6802d553-49da-0778-9f85-1599a2266526");
+LLUUID const ANIM_AGENT_SMOKE_THROW_DOWN ("0a9fb970-8b44-9114-d3a9-bf69cfe804d6");
+LLUUID const ANIM_AGENT_SNAPSHOT ("eae8905b-271a-99e2-4c0e-31106afd100c");
+LLUUID const ANIM_AGENT_STAND ("2408fe9e-df1d-1d7d-f4ff-1384fa7b350f");
+LLUUID const ANIM_AGENT_STANDUP ("3da1d753-028a-5446-24f3-9c9b856d9422");
+LLUUID const ANIM_AGENT_STAND_1 ("15468e00-3400-bb66-cecc-646d7c14458e");
+LLUUID const ANIM_AGENT_STAND_2 ("370f3a20-6ca6-9971-848c-9a01bc42ae3c");
+LLUUID const ANIM_AGENT_STAND_3 ("42b46214-4b44-79ae-deb8-0df61424ff4b");
+LLUUID const ANIM_AGENT_STAND_4 ("f22fed8b-a5ed-2c93-64d5-bdd8b93c889f");
+LLUUID const ANIM_AGENT_STRETCH ("80700431-74ec-a008-14f8-77575e73693f");
+LLUUID const ANIM_AGENT_STRIDE ("1cb562b0-ba21-2202-efb3-30f82cdf9595");
+LLUUID const ANIM_AGENT_SURF ("41426836-7437-7e89-025d-0aa4d10f1d69");
+LLUUID const ANIM_AGENT_SURPRISE ("313b9881-4302-73c0-c7d0-0e7a36b6c224");
+LLUUID const ANIM_AGENT_SWORD_STRIKE ("85428680-6bf9-3e64-b489-6f81087c24bd");
+LLUUID const ANIM_AGENT_TALK ("5c682a95-6da4-a463-0bf6-0f5b7be129d1");
+LLUUID const ANIM_AGENT_TANTRUM ("11000694-3f41-adc2-606b-eee1d66f3724");
+LLUUID const ANIM_AGENT_THROW_R ("aa134404-7dac-7aca-2cba-435f9db875ca");
+LLUUID const ANIM_AGENT_TRYON_SHIRT ("83ff59fe-2346-f236-9009-4e3608af64c1");
+LLUUID const ANIM_AGENT_TURNLEFT ("56e0ba0d-4a9f-7f27-6117-32f2ebbf6135");
+LLUUID const ANIM_AGENT_TURNRIGHT ("2d6daa51-3192-6794-8e2e-a15f8338ec30");
+LLUUID const ANIM_AGENT_TYPE ("c541c47f-e0c0-058b-ad1a-d6ae3a4584d9");
+LLUUID const ANIM_AGENT_WALK ("6ed24bd8-91aa-4b12-ccc7-c97c857ab4e0");
+LLUUID const ANIM_AGENT_WALK_NEW ("33339176-7ddc-9397-94a4-bf3403cbc8f5");
+LLUUID const ANIM_AGENT_WHISPER ("7693f268-06c7-ea71-fa21-2b30d6533f8f");
+LLUUID const ANIM_AGENT_WHISTLE ("b1ed7982-c68e-a982-7561-52a88a5298c0");
+LLUUID const ANIM_AGENT_WINK ("869ecdad-a44b-671e-3266-56aef2e3ac2e");
+LLUUID const ANIM_AGENT_WINK_HOLLYWOOD ("c0c4030f-c02b-49de-24ba-2331f43fe41c");
+LLUUID const ANIM_AGENT_WORRY ("9f496bd2-589a-709f-16cc-69bf7df1d36c");
+LLUUID const ANIM_AGENT_YES ("15dd911d-be82-2856-26db-27659b142875");
+LLUUID const ANIM_AGENT_YES_HAPPY ("b8c8b2a3-9008-1771-3bfc-90924955ab2d");
+LLUUID const ANIM_AGENT_YOGA_FLOAT ("42ecd00b-9947-a97c-400a-bbc9174c7aeb");
LLUUID AGENT_WALK_ANIMS[] = {ANIM_AGENT_WALK, ANIM_AGENT_RUN, ANIM_AGENT_CROUCHWALK, ANIM_AGENT_TURNLEFT, ANIM_AGENT_TURNRIGHT};
S32 NUM_AGENT_WALK_ANIMS = LL_ARRAY_SIZE(AGENT_WALK_ANIMS);
diff --git a/indra/llcharacter/llbvhloader.cpp b/indra/llcharacter/llbvhloader.cpp
index 532a2c1b0d..f3cf950afa 100644
--- a/indra/llcharacter/llbvhloader.cpp
+++ b/indra/llcharacter/llbvhloader.cpp
@@ -42,10 +42,10 @@ using namespace std;
#define INCHES_TO_METERS 0.02540005f
-const F32 POSITION_KEYFRAME_THRESHOLD = 0.03f;
+const F32 POSITION_KEYFRAME_THRESHOLD_SQUARED = 0.03f * 0.03f;
const F32 ROTATION_KEYFRAME_THRESHOLD = 0.01f;
-const F32 POSITION_MOTION_THRESHOLD = 0.001f;
+const F32 POSITION_MOTION_THRESHOLD_SQUARED = 0.001f * 0.001f;
const F32 ROTATION_MOTION_THRESHOLD = 0.001f;
char gInFile[1024]; /* Flawfinder: ignore */
@@ -1196,7 +1196,7 @@ void LLBVHLoader::optimize()
if (ki_prev == ki_last_good_pos)
{
joint->mNumPosKeys++;
- if (dist_vec(LLVector3(ki_prev->mPos), first_frame_pos) > POSITION_MOTION_THRESHOLD)
+ if (dist_vec_squared(LLVector3(ki_prev->mPos), first_frame_pos) > POSITION_MOTION_THRESHOLD_SQUARED)
{
pos_changed = TRUE;
}
@@ -1209,12 +1209,12 @@ void LLBVHLoader::optimize()
LLVector3 current_pos(ki->mPos);
LLVector3 interp_pos = lerp(current_pos, last_good_pos, 1.f / (F32)numPosFramesConsidered);
- if (dist_vec(current_pos, first_frame_pos) > POSITION_MOTION_THRESHOLD)
+ if (dist_vec_squared(current_pos, first_frame_pos) > POSITION_MOTION_THRESHOLD_SQUARED)
{
pos_changed = TRUE;
}
- if (dist_vec(interp_pos, test_pos) < POSITION_KEYFRAME_THRESHOLD)
+ if (dist_vec_squared(interp_pos, test_pos) < POSITION_KEYFRAME_THRESHOLD_SQUARED)
{
ki_prev->mIgnorePos = TRUE;
numPosFramesConsidered++;
diff --git a/indra/llcharacter/lljoint.cpp b/indra/llcharacter/lljoint.cpp
index 5d750c6c96..19907933cb 100644
--- a/indra/llcharacter/lljoint.cpp
+++ b/indra/llcharacter/lljoint.cpp
@@ -50,6 +50,7 @@ LLJoint::LLJoint()
mUpdateXform = TRUE;
mJointNum = -1;
touch();
+ mResetAfterRestoreOldXform = false;
}
@@ -235,6 +236,42 @@ void LLJoint::setPosition( const LLVector3& pos )
//--------------------------------------------------------------------
+// setPosition()
+//--------------------------------------------------------------------
+void LLJoint::setDefaultFromCurrentXform( void )
+{
+ mDefaultXform = mXform;
+ touch(MATRIX_DIRTY | POSITION_DIRTY);
+
+}
+
+//--------------------------------------------------------------------
+// storeCurrentXform()
+//--------------------------------------------------------------------
+void LLJoint::storeCurrentXform( const LLVector3& pos )
+{
+ mOldXform = mXform;
+ mResetAfterRestoreOldXform = true;
+ setPosition( pos );
+}
+//--------------------------------------------------------------------
+// restoreOldXform()
+//--------------------------------------------------------------------
+void LLJoint::restoreOldXform( void )
+{
+ mResetAfterRestoreOldXform = false;
+ mXform = mOldXform;
+}
+//--------------------------------------------------------------------
+// restoreOldXform()
+//--------------------------------------------------------------------
+void LLJoint::restoreToDefaultXform( void )
+{
+ mXform = mDefaultXform;
+ setPosition( mXform.getPosition() );
+}
+
+//--------------------------------------------------------------------
// getWorldPosition()
//--------------------------------------------------------------------
LLVector3 LLJoint::getWorldPosition()
@@ -522,3 +559,4 @@ void LLJoint::clampRotation(LLQuaternion old_rot, LLQuaternion new_rot)
}
// End
+
diff --git a/indra/llcharacter/lljoint.h b/indra/llcharacter/lljoint.h
index 8c8e5930fb..dc3c58cf64 100644
--- a/indra/llcharacter/lljoint.h
+++ b/indra/llcharacter/lljoint.h
@@ -80,11 +80,16 @@ protected:
// explicit transformation members
LLXformMatrix mXform;
+ LLXformMatrix mOldXform;
+ LLXformMatrix mDefaultXform;
+ LLUUID mId;
public:
U32 mDirtyFlags;
BOOL mUpdateXform;
+ BOOL mResetAfterRestoreOldXform;
+
// describes the skin binding pose
LLVector3 mSkinOffset;
@@ -130,7 +135,9 @@ public:
// get/set local position
const LLVector3& getPosition();
void setPosition( const LLVector3& pos );
-
+
+ void setDefaultPosition( const LLVector3& pos );
+
// get/set world position
LLVector3 getWorldPosition();
LLVector3 getLastWorldPosition();
@@ -172,6 +179,21 @@ public:
S32 getJointNum() const { return mJointNum; }
void setJointNum(S32 joint_num) { mJointNum = joint_num; }
+
+ void restoreOldXform( void );
+ void restoreToDefaultXform( void );
+ void setDefaultFromCurrentXform( void );
+ void storeCurrentXform( const LLVector3& pos );
+
+ //Accessor for the joint id
+ LLUUID getId( void ) { return mId; }
+ //Setter for the joints id
+ void setId( const LLUUID& id ) { mId = id;}
+
+ //If the old transform flag has been set, then the reset logic in avatar needs to be aware(test) of it
+ const BOOL doesJointNeedToBeReset( void ) const { return mResetAfterRestoreOldXform; }
+ //Setter for joint reset flag
+ void setJointToBeReset( BOOL val ) { mResetAfterRestoreOldXform = val; }
};
#endif // LL_LLJOINT_H
diff --git a/indra/llcharacter/llkeyframemotion.cpp b/indra/llcharacter/llkeyframemotion.cpp
index 5b0867524e..9df033a4ca 100644
--- a/indra/llcharacter/llkeyframemotion.cpp
+++ b/indra/llcharacter/llkeyframemotion.cpp
@@ -1145,7 +1145,7 @@ void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8
constraint->mPositions[joint_num] = new_pos;
}
constraint->mFixupDistanceRMS *= 1.f / (constraint->mTotalLength * (F32)(shared_data->mChainLength - 1));
- constraint->mFixupDistanceRMS = fsqrtf(constraint->mFixupDistanceRMS);
+ constraint->mFixupDistanceRMS = (F32) sqrt(constraint->mFixupDistanceRMS);
//reset old joint rots
for (joint_num = 0; joint_num <= shared_data->mChainLength; joint_num++)
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 7bad780dd8..80df91a5c1 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -7,17 +7,16 @@ include(00-Common)
include(LLCommon)
include(Linking)
include(Boost)
-include(Pth)
include(LLSharedLibs)
include(GoogleBreakpad)
include(GooglePerfTools)
include(Copy3rdPartyLibs)
+include(ZLIB)
include_directories(
${EXPAT_INCLUDE_DIRS}
${LLCOMMON_INCLUDE_DIRS}
${ZLIB_INCLUDE_DIRS}
- ${PTH_INCLUDE_DIRS}
)
# add_executable(lltreeiterators lltreeiterators.cpp)
@@ -62,6 +61,7 @@ set(llcommon_SOURCE_FILES
llformat.cpp
llframetimer.cpp
llheartbeat.cpp
+ llinstancetracker.cpp
llliveappconfig.cpp
lllivefile.cpp
lllog.cpp
@@ -70,6 +70,7 @@ set(llcommon_SOURCE_FILES
llmemorystream.cpp
llmemtype.cpp
llmetrics.cpp
+ llmetricperformancetester.cpp
llmortician.cpp
lloptioninterface.cpp
llptrto.cpp
@@ -92,6 +93,7 @@ set(llcommon_SOURCE_FILES
llstringtable.cpp
llsys.cpp
llthread.cpp
+ llthreadsafequeue.cpp
lltimer.cpp
lluri.cpp
lluuid.cpp
@@ -186,6 +188,7 @@ set(llcommon_HEADER_FILES
llmemorystream.h
llmemtype.h
llmetrics.h
+ llmetricperformancetester.h
llmortician.h
llnametable.h
lloptioninterface.h
@@ -223,6 +226,7 @@ set(llcommon_HEADER_FILES
llstringtable.h
llsys.h
llthread.h
+ llthreadsafequeue.h
lltimer.h
lltreeiterators.h
lluri.h
@@ -262,6 +266,10 @@ if(LLCOMMON_LINK_SHARED)
add_definitions(-fPIC)
endif(WINDOWS)
endif(NOT WORD_SIZE EQUAL 32)
+ if(WINDOWS)
+ # always generate llcommon.pdb, even for "Release" builds
+ set_target_properties(llcommon PROPERTIES LINK_FLAGS "/DEBUG")
+ endif(WINDOWS)
ll_stage_sharedlib(llcommon)
else(LLCOMMON_LINK_SHARED)
add_library (llcommon ${llcommon_SOURCE_FILES})
@@ -277,10 +285,15 @@ target_link_libraries(
${WINDOWS_LIBRARIES}
${BOOST_PROGRAM_OPTIONS_LIBRARY}
${BOOST_REGEX_LIBRARY}
- ${PTH_LIBRARIES}
${GOOGLE_PERFTOOLS_LIBRARIES}
)
+if (DARWIN)
+ include(CMakeFindFrameworks)
+ find_library(CARBON_LIBRARY Carbon)
+ target_link_libraries(llcommon ${CARBON_LIBRARY})
+endif (DARWIN)
+
add_dependencies(llcommon stage_third_party_libs)
if (LL_TESTS)
@@ -309,6 +322,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/indra_constants.h b/indra/llcommon/indra_constants.h
index b0618bfe59..d0f287657e 100644
--- a/indra/llcommon/indra_constants.h
+++ b/indra/llcommon/indra_constants.h
@@ -245,9 +245,6 @@ const U8 SIM_ACCESS_ADULT = 42; // Seriously Adult Only
const U8 SIM_ACCESS_DOWN = 254;
const U8 SIM_ACCESS_MAX = SIM_ACCESS_ADULT;
-// group constants
-const S32 MAX_AGENT_GROUPS = 25;
-
// attachment constants
const S32 MAX_AGENT_ATTACHMENTS = 38;
const U8 ATTACHMENT_ADD = 0x80;
@@ -300,6 +297,14 @@ const U32 START_LOCATION_ID_COUNT = 6;
// group constants
const U32 GROUP_MIN_SIZE = 2;
+// gMaxAgentGroups is now sent by login.cgi, which
+// looks it up from globals.xml.
+//
+// For now we need an old default value however,
+// so the viewer can be deployed ahead of login.cgi.
+//
+const S32 DEFAULT_MAX_AGENT_GROUPS = 25;
+
// radius within which a chat message is fully audible
const F32 CHAT_WHISPER_RADIUS = 10.f;
const F32 CHAT_NORMAL_RADIUS = 20.f;
@@ -307,6 +312,14 @@ const F32 CHAT_SHOUT_RADIUS = 100.f;
const F32 CHAT_MAX_RADIUS = CHAT_SHOUT_RADIUS;
const F32 CHAT_MAX_RADIUS_BY_TWO = CHAT_MAX_RADIUS / 2.f;
+// squared editions of the above for distance checks
+const F32 CHAT_WHISPER_RADIUS_SQUARED = CHAT_WHISPER_RADIUS * CHAT_WHISPER_RADIUS;
+const F32 CHAT_NORMAL_RADIUS_SQUARED = CHAT_NORMAL_RADIUS * CHAT_NORMAL_RADIUS;
+const F32 CHAT_SHOUT_RADIUS_SQUARED = CHAT_SHOUT_RADIUS * CHAT_SHOUT_RADIUS;
+const F32 CHAT_MAX_RADIUS_SQUARED = CHAT_SHOUT_RADIUS_SQUARED;
+const F32 CHAT_MAX_RADIUS_BY_TWO_SQUARED = CHAT_MAX_RADIUS_BY_TWO * CHAT_MAX_RADIUS_BY_TWO;
+
+
// this times above gives barely audible radius
const F32 CHAT_BARELY_AUDIBLE_FACTOR = 2.0f;
diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp
index eebd5ed0a6..ed192a9975 100644
--- a/indra/llcommon/llapp.cpp
+++ b/indra/llcommon/llapp.cpp
@@ -24,6 +24,10 @@
* $/LicenseInfo$
*/
+#include "linden_common.h"
+
+#include "llapp.h"
+
#include <cstdlib>
#ifdef LL_DARWIN
@@ -32,9 +36,6 @@
#include <sys/sysctl.h>
#endif
-#include "linden_common.h"
-#include "llapp.h"
-
#include "llcommon.h"
#include "llapr.h"
#include "llerrorcontrol.h"
@@ -90,6 +91,10 @@ S32 LL_HEARTBEAT_SIGNAL = (SIGRTMAX >= 0) ? (SIGRTMAX-0) : SIGUSR2;
// the static application instance
LLApp* LLApp::sApplication = NULL;
+// Allows the generation of core files for post mortem under gdb
+// and disables crashlogger
+BOOL LLApp::sDisableCrashlogger = FALSE;
+
// Local flag for whether or not to do logging in signal handlers.
//static
BOOL LLApp::sLogInSignal = FALSE;
@@ -461,11 +466,30 @@ bool LLApp::isQuitting()
return (APP_STATUS_QUITTING == sStatus);
}
+// static
bool LLApp::isExiting()
{
return isQuitting() || isError();
}
+void LLApp::disableCrashlogger()
+{
+ // Disable Breakpad exception handler.
+ if (mExceptionHandler != 0)
+ {
+ delete mExceptionHandler;
+ mExceptionHandler = 0;
+ }
+
+ sDisableCrashlogger = TRUE;
+}
+
+// static
+bool LLApp::isCrashloggerDisabled()
+{
+ return (sDisableCrashlogger == TRUE);
+}
+
#if !LL_WINDOWS
// static
U32 LLApp::getSigChildCount()
@@ -799,6 +823,15 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *)
{
llwarns << "Signal handler - Flagging error status and waiting for shutdown" << llendl;
}
+
+ if (LLApp::isCrashloggerDisabled()) // Don't gracefully handle any signal, crash and core for a gdb post mortem
+ {
+ clear_signals();
+ llwarns << "Fatal signal received, not handling the crash here, passing back to operating system" << llendl;
+ raise(signum);
+ return;
+ }
+
// Flag status to ERROR, so thread_error does its work.
LLApp::setError();
// Block in the signal handler until somebody says that we're done.
diff --git a/indra/llcommon/llapp.h b/indra/llcommon/llapp.h
index ee1d696829..a536a06ea5 100644
--- a/indra/llcommon/llapp.h
+++ b/indra/llcommon/llapp.h
@@ -189,6 +189,11 @@ public:
//
virtual bool mainLoop() = 0; // Override for the application main loop. Needs to at least gracefully notice the QUITTING state and exit.
+ //
+ // Crash logging
+ //
+ void disableCrashlogger(); // Let the OS handle the crashes
+ static bool isCrashloggerDisabled(); // Get the here above set value
//
// Application status
@@ -280,6 +285,7 @@ protected:
static void setStatus(EAppStatus status); // Use this to change the application status.
static EAppStatus sStatus; // Reflects current application status
static BOOL sErrorThreadRunning; // Set while the error thread is running
+ static BOOL sDisableCrashlogger; // Let the OS handle crashes for us.
#if !LL_WINDOWS
static LLAtomicU32* sSigChildCount; // Number of SIGCHLDs received.
diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp
index 66ec5bad2c..d1c44c9403 100644
--- a/indra/llcommon/llapr.cpp
+++ b/indra/llcommon/llapr.cpp
@@ -28,6 +28,7 @@
#include "linden_common.h"
#include "llapr.h"
+#include "apr_dso.h"
apr_pool_t *gAPRPoolp = NULL; // Global APR memory pool
LLVolatileAPRPool *LLAPRFile::sAPRFilePoolp = NULL ; //global volatile APR memory pool.
@@ -279,14 +280,31 @@ bool ll_apr_warn_status(apr_status_t status)
{
if(APR_SUCCESS == status) return false;
char buf[MAX_STRING]; /* Flawfinder: ignore */
- apr_strerror(status, buf, MAX_STRING);
+ apr_strerror(status, buf, sizeof(buf));
LL_WARNS("APR") << "APR: " << buf << LL_ENDL;
return true;
}
+bool ll_apr_warn_status(apr_status_t status, apr_dso_handle_t *handle)
+{
+ bool result = ll_apr_warn_status(status);
+ // Despite observed truncation of actual Mac dylib load errors, increasing
+ // this buffer to more than MAX_STRING doesn't help: it appears that APR
+ // stores the output in a fixed 255-character internal buffer. (*sigh*)
+ char buf[MAX_STRING]; /* Flawfinder: ignore */
+ apr_dso_error(handle, buf, sizeof(buf));
+ LL_WARNS("APR") << "APR: " << buf << LL_ENDL;
+ return result;
+}
+
void ll_apr_assert_status(apr_status_t status)
{
- llassert(ll_apr_warn_status(status) == false);
+ llassert(! ll_apr_warn_status(status));
+}
+
+void ll_apr_assert_status(apr_status_t status, apr_dso_handle_t *handle)
+{
+ llassert(! ll_apr_warn_status(status, handle));
}
//---------------------------------------------------------------------
diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h
index 4930270af8..af33ce666f 100644
--- a/indra/llcommon/llapr.h
+++ b/indra/llcommon/llapr.h
@@ -53,6 +53,8 @@
extern LL_COMMON_API apr_thread_mutex_t* gLogMutexp;
extern apr_thread_mutex_t* gCallStacksLogMutexp;
+struct apr_dso_handle_t;
+
/**
* @brief initialize the common apr constructs -- apr itself, the
* global pool, and a mutex.
@@ -259,8 +261,11 @@ public:
* @return Returns <code>true</code> if status is an error condition.
*/
bool LL_COMMON_API ll_apr_warn_status(apr_status_t status);
+/// There's a whole other APR error-message function if you pass a DSO handle.
+bool LL_COMMON_API ll_apr_warn_status(apr_status_t status, apr_dso_handle_t* handle);
void LL_COMMON_API ll_apr_assert_status(apr_status_t status);
+void LL_COMMON_API ll_apr_assert_status(apr_status_t status, apr_dso_handle_t* handle);
extern "C" LL_COMMON_API apr_pool_t* gAPRPoolp; // Global APR memory pool
diff --git a/indra/llcommon/llassettype.cpp b/indra/llcommon/llassettype.cpp
index eb610f625a..145dddd543 100644
--- a/indra/llcommon/llassettype.cpp
+++ b/indra/llcommon/llassettype.cpp
@@ -93,8 +93,9 @@ LLAssetDictionary::LLAssetDictionary()
addEntry(LLAssetType::AT_LINK, new AssetEntry("LINK", "link", "sym link", false, false, true));
addEntry(LLAssetType::AT_LINK_FOLDER, new AssetEntry("FOLDER_LINK", "link_f", "sym folder link", false, false, true));
+ addEntry(LLAssetType::AT_MESH, new AssetEntry("MESH", "mesh", "mesh", false, false, false));
+ addEntry(LLAssetType::AT_NONE, new AssetEntry("NONE", "-1", NULL, FALSE, FALSE, FALSE));
- addEntry(LLAssetType::AT_NONE, new AssetEntry("NONE", "-1", NULL, false, false, false));
};
// static
diff --git a/indra/llcommon/llassettype.h b/indra/llcommon/llassettype.h
index c5ff2364cc..74ccd00324 100644
--- a/indra/llcommon/llassettype.h
+++ b/indra/llcommon/llassettype.h
@@ -108,8 +108,10 @@ public:
AT_LINK_FOLDER = 25,
// Inventory folder link
-
- AT_COUNT = 26,
+ AT_MESH = 49,
+ // Mesh data in our proprietary SLM format
+
+ AT_COUNT = 50,
// +*********************************************************+
// | TO ADD AN ELEMENT TO THIS ENUM: |
diff --git a/indra/llcommon/llavatarconstants.h b/indra/llcommon/llavatarconstants.h
index 596b0643ef..f47f447b45 100644
--- a/indra/llcommon/llavatarconstants.h
+++ b/indra/llcommon/llavatarconstants.h
@@ -46,10 +46,10 @@ const U32 AVATAR_TRANSACTED = 0x1 << 3; // whether avatar has actively used p
const U32 AVATAR_ONLINE = 0x1 << 4; // the online status of this avatar, if known.
const U32 AVATAR_AGEVERIFIED = 0x1 << 5; // whether avatar has been age-verified
-static const std::string VISIBILITY_DEFAULT("default");
-static const std::string VISIBILITY_HIDDEN("hidden");
-static const std::string VISIBILITY_VISIBLE("visible");
-static const std::string VISIBILITY_INVISIBLE("invisible");
+char const* const VISIBILITY_DEFAULT = "default";
+char const* const VISIBILITY_HIDDEN = "hidden";
+char const* const VISIBILITY_VISIBLE = "visible";
+char const* const VISIBILITY_INVISIBLE = "invisible";
#endif
diff --git a/indra/llcommon/llavatarname.cpp b/indra/llcommon/llavatarname.cpp
index b1ec9e9875..ba3dd6d6b4 100644
--- a/indra/llcommon/llavatarname.cpp
+++ b/indra/llcommon/llavatarname.cpp
@@ -48,7 +48,7 @@ LLAvatarName::LLAvatarName()
mLegacyFirstName(),
mLegacyLastName(),
mIsDisplayNameDefault(false),
- mIsDummy(false),
+ mIsTemporaryName(false),
mExpires(F64_MAX),
mNextUpdate(0.0)
{ }
@@ -90,14 +90,16 @@ void LLAvatarName::fromLLSD(const LLSD& sd)
std::string LLAvatarName::getCompleteName() const
{
std::string name;
- if (!mUsername.empty())
+ if (mUsername.empty() || mIsDisplayNameDefault)
+ // If the display name feature is off
+ // OR this particular display name is defaulted (i.e. based on user name),
+ // then display only the easier to read instance of the person's name.
{
- name = mDisplayName + " (" + mUsername + ")";
+ name = mDisplayName;
}
else
{
- // ...display names are off, legacy name is in mDisplayName
- name = mDisplayName;
+ name = mDisplayName + " (" + mUsername + ")";
}
return name;
}
diff --git a/indra/llcommon/llavatarname.h b/indra/llcommon/llavatarname.h
index 145aeccd35..ba258d6d52 100644
--- a/indra/llcommon/llavatarname.h
+++ b/indra/llcommon/llavatarname.h
@@ -79,7 +79,7 @@ public:
// Under error conditions, we may insert "dummy" records with
// names like "???" into caches as placeholders. These can be
// shown in UI, but are not serialized.
- bool mIsDummy;
+ bool mIsTemporaryName;
// Names can change, so need to keep track of when name was
// last checked.
diff --git a/indra/llcommon/lldarray.h b/indra/llcommon/lldarray.h
index a8cd03b42a..131b819c99 100644
--- a/indra/llcommon/lldarray.h
+++ b/indra/llcommon/lldarray.h
@@ -51,7 +51,7 @@ public:
LLDynamicArray(S32 size=0) : std::vector<Type>(size) { if (size < BlockSize) std::vector<Type>::reserve(BlockSize); }
- void reset() { std::vector<Type>::resize(0); }
+ void reset() { std::vector<Type>::clear(); }
// ACCESSORS
const Type& get(S32 index) const { return std::vector<Type>::operator[](index); }
diff --git a/indra/llcommon/lldefs.h b/indra/llcommon/lldefs.h
index 6b38de6500..5a4b8325f4 100644
--- a/indra/llcommon/lldefs.h
+++ b/indra/llcommon/lldefs.h
@@ -236,5 +236,13 @@ inline LLDATATYPE llclampb(const LLDATATYPE& a)
return llmin(llmax(a, (LLDATATYPE)0), (LLDATATYPE)255);
}
+template <class LLDATATYPE>
+inline void llswap(LLDATATYPE& lhs, LLDATATYPE& rhs)
+{
+ LLDATATYPE tmp = lhs;
+ lhs = rhs;
+ rhs = tmp;
+}
+
#endif // LL_LLDEFS_H
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 84a6620a77..ff03506e84 100644
--- a/indra/llcommon/llevents.cpp
+++ b/indra/llcommon/llevents.cpp
@@ -475,7 +475,7 @@ void LLEventPump::stopListening(const std::string& name)
*****************************************************************************/
bool LLEventStream::post(const LLSD& event)
{
- if (! mEnabled)
+ if (! mEnabled || !mSignal)
{
return false;
}
@@ -515,6 +515,8 @@ bool LLEventQueue::post(const LLSD& event)
void LLEventQueue::flush()
{
+ if(!mSignal) return;
+
// Consider the case when a given listener on this LLEventQueue posts yet
// another event on the same queue. If we loop over mEventQueue directly,
// we'll end up processing all those events during the same flush() call
@@ -586,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 4ff93a553c..2b25f2fabb 100644
--- a/indra/llcommon/llfasttimer.h
+++ b/indra/llcommon/llfasttimer.h
@@ -27,140 +27,9 @@
#ifndef LL_FASTTIMER_H
#define LL_FASTTIMER_H
+// Implementation of getCPUClockCount32() and getCPUClockCount64 are now in llfastertimer_class.cpp.
+
// pull in the actual class definition
#include "llfasttimer_class.h"
-//
-// Important note: These implementations must be FAST!
-//
-
-#if LL_WINDOWS
-//
-// Windows implementation of CPU clock
-//
-
-//
-// NOTE: put back in when we aren't using platform sdk anymore
-//
-// because MS has different signatures for these functions in winnt.h
-// need to rename them to avoid conflicts
-//#define _interlockedbittestandset _renamed_interlockedbittestandset
-//#define _interlockedbittestandreset _renamed_interlockedbittestandreset
-//#include <intrin.h>
-//#undef _interlockedbittestandset
-//#undef _interlockedbittestandreset
-
-//inline U32 LLFastTimer::getCPUClockCount32()
-//{
-// U64 time_stamp = __rdtsc();
-// return (U32)(time_stamp >> 8);
-//}
-//
-//// return full timer value, *not* shifted by 8 bits
-//inline U64 LLFastTimer::getCPUClockCount64()
-//{
-// return __rdtsc();
-//}
-
-// shift off lower 8 bits for lower resolution but longer term timing
-// on 1Ghz machine, a 32-bit word will hold ~1000 seconds of timing
-inline U32 LLFastTimer::getCPUClockCount32()
-{
- U32 ret_val;
- __asm
- {
- _emit 0x0f
- _emit 0x31
- shr eax,8
- shl edx,24
- or eax, edx
- mov dword ptr [ret_val], eax
- }
- return ret_val;
-}
-
-// return full timer value, *not* shifted by 8 bits
-inline U64 LLFastTimer::getCPUClockCount64()
-{
- U64 ret_val;
- __asm
- {
- _emit 0x0f
- _emit 0x31
- mov eax,eax
- mov edx,edx
- mov dword ptr [ret_val+4], edx
- mov dword ptr [ret_val], eax
- }
- return ret_val;
-}
-#endif
-
-
-#if (LL_LINUX || LL_SOLARIS) && !(defined(__i386__) || defined(__amd64__))
-//
-// Linux and Solaris implementation of CPU clock - non-x86.
-// This is accurate but SLOW! Only use out of desperation.
-//
-// Try to use the MONOTONIC clock if available, this is a constant time counter
-// with nanosecond resolution (but not necessarily accuracy) and attempts are
-// made to synchronize this value between cores at kernel start. It should not
-// be affected by CPU frequency. If not available use the REALTIME clock, but
-// this may be affected by NTP adjustments or other user activity affecting
-// the system time.
-inline U64 LLFastTimer::getCPUClockCount64()
-{
- struct timespec tp;
-
-#ifdef CLOCK_MONOTONIC // MONOTONIC supported at build-time?
- if (-1 == clock_gettime(CLOCK_MONOTONIC,&tp)) // if MONOTONIC isn't supported at runtime then ouch, try REALTIME
-#endif
- clock_gettime(CLOCK_REALTIME,&tp);
-
- return (tp.tv_sec*LLFastTimer::sClockResolution)+tp.tv_nsec;
-}
-
-inline U32 LLFastTimer::getCPUClockCount32()
-{
- return (U32)(LLFastTimer::getCPUClockCount64() >> 8);
-}
-#endif // (LL_LINUX || LL_SOLARIS) && !(defined(__i386__) || defined(__amd64__))
-
-
-#if (LL_LINUX || LL_SOLARIS || LL_DARWIN) && (defined(__i386__) || defined(__amd64__))
-//
-// Mac+Linux+Solaris FAST x86 implementation of CPU clock
-inline U32 LLFastTimer::getCPUClockCount32()
-{
- U64 x;
- __asm__ volatile (".byte 0x0f, 0x31": "=A"(x));
- return (U32)(x >> 8);
-}
-
-inline U64 LLFastTimer::getCPUClockCount64()
-{
- U64 x;
- __asm__ volatile (".byte 0x0f, 0x31": "=A"(x));
- return x;
-}
-#endif
-
-
-#if ( LL_DARWIN && !(defined(__i386__) || defined(__amd64__)))
-//
-// Mac PPC (deprecated) implementation of CPU clock
-//
-// Just use gettimeofday implementation for now
-
-inline U32 LLFastTimer::getCPUClockCount32()
-{
- return (U32)(get_clock_count()>>8);
-}
-
-inline U64 LLFastTimer::getCPUClockCount64()
-{
- return get_clock_count();
-}
-#endif
-
#endif // LL_LLFASTTIMER_H
diff --git a/indra/llcommon/llfasttimer_class.cpp b/indra/llcommon/llfasttimer_class.cpp
index c45921cdec..bd594b06cf 100644
--- a/indra/llcommon/llfasttimer_class.cpp
+++ b/indra/llcommon/llfasttimer_class.cpp
@@ -35,10 +35,13 @@
#include <boost/bind.hpp>
+
#if LL_WINDOWS
+#include "lltimer.h"
#elif LL_LINUX || LL_SOLARIS
#include <sys/time.h>
#include <sched.h>
+#include "lltimer.h"
#elif LL_DARWIN
#include <sys/time.h>
#include "lltimer.h" // get_clock_count()
@@ -56,10 +59,13 @@ bool LLFastTimer::sPauseHistory = 0;
bool LLFastTimer::sResetHistory = 0;
LLFastTimer::CurTimerData LLFastTimer::sCurTimerData;
BOOL LLFastTimer::sLog = FALSE;
+std::string LLFastTimer::sLogName = "";
BOOL LLFastTimer::sMetricLog = FALSE;
LLMutex* LLFastTimer::sLogLock = NULL;
std::queue<LLSD> LLFastTimer::sLogQueue;
+#define USE_RDTSC 0
+
#if LL_LINUX || LL_SOLARIS
U64 LLFastTimer::sClockResolution = 1000000000; // Nanosecond resolution
#else
@@ -233,10 +239,23 @@ U64 LLFastTimer::countsPerSecond() // counts per second for the *32-bit* timer
#else // windows or x86-mac or x86-linux or x86-solaris
U64 LLFastTimer::countsPerSecond() // counts per second for the *32-bit* timer
{
+#if USE_RDTSC || !LL_WINDOWS
//getCPUFrequency returns MHz and sCPUClockFrequency wants to be in Hz
static U64 sCPUClockFrequency = U64(LLProcessorInfo().getCPUFrequency()*1000000.0);
// we drop the low-order byte in our timers, so report a lower frequency
+#else
+ // If we're not using RDTSC, each fasttimer tick is just a performance counter tick.
+ // Not redefining the clock frequency itself (in llprocessor.cpp/calculate_cpu_frequency())
+ // since that would change displayed MHz stats for CPUs
+ static bool firstcall = true;
+ static U64 sCPUClockFrequency;
+ if (firstcall)
+ {
+ QueryPerformanceFrequency((LARGE_INTEGER*)&sCPUClockFrequency);
+ firstcall = false;
+ }
+#endif
return sCPUClockFrequency >> 8;
}
#endif
@@ -481,6 +500,19 @@ void LLFastTimer::NamedTimer::resetFrame()
{
if (sLog)
{ //output current frame counts to performance log
+
+ static S32 call_count = 0;
+ if (call_count % 100 == 0)
+ {
+ llinfos << "countsPerSecond (32 bit): " << countsPerSecond() << llendl;
+ llinfos << "get_clock_count (64 bit): " << get_clock_count() << llendl;
+ llinfos << "LLProcessorInfo().getCPUFrequency() " << LLProcessorInfo().getCPUFrequency() << llendl;
+ llinfos << "getCPUClockCount32() " << getCPUClockCount32() << llendl;
+ llinfos << "getCPUClockCount64() " << getCPUClockCount64() << llendl;
+ llinfos << "elapsed sec " << ((F64)getCPUClockCount64())/((F64)LLProcessorInfo().getCPUFrequency()*1000000.0) << llendl;
+ }
+ call_count++;
+
F64 iclock_freq = 1000.0 / countsPerSecond(); // good place to calculate clock frequency
F64 total_time = 0;
@@ -762,3 +794,144 @@ LLFastTimer::LLFastTimer(LLFastTimer::FrameState* state)
//////////////////////////////////////////////////////////////////////////////
+//
+// Important note: These implementations must be FAST!
+//
+
+
+#if LL_WINDOWS
+//
+// Windows implementation of CPU clock
+//
+
+//
+// NOTE: put back in when we aren't using platform sdk anymore
+//
+// because MS has different signatures for these functions in winnt.h
+// need to rename them to avoid conflicts
+//#define _interlockedbittestandset _renamed_interlockedbittestandset
+//#define _interlockedbittestandreset _renamed_interlockedbittestandreset
+//#include <intrin.h>
+//#undef _interlockedbittestandset
+//#undef _interlockedbittestandreset
+
+//inline U32 LLFastTimer::getCPUClockCount32()
+//{
+// U64 time_stamp = __rdtsc();
+// return (U32)(time_stamp >> 8);
+//}
+//
+//// return full timer value, *not* shifted by 8 bits
+//inline U64 LLFastTimer::getCPUClockCount64()
+//{
+// return __rdtsc();
+//}
+
+// shift off lower 8 bits for lower resolution but longer term timing
+// on 1Ghz machine, a 32-bit word will hold ~1000 seconds of timing
+#if USE_RDTSC
+U32 LLFastTimer::getCPUClockCount32()
+{
+ U32 ret_val;
+ __asm
+ {
+ _emit 0x0f
+ _emit 0x31
+ shr eax,8
+ shl edx,24
+ or eax, edx
+ mov dword ptr [ret_val], eax
+ }
+ return ret_val;
+}
+
+// return full timer value, *not* shifted by 8 bits
+U64 LLFastTimer::getCPUClockCount64()
+{
+ U64 ret_val;
+ __asm
+ {
+ _emit 0x0f
+ _emit 0x31
+ mov eax,eax
+ mov edx,edx
+ mov dword ptr [ret_val+4], edx
+ mov dword ptr [ret_val], eax
+ }
+ return ret_val;
+}
+
+std::string LLFastTimer::sClockType = "rdtsc";
+
+#else
+//LL_COMMON_API U64 get_clock_count(); // in lltimer.cpp
+// These use QueryPerformanceCounter, which is arguably fine and also works on amd architectures.
+U32 LLFastTimer::getCPUClockCount32()
+{
+ return (U32)(get_clock_count()>>8);
+}
+
+U64 LLFastTimer::getCPUClockCount64()
+{
+ return get_clock_count();
+}
+
+std::string LLFastTimer::sClockType = "QueryPerformanceCounter";
+#endif
+
+#endif
+
+
+#if (LL_LINUX || LL_SOLARIS) && !(defined(__i386__) || defined(__amd64__))
+//
+// Linux and Solaris implementation of CPU clock - non-x86.
+// This is accurate but SLOW! Only use out of desperation.
+//
+// Try to use the MONOTONIC clock if available, this is a constant time counter
+// with nanosecond resolution (but not necessarily accuracy) and attempts are
+// made to synchronize this value between cores at kernel start. It should not
+// be affected by CPU frequency. If not available use the REALTIME clock, but
+// this may be affected by NTP adjustments or other user activity affecting
+// the system time.
+U64 LLFastTimer::getCPUClockCount64()
+{
+ struct timespec tp;
+
+#ifdef CLOCK_MONOTONIC // MONOTONIC supported at build-time?
+ if (-1 == clock_gettime(CLOCK_MONOTONIC,&tp)) // if MONOTONIC isn't supported at runtime then ouch, try REALTIME
+#endif
+ clock_gettime(CLOCK_REALTIME,&tp);
+
+ return (tp.tv_sec*LLFastTimer::sClockResolution)+tp.tv_nsec;
+}
+
+U32 LLFastTimer::getCPUClockCount32()
+{
+ return (U32)(LLFastTimer::getCPUClockCount64() >> 8);
+}
+
+std::string LLFastTimer::sClockType = "clock_gettime";
+
+#endif // (LL_LINUX || LL_SOLARIS) && !(defined(__i386__) || defined(__amd64__))
+
+
+#if (LL_LINUX || LL_SOLARIS || LL_DARWIN) && (defined(__i386__) || defined(__amd64__))
+//
+// Mac+Linux+Solaris FAST x86 implementation of CPU clock
+U32 LLFastTimer::getCPUClockCount32()
+{
+ U64 x;
+ __asm__ volatile (".byte 0x0f, 0x31": "=A"(x));
+ return (U32)(x >> 8);
+}
+
+U64 LLFastTimer::getCPUClockCount64()
+{
+ U64 x;
+ __asm__ volatile (".byte 0x0f, 0x31": "=A"(x));
+ return x;
+}
+
+std::string LLFastTimer::sClockType = "rdtsc";
+#endif
+
diff --git a/indra/llcommon/llfasttimer_class.h b/indra/llcommon/llfasttimer_class.h
index 1158ac5140..827747f0c6 100644
--- a/indra/llcommon/llfasttimer_class.h
+++ b/indra/llcommon/llfasttimer_class.h
@@ -31,12 +31,15 @@
#define FAST_TIMER_ON 1
#define TIME_FAST_TIMERS 0
+#define DEBUG_FAST_TIMER_THREADS 1
class LLMutex;
#include <queue>
#include "llsd.h"
+LL_COMMON_API void assert_main_thread();
+
class LL_COMMON_API LLFastTimer
{
public:
@@ -176,6 +179,11 @@ public:
U64 timer_end = getCPUClockCount64();
sTimerCycles += timer_end - timer_start;
#endif
+#if DEBUG_FAST_TIMER_THREADS
+#if !LL_RELEASE
+ assert_main_thread();
+#endif
+#endif
}
LL_FORCE_INLINE ~LLFastTimer()
@@ -211,6 +219,7 @@ public:
static std::queue<LLSD> sLogQueue;
static BOOL sLog;
static BOOL sMetricLog;
+ static std::string sLogName;
static bool sPauseHistory;
static bool sResetHistory;
static U64 sTimerCycles;
@@ -244,6 +253,7 @@ public:
U32 mChildTime;
};
static CurTimerData sCurTimerData;
+ static std::string sClockType;
private:
static U32 getCPUClockCount32();
diff --git a/indra/llcommon/llfile.cpp b/indra/llcommon/llfile.cpp
index 289ce0bc2c..c32a776c3f 100644
--- a/indra/llcommon/llfile.cpp
+++ b/indra/llcommon/llfile.cpp
@@ -92,6 +92,17 @@ LLFILE* LLFile::_fsopen(const std::string& filename, const char* mode, int shari
#endif
}
+int LLFile::close(LLFILE * file)
+{
+ int ret_value = 0;
+ if (file)
+ {
+ ret_value = fclose(file);
+ }
+ return ret_value;
+}
+
+
int LLFile::remove(const std::string& filename)
{
#if LL_WINDOWS
@@ -318,7 +329,12 @@ void llofstream::close()
if(is_open())
{
if (_Filebuffer->close() == 0)
+ {
_Myios::setstate(ios_base::failbit); /*Flawfinder: ignore*/
+ }
+ delete _Filebuffer;
+ _Filebuffer = NULL;
+ _ShouldClose = false;
}
}
diff --git a/indra/llcommon/llfile.h b/indra/llcommon/llfile.h
index 4913af7cb5..dd7d36513a 100644
--- a/indra/llcommon/llfile.h
+++ b/indra/llcommon/llfile.h
@@ -71,6 +71,8 @@ public:
static LLFILE* fopen(const std::string& filename,const char* accessmode); /* Flawfinder: ignore */
static LLFILE* _fsopen(const std::string& filename,const char* accessmode,int sharingFlag);
+ static int close(LLFILE * file);
+
// perms is a permissions mask like 0777 or 0700. In most cases it will
// be overridden by the user's umask. It is ignored on Windows.
static int mkdir(const std::string& filename, int perms = 0700);
diff --git a/indra/llcommon/llfoldertype.cpp b/indra/llcommon/llfoldertype.cpp
index ebc79af412..c2cfb7286e 100644
--- a/indra/llcommon/llfoldertype.cpp
+++ b/indra/llcommon/llfoldertype.cpp
@@ -89,6 +89,9 @@ LLFolderDictionary::LLFolderDictionary()
addEntry(LLFolderType::FT_CURRENT_OUTFIT, new FolderEntry("current", TRUE));
addEntry(LLFolderType::FT_OUTFIT, new FolderEntry("outfit", FALSE));
addEntry(LLFolderType::FT_MY_OUTFITS, new FolderEntry("my_otfts", TRUE));
+
+ addEntry(LLFolderType::FT_MESH, new FolderEntry("mesh", TRUE));
+
addEntry(LLFolderType::FT_INBOX, new FolderEntry("inbox", TRUE));
addEntry(LLFolderType::FT_NONE, new FolderEntry("-1", FALSE));
diff --git a/indra/llcommon/llfoldertype.h b/indra/llcommon/llfoldertype.h
index 936fbed17d..cb32cb075b 100644
--- a/indra/llcommon/llfoldertype.h
+++ b/indra/llcommon/llfoldertype.h
@@ -80,9 +80,11 @@ public:
FT_OUTFIT = 47,
FT_MY_OUTFITS = 48,
- FT_INBOX = 49,
+ FT_MESH = 49,
- FT_COUNT = 50,
+ FT_INBOX = 50,
+
+ FT_COUNT = 51,
FT_NONE = -1
};
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/lllslconstants.h b/indra/llcommon/lllslconstants.h
index 539c807020..9f32598e61 100644
--- a/indra/llcommon/lllslconstants.h
+++ b/indra/llcommon/lllslconstants.h
@@ -181,7 +181,7 @@ const S32 OBJECT_GROUP = 7;
const S32 OBJECT_CREATOR = 8;
// llTextBox() magic token string - yes this is a hack. sue me.
-const std::string TEXTBOX_MAGIC_TOKEN = "!!llTextBox!!";
+char const* const TEXTBOX_MAGIC_TOKEN = "!!llTextBox!!";
// changed() event flags
const U32 CHANGED_NONE = 0x0;
diff --git a/indra/llcommon/llmd5.h b/indra/llcommon/llmd5.h
index c8acbbe591..1526e6ac3c 100644
--- a/indra/llcommon/llmd5.h
+++ b/indra/llcommon/llmd5.h
@@ -103,7 +103,7 @@ public:
void raw_digest(unsigned char *array) const; // provide 16-byte array for binary data
void hex_digest(char *string) const; // provide 33-byte array for ascii-hex string
- friend std::ostream& operator<< (std::ostream&, LLMD5 context);
+ friend LL_COMMON_API std::ostream& operator<< (std::ostream&, LLMD5 context);
private:
diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp
index a502d1a7eb..21d1c84d69 100644
--- a/indra/llcommon/llmemory.cpp
+++ b/indra/llcommon/llmemory.cpp
@@ -26,6 +26,12 @@
#include "linden_common.h"
+#include "llmemory.h"
+
+#if MEM_TRACK_MEM
+#include "llthread.h"
+#endif
+
#if defined(LL_WINDOWS)
# include <windows.h>
# include <psapi.h>
@@ -37,8 +43,6 @@
# include <unistd.h>
#endif
-#include "llmemory.h"
-
//----------------------------------------------------------------------------
//static
@@ -67,25 +71,6 @@ void LLMemory::freeReserve()
reserveMem = NULL;
}
-void* ll_allocate (size_t size)
-{
- if (size == 0)
- {
- llwarns << "Null allocation" << llendl;
- }
- void *p = malloc(size);
- if (p == NULL)
- {
- LLMemory::freeReserve();
- llerrs << "Out of memory Error" << llendl;
- }
- return p;
-}
-
-void ll_release (void *p)
-{
- free(p);
-}
//----------------------------------------------------------------------------
@@ -105,6 +90,20 @@ U64 LLMemory::getCurrentRSS()
return counters.WorkingSetSize;
}
+//static
+U32 LLMemory::getWorkingSetSize()
+{
+ PROCESS_MEMORY_COUNTERS pmc ;
+ U32 ret = 0 ;
+
+ if (GetProcessMemoryInfo( GetCurrentProcess(), &pmc, sizeof(pmc)) )
+ {
+ ret = pmc.WorkingSetSize ;
+ }
+
+ return ret ;
+}
+
#elif defined(LL_DARWIN)
/*
@@ -151,6 +150,11 @@ U64 LLMemory::getCurrentRSS()
return residentSize;
}
+U32 LLMemory::getWorkingSetSize()
+{
+ return 0 ;
+}
+
#elif defined(LL_LINUX)
U64 LLMemory::getCurrentRSS()
@@ -185,6 +189,11 @@ bail:
return rss;
}
+U32 LLMemory::getWorkingSetSize()
+{
+ return 0 ;
+}
+
#elif LL_SOLARIS
#include <sys/types.h>
#include <sys/stat.h>
@@ -213,6 +222,12 @@ U64 LLMemory::getCurrentRSS()
return((U64)proc_psinfo.pr_rssize * 1024);
}
+
+U32 LLMemory::getWorkingSetSize()
+{
+ return 0 ;
+}
+
#else
U64 LLMemory::getCurrentRSS()
@@ -220,4 +235,144 @@ U64 LLMemory::getCurrentRSS()
return 0;
}
+U32 LLMemory::getWorkingSetSize()
+{
+ return 0 ;
+}
+
#endif
+
+//--------------------------------------------------------------------------------------------------
+#if MEM_TRACK_MEM
+#include "llframetimer.h"
+
+//static
+LLMemTracker* LLMemTracker::sInstance = NULL ;
+
+LLMemTracker::LLMemTracker()
+{
+ mLastAllocatedMem = LLMemory::getWorkingSetSize() ;
+ mCapacity = 128 ;
+ mCurIndex = 0 ;
+ mCounter = 0 ;
+ mDrawnIndex = 0 ;
+ mPaused = FALSE ;
+
+ mMutexp = new LLMutex(NULL) ;
+ mStringBuffer = new char*[128] ;
+ mStringBuffer[0] = new char[mCapacity * 128] ;
+ for(S32 i = 1 ; i < mCapacity ; i++)
+ {
+ mStringBuffer[i] = mStringBuffer[i-1] + 128 ;
+ }
+}
+
+LLMemTracker::~LLMemTracker()
+{
+ delete[] mStringBuffer[0] ;
+ delete[] mStringBuffer;
+ delete mMutexp ;
+}
+
+//static
+LLMemTracker* LLMemTracker::getInstance()
+{
+ if(!sInstance)
+ {
+ sInstance = new LLMemTracker() ;
+ }
+ return sInstance ;
+}
+
+//static
+void LLMemTracker::release()
+{
+ if(sInstance)
+ {
+ delete sInstance ;
+ sInstance = NULL ;
+ }
+}
+
+//static
+void LLMemTracker::track(const char* function, const int line)
+{
+ static const S32 MIN_ALLOCATION = 0 ; //1KB
+
+ if(mPaused)
+ {
+ return ;
+ }
+
+ U32 allocated_mem = LLMemory::getWorkingSetSize() ;
+
+ LLMutexLock lock(mMutexp) ;
+
+ S32 delta_mem = allocated_mem - mLastAllocatedMem ;
+ mLastAllocatedMem = allocated_mem ;
+
+ if(delta_mem <= 0)
+ {
+ return ; //occupied memory does not grow
+ }
+
+ if(delta_mem < MIN_ALLOCATION)
+ {
+ return ;
+ }
+
+ char* buffer = mStringBuffer[mCurIndex++] ;
+ F32 time = (F32)LLFrameTimer::getElapsedSeconds() ;
+ S32 hours = (S32)(time / (60*60));
+ S32 mins = (S32)((time - hours*(60*60)) / 60);
+ S32 secs = (S32)((time - hours*(60*60) - mins*60));
+ strcpy(buffer, function) ;
+ sprintf(buffer + strlen(function), " line: %d DeltaMem: %d (bytes) Time: %d:%02d:%02d", line, delta_mem, hours,mins,secs) ;
+
+ if(mCounter < mCapacity)
+ {
+ mCounter++ ;
+ }
+ if(mCurIndex >= mCapacity)
+ {
+ mCurIndex = 0 ;
+ }
+}
+
+
+//static
+void LLMemTracker::preDraw(BOOL pause)
+{
+ mMutexp->lock() ;
+
+ mPaused = pause ;
+ mDrawnIndex = mCurIndex - 1;
+ mNumOfDrawn = 0 ;
+}
+
+//static
+void LLMemTracker::postDraw()
+{
+ mMutexp->unlock() ;
+}
+
+//static
+const char* LLMemTracker::getNextLine()
+{
+ if(mNumOfDrawn >= mCounter)
+ {
+ return NULL ;
+ }
+ mNumOfDrawn++;
+
+ if(mDrawnIndex < 0)
+ {
+ mDrawnIndex = mCapacity - 1 ;
+ }
+
+ return mStringBuffer[mDrawnIndex--] ;
+}
+
+#endif //MEM_TRACK_MEM
+//--------------------------------------------------------------------------------------------------
+
diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h
index 9bf4248bb7..3bd1403576 100644
--- a/indra/llcommon/llmemory.h
+++ b/indra/llcommon/llmemory.h
@@ -1,39 +1,109 @@
-/**
+/**
* @file llmemory.h
* @brief Memory allocation/deallocation header-stuff goes here.
*
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
- *
+ *
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
- *
+ *
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
- *
+ *
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
+ *
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LLMEMORY_H
#define LLMEMORY_H
+#include "llmemtype.h"
+
+#if LL_DEBUG
+inline void* ll_aligned_malloc( size_t size, int align )
+{
+ void* mem = malloc( size + (align - 1) + sizeof(void*) );
+ char* aligned = ((char*)mem) + sizeof(void*);
+ aligned += align - ((uintptr_t)aligned & (align - 1));
+
+ ((void**)aligned)[-1] = mem;
+ return aligned;
+}
+
+inline void ll_aligned_free( void* ptr )
+{
+ free( ((void**)ptr)[-1] );
+}
+
+inline void* ll_aligned_malloc_16(size_t size) // returned hunk MUST be freed with ll_aligned_free_16().
+{
+#if defined(LL_WINDOWS)
+ return _mm_malloc(size, 16);
+#elif defined(LL_DARWIN)
+ return malloc(size); // default osx malloc is 16 byte aligned.
+#else
+ void *rtn;
+ if (LL_LIKELY(0 == posix_memalign(&rtn, 16, size)))
+ return rtn;
+ else // bad alignment requested, or out of memory
+ return NULL;
+#endif
+}
+inline void ll_aligned_free_16(void *p)
+{
+#if defined(LL_WINDOWS)
+ _mm_free(p);
+#elif defined(LL_DARWIN)
+ return free(p);
+#else
+ free(p); // posix_memalign() is compatible with heap deallocator
+#endif
+}
-extern S32 gTotalDAlloc;
-extern S32 gTotalDAUse;
-extern S32 gDACount;
+inline void* ll_aligned_malloc_32(size_t size) // returned hunk MUST be freed with ll_aligned_free_32().
+{
+#if defined(LL_WINDOWS)
+ return _mm_malloc(size, 32);
+#elif defined(LL_DARWIN)
+ return ll_aligned_malloc( size, 32 );
+#else
+ void *rtn;
+ if (LL_LIKELY(0 == posix_memalign(&rtn, 32, size)))
+ return rtn;
+ else // bad alignment requested, or out of memory
+ return NULL;
+#endif
+}
-extern void* ll_allocate (size_t size);
-extern void ll_release (void *p);
+inline void ll_aligned_free_32(void *p)
+{
+#if defined(LL_WINDOWS)
+ _mm_free(p);
+#elif defined(LL_DARWIN)
+ ll_aligned_free( p );
+#else
+ free(p); // posix_memalign() is compatible with heap deallocator
+#endif
+}
+#else // LL_DEBUG
+// ll_aligned_foo are noops now that we use tcmalloc everywhere (tcmalloc aligns automatically at appropriate intervals)
+#define ll_aligned_malloc( size, align ) malloc(size)
+#define ll_aligned_free( ptr ) free(ptr)
+#define ll_aligned_malloc_16 malloc
+#define ll_aligned_free_16 free
+#define ll_aligned_malloc_32 malloc
+#define ll_aligned_free_32 free
+#endif // LL_DEBUG
class LL_COMMON_API LLMemory
{
@@ -44,10 +114,55 @@ public:
// Return the resident set size of the current process, in bytes.
// Return value is zero if not known.
static U64 getCurrentRSS();
+ static U32 getWorkingSetSize();
private:
static char* reserveMem;
};
+//----------------------------------------------------------------------------
+#if MEM_TRACK_MEM
+class LLMutex ;
+class LL_COMMON_API LLMemTracker
+{
+private:
+ LLMemTracker() ;
+ ~LLMemTracker() ;
+
+public:
+ static void release() ;
+ static LLMemTracker* getInstance() ;
+
+ void track(const char* function, const int line) ;
+ void preDraw(BOOL pause) ;
+ void postDraw() ;
+ const char* getNextLine() ;
+
+private:
+ static LLMemTracker* sInstance ;
+
+ char** mStringBuffer ;
+ S32 mCapacity ;
+ U32 mLastAllocatedMem ;
+ S32 mCurIndex ;
+ S32 mCounter;
+ S32 mDrawnIndex;
+ S32 mNumOfDrawn;
+ BOOL mPaused;
+ LLMutex* mMutexp ;
+};
+
+#define MEM_TRACK_RELEASE LLMemTracker::release() ;
+#define MEM_TRACK LLMemTracker::getInstance()->track(__FUNCTION__, __LINE__) ;
+
+#else // MEM_TRACK_MEM
+
+#define MEM_TRACK_RELEASE
+#define MEM_TRACK
+
+#endif // MEM_TRACK_MEM
+
+//----------------------------------------------------------------------------
+
// LLRefCount moved to llrefcount.h
// LLPointer moved to llpointer.h
diff --git a/indra/llcommon/llmemtype.cpp b/indra/llcommon/llmemtype.cpp
index fe83f87d4b..6290a7158f 100644
--- a/indra/llcommon/llmemtype.cpp
+++ b/indra/llcommon/llmemtype.cpp
@@ -229,3 +229,4 @@ char const * LLMemType::getNameFromID(S32 id)
return DeclareMemType::mNameList[id];
}
+//--------------------------------------------------------------------------------------------------
diff --git a/indra/llcommon/llmetricperformancetester.cpp b/indra/llcommon/llmetricperformancetester.cpp
new file mode 100644
index 0000000000..41d3eb0bf3
--- /dev/null
+++ b/indra/llcommon/llmetricperformancetester.cpp
@@ -0,0 +1,336 @@
+/**
+ * @file llmetricperformancetester.cpp
+ * @brief LLMetricPerformanceTesterBasic and LLMetricPerformanceTesterWithSession classes 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 "linden_common.h"
+
+#include "indra_constants.h"
+#include "llerror.h"
+#include "llsdserialize.h"
+#include "llstat.h"
+#include "lltreeiterators.h"
+#include "llmetricperformancetester.h"
+
+//----------------------------------------------------------------------------------------------
+// LLMetricPerformanceTesterBasic : static methods and testers management
+//----------------------------------------------------------------------------------------------
+
+LLMetricPerformanceTesterBasic::name_tester_map_t LLMetricPerformanceTesterBasic::sTesterMap ;
+
+/*static*/
+void LLMetricPerformanceTesterBasic::cleanClass()
+{
+ for (name_tester_map_t::iterator iter = sTesterMap.begin() ; iter != sTesterMap.end() ; ++iter)
+ {
+ delete iter->second ;
+ }
+ sTesterMap.clear() ;
+}
+
+/*static*/
+BOOL LLMetricPerformanceTesterBasic::addTester(LLMetricPerformanceTesterBasic* tester)
+{
+ llassert_always(tester != NULL);
+ std::string name = tester->getTesterName() ;
+ if (getTester(name))
+ {
+ llerrs << "Tester name is already used by some other tester : " << name << llendl ;
+ return FALSE;
+ }
+
+ sTesterMap.insert(std::make_pair(name, tester));
+ return TRUE;
+}
+
+/*static*/
+void LLMetricPerformanceTesterBasic::deleteTester(std::string name)
+{
+ name_tester_map_t::iterator tester = sTesterMap.find(name);
+ if (tester != sTesterMap.end())
+ {
+ delete tester->second;
+ sTesterMap.erase(tester);
+ }
+}
+
+/*static*/
+LLMetricPerformanceTesterBasic* LLMetricPerformanceTesterBasic::getTester(std::string name)
+{
+ // Check for the requested metric name
+ name_tester_map_t::iterator found_it = sTesterMap.find(name) ;
+ if (found_it != sTesterMap.end())
+ {
+ return found_it->second ;
+ }
+ return NULL ;
+}
+
+/*static*/
+// Return TRUE if this metric is requested or if the general default "catch all" metric is requested
+BOOL LLMetricPerformanceTesterBasic::isMetricLogRequested(std::string name)
+{
+ return (LLFastTimer::sMetricLog && ((LLFastTimer::sLogName == name) || (LLFastTimer::sLogName == DEFAULT_METRIC_NAME)));
+}
+
+/*static*/
+LLSD LLMetricPerformanceTesterBasic::analyzeMetricPerformanceLog(std::istream& is)
+{
+ LLSD ret;
+ LLSD cur;
+
+ while (!is.eof() && LLSDSerialize::fromXML(cur, is))
+ {
+ for (LLSD::map_iterator iter = cur.beginMap(); iter != cur.endMap(); ++iter)
+ {
+ std::string label = iter->first;
+
+ LLMetricPerformanceTesterBasic* tester = LLMetricPerformanceTesterBasic::getTester(iter->second["Name"].asString()) ;
+ if(tester)
+ {
+ ret[label]["Name"] = iter->second["Name"] ;
+
+ S32 num_of_metrics = tester->getNumberOfMetrics() ;
+ for(S32 index = 0 ; index < num_of_metrics ; index++)
+ {
+ ret[label][ tester->getMetricName(index) ] = iter->second[ tester->getMetricName(index) ] ;
+ }
+ }
+ }
+ }
+
+ return ret;
+}
+
+/*static*/
+void LLMetricPerformanceTesterBasic::doAnalysisMetrics(std::string baseline, std::string target, std::string output)
+{
+ if(!LLMetricPerformanceTesterBasic::hasMetricPerformanceTesters())
+ {
+ return ;
+ }
+
+ // Open baseline and current target, exit if one is inexistent
+ std::ifstream base_is(baseline.c_str());
+ std::ifstream target_is(target.c_str());
+ if (!base_is.is_open() || !target_is.is_open())
+ {
+ llwarns << "'-analyzeperformance' error : baseline or current target file inexistent" << llendl;
+ base_is.close();
+ target_is.close();
+ return;
+ }
+
+ //analyze baseline
+ LLSD base = analyzeMetricPerformanceLog(base_is);
+ base_is.close();
+
+ //analyze current
+ LLSD current = analyzeMetricPerformanceLog(target_is);
+ target_is.close();
+
+ //output comparision
+ std::ofstream os(output.c_str());
+
+ os << "Label, Metric, Base(B), Target(T), Diff(T-B), Percentage(100*T/B)\n";
+ for(LLMetricPerformanceTesterBasic::name_tester_map_t::iterator iter = LLMetricPerformanceTesterBasic::sTesterMap.begin() ;
+ iter != LLMetricPerformanceTesterBasic::sTesterMap.end() ; ++iter)
+ {
+ LLMetricPerformanceTesterBasic* tester = ((LLMetricPerformanceTesterBasic*)iter->second) ;
+ tester->analyzePerformance(&os, &base, &current) ;
+ }
+
+ os.flush();
+ os.close();
+}
+
+
+//----------------------------------------------------------------------------------------------
+// LLMetricPerformanceTesterBasic : Tester instance methods
+//----------------------------------------------------------------------------------------------
+
+LLMetricPerformanceTesterBasic::LLMetricPerformanceTesterBasic(std::string name) :
+ mName(name),
+ mCount(0)
+{
+ if (mName == std::string())
+ {
+ llerrs << "LLMetricPerformanceTesterBasic construction invalid : Empty name passed to constructor" << llendl ;
+ }
+
+ mValidInstance = LLMetricPerformanceTesterBasic::addTester(this) ;
+}
+
+LLMetricPerformanceTesterBasic::~LLMetricPerformanceTesterBasic()
+{
+}
+
+void LLMetricPerformanceTesterBasic::preOutputTestResults(LLSD* sd)
+{
+ incrementCurrentCount() ;
+ (*sd)[getCurrentLabelName()]["Name"] = mName ;
+}
+
+void LLMetricPerformanceTesterBasic::postOutputTestResults(LLSD* sd)
+{
+ LLMutexLock lock(LLFastTimer::sLogLock);
+ LLFastTimer::sLogQueue.push((*sd));
+}
+
+void LLMetricPerformanceTesterBasic::outputTestResults()
+{
+ LLSD sd;
+
+ preOutputTestResults(&sd) ;
+ outputTestRecord(&sd) ;
+ postOutputTestResults(&sd) ;
+}
+
+void LLMetricPerformanceTesterBasic::addMetric(std::string str)
+{
+ mMetricStrings.push_back(str) ;
+}
+
+/*virtual*/
+void LLMetricPerformanceTesterBasic::analyzePerformance(std::ofstream* os, LLSD* base, LLSD* current)
+{
+ resetCurrentCount() ;
+
+ std::string current_label = getCurrentLabelName();
+ BOOL in_base = (*base).has(current_label) ;
+ BOOL in_current = (*current).has(current_label) ;
+
+ while(in_base || in_current)
+ {
+ LLSD::String label = current_label ;
+
+ if(in_base && in_current)
+ {
+ *os << llformat("%s\n", label.c_str()) ;
+
+ for(U32 index = 0 ; index < mMetricStrings.size() ; index++)
+ {
+ switch((*current)[label][ mMetricStrings[index] ].type())
+ {
+ case LLSD::TypeInteger:
+ compareTestResults(os, mMetricStrings[index],
+ (S32)((*base)[label][ mMetricStrings[index] ].asInteger()), (S32)((*current)[label][ mMetricStrings[index] ].asInteger())) ;
+ break ;
+ case LLSD::TypeReal:
+ compareTestResults(os, mMetricStrings[index],
+ (F32)((*base)[label][ mMetricStrings[index] ].asReal()), (F32)((*current)[label][ mMetricStrings[index] ].asReal())) ;
+ break;
+ default:
+ llerrs << "unsupported metric " << mMetricStrings[index] << " LLSD type: " << (S32)(*current)[label][ mMetricStrings[index] ].type() << llendl ;
+ }
+ }
+ }
+
+ incrementCurrentCount();
+ current_label = getCurrentLabelName();
+ in_base = (*base).has(current_label) ;
+ in_current = (*current).has(current_label) ;
+ }
+}
+
+/*virtual*/
+void LLMetricPerformanceTesterBasic::compareTestResults(std::ofstream* os, std::string metric_string, S32 v_base, S32 v_current)
+{
+ *os << llformat(" ,%s, %d, %d, %d, %.4f\n", metric_string.c_str(), v_base, v_current,
+ v_current - v_base, (v_base != 0) ? 100.f * v_current / v_base : 0) ;
+}
+
+/*virtual*/
+void LLMetricPerformanceTesterBasic::compareTestResults(std::ofstream* os, std::string metric_string, F32 v_base, F32 v_current)
+{
+ *os << llformat(" ,%s, %.4f, %.4f, %.4f, %.4f\n", metric_string.c_str(), v_base, v_current,
+ v_current - v_base, (fabs(v_base) > 0.0001f) ? 100.f * v_current / v_base : 0.f ) ;
+}
+
+//----------------------------------------------------------------------------------------------
+// LLMetricPerformanceTesterWithSession
+//----------------------------------------------------------------------------------------------
+
+LLMetricPerformanceTesterWithSession::LLMetricPerformanceTesterWithSession(std::string name) :
+ LLMetricPerformanceTesterBasic(name),
+ mBaseSessionp(NULL),
+ mCurrentSessionp(NULL)
+{
+}
+
+LLMetricPerformanceTesterWithSession::~LLMetricPerformanceTesterWithSession()
+{
+ if (mBaseSessionp)
+ {
+ delete mBaseSessionp ;
+ mBaseSessionp = NULL ;
+ }
+ if (mCurrentSessionp)
+ {
+ delete mCurrentSessionp ;
+ mCurrentSessionp = NULL ;
+ }
+}
+
+/*virtual*/
+void LLMetricPerformanceTesterWithSession::analyzePerformance(std::ofstream* os, LLSD* base, LLSD* current)
+{
+ // Load the base session
+ resetCurrentCount() ;
+ mBaseSessionp = loadTestSession(base) ;
+
+ // Load the current session
+ resetCurrentCount() ;
+ mCurrentSessionp = loadTestSession(current) ;
+
+ if (!mBaseSessionp || !mCurrentSessionp)
+ {
+ llerrs << "Error loading test sessions." << llendl ;
+ }
+
+ // Compare
+ compareTestSessions(os) ;
+
+ // Release memory
+ if (mBaseSessionp)
+ {
+ delete mBaseSessionp ;
+ mBaseSessionp = NULL ;
+ }
+ if (mCurrentSessionp)
+ {
+ delete mCurrentSessionp ;
+ mCurrentSessionp = NULL ;
+ }
+}
+
+
+//----------------------------------------------------------------------------------------------
+// LLTestSession
+//----------------------------------------------------------------------------------------------
+
+LLMetricPerformanceTesterWithSession::LLTestSession::~LLTestSession()
+{
+}
+
diff --git a/indra/llcommon/llmetricperformancetester.h b/indra/llcommon/llmetricperformancetester.h
new file mode 100644
index 0000000000..1a18cdf36f
--- /dev/null
+++ b/indra/llcommon/llmetricperformancetester.h
@@ -0,0 +1,215 @@
+/**
+ * @file llmetricperformancetester.h
+ * @brief LLMetricPerformanceTesterBasic and LLMetricPerformanceTesterWithSession classes definition
+ *
+ * $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_METRICPERFORMANCETESTER_H
+#define LL_METRICPERFORMANCETESTER_H
+
+char const* const DEFAULT_METRIC_NAME = "metric";
+
+/**
+ * @class LLMetricPerformanceTesterBasic
+ * @brief Performance Metric Base Class
+ */
+class LL_COMMON_API LLMetricPerformanceTesterBasic
+{
+public:
+ /**
+ * @brief Creates a basic tester instance.
+ * @param[in] name - Unique string identifying this tester instance.
+ */
+ LLMetricPerformanceTesterBasic(std::string name);
+ virtual ~LLMetricPerformanceTesterBasic();
+
+ /**
+ * @return Returns true if the instance has been added to the tester map.
+ * Need to be tested after creation of a tester instance so to know if the tester is correctly handled.
+ * A tester might not be added to the map if another tester with the same name already exists.
+ */
+ BOOL isValid() const { return mValidInstance; }
+
+ /**
+ * @brief Write a set of test results to the log LLSD.
+ */
+ void outputTestResults() ;
+
+ /**
+ * @brief Compare the test results.
+ * By default, compares the test results against the baseline one by one, item by item,
+ * in the increasing order of the LLSD record counter, starting from the first one.
+ */
+ virtual void analyzePerformance(std::ofstream* os, LLSD* base, LLSD* current) ;
+
+ static void doAnalysisMetrics(std::string baseline, std::string target, std::string output) ;
+
+ /**
+ * @return Returns the number of the test metrics in this tester instance.
+ */
+ S32 getNumberOfMetrics() const { return mMetricStrings.size() ;}
+ /**
+ * @return Returns the metric name at index
+ * @param[in] index - Index on the list of metrics managed by this tester instance.
+ */
+ std::string getMetricName(S32 index) const { return mMetricStrings[index] ;}
+
+protected:
+ /**
+ * @return Returns the name of this tester instance.
+ */
+ std::string getTesterName() const { return mName ;}
+
+ /**
+ * @brief Insert a new metric to be managed by this tester instance.
+ * @param[in] str - Unique string identifying the new metric.
+ */
+ void addMetric(std::string str) ;
+
+ /**
+ * @brief Compare test results, provided in 2 flavors: compare integers and compare floats.
+ * @param[out] os - Formatted output string holding the compared values.
+ * @param[in] metric_string - Name of the metric.
+ * @param[in] v_base - Base value of the metric.
+ * @param[in] v_current - Current value of the metric.
+ */
+ virtual void compareTestResults(std::ofstream* os, std::string metric_string, S32 v_base, S32 v_current) ;
+ virtual void compareTestResults(std::ofstream* os, std::string metric_string, F32 v_base, F32 v_current) ;
+
+ /**
+ * @brief Reset internal record count. Count starts with 1.
+ */
+ void resetCurrentCount() { mCount = 1; }
+ /**
+ * @brief Increment internal record count.
+ */
+ void incrementCurrentCount() { mCount++; }
+ /**
+ * @return Returns the label to be used for the current count. It's "TesterName"-"Count".
+ */
+ std::string getCurrentLabelName() const { return llformat("%s-%d", mName.c_str(), mCount) ;}
+
+ /**
+ * @brief Write a test record to the LLSD. Implementers need to overload this method.
+ * @param[out] sd - The LLSD record to store metric data into.
+ */
+ virtual void outputTestRecord(LLSD* sd) = 0 ;
+
+private:
+ void preOutputTestResults(LLSD* sd) ;
+ void postOutputTestResults(LLSD* sd) ;
+ static LLSD analyzeMetricPerformanceLog(std::istream& is) ;
+
+ std::string mName ; // Name of this tester instance
+ S32 mCount ; // Current record count
+ BOOL mValidInstance; // TRUE if the instance is managed by the map
+ std::vector< std::string > mMetricStrings ; // Metrics strings
+
+// Static members managing the collection of testers
+public:
+ // Map of all the tester instances in use
+ typedef std::map< std::string, LLMetricPerformanceTesterBasic* > name_tester_map_t;
+ static name_tester_map_t sTesterMap ;
+
+ /**
+ * @return Returns a pointer to the tester
+ * @param[in] name - Name of the tester instance queried.
+ */
+ static LLMetricPerformanceTesterBasic* getTester(std::string name) ;
+
+ /**
+ * @return Delete the named tester from the list
+ * @param[in] name - Name of the tester instance to delete.
+ */
+ static void deleteTester(std::string name);
+
+ /**
+ * @return Returns TRUE if that metric *or* the default catch all metric has been requested to be logged
+ * @param[in] name - Name of the tester queried.
+ */
+ static BOOL isMetricLogRequested(std::string name);
+
+ /**
+ * @return Returns TRUE if there's a tester defined, FALSE otherwise.
+ */
+ static BOOL hasMetricPerformanceTesters() { return !sTesterMap.empty() ;}
+ /**
+ * @brief Delete all testers and reset the tester map
+ */
+ static void cleanClass() ;
+
+private:
+ // Add a tester to the map. Returns false if adding fails.
+ static BOOL addTester(LLMetricPerformanceTesterBasic* tester) ;
+};
+
+/**
+ * @class LLMetricPerformanceTesterWithSession
+ * @brief Performance Metric Class with custom session
+ */
+class LL_COMMON_API LLMetricPerformanceTesterWithSession : public LLMetricPerformanceTesterBasic
+{
+public:
+ /**
+ * @param[in] name - Unique string identifying this tester instance.
+ */
+ LLMetricPerformanceTesterWithSession(std::string name);
+ virtual ~LLMetricPerformanceTesterWithSession();
+
+ /**
+ * @brief Compare the test results.
+ * This will be loading the base and current sessions and compare them using the virtual
+ * abstract methods loadTestSession() and compareTestSessions()
+ */
+ virtual void analyzePerformance(std::ofstream* os, LLSD* base, LLSD* current) ;
+
+protected:
+ /**
+ * @class LLMetricPerformanceTesterWithSession::LLTestSession
+ * @brief Defines an interface for the two abstract virtual functions loadTestSession() and compareTestSessions()
+ */
+ class LL_COMMON_API LLTestSession
+ {
+ public:
+ virtual ~LLTestSession() ;
+ };
+
+ /**
+ * @brief Convert an LLSD log into a test session.
+ * @param[in] log - The LLSD record
+ * @return Returns the record as a test session
+ */
+ virtual LLMetricPerformanceTesterWithSession::LLTestSession* loadTestSession(LLSD* log) = 0;
+
+ /**
+ * @brief Compare the base session and the target session. Assumes base and current sessions have been loaded.
+ * @param[out] os - The comparison result as a standard stream
+ */
+ virtual void compareTestSessions(std::ofstream* os) = 0;
+
+ LLTestSession* mBaseSessionp;
+ LLTestSession* mCurrentSessionp;
+};
+
+#endif
+
diff --git a/indra/llcommon/llprocesslauncher.cpp b/indra/llcommon/llprocesslauncher.cpp
index 99308c94e7..10950181fd 100644
--- a/indra/llcommon/llprocesslauncher.cpp
+++ b/indra/llcommon/llprocesslauncher.cpp
@@ -58,6 +58,11 @@ void LLProcessLauncher::setWorkingDirectory(const std::string &dir)
mWorkingDir = dir;
}
+const std::string& LLProcessLauncher::getExecutable() const
+{
+ return mExecutable;
+}
+
void LLProcessLauncher::clearArguments()
{
mLaunchArguments.clear();
@@ -98,10 +103,30 @@ int LLProcessLauncher::launch(void)
char *args2 = new char[args.size() + 1];
strcpy(args2, args.c_str());
- if( ! CreateProcessA( NULL, args2, NULL, NULL, FALSE, 0, NULL, NULL, &sinfo, &pinfo ) )
+ const char * working_directory = 0;
+ if(!mWorkingDir.empty()) working_directory = mWorkingDir.c_str();
+ if( ! CreateProcessA( NULL, args2, NULL, NULL, FALSE, 0, NULL, working_directory, &sinfo, &pinfo ) )
{
- // TODO: do better than returning the OS-specific error code on failure...
result = GetLastError();
+
+ LPTSTR error_str = 0;
+ if(
+ FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ result,
+ 0,
+ (LPTSTR)&error_str,
+ 0,
+ NULL)
+ != 0)
+ {
+ char message[256];
+ wcstombs(message, error_str, 256);
+ message[255] = 0;
+ llwarns << "CreateProcessA failed: " << message << llendl;
+ LocalFree(error_str);
+ }
+
if(result == 0)
{
// Make absolutely certain we return a non-zero value on failure.
@@ -260,14 +285,7 @@ int LLProcessLauncher::launch(void)
delete[] fake_argv;
mProcessID = id;
-
- // At this point, the child process will have been created (since that's how vfork works -- the child borrowed our execution context until it forked)
- // If the process doesn't exist at this point, the exec failed.
- if(!isRunning())
- {
- result = -1;
- }
-
+
return result;
}
diff --git a/indra/llcommon/llprocesslauncher.h b/indra/llcommon/llprocesslauncher.h
index 479aeb664a..954c249147 100644
--- a/indra/llcommon/llprocesslauncher.h
+++ b/indra/llcommon/llprocesslauncher.h
@@ -47,6 +47,8 @@ public:
void setExecutable(const std::string &executable);
void setWorkingDirectory(const std::string &dir);
+ const std::string& getExecutable() const;
+
void clearArguments();
void addArgument(const std::string &arg);
void addArgument(const char *arg);
diff --git a/indra/llcommon/llqueuedthread.h b/indra/llcommon/llqueuedthread.h
index c75e0e2bbf..a53b22f6fc 100644
--- a/indra/llcommon/llqueuedthread.h
+++ b/indra/llcommon/llqueuedthread.h
@@ -179,7 +179,7 @@ public:
void waitOnPending();
void printQueueStats();
- S32 getPending();
+ virtual S32 getPending();
bool getThreaded() { return mThreaded ? true : false; }
// Request accessors
diff --git a/indra/llcommon/llrefcount.cpp b/indra/llcommon/llrefcount.cpp
index 55d0c85cbd..e1876599fc 100644
--- a/indra/llcommon/llrefcount.cpp
+++ b/indra/llcommon/llrefcount.cpp
@@ -29,9 +29,25 @@
#include "llerror.h"
+#if LL_REF_COUNT_DEBUG
+#include "llthread.h"
+#include "llapr.h"
+#endif
+
LLRefCount::LLRefCount(const LLRefCount& other)
: mRef(0)
{
+#if LL_REF_COUNT_DEBUG
+ if(gAPRPoolp)
+ {
+ mMutexp = new LLMutex(gAPRPoolp) ;
+ }
+ else
+ {
+ mMutexp = NULL ;
+ }
+ mCrashAtUnlock = FALSE ;
+#endif
}
LLRefCount& LLRefCount::operator=(const LLRefCount&)
@@ -43,6 +59,17 @@ LLRefCount& LLRefCount::operator=(const LLRefCount&)
LLRefCount::LLRefCount() :
mRef(0)
{
+#if LL_REF_COUNT_DEBUG
+ if(gAPRPoolp)
+ {
+ mMutexp = new LLMutex(gAPRPoolp) ;
+ }
+ else
+ {
+ mMutexp = NULL ;
+ }
+ mCrashAtUnlock = FALSE ;
+#endif
}
LLRefCount::~LLRefCount()
@@ -51,4 +78,87 @@ LLRefCount::~LLRefCount()
{
llerrs << "deleting non-zero reference" << llendl;
}
+
+#if LL_REF_COUNT_DEBUG
+ if(gAPRPoolp)
+ {
+ delete mMutexp ;
+ }
+#endif
}
+
+#if LL_REF_COUNT_DEBUG
+void LLRefCount::ref() const
+{
+ if(mMutexp)
+ {
+ if(mMutexp->isLocked())
+ {
+ mCrashAtUnlock = TRUE ;
+ llerrs << "the mutex is locked by the thread: " << mLockedThreadID
+ << " Current thread: " << LLThread::currentID() << llendl ;
+ }
+
+ mMutexp->lock() ;
+ mLockedThreadID = LLThread::currentID() ;
+
+ mRef++;
+
+ if(mCrashAtUnlock)
+ {
+ while(1); //crash here.
+ }
+ mMutexp->unlock() ;
+ }
+ else
+ {
+ mRef++;
+ }
+}
+
+S32 LLRefCount::unref() const
+{
+ if(mMutexp)
+ {
+ if(mMutexp->isLocked())
+ {
+ mCrashAtUnlock = TRUE ;
+ llerrs << "the mutex is locked by the thread: " << mLockedThreadID
+ << " Current thread: " << LLThread::currentID() << llendl ;
+ }
+
+ mMutexp->lock() ;
+ mLockedThreadID = LLThread::currentID() ;
+
+ llassert(mRef >= 1);
+ if (0 == --mRef)
+ {
+ if(mCrashAtUnlock)
+ {
+ while(1); //crash here.
+ }
+ mMutexp->unlock() ;
+
+ delete this;
+ return 0;
+ }
+
+ if(mCrashAtUnlock)
+ {
+ while(1); //crash here.
+ }
+ mMutexp->unlock() ;
+ return mRef;
+ }
+ else
+ {
+ llassert(mRef >= 1);
+ if (0 == --mRef)
+ {
+ delete this;
+ return 0;
+ }
+ return mRef;
+ }
+}
+#endif
diff --git a/indra/llcommon/llrefcount.h b/indra/llcommon/llrefcount.h
index 19f008b15c..8eb5d53f3f 100644
--- a/indra/llcommon/llrefcount.h
+++ b/indra/llcommon/llrefcount.h
@@ -28,6 +28,11 @@
#include <boost/noncopyable.hpp>
+#define LL_REF_COUNT_DEBUG 0
+#if LL_REF_COUNT_DEBUG
+class LLMutex ;
+#endif
+
//----------------------------------------------------------------------------
// RefCount objects should generally only be accessed by way of LLPointer<>'s
// see llthread.h for LLThreadSafeRefCount
@@ -43,12 +48,16 @@ protected:
public:
LLRefCount();
- void ref() const
+#if LL_REF_COUNT_DEBUG
+ void ref() const ;
+ S32 unref() const ;
+#else
+ inline void ref() const
{
mRef++;
}
- S32 unref() const
+ inline S32 unref() const
{
llassert(mRef >= 1);
if (0 == --mRef)
@@ -58,6 +67,7 @@ public:
}
return mRef;
}
+#endif
//NOTE: when passing around a const LLRefCount object, this can return different results
// at different types, since mRef is mutable
@@ -68,6 +78,12 @@ public:
private:
mutable S32 mRef;
+
+#if LL_REF_COUNT_DEBUG
+ LLMutex* mMutexp ;
+ mutable U32 mLockedThreadID ;
+ mutable BOOL mCrashAtUnlock ;
+#endif
};
#endif
diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp
index 10f460e8a6..5be5ecc492 100644
--- a/indra/llcommon/llsdserialize.cpp
+++ b/indra/llcommon/llsdserialize.cpp
@@ -34,6 +34,12 @@
#include <iostream>
#include "apr_base64.h"
+#ifdef LL_STANDALONE
+# include <zlib.h>
+#else
+# include "zlib/zlib.h" // for davep's dirty little zip functions
+#endif
+
#if !LL_WINDOWS
#include <netinet/in.h> // htonl & ntohl
#endif
@@ -1983,3 +1989,180 @@ std::ostream& operator<<(std::ostream& s, const LLSD& llsd)
return s;
}
+
+//dirty little zippers -- yell at davep if these are horrid
+
+//return a string containing gzipped bytes of binary serialized LLSD
+// VERY inefficient -- creates several copies of LLSD block in memory
+std::string zip_llsd(LLSD& data)
+{
+ std::stringstream llsd_strm;
+
+ LLSDSerialize::toBinary(data, llsd_strm);
+
+ const U32 CHUNK = 65536;
+
+ z_stream strm;
+ strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
+ strm.opaque = Z_NULL;
+
+ S32 ret = deflateInit(&strm, Z_BEST_COMPRESSION);
+ if (ret != Z_OK)
+ {
+ llwarns << "Failed to compress LLSD block." << llendl;
+ return std::string();
+ }
+
+ std::string source = llsd_strm.str();
+
+ U8 out[CHUNK];
+
+ strm.avail_in = source.size();
+ strm.next_in = (U8*) source.data();
+ U8* output = NULL;
+
+ U32 cur_size = 0;
+
+ U32 have = 0;
+
+ do
+ {
+ strm.avail_out = CHUNK;
+ strm.next_out = out;
+
+ ret = deflate(&strm, Z_FINISH);
+ if (ret == Z_OK || ret == Z_STREAM_END)
+ { //copy result into output
+ if (strm.avail_out >= CHUNK)
+ {
+ llerrs << "WTF?" << llendl;
+ }
+
+ have = CHUNK-strm.avail_out;
+ output = (U8*) realloc(output, cur_size+have);
+ memcpy(output+cur_size, out, have);
+ cur_size += have;
+ }
+ else
+ {
+ free(output);
+ llwarns << "Failed to compress LLSD block." << llendl;
+ return std::string();
+ }
+ }
+ while (ret == Z_OK);
+
+ std::string::size_type size = cur_size;
+
+ std::string result((char*) output, size);
+ deflateEnd(&strm);
+ free(output);
+
+#if 0 //verify results work with unzip_llsd
+ std::istringstream test(result);
+ LLSD test_sd;
+ if (!unzip_llsd(test_sd, test, result.size()))
+ {
+ llerrs << "Invalid compression result!" << llendl;
+ }
+#endif
+
+ return result;
+}
+
+//decompress a block of LLSD from provided istream
+// not very efficient -- creats a copy of decompressed LLSD block in memory
+// and deserializes from that copy using LLSDSerialize
+bool unzip_llsd(LLSD& data, std::istream& is, S32 size)
+{
+ U8* result = NULL;
+ U32 cur_size = 0;
+ z_stream strm;
+
+ const U32 CHUNK = 65536;
+
+ U8 *in = new U8[size];
+ is.read((char*) in, size);
+
+ U8 out[CHUNK];
+
+ strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
+ strm.opaque = Z_NULL;
+ strm.avail_in = size;
+ strm.next_in = in;
+
+ S32 ret = inflateInit(&strm);
+
+ do
+ {
+ strm.avail_out = CHUNK;
+ strm.next_out = out;
+ ret = inflate(&strm, Z_NO_FLUSH);
+ if (ret == Z_STREAM_ERROR)
+ {
+ inflateEnd(&strm);
+ free(result);
+ delete [] in;
+ return false;
+ }
+
+ switch (ret)
+ {
+ case Z_NEED_DICT:
+ ret = Z_DATA_ERROR;
+ case Z_DATA_ERROR:
+ case Z_MEM_ERROR:
+ inflateEnd(&strm);
+ free(result);
+ delete [] in;
+ return false;
+ break;
+ }
+
+ U32 have = CHUNK-strm.avail_out;
+
+ result = (U8*) realloc(result, cur_size + have);
+ memcpy(result+cur_size, out, have);
+ cur_size += have;
+
+ } while (ret == Z_OK);
+
+ inflateEnd(&strm);
+ delete [] in;
+
+ if (ret != Z_STREAM_END)
+ {
+ free(result);
+ return false;
+ }
+
+ //result now points to the decompressed LLSD block
+ {
+ std::string res_str((char*) result, cur_size);
+
+ std::string deprecated_header("<? LLSD/Binary ?>");
+
+ if (res_str.substr(0, deprecated_header.size()) == deprecated_header)
+ {
+ res_str = res_str.substr(deprecated_header.size()+1, cur_size);
+ }
+ cur_size = res_str.size();
+
+ std::istringstream istr(res_str);
+
+ if (!LLSDSerialize::fromBinary(data, istr, cur_size))
+ {
+ llwarns << "Failed to unzip LLSD block" << llendl;
+ free(result);
+ return false;
+ }
+ }
+
+ free(result);
+ return true;
+}
+
+
+
diff --git a/indra/llcommon/llsdserialize.h b/indra/llcommon/llsdserialize.h
index 1f096b5254..99a3ea3cd4 100644
--- a/indra/llcommon/llsdserialize.h
+++ b/indra/llcommon/llsdserialize.h
@@ -790,4 +790,8 @@ public:
}
};
+//dirty little zip functions -- yell at davep
+LL_COMMON_API std::string zip_llsd(LLSD& data);
+LL_COMMON_API bool unzip_llsd(LLSD& data, std::istream& is, S32 size);
+
#endif // LL_LLSDSERIALIZE_H
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/llsys.cpp b/indra/llcommon/llsys.cpp
index 00c94404d4..ca2d3f9181 100644
--- a/indra/llcommon/llsys.cpp
+++ b/indra/llcommon/llsys.cpp
@@ -46,6 +46,7 @@
# include <sys/sysctl.h>
# include <sys/utsname.h>
# include <stdint.h>
+# include <Carbon/Carbon.h>
#elif LL_LINUX
# include <errno.h>
# include <sys/utsname.h>
@@ -318,7 +319,58 @@ LLOSInfo::LLOSInfo() :
}
mOSString += compatibility_mode;
+#elif LL_DARWIN
+
+ // Initialize mOSStringSimple to something like:
+ // "Mac OS X 10.6.7"
+ {
+ const char * DARWIN_PRODUCT_NAME = "Mac OS X";
+
+ SInt32 major_version, minor_version, bugfix_version;
+ OSErr r1 = Gestalt(gestaltSystemVersionMajor, &major_version);
+ OSErr r2 = Gestalt(gestaltSystemVersionMinor, &minor_version);
+ OSErr r3 = Gestalt(gestaltSystemVersionBugFix, &bugfix_version);
+
+ if((r1 == noErr) && (r2 == noErr) && (r3 == noErr))
+ {
+ mMajorVer = major_version;
+ mMinorVer = minor_version;
+ mBuild = bugfix_version;
+
+ std::stringstream os_version_string;
+ os_version_string << DARWIN_PRODUCT_NAME << " " << mMajorVer << "." << mMinorVer << "." << mBuild;
+
+ // Put it in the OS string we are compiling
+ mOSStringSimple.append(os_version_string.str());
+ }
+ else
+ {
+ mOSStringSimple.append("Unable to collect OS info");
+ }
+ }
+
+ // Initialize mOSString to something like:
+ // "Mac OS X 10.6.7 Darwin Kernel Version 10.7.0: Sat Jan 29 15:17:16 PST 2011; root:xnu-1504.9.37~1/RELEASE_I386 i386"
+ struct utsname un;
+ if(uname(&un) != -1)
+ {
+ mOSString = mOSStringSimple;
+ mOSString.append(" ");
+ mOSString.append(un.sysname);
+ mOSString.append(" ");
+ mOSString.append(un.release);
+ mOSString.append(" ");
+ mOSString.append(un.version);
+ mOSString.append(" ");
+ mOSString.append(un.machine);
+ }
+ else
+ {
+ mOSString = mOSStringSimple;
+ }
+
#else
+
struct utsname un;
if(uname(&un) != -1)
{
@@ -334,15 +386,7 @@ LLOSInfo::LLOSInfo() :
// Simplify 'Simple'
std::string ostype = mOSStringSimple.substr(0, mOSStringSimple.find_first_of(" ", 0));
- if (ostype == "Darwin")
- {
- // Only care about major Darwin versions, truncate at first '.'
- S32 idx1 = mOSStringSimple.find_first_of(".", 0);
- std::string simple = mOSStringSimple.substr(0, idx1);
- if (simple.length() > 0)
- mOSStringSimple = simple;
- }
- else if (ostype == "Linux")
+ if (ostype == "Linux")
{
// Only care about major and minor Linux versions, truncate at second '.'
std::string::size_type idx1 = mOSStringSimple.find_first_of(".", 0);
@@ -635,6 +679,26 @@ U32 LLMemoryInfo::getPhysicalMemoryClamped() const
}
}
+//static
+void LLMemoryInfo::getAvailableMemoryKB(U32& avail_physical_mem_kb, U32& avail_virtual_mem_kb)
+{
+#if LL_WINDOWS
+ MEMORYSTATUSEX state;
+ state.dwLength = sizeof(state);
+ GlobalMemoryStatusEx(&state);
+
+ avail_physical_mem_kb = (U32)(state.ullAvailPhys/1024) ;
+ avail_virtual_mem_kb = (U32)(state.ullAvailVirtual/1024) ;
+
+#else
+ //do not know how to collect available memory info for other systems.
+ //leave it blank here for now.
+
+ avail_physical_mem_kb = -1 ;
+ avail_virtual_mem_kb = -1 ;
+#endif
+}
+
void LLMemoryInfo::stream(std::ostream& s) const
{
#if LL_WINDOWS
diff --git a/indra/llcommon/llsys.h b/indra/llcommon/llsys.h
index 39af74e5c8..41a4f25000 100644
--- a/indra/llcommon/llsys.h
+++ b/indra/llcommon/llsys.h
@@ -114,6 +114,9 @@ public:
** be returned.
*/
U32 getPhysicalMemoryClamped() const; ///< Memory size in clamped bytes
+
+ //get the available memory infomation in KiloBytes.
+ static void getAvailableMemoryKB(U32& avail_physical_mem_kb, U32& avail_virtual_mem_kb);
};
diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp
index d7b7c3699c..d9400fb5b3 100644
--- a/indra/llcommon/llthread.cpp
+++ b/indra/llcommon/llthread.cpp
@@ -56,6 +56,21 @@
//
//----------------------------------------------------------------------------
+#if !LL_DARWIN
+U32 ll_thread_local sThreadID = 0;
+#endif
+
+U32 LLThread::sIDIter = 0;
+
+LL_COMMON_API void assert_main_thread()
+{
+ static U32 s_thread_id = LLThread::currentID();
+ if (LLThread::currentID() != s_thread_id)
+ {
+ llerrs << "Illegal execution outside main thread." << llendl;
+ }
+}
+
//
// Handed to the APR thread creation function
//
@@ -63,13 +78,14 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap
{
LLThread *threadp = (LLThread *)datap;
- // Set thread state to running
- threadp->mStatus = RUNNING;
+#if !LL_DARWIN
+ sThreadID = threadp->mID;
+#endif
// Run the user supplied function
threadp->run();
- llinfos << "LLThread::staticRun() Exiting: " << threadp->mName << llendl;
+ //llinfos << "LLThread::staticRun() Exiting: " << threadp->mName << llendl;
// We're done with the run function, this thread is done executing now.
threadp->mStatus = STOPPED;
@@ -84,6 +100,8 @@ LLThread::LLThread(const std::string& name, apr_pool_t *poolp) :
mAPRThreadp(NULL),
mStatus(STOPPED)
{
+ mID = ++sIDIter;
+
// Thread creation probably CAN be paranoid about APR being initialized, if necessary
if (poolp)
{
@@ -124,7 +142,7 @@ void LLThread::shutdown()
// First, set the flag that indicates that we're ready to die
setQuitting();
- llinfos << "LLThread::~LLThread() Killing thread " << mName << " Status: " << mStatus << llendl;
+ //llinfos << "LLThread::~LLThread() Killing thread " << mName << " Status: " << mStatus << llendl;
// Now wait a bit for the thread to exit
// It's unclear whether I should even bother doing this - this destructor
// should netver get called unless we're already stopped, really...
@@ -146,27 +164,46 @@ void LLThread::shutdown()
if (!isStopped())
{
// This thread just wouldn't stop, even though we gave it time
- llwarns << "LLThread::~LLThread() exiting thread before clean exit!" << llendl;
+ //llwarns << "LLThread::~LLThread() exiting thread before clean exit!" << llendl;
+ // Put a stake in its heart.
+ apr_thread_exit(mAPRThreadp, -1);
return;
}
mAPRThreadp = NULL;
}
delete mRunCondition;
+ mRunCondition = 0;
- if (mIsLocalPool)
+ if (mIsLocalPool && mAPRPoolp)
{
apr_pool_destroy(mAPRPoolp);
+ mAPRPoolp = 0;
}
}
void LLThread::start()
{
- apr_thread_create(&mAPRThreadp, NULL, staticRun, (void *)this, mAPRPoolp);
+ llassert(isStopped());
+
+ // Set thread state to running
+ mStatus = RUNNING;
- // We won't bother joining
- apr_thread_detach(mAPRThreadp);
+ apr_status_t status =
+ apr_thread_create(&mAPRThreadp, NULL, staticRun, (void *)this, mAPRPoolp);
+
+ if(status == APR_SUCCESS)
+ {
+ // We won't bother joining
+ apr_thread_detach(mAPRThreadp);
+ }
+ else
+ {
+ mStatus = STOPPED;
+ llwarns << "failed to start thread " << mName << llendl;
+ ll_apr_warn_status(status);
+ }
}
//============================================================================
@@ -267,7 +304,7 @@ void LLThread::wakeLocked()
//============================================================================
LLMutex::LLMutex(apr_pool_t *poolp) :
- mAPRMutexp(NULL)
+ mAPRMutexp(NULL), mCount(0), mLockingThread(NO_THREAD)
{
//if (poolp)
//{
@@ -299,7 +336,18 @@ LLMutex::~LLMutex()
void LLMutex::lock()
{
+#if LL_DARWIN
+ if (mLockingThread == LLThread::currentID())
+#else
+ if (mLockingThread == sThreadID)
+#endif
+ { //redundant lock
+ mCount++;
+ return;
+ }
+
apr_thread_mutex_lock(mAPRMutexp);
+
#if MUTEX_DEBUG
// Have to have the lock before we can access the debug info
U32 id = LLThread::currentID();
@@ -307,10 +355,22 @@ void LLMutex::lock()
llerrs << "Already locked in Thread: " << id << llendl;
mIsLocked[id] = TRUE;
#endif
+
+#if LL_DARWIN
+ mLockingThread = LLThread::currentID();
+#else
+ mLockingThread = sThreadID;
+#endif
}
void LLMutex::unlock()
{
+ if (mCount > 0)
+ { //not the root unlock
+ mCount--;
+ return;
+ }
+
#if MUTEX_DEBUG
// Access the debug info while we have the lock
U32 id = LLThread::currentID();
@@ -318,6 +378,8 @@ void LLMutex::unlock()
llerrs << "Not locked in Thread: " << id << llendl;
mIsLocked[id] = FALSE;
#endif
+
+ mLockingThread = NO_THREAD;
apr_thread_mutex_unlock(mAPRMutexp);
}
@@ -335,6 +397,11 @@ bool LLMutex::isLocked()
}
}
+U32 LLMutex::lockingThread() const
+{
+ return mLockingThread;
+}
+
//============================================================================
LLCondition::LLCondition(apr_pool_t *poolp) :
@@ -355,6 +422,15 @@ LLCondition::~LLCondition()
void LLCondition::wait()
{
+ if (!isLocked())
+ { //mAPRMutexp MUST be locked before calling apr_thread_cond_wait
+ apr_thread_mutex_lock(mAPRMutexp);
+#if MUTEX_DEBUG
+ // avoid asserts on destruction in non-release builds
+ U32 id = LLThread::currentID();
+ mIsLocked[id] = TRUE;
+#endif
+ }
apr_thread_cond_wait(mAPRCondp, mAPRMutexp);
}
diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h
index f1c6cd75af..40291a2569 100644
--- a/indra/llcommon/llthread.h
+++ b/indra/llcommon/llthread.h
@@ -35,8 +35,17 @@ class LLThread;
class LLMutex;
class LLCondition;
+#if LL_WINDOWS
+#define ll_thread_local __declspec(thread)
+#else
+#define ll_thread_local __thread
+#endif
+
class LL_COMMON_API LLThread
{
+private:
+ static U32 sIDIter;
+
public:
typedef enum e_thread_status
{
@@ -77,6 +86,8 @@ public:
apr_pool_t *getAPRPool() { return mAPRPoolp; }
LLVolatileAPRPool* getLocalAPRFilePool() { return mLocalAPRFilePoolp ; }
+ U32 getID() const { return mID; }
+
private:
BOOL mPaused;
@@ -91,6 +102,7 @@ protected:
apr_pool_t *mAPRPoolp;
BOOL mIsLocalPool;
EThreadStatus mStatus;
+ U32 mID;
//a local apr_pool for APRFile operations in this thread. If it exists, LLAPRFile::sAPRFilePoolp should not be used.
//Note: this pool is used by APRFile ONLY, do NOT use it for any other purposes.
@@ -128,17 +140,27 @@ protected:
class LL_COMMON_API LLMutex
{
public:
+ typedef enum
+ {
+ NO_THREAD = 0xFFFFFFFF
+ } e_locking_thread;
+
LLMutex(apr_pool_t *apr_poolp); // NULL pool constructs a new pool for the mutex
virtual ~LLMutex();
void lock(); // blocks
void unlock();
bool isLocked(); // non-blocking, but does do a lock/unlock so not free
+ U32 lockingThread() const; //get ID of locking thread
protected:
apr_thread_mutex_t *mAPRMutexp;
+ mutable U32 mCount;
+ mutable U32 mLockingThread;
+
apr_pool_t *mAPRPoolp;
BOOL mIsLocalPool;
+
#if MUTEX_DEBUG
std::map<U32, BOOL> mIsLocked;
#endif
diff --git a/indra/llcommon/llthreadsafequeue.cpp b/indra/llcommon/llthreadsafequeue.cpp
new file mode 100644
index 0000000000..8a73e632a9
--- /dev/null
+++ b/indra/llcommon/llthreadsafequeue.cpp
@@ -0,0 +1,109 @@
+/**
+ * @file llthread.cpp
+ *
+ * $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 "linden_common.h"
+#include <apr_pools.h>
+#include <apr_queue.h>
+#include "llthreadsafequeue.h"
+
+
+
+// LLThreadSafeQueueImplementation
+//-----------------------------------------------------------------------------
+
+
+LLThreadSafeQueueImplementation::LLThreadSafeQueueImplementation(apr_pool_t * pool, unsigned int capacity):
+ mOwnsPool(pool == 0),
+ mPool(pool),
+ mQueue(0)
+{
+ if(mOwnsPool) {
+ apr_status_t status = apr_pool_create(&mPool, 0);
+ if(status != APR_SUCCESS) throw LLThreadSafeQueueError("failed to allocate pool");
+ } else {
+ ; // No op.
+ }
+
+ apr_status_t status = apr_queue_create(&mQueue, capacity, mPool);
+ if(status != APR_SUCCESS) throw LLThreadSafeQueueError("failed to allocate queue");
+}
+
+
+LLThreadSafeQueueImplementation::~LLThreadSafeQueueImplementation()
+{
+ if(mQueue != 0) {
+ if(apr_queue_size(mQueue) != 0) llwarns <<
+ "terminating queue which still contains " << apr_queue_size(mQueue) <<
+ " elements;" << "memory will be leaked" << LL_ENDL;
+ apr_queue_term(mQueue);
+ }
+ if(mOwnsPool && (mPool != 0)) apr_pool_destroy(mPool);
+}
+
+
+void LLThreadSafeQueueImplementation::pushFront(void * element)
+{
+ apr_status_t status = apr_queue_push(mQueue, element);
+
+ if(status == APR_EINTR) {
+ throw LLThreadSafeQueueInterrupt();
+ } else if(status != APR_SUCCESS) {
+ throw LLThreadSafeQueueError("push failed");
+ } else {
+ ; // Success.
+ }
+}
+
+
+bool LLThreadSafeQueueImplementation::tryPushFront(void * element){
+ return apr_queue_trypush(mQueue, element) == APR_SUCCESS;
+}
+
+
+void * LLThreadSafeQueueImplementation::popBack(void)
+{
+ void * element;
+ apr_status_t status = apr_queue_pop(mQueue, &element);
+
+ if(status == APR_EINTR) {
+ throw LLThreadSafeQueueInterrupt();
+ } else if(status != APR_SUCCESS) {
+ throw LLThreadSafeQueueError("pop failed");
+ } else {
+ return element;
+ }
+}
+
+
+bool LLThreadSafeQueueImplementation::tryPopBack(void *& element)
+{
+ return apr_queue_trypop(mQueue, &element) == APR_SUCCESS;
+}
+
+
+size_t LLThreadSafeQueueImplementation::size()
+{
+ return apr_queue_size(mQueue);
+}
diff --git a/indra/llcommon/llthreadsafequeue.h b/indra/llcommon/llthreadsafequeue.h
new file mode 100644
index 0000000000..58cac38769
--- /dev/null
+++ b/indra/llcommon/llthreadsafequeue.h
@@ -0,0 +1,205 @@
+/**
+ * @file llthreadsafequeue.h
+ * @brief Base classes for thread, mutex and condition handling.
+ *
+ * $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_LLTHREADSAFEQUEUE_H
+#define LL_LLTHREADSAFEQUEUE_H
+
+
+#include <string>
+#include <stdexcept>
+
+
+struct apr_pool_t; // From apr_pools.h
+class LLThreadSafeQueueImplementation; // See below.
+
+
+//
+// A general queue exception.
+//
+class LL_COMMON_API LLThreadSafeQueueError:
+public std::runtime_error
+{
+public:
+ LLThreadSafeQueueError(std::string const & message):
+ std::runtime_error(message)
+ {
+ ; // No op.
+ }
+};
+
+
+//
+// An exception raised when blocking operations are interrupted.
+//
+class LL_COMMON_API LLThreadSafeQueueInterrupt:
+ public LLThreadSafeQueueError
+{
+public:
+ LLThreadSafeQueueInterrupt(void):
+ LLThreadSafeQueueError("queue operation interrupted")
+ {
+ ; // No op.
+ }
+};
+
+
+struct apr_queue_t; // From apr_queue.h
+
+
+//
+// Implementation details.
+//
+class LL_COMMON_API LLThreadSafeQueueImplementation
+{
+public:
+ LLThreadSafeQueueImplementation(apr_pool_t * pool, unsigned int capacity);
+ ~LLThreadSafeQueueImplementation();
+ void pushFront(void * element);
+ bool tryPushFront(void * element);
+ void * popBack(void);
+ bool tryPopBack(void *& element);
+ size_t size();
+
+private:
+ bool mOwnsPool;
+ apr_pool_t * mPool;
+ apr_queue_t * mQueue;
+};
+
+
+//
+// Implements a thread safe FIFO.
+//
+template<typename ElementT>
+class LLThreadSafeQueue
+{
+public:
+ typedef ElementT value_type;
+
+ // If the pool is set to NULL one will be allocated and managed by this
+ // queue.
+ LLThreadSafeQueue(apr_pool_t * pool = 0, unsigned int capacity = 1024);
+
+ // Add an element to the front of queue (will block if the queue has
+ // reached capacity).
+ //
+ // This call will raise an interrupt error if the queue is deleted while
+ // the caller is blocked.
+ void pushFront(ElementT const & element);
+
+ // Try to add an element to the front ofqueue without blocking. Returns
+ // true only if the element was actually added.
+ bool tryPushFront(ElementT const & element);
+
+ // Pop the element at the end of the queue (will block if the queue is
+ // empty).
+ //
+ // This call will raise an interrupt error if the queue is deleted while
+ // the caller is blocked.
+ ElementT popBack(void);
+
+ // Pop an element from the end of the queue if there is one available.
+ // Returns true only if an element was popped.
+ bool tryPopBack(ElementT & element);
+
+ // Returns the size of the queue.
+ size_t size();
+
+private:
+ LLThreadSafeQueueImplementation mImplementation;
+};
+
+
+
+// LLThreadSafeQueue
+//-----------------------------------------------------------------------------
+
+
+template<typename ElementT>
+LLThreadSafeQueue<ElementT>::LLThreadSafeQueue(apr_pool_t * pool, unsigned int capacity):
+ mImplementation(pool, capacity)
+{
+ ; // No op.
+}
+
+
+template<typename ElementT>
+void LLThreadSafeQueue<ElementT>::pushFront(ElementT const & element)
+{
+ ElementT * elementCopy = new ElementT(element);
+ try {
+ mImplementation.pushFront(elementCopy);
+ } catch (LLThreadSafeQueueInterrupt) {
+ delete elementCopy;
+ throw;
+ }
+}
+
+
+template<typename ElementT>
+bool LLThreadSafeQueue<ElementT>::tryPushFront(ElementT const & element)
+{
+ ElementT * elementCopy = new ElementT(element);
+ bool result = mImplementation.tryPushFront(elementCopy);
+ if(!result) delete elementCopy;
+ return result;
+}
+
+
+template<typename ElementT>
+ElementT LLThreadSafeQueue<ElementT>::popBack(void)
+{
+ ElementT * element = reinterpret_cast<ElementT *> (mImplementation.popBack());
+ ElementT result(*element);
+ delete element;
+ return result;
+}
+
+
+template<typename ElementT>
+bool LLThreadSafeQueue<ElementT>::tryPopBack(ElementT & element)
+{
+ void * storedElement;
+ bool result = mImplementation.tryPopBack(storedElement);
+ if(result) {
+ ElementT * elementPtr = reinterpret_cast<ElementT *>(storedElement);
+ element = *elementPtr;
+ delete elementPtr;
+ } else {
+ ; // No op.
+ }
+ return result;
+}
+
+
+template<typename ElementT>
+size_t LLThreadSafeQueue<ElementT>::size(void)
+{
+ return mImplementation.size();
+}
+
+
+#endif
diff --git a/indra/llcommon/llversionviewer.h b/indra/llcommon/llversionviewer.h
index 12bddbfeed..7703132d90 100644
--- a/indra/llcommon/llversionviewer.h
+++ b/indra/llcommon/llversionviewer.h
@@ -28,10 +28,14 @@
#define LL_LLVERSIONVIEWER_H
const S32 LL_VERSION_MAJOR = 2;
-const S32 LL_VERSION_MINOR = 3;
+const S32 LL_VERSION_MINOR = 7;
const S32 LL_VERSION_PATCH = 0;
const S32 LL_VERSION_BUILD = 0;
const char * const LL_CHANNEL = "Second Life Developer";
+#if LL_DARWIN
+const char * const LL_VERSION_BUNDLE_ID = "com.secondlife.indra.viewer";
+#endif
+
#endif
diff --git a/indra/llcommon/stdenums.h b/indra/llcommon/stdenums.h
index 9f86de124e..556eff8370 100644
--- a/indra/llcommon/stdenums.h
+++ b/indra/llcommon/stdenums.h
@@ -49,7 +49,8 @@ enum EDragAndDropType
DAD_ANIMATION = 12,
DAD_GESTURE = 13,
DAD_LINK = 14,
- DAD_COUNT = 15, // number of types in this enum
+ DAD_MESH = 15,
+ DAD_COUNT = 16, // number of types in this enum
};
// Reasons for drags to be denied.
diff --git a/indra/llcommon/tests/lldependencies_test.cpp b/indra/llcommon/tests/lldependencies_test.cpp
index e40743ccf7..5395d785b6 100644
--- a/indra/llcommon/tests/lldependencies_test.cpp
+++ b/indra/llcommon/tests/lldependencies_test.cpp
@@ -258,10 +258,10 @@ namespace tut
++const_iterator;
ensure_equals(const_iterator->first, "def");
ensure_equals(const_iterator->second, 2);
- NameIndexDeps::node_range node_range(nideps.get_node_range());
- ensure_equals(instance_from_range<std::vector<int> >(node_range), make< std::vector<int> >(list_of(1)(2)(3)));
- *node_range.begin() = 0;
- *node_range.begin() = 1;
+// NameIndexDeps::node_range node_range(nideps.get_node_range());
+// ensure_equals(instance_from_range<std::vector<int> >(node_range), make< std::vector<int> >(list_of(1)(2)(3)));
+// *node_range.begin() = 0;
+// *node_range.begin() = 1;
NameIndexDeps::const_node_range const_node_range(const_nideps.get_node_range());
ensure_equals(instance_from_range<std::vector<int> >(const_node_range), make< std::vector<int> >(list_of(1)(2)(3)));
NameIndexDeps::const_key_range const_key_range(const_nideps.get_key_range());
@@ -278,8 +278,8 @@ namespace tut
def);
ensure_equals(instance_from_range<StringList>(const_nideps.get_after_range(const_nideps.get_range().begin())),
def);
- ensure_equals(instance_from_range<StringList>(nideps.get_after_range(nideps.get_node_range().begin())),
- def);
+// ensure_equals(instance_from_range<StringList>(nideps.get_after_range(nideps.get_node_range().begin())),
+// def);
ensure_equals(instance_from_range<StringList>(const_nideps.get_after_range(const_nideps.get_node_range().begin())),
def);
ensure_equals(instance_from_range<StringList>(nideps.get_after_range(nideps.get_key_range().begin())),
diff --git a/indra/llcommon/tests/llerror_test.cpp b/indra/llcommon/tests/llerror_test.cpp
index 1ef8fc9712..09a20231de 100644
--- a/indra/llcommon/tests/llerror_test.cpp
+++ b/indra/llcommon/tests/llerror_test.cpp
@@ -48,7 +48,10 @@ namespace
{
static bool fatalWasCalled;
void fatalCall(const std::string&) { fatalWasCalled = true; }
+}
+namespace tut
+{
class TestRecorder : public LLError::Recorder
{
public:
@@ -56,7 +59,7 @@ namespace
~TestRecorder() { LLError::removeRecorder(this); }
void recordMessage(LLError::ELevel level,
- const std::string& message)
+ const std::string& message)
{
mMessages.push_back(message);
}
@@ -66,12 +69,12 @@ namespace
void setWantsTime(bool t) { mWantsTime = t; }
bool wantsTime() { return mWantsTime; }
-
+
std::string message(int n)
{
std::ostringstream test_name;
test_name << "testing message " << n << ", not enough messages";
-
+
tut::ensure(test_name.str(), n < countMessages());
return mMessages[n];
}
@@ -82,10 +85,7 @@ namespace
bool mWantsTime;
};
-}
-
-namespace tut
-{
+
struct ErrorTestData
{
TestRecorder mRecorder;
@@ -381,7 +381,7 @@ namespace
}
typedef std::string (*LogFromFunction)(bool);
- void testLogName(TestRecorder& recorder, LogFromFunction f,
+ void testLogName(tut::TestRecorder& recorder, LogFromFunction f,
const std::string& class_name = "")
{
recorder.clearMessages();
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/llcommon/tests/llsdserialize_test.cpp b/indra/llcommon/tests/llsdserialize_test.cpp
index 770443da1d..7b4c7d6a48 100644
--- a/indra/llcommon/tests/llsdserialize_test.cpp
+++ b/indra/llcommon/tests/llsdserialize_test.cpp
@@ -452,7 +452,7 @@ namespace tut
checkRoundTrip(msg + " nested arrays", v);
v = LLSD::emptyMap();
- fillmap(v, 10, 6); // 10^6 maps
+ fillmap(v, 10, 3); // 10^6 maps
checkRoundTrip(msg + " many nested maps", v);
}
diff --git a/indra/llimage/CMakeLists.txt b/indra/llimage/CMakeLists.txt
index a69621a57b..ea8c1a1107 100644
--- a/indra/llimage/CMakeLists.txt
+++ b/indra/llimage/CMakeLists.txt
@@ -3,12 +3,13 @@
project(llimage)
include(00-Common)
-include(LLAddBuildTest)
include(LLCommon)
include(LLImage)
include(LLMath)
include(LLVFS)
include(ZLIB)
+include(LLAddBuildTest)
+include(Tut)
include_directories(
${LLCOMMON_INCLUDE_DIRS}
@@ -57,11 +58,18 @@ add_library (llimage ${llimage_SOURCE_FILES})
# Sort by high-level to low-level
target_link_libraries(llimage
llcommon
- llimagej2coj # *HACK: In theory a noop for KDU builds?
${JPEG_LIBRARIES}
${PNG_LIBRARIES}
${ZLIB_LIBRARIES}
)
# Add tests
-#ADD_BUILD_TEST(llimageworker llimage)
+if (LL_TESTS)
+ SET(llimage_TEST_SOURCE_FILES
+ llimageworker.cpp
+ )
+ LL_ADD_PROJECT_UNIT_TESTS(llimage "${llimage_TEST_SOURCE_FILES}")
+endif (LL_TESTS)
+
+
+
diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp
index 5c33b675ca..f0d15d9607 100644
--- a/indra/llimage/llimage.cpp
+++ b/indra/llimage/llimage.cpp
@@ -52,13 +52,11 @@ LLMutex* LLImage::sMutex = NULL;
void LLImage::initClass()
{
sMutex = new LLMutex(NULL);
- LLImageJ2C::openDSO();
}
//static
void LLImage::cleanupClass()
{
- LLImageJ2C::closeDSO();
delete sMutex;
sMutex = NULL;
}
@@ -276,11 +274,11 @@ LLImageRaw::LLImageRaw(U8 *data, U16 width, U16 height, S8 components)
++sRawImageCount;
}
-LLImageRaw::LLImageRaw(const std::string& filename, bool j2c_lowest_mip_only)
- : LLImageBase()
-{
- createFromFile(filename, j2c_lowest_mip_only);
-}
+//LLImageRaw::LLImageRaw(const std::string& filename, bool j2c_lowest_mip_only)
+// : LLImageBase()
+//{
+// createFromFile(filename, j2c_lowest_mip_only);
+//}
LLImageRaw::~LLImageRaw()
{
@@ -1180,7 +1178,7 @@ file_extensions[] =
{ "png", IMG_CODEC_PNG }
};
#define NUM_FILE_EXTENSIONS LL_ARRAY_SIZE(file_extensions)
-
+#if 0
static std::string find_file(std::string &name, S8 *codec)
{
std::string tname;
@@ -1198,7 +1196,7 @@ static std::string find_file(std::string &name, S8 *codec)
}
return std::string("");
}
-
+#endif
EImageCodec LLImageBase::getCodecFromExtension(const std::string& exten)
{
for (int i=0; i<(int)(NUM_FILE_EXTENSIONS); i++)
@@ -1208,7 +1206,7 @@ EImageCodec LLImageBase::getCodecFromExtension(const std::string& exten)
}
return IMG_CODEC_INVALID;
}
-
+#if 0
bool LLImageRaw::createFromFile(const std::string &filename, bool j2c_lowest_mip_only)
{
std::string name = filename;
@@ -1256,28 +1254,7 @@ bool LLImageRaw::createFromFile(const std::string &filename, bool j2c_lowest_mip
return false;
}
- LLPointer<LLImageFormatted> image;
- switch(codec)
- {
- //case IMG_CODEC_RGB:
- case IMG_CODEC_BMP:
- image = new LLImageBMP();
- break;
- case IMG_CODEC_TGA:
- image = new LLImageTGA();
- break;
- case IMG_CODEC_JPEG:
- image = new LLImageJPEG();
- break;
- case IMG_CODEC_J2C:
- image = new LLImageJ2C();
- break;
- case IMG_CODEC_DXT:
- image = new LLImageDXT();
- break;
- default:
- return false;
- }
+ LLPointer<LLImageFormatted> image = LLImageFormatted::createFromType(codec);
llassert(image.notNull());
U8 *buffer = image->allocateData(length);
@@ -1315,7 +1292,7 @@ bool LLImageRaw::createFromFile(const std::string &filename, bool j2c_lowest_mip
return true;
}
-
+#endif
//---------------------------------------------------------------------------
// LLImageFormatted
//---------------------------------------------------------------------------
diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h
index bca7e915fa..c464c3b2b6 100644
--- a/indra/llimage/llimage.h
+++ b/indra/llimage/llimage.h
@@ -35,8 +35,21 @@
const S32 MIN_IMAGE_MIP = 2; // 4x4, only used for expand/contract power of 2
const S32 MAX_IMAGE_MIP = 11; // 2048x2048
+
+// *TODO : Use MAX_IMAGE_MIP as max discard level and modify j2c management so that the number
+// of levels is read from the header's file, not inferred from its size.
const S32 MAX_DISCARD_LEVEL = 5;
+// JPEG2000 size constraints
+// Those are declared here as they are germane to other image constraints used in the viewer
+// and declared right here. Some come from the JPEG2000 spec, some conventions specific to SL.
+const S32 MAX_DECOMPOSITION_LEVELS = 32; // Number of decomposition levels cannot exceed 32 according to jpeg2000 spec
+const S32 MIN_DECOMPOSITION_LEVELS = 5; // the SL viewer will *crash* trying to decode images with fewer than 5 decomposition levels (unless image is small that is)
+const S32 MAX_PRECINCT_SIZE = 2048; // No reason to be bigger than MAX_IMAGE_SIZE
+const S32 MIN_PRECINCT_SIZE = 4; // Can't be smaller than MIN_BLOCK_SIZE
+const S32 MAX_BLOCK_SIZE = 64; // Max total block size is 4096, hence 64x64 when using square blocks
+const S32 MIN_BLOCK_SIZE = 4; // Min block dim is 4 according to jpeg2000 spec
+
const S32 MIN_IMAGE_SIZE = (1<<MIN_IMAGE_MIP); // 4, only used for expand/contract power of 2
const S32 MAX_IMAGE_SIZE = (1<<MAX_IMAGE_MIP); // 2048
const S32 MIN_IMAGE_AREA = MIN_IMAGE_SIZE * MIN_IMAGE_SIZE;
@@ -164,7 +177,7 @@ public:
LLImageRaw(U16 width, U16 height, S8 components);
LLImageRaw(U8 *data, U16 width, U16 height, S8 components);
// Construct using createFromFile (used by tools)
- LLImageRaw(const std::string& filename, bool j2c_lowest_mip_only = false);
+ //LLImageRaw(const std::string& filename, bool j2c_lowest_mip_only = false);
/*virtual*/ void deleteData();
/*virtual*/ U8* allocateData(S32 size = -1);
@@ -226,7 +239,7 @@ public:
protected:
// Create an image from a local file (generally used in tools)
- bool createFromFile(const std::string& filename, bool j2c_lowest_mip_only = false);
+ //bool createFromFile(const std::string& filename, bool j2c_lowest_mip_only = false);
void copyLineScaled( U8* in, U8* out, S32 in_pixel_len, S32 out_pixel_len, S32 in_pixel_step, S32 out_pixel_step );
void compositeRowScaled4onto3( U8* in, U8* out, S32 in_pixel_len, S32 out_pixel_len );
@@ -266,13 +279,13 @@ public:
// subclasses must return a prefered file extension (lowercase without a leading dot)
virtual std::string getExtension() = 0;
// calcHeaderSize() returns the maximum size of header;
- // 0 indicates we don't know have a header and have to lead the entire file
+ // 0 indicates we don't have a header and have to read the entire file
virtual S32 calcHeaderSize() { return 0; };
// calcDataSize() returns how many bytes to read to load discard_level (including header)
virtual S32 calcDataSize(S32 discard_level);
// calcDiscardLevelBytes() returns the smallest valid discard level based on the number of input bytes
virtual S32 calcDiscardLevelBytes(S32 bytes);
- // getRawDiscardLevel()by default returns mDiscardLevel, but may be overridden (LLImageJ2C)
+ // getRawDiscardLevel() by default returns mDiscardLevel, but may be overridden (LLImageJ2C)
virtual S8 getRawDiscardLevel() { return mDiscardLevel; }
BOOL load(const std::string& filename);
diff --git a/indra/llimage/llimagedimensionsinfo.cpp b/indra/llimage/llimagedimensionsinfo.cpp
index 5ea4a236b5..c6bfa50b40 100644
--- a/indra/llimage/llimagedimensionsinfo.cpp
+++ b/indra/llimage/llimagedimensionsinfo.cpp
@@ -30,6 +30,9 @@
#include "llimagedimensionsinfo.h"
+// Value is true if one of Libjpeg's functions has encountered an error while working.
+static bool sJpegErrorEncountered = false;
+
bool LLImageDimensionsInfo::load(const std::string& src_filename,U32 codec)
{
clean();
@@ -70,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();
@@ -83,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;
@@ -92,18 +122,46 @@ 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;
+ }
+
+ // 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);
- mInfile.seek(APR_CUR,PNG_FILE_MARKER_SIZE + 8/*header offset+chunk length+chunk type*/);
+ // 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();
return true;
}
+// Called instead of exit() if Libjpeg encounters an error.
+void on_jpeg_error(j_common_ptr cinfo)
+{
+ (void) cinfo;
+ sJpegErrorEncountered = true;
+ llwarns << "Libjpeg has encountered an error!" << llendl;
+}
bool LLImageDimensionsInfo::getImageDimensionsJpeg()
{
+ sJpegErrorEncountered = false;
clean();
FILE *fp = fopen (mSrcFilename.c_str(), "rb");
if (fp == NULL)
@@ -111,10 +169,31 @@ 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;
cinfo.err = jpeg_std_error(&jerr);
+ // Call our function instead of exit() if Libjpeg encounters an error.
+ // This is done to avoid crash in this case (STORM-472).
+ cinfo.err->error_exit = on_jpeg_error;
jpeg_create_decompress (&cinfo);
jpeg_stdio_src (&cinfo, fp);
@@ -128,6 +207,16 @@ bool LLImageDimensionsInfo::getImageDimensionsJpeg()
jpeg_destroy_decompress(&cinfo);
fclose(fp);
- return true;
+ 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/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp
index c8c866b7f2..44e6b89dd3 100644
--- a/indra/llimage/llimagej2c.cpp
+++ b/indra/llimage/llimagej2c.cpp
@@ -24,148 +24,32 @@
*/
#include "linden_common.h"
-#include "apr_pools.h"
-#include "apr_dso.h"
-
#include "lldir.h"
#include "llimagej2c.h"
#include "llmemtype.h"
+#include "lltimer.h"
+#include "llmath.h"
typedef LLImageJ2CImpl* (*CreateLLImageJ2CFunction)();
typedef void (*DestroyLLImageJ2CFunction)(LLImageJ2CImpl*);
typedef const char* (*EngineInfoLLImageJ2CFunction)();
-//some "private static" variables so we only attempt to load
-//dynamic libaries once
-CreateLLImageJ2CFunction j2cimpl_create_func;
-DestroyLLImageJ2CFunction j2cimpl_destroy_func;
-EngineInfoLLImageJ2CFunction j2cimpl_engineinfo_func;
-apr_pool_t *j2cimpl_dso_memory_pool;
-apr_dso_handle_t *j2cimpl_dso_handle;
-
-//Declare the prototype for theses functions here, their functionality
-//will be implemented in other files which define a derived LLImageJ2CImpl
-//but only ONE static library which has the implementation for this
-//function should ever be included
+// Declare the prototype for theses functions here. Their functionality
+// will be implemented in other files which define a derived LLImageJ2CImpl
+// but only ONE static library which has the implementation for these
+// functions should ever be included.
LLImageJ2CImpl* fallbackCreateLLImageJ2CImpl();
void fallbackDestroyLLImageJ2CImpl(LLImageJ2CImpl* impl);
const char* fallbackEngineInfoLLImageJ2CImpl();
-//static
-//Loads the required "create", "destroy" and "engineinfo" functions needed
-void LLImageJ2C::openDSO()
-{
- //attempt to load a DSO and get some functions from it
- std::string dso_name;
- std::string dso_path;
-
- bool all_functions_loaded = false;
- apr_status_t rv;
-
-#if LL_WINDOWS
- dso_name = "llkdu.dll";
-#elif LL_DARWIN
- dso_name = "libllkdu.dylib";
-#else
- dso_name = "libllkdu.so";
-#endif
-
- dso_path = gDirUtilp->findFile(dso_name,
- gDirUtilp->getAppRODataDir(),
- gDirUtilp->getExecutableDir());
-
- j2cimpl_dso_handle = NULL;
- j2cimpl_dso_memory_pool = NULL;
-
- //attempt to load the shared library
- apr_pool_create(&j2cimpl_dso_memory_pool, NULL);
- rv = apr_dso_load(&j2cimpl_dso_handle,
- dso_path.c_str(),
- j2cimpl_dso_memory_pool);
-
- //now, check for success
- if ( rv == APR_SUCCESS )
- {
- //found the dynamic library
- //now we want to load the functions we're interested in
- CreateLLImageJ2CFunction create_func = NULL;
- DestroyLLImageJ2CFunction dest_func = NULL;
- EngineInfoLLImageJ2CFunction engineinfo_func = NULL;
-
- rv = apr_dso_sym((apr_dso_handle_sym_t*)&create_func,
- j2cimpl_dso_handle,
- "createLLImageJ2CKDU");
- if ( rv == APR_SUCCESS )
- {
- //we've loaded the create function ok
- //we need to delete via the DSO too
- //so lets check for a destruction function
- rv = apr_dso_sym((apr_dso_handle_sym_t*)&dest_func,
- j2cimpl_dso_handle,
- "destroyLLImageJ2CKDU");
- if ( rv == APR_SUCCESS )
- {
- //we've loaded the destroy function ok
- rv = apr_dso_sym((apr_dso_handle_sym_t*)&engineinfo_func,
- j2cimpl_dso_handle,
- "engineInfoLLImageJ2CKDU");
- if ( rv == APR_SUCCESS )
- {
- //ok, everything is loaded alright
- j2cimpl_create_func = create_func;
- j2cimpl_destroy_func = dest_func;
- j2cimpl_engineinfo_func = engineinfo_func;
- all_functions_loaded = true;
- }
- }
- }
- }
-
- if ( !all_functions_loaded )
- {
- //something went wrong with the DSO or function loading..
- //fall back onto our satefy impl creation function
-
-#if 0
- // precious verbose debugging, sadly we can't use our
- // 'llinfos' stream etc. this early in the initialisation seq.
- char errbuf[256];
- fprintf(stderr, "failed to load syms from DSO %s (%s)\n",
- dso_name.c_str(), dso_path.c_str());
- apr_strerror(rv, errbuf, sizeof(errbuf));
- fprintf(stderr, "error: %d, %s\n", rv, errbuf);
- apr_dso_error(j2cimpl_dso_handle, errbuf, sizeof(errbuf));
- fprintf(stderr, "dso-error: %d, %s\n", rv, errbuf);
-#endif
-
- if ( j2cimpl_dso_handle )
- {
- apr_dso_unload(j2cimpl_dso_handle);
- j2cimpl_dso_handle = NULL;
- }
-
- if ( j2cimpl_dso_memory_pool )
- {
- apr_pool_destroy(j2cimpl_dso_memory_pool);
- j2cimpl_dso_memory_pool = NULL;
- }
- }
-}
-
-//static
-void LLImageJ2C::closeDSO()
-{
- if ( j2cimpl_dso_handle ) apr_dso_unload(j2cimpl_dso_handle);
- if (j2cimpl_dso_memory_pool) apr_pool_destroy(j2cimpl_dso_memory_pool);
-}
+// Test data gathering handle
+LLImageCompressionTester* LLImageJ2C::sTesterp = NULL ;
+const std::string sTesterName("ImageCompressionTester");
//static
std::string LLImageJ2C::getEngineInfo()
{
- if (!j2cimpl_engineinfo_func)
- j2cimpl_engineinfo_func = fallbackEngineInfoLLImageJ2CImpl;
-
- return j2cimpl_engineinfo_func();
+ return fallbackEngineInfoLLImageJ2CImpl();
}
LLImageJ2C::LLImageJ2C() : LLImageFormatted(IMG_CODEC_J2C),
@@ -175,47 +59,32 @@ LLImageJ2C::LLImageJ2C() : LLImageFormatted(IMG_CODEC_J2C),
mReversible(FALSE),
mAreaUsedForDataSizeCalcs(0)
{
- //We assume here that if we wanted to create via
- //a dynamic library that the approriate open calls were made
- //before any calls to this constructor.
-
- //Therefore, a NULL creation function pointer here means
- //we either did not want to create using functions from the dynamic
- //library or there were issues loading it, either way
- //use our fall back
- if ( !j2cimpl_create_func )
- {
- j2cimpl_create_func = fallbackCreateLLImageJ2CImpl;
- }
-
- mImpl = j2cimpl_create_func();
+ mImpl = fallbackCreateLLImageJ2CImpl();
// Clear data size table
for( S32 i = 0; i <= MAX_DISCARD_LEVEL; i++)
{ // Array size is MAX_DISCARD_LEVEL+1
mDataSizes[i] = 0;
}
+
+ // If that test log has ben requested but not yet created, create it
+ if (LLMetricPerformanceTesterBasic::isMetricLogRequested(sTesterName) && !LLMetricPerformanceTesterBasic::getTester(sTesterName))
+ {
+ sTesterp = new LLImageCompressionTester() ;
+ if (!sTesterp->isValid())
+ {
+ delete sTesterp;
+ sTesterp = NULL;
+ }
+ }
}
// virtual
LLImageJ2C::~LLImageJ2C()
{
- //We assume here that if we wanted to destroy via
- //a dynamic library that the approriate open calls were made
- //before any calls to this destructor.
-
- //Therefore, a NULL creation function pointer here means
- //we either did not want to destroy using functions from the dynamic
- //library or there were issues loading it, either way
- //use our fall back
- if ( !j2cimpl_destroy_func )
- {
- j2cimpl_destroy_func = fallbackDestroyLLImageJ2CImpl;
- }
-
if ( mImpl )
{
- j2cimpl_destroy_func(mImpl);
+ fallbackDestroyLLImageJ2CImpl(mImpl);
}
}
@@ -270,6 +139,15 @@ BOOL LLImageJ2C::updateData()
return res;
}
+BOOL LLImageJ2C::initDecode(LLImageRaw &raw_image, int discard_level, int* region)
+{
+ return mImpl->initDecode(*this,raw_image,discard_level,region);
+}
+
+BOOL LLImageJ2C::initEncode(LLImageRaw &raw_image, int blocks_size, int precincts_size, int levels)
+{
+ return mImpl->initEncode(*this,raw_image,blocks_size,precincts_size,levels);
+}
BOOL LLImageJ2C::decode(LLImageRaw *raw_imagep, F32 decode_time)
{
@@ -280,6 +158,7 @@ BOOL LLImageJ2C::decode(LLImageRaw *raw_imagep, F32 decode_time)
// Returns TRUE to mean done, whether successful or not.
BOOL LLImageJ2C::decodeChannels(LLImageRaw *raw_imagep, F32 decode_time, S32 first_channel, S32 max_channel_count )
{
+ LLTimer elapsed;
LLMemType mt1(mMemType);
BOOL res = TRUE;
@@ -318,6 +197,21 @@ BOOL LLImageJ2C::decodeChannels(LLImageRaw *raw_imagep, F32 decode_time, S32 fir
LLImage::setLastError(mLastError);
}
+ LLImageCompressionTester* tester = (LLImageCompressionTester*)LLMetricPerformanceTesterBasic::getTester(sTesterName);
+ if (tester)
+ {
+ // Decompression stat gathering
+ // Note that we *do not* take into account the decompression failures data so we might overestimate the time spent processing
+
+ // Always add the decompression time to the stat
+ tester->updateDecompressionStats(elapsed.getElapsedTimeF32()) ;
+ if (res)
+ {
+ // The whole data stream is finally decompressed when res is returned as TRUE
+ tester->updateDecompressionStats(this->getDataSize(), raw_imagep->getDataSize()) ;
+ }
+ }
+
return res;
}
@@ -330,6 +224,7 @@ BOOL LLImageJ2C::encode(const LLImageRaw *raw_imagep, F32 encode_time)
BOOL LLImageJ2C::encode(const LLImageRaw *raw_imagep, const char* comment_text, F32 encode_time)
{
+ LLTimer elapsed;
LLMemType mt1(mMemType);
resetLastError();
BOOL res = mImpl->encodeImpl(*this, *raw_imagep, comment_text, encode_time, mReversible);
@@ -337,6 +232,22 @@ BOOL LLImageJ2C::encode(const LLImageRaw *raw_imagep, const char* comment_text,
{
LLImage::setLastError(mLastError);
}
+
+ LLImageCompressionTester* tester = (LLImageCompressionTester*)LLMetricPerformanceTesterBasic::getTester(sTesterName);
+ if (tester)
+ {
+ // Compression stat gathering
+ // Note that we *do not* take into account the compression failures cases so we night overestimate the time spent processing
+
+ // Always add the compression time to the stat
+ tester->updateCompressionStats(elapsed.getElapsedTimeF32()) ;
+ if (res)
+ {
+ // The whole data stream is finally compressed when res is returned as TRUE
+ tester->updateCompressionStats(this->getDataSize(), raw_imagep->getDataSize()) ;
+ }
+ }
+
return res;
}
@@ -349,6 +260,9 @@ S32 LLImageJ2C::calcHeaderSizeJ2C()
//static
S32 LLImageJ2C::calcDataSizeJ2C(S32 w, S32 h, S32 comp, S32 discard_level, F32 rate)
{
+ // Note: this only provides an *estimate* of the size in bytes of an image level
+ // *TODO: find a way to read the true size (when available) and convey the fact
+ // that the result is an estimate in the other cases
if (rate <= 0.f) rate = .125f;
while (discard_level > 0)
{
@@ -540,3 +454,126 @@ void LLImageJ2C::updateRawDiscardLevel()
LLImageJ2CImpl::~LLImageJ2CImpl()
{
}
+
+//----------------------------------------------------------------------------------------------
+// Start of LLImageCompressionTester
+//----------------------------------------------------------------------------------------------
+LLImageCompressionTester::LLImageCompressionTester() : LLMetricPerformanceTesterBasic(sTesterName)
+{
+ addMetric("Time Decompression (s)");
+ addMetric("Volume In Decompression (kB)");
+ addMetric("Volume Out Decompression (kB)");
+ addMetric("Decompression Ratio (x:1)");
+ addMetric("Perf Decompression (kB/s)");
+
+ addMetric("Time Compression (s)");
+ addMetric("Volume In Compression (kB)");
+ addMetric("Volume Out Compression (kB)");
+ addMetric("Compression Ratio (x:1)");
+ addMetric("Perf Compression (kB/s)");
+
+ mRunBytesInDecompression = 0;
+ mRunBytesInCompression = 0;
+
+ mTotalBytesInDecompression = 0;
+ mTotalBytesOutDecompression = 0;
+ mTotalBytesInCompression = 0;
+ mTotalBytesOutCompression = 0;
+
+ mTotalTimeDecompression = 0.0f;
+ mTotalTimeCompression = 0.0f;
+}
+
+LLImageCompressionTester::~LLImageCompressionTester()
+{
+ outputTestResults();
+ LLImageJ2C::sTesterp = NULL;
+}
+
+//virtual
+void LLImageCompressionTester::outputTestRecord(LLSD *sd)
+{
+ std::string currentLabel = getCurrentLabelName();
+
+ F32 decompressionPerf = 0.0f;
+ F32 compressionPerf = 0.0f;
+ F32 decompressionRate = 0.0f;
+ F32 compressionRate = 0.0f;
+
+ F32 totalkBInDecompression = (F32)(mTotalBytesInDecompression) / 1000.0;
+ F32 totalkBOutDecompression = (F32)(mTotalBytesOutDecompression) / 1000.0;
+ F32 totalkBInCompression = (F32)(mTotalBytesInCompression) / 1000.0;
+ F32 totalkBOutCompression = (F32)(mTotalBytesOutCompression) / 1000.0;
+
+ if (!is_approx_zero(mTotalTimeDecompression))
+ {
+ decompressionPerf = totalkBInDecompression / mTotalTimeDecompression;
+ }
+ if (!is_approx_zero(totalkBInDecompression))
+ {
+ decompressionRate = totalkBOutDecompression / totalkBInDecompression;
+ }
+ if (!is_approx_zero(mTotalTimeCompression))
+ {
+ compressionPerf = totalkBInCompression / mTotalTimeCompression;
+ }
+ if (!is_approx_zero(totalkBOutCompression))
+ {
+ compressionRate = totalkBInCompression / totalkBOutCompression;
+ }
+
+ (*sd)[currentLabel]["Time Decompression (s)"] = (LLSD::Real)mTotalTimeDecompression;
+ (*sd)[currentLabel]["Volume In Decompression (kB)"] = (LLSD::Real)totalkBInDecompression;
+ (*sd)[currentLabel]["Volume Out Decompression (kB)"]= (LLSD::Real)totalkBOutDecompression;
+ (*sd)[currentLabel]["Decompression Ratio (x:1)"] = (LLSD::Real)decompressionRate;
+ (*sd)[currentLabel]["Perf Decompression (kB/s)"] = (LLSD::Real)decompressionPerf;
+
+ (*sd)[currentLabel]["Time Compression (s)"] = (LLSD::Real)mTotalTimeCompression;
+ (*sd)[currentLabel]["Volume In Compression (kB)"] = (LLSD::Real)totalkBInCompression;
+ (*sd)[currentLabel]["Volume Out Compression (kB)"] = (LLSD::Real)totalkBOutCompression;
+ (*sd)[currentLabel]["Compression Ratio (x:1)"] = (LLSD::Real)compressionRate;
+ (*sd)[currentLabel]["Perf Compression (kB/s)"] = (LLSD::Real)compressionPerf;
+}
+
+void LLImageCompressionTester::updateCompressionStats(const F32 deltaTime)
+{
+ mTotalTimeCompression += deltaTime;
+}
+
+void LLImageCompressionTester::updateCompressionStats(const S32 bytesCompress, const S32 bytesRaw)
+{
+ mTotalBytesInCompression += bytesRaw;
+ mRunBytesInCompression += bytesRaw;
+ mTotalBytesOutCompression += bytesCompress;
+ if (mRunBytesInCompression > (1000000))
+ {
+ // Output everything
+ outputTestResults();
+ // Reset the compression data of the run
+ mRunBytesInCompression = 0;
+ }
+}
+
+void LLImageCompressionTester::updateDecompressionStats(const F32 deltaTime)
+{
+ mTotalTimeDecompression += deltaTime;
+}
+
+void LLImageCompressionTester::updateDecompressionStats(const S32 bytesIn, const S32 bytesOut)
+{
+ mTotalBytesInDecompression += bytesIn;
+ mRunBytesInDecompression += bytesIn;
+ mTotalBytesOutDecompression += bytesOut;
+ if (mRunBytesInDecompression > (1000000))
+ {
+ // Output everything
+ outputTestResults();
+ // Reset the decompression data of the run
+ mRunBytesInDecompression = 0;
+ }
+}
+
+//----------------------------------------------------------------------------------------------
+// End of LLTexturePipelineTester
+//----------------------------------------------------------------------------------------------
+
diff --git a/indra/llimage/llimagej2c.h b/indra/llimage/llimagej2c.h
index cdb3faa207..914174fc57 100644
--- a/indra/llimage/llimagej2c.h
+++ b/indra/llimage/llimagej2c.h
@@ -29,8 +29,11 @@
#include "llimage.h"
#include "llassettype.h"
+#include "llmetricperformancetester.h"
class LLImageJ2CImpl;
+class LLImageCompressionTester ;
+
class LLImageJ2C : public LLImageFormatted
{
protected:
@@ -53,6 +56,8 @@ public:
/*virtual*/ void resetLastError();
/*virtual*/ void setLastError(const std::string& message, const std::string& filename = std::string());
+ BOOL initDecode(LLImageRaw &raw_image, int discard_level, int* region);
+ BOOL initEncode(LLImageRaw &raw_image, int blocks_size, int precincts_size, int levels);
// Encode with comment text
BOOL encode(const LLImageRaw *raw_imagep, const char* comment_text, F32 encode_time=0.0);
@@ -69,14 +74,13 @@ public:
static S32 calcHeaderSizeJ2C();
static S32 calcDataSizeJ2C(S32 w, S32 h, S32 comp, S32 discard_level, F32 rate = 0.f);
- static void openDSO();
- static void closeDSO();
static std::string getEngineInfo();
-
+
protected:
friend class LLImageJ2CImpl;
friend class LLImageJ2COJ;
friend class LLImageJ2CKDU;
+ friend class LLImageCompressionTester;
void decodeFailed();
void updateRawDiscardLevel();
@@ -90,6 +94,9 @@ protected:
BOOL mReversible;
LLImageJ2CImpl *mImpl;
std::string mLastError;
+
+ // Image compression/decompression tester
+ static LLImageCompressionTester* sTesterp;
};
// Derive from this class to implement JPEG2000 decoding
@@ -112,10 +119,48 @@ protected:
virtual BOOL decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count) = 0;
virtual BOOL encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text, F32 encode_time=0.0,
BOOL reversible=FALSE) = 0;
+ virtual BOOL initDecode(LLImageJ2C &base, LLImageRaw &raw_image, int discard_level = -1, int* region = NULL) = 0;
+ virtual BOOL initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int blocks_size = -1, int precincts_size = -1, int levels = 0) = 0;
friend class LLImageJ2C;
};
#define LINDEN_J2C_COMMENT_PREFIX "LL_"
+//
+// This class is used for performance data gathering only.
+// Tracks the image compression / decompression data,
+// records and outputs them to the log file.
+//
+class LLImageCompressionTester : public LLMetricPerformanceTesterBasic
+{
+ public:
+ LLImageCompressionTester();
+ ~LLImageCompressionTester();
+
+ void updateDecompressionStats(const F32 deltaTime) ;
+ void updateDecompressionStats(const S32 bytesIn, const S32 bytesOut) ;
+ void updateCompressionStats(const F32 deltaTime) ;
+ void updateCompressionStats(const S32 bytesIn, const S32 bytesOut) ;
+
+ protected:
+ /*virtual*/ void outputTestRecord(LLSD* sd);
+
+ private:
+ //
+ // Data size
+ //
+ U32 mTotalBytesInDecompression; // Total bytes fed to decompressor
+ U32 mTotalBytesOutDecompression; // Total bytes produced by decompressor
+ U32 mTotalBytesInCompression; // Total bytes fed to compressor
+ U32 mTotalBytesOutCompression; // Total bytes produced by compressor
+ U32 mRunBytesInDecompression; // Bytes fed to decompressor in this run
+ U32 mRunBytesInCompression; // Bytes fed to compressor in this run
+ //
+ // Time
+ //
+ F32 mTotalTimeDecompression; // Total time spent in computing decompression
+ F32 mTotalTimeCompression; // Total time spent in computing compression
+ };
+
#endif
diff --git a/indra/llimage/llimageworker.cpp b/indra/llimage/llimageworker.cpp
index d1c74b6fa1..28dc3bd313 100644
--- a/indra/llimage/llimageworker.cpp
+++ b/indra/llimage/llimageworker.cpp
@@ -38,6 +38,12 @@ LLImageDecodeThread::LLImageDecodeThread(bool threaded)
mCreationMutex = new LLMutex(getAPRPool());
}
+//virtual
+LLImageDecodeThread::~LLImageDecodeThread()
+{
+ delete mCreationMutex ;
+}
+
// MAIN THREAD
// virtual
S32 LLImageDecodeThread::update(U32 max_time_ms)
diff --git a/indra/llimage/llimageworker.h b/indra/llimage/llimageworker.h
index c3c92ec832..c684222fa5 100644
--- a/indra/llimage/llimageworker.h
+++ b/indra/llimage/llimageworker.h
@@ -73,6 +73,8 @@ public:
public:
LLImageDecodeThread(bool threaded = true);
+ virtual ~LLImageDecodeThread();
+
handle_t decodeImage(LLImageFormatted* image,
U32 priority, S32 discard, BOOL needs_aux,
Responder* responder);
diff --git a/indra/llimage/llpngwrapper.cpp b/indra/llimage/llpngwrapper.cpp
index fe737e2072..2cc7d3c460 100644
--- a/indra/llimage/llpngwrapper.cpp
+++ b/indra/llimage/llpngwrapper.cpp
@@ -50,8 +50,6 @@ LLPngWrapper::LLPngWrapper()
mCompressionType( 0 ),
mFilterMethod( 0 ),
mFinalSize( 0 ),
- mHasBKGD(false),
- mBackgroundColor(),
mGamma(0.f)
{
}
@@ -111,9 +109,9 @@ void LLPngWrapper::writeFlush(png_structp png_ptr)
}
// Read the PNG file using the libpng. The low-level interface is used here
-// because we want to do various transformations (including setting the
-// matte background if any, and applying gama) which can't be done with
-// the high-level interface. The scanline also begins at the bottom of
+// because we want to do various transformations (including applying gama)
+// which can't be done with the high-level interface.
+// The scanline also begins at the bottom of
// the image (per SecondLife conventions) instead of at the top, so we
// must assign row-pointers in "reverse" order.
BOOL LLPngWrapper::readPng(U8* src, LLImageRaw* rawImage, ImageInfo *infop)
@@ -201,8 +199,7 @@ void LLPngWrapper::normalizeImage()
// 2. Convert grayscales to RGB
// 3. Create alpha layer from transparency
// 4. Ensure 8-bpp for all images
- // 5. Apply background matte if any
- // 6. Set (or guess) gamma
+ // 5. Set (or guess) gamma
if (mColorType == PNG_COLOR_TYPE_PALETTE)
{
@@ -229,12 +226,6 @@ void LLPngWrapper::normalizeImage()
{
png_set_strip_16(mReadPngPtr);
}
- mHasBKGD = png_get_bKGD(mReadPngPtr, mReadInfoPtr, &mBackgroundColor);
- if (mHasBKGD)
- {
- png_set_background(mReadPngPtr, mBackgroundColor,
- PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
- }
#if LL_DARWIN
const F64 SCREEN_GAMMA = 1.8;
@@ -261,7 +252,6 @@ void LLPngWrapper::updateMetaData()
mBitDepth = png_get_bit_depth(mReadPngPtr, mReadInfoPtr);
mColorType = png_get_color_type(mReadPngPtr, mReadInfoPtr);
mChannels = png_get_channels(mReadPngPtr, mReadInfoPtr);
- mHasBKGD = png_get_bKGD(mReadPngPtr, mReadInfoPtr, &mBackgroundColor);
}
// Method to write raw image into PNG at dest. The raw scanline begins
diff --git a/indra/llimage/llpngwrapper.h b/indra/llimage/llpngwrapper.h
index 47a4207d66..739f435996 100644
--- a/indra/llimage/llpngwrapper.h
+++ b/indra/llimage/llpngwrapper.h
@@ -88,9 +88,6 @@ private:
U32 mFinalSize;
- bool mHasBKGD;
- png_color_16p mBackgroundColor;
-
F64 mGamma;
std::string mErrorMessage;
diff --git a/indra/llimage/tests/llimageworker_test.cpp b/indra/llimage/tests/llimageworker_test.cpp
index a109276709..08476fb72c 100644
--- a/indra/llimage/tests/llimageworker_test.cpp
+++ b/indra/llimage/tests/llimageworker_test.cpp
@@ -26,10 +26,8 @@
*/
// Precompiled header: almost always required for newview cpp files
-#include <list>
-#include <map>
-#include <algorithm>
-// Class to test
+#include "linden_common.h"
+// Class to test
#include "../llimageworker.h"
// For timer class
#include "../llcommon/lltimer.h"
@@ -44,7 +42,17 @@
// * Do not make any assumption as to how those classes or methods work (i.e. don't copy/paste code)
// * A simulator for a class can be implemented here. Please comment and document thoroughly.
-LLImageBase::LLImageBase() {}
+LLImageBase::LLImageBase()
+: mData(NULL),
+mDataSize(0),
+mWidth(0),
+mHeight(0),
+mComponents(0),
+mBadBufferAllocation(false),
+mAllowOverSize(false),
+mMemType(LLMemType::MTYPE_IMAGEBASE)
+{
+}
LLImageBase::~LLImageBase() {}
void LLImageBase::dump() { }
void LLImageBase::sanityCheck() { }
diff --git a/indra/llimagej2coj/llimagej2coj.cpp b/indra/llimagej2coj/llimagej2coj.cpp
index 95e0997d5b..d15824ce5a 100644
--- a/indra/llimagej2coj/llimagej2coj.cpp
+++ b/indra/llimagej2coj/llimagej2coj.cpp
@@ -90,6 +90,12 @@ void info_callback(const char* msg, void*)
lldebugs << "LLImageJ2COJ: " << chomp(msg) << llendl;
}
+// Divide a by 2 to the power of b and round upwards
+int ceildivpow2(int a, int b)
+{
+ return (a + (1 << b) - 1) >> b;
+}
+
LLImageJ2COJ::LLImageJ2COJ()
: LLImageJ2CImpl()
@@ -101,6 +107,17 @@ LLImageJ2COJ::~LLImageJ2COJ()
{
}
+BOOL LLImageJ2COJ::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, int discard_level, int* region)
+{
+ // No specific implementation for this method in the OpenJpeg case
+ return FALSE;
+}
+
+BOOL LLImageJ2COJ::initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int blocks_size, int precincts_size, int levels)
+{
+ // No specific implementation for this method in the OpenJpeg case
+ return FALSE;
+}
BOOL LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count)
{
diff --git a/indra/llimagej2coj/llimagej2coj.h b/indra/llimagej2coj/llimagej2coj.h
index 7edacbe97c..40ad4edb00 100644
--- a/indra/llimagej2coj/llimagej2coj.h
+++ b/indra/llimagej2coj/llimagej2coj.h
@@ -34,17 +34,13 @@ class LLImageJ2COJ : public LLImageJ2CImpl
public:
LLImageJ2COJ();
virtual ~LLImageJ2COJ();
-
protected:
/*virtual*/ BOOL getMetadata(LLImageJ2C &base);
/*virtual*/ BOOL decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count);
/*virtual*/ BOOL encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text, F32 encode_time=0.0,
BOOL reversible = FALSE);
- int ceildivpow2(int a, int b)
- {
- // Divide a by b to the power of 2 and round upwards.
- return (a + (1 << b) - 1) >> b;
- }
+ /*virtual*/ BOOL initDecode(LLImageJ2C &base, LLImageRaw &raw_image, int discard_level = -1, int* region = NULL);
+ /*virtual*/ BOOL initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int blocks_size = -1, int precincts_size = -1, int levels = 0);
};
#endif
diff --git a/indra/llinventory/CMakeLists.txt b/indra/llinventory/CMakeLists.txt
index 6b2b61f883..35a764b111 100644
--- a/indra/llinventory/CMakeLists.txt
+++ b/indra/llinventory/CMakeLists.txt
@@ -59,16 +59,17 @@ list(APPEND llinventory_SOURCE_FILES ${llinventory_HEADER_FILES})
add_library (llinventory ${llinventory_SOURCE_FILES})
-if(LL_TESTS)
- #add unit tests
- INCLUDE(LLAddBuildTest)
- SET(llinventory_TEST_SOURCE_FILES
- # no real unit tests yet!
- )
- LL_ADD_PROJECT_UNIT_TESTS(llinventory "${llinventory_TEST_SOURCE_FILES}")
- #set(TEST_DEBUG on)
- set(test_libs llinventory ${LLMESSAGE_LIBRARIES} ${LLVFS_LIBRARIES} ${LLMATH_LIBRARIES} ${LLCOMMON_LIBRARIES} ${WINDOWS_LIBRARIES})
- LL_ADD_INTEGRATION_TEST(inventorymisc "" "${test_libs}")
- LL_ADD_INTEGRATION_TEST(llparcel "" "${test_libs}")
-endif(LL_TESTS)
+#add unit tests
+if (LL_TESTS)
+ INCLUDE(LLAddBuildTest)
+ SET(llinventory_TEST_SOURCE_FILES
+ # no real unit tests yet!
+ )
+ LL_ADD_PROJECT_UNIT_TESTS(llinventory "${llinventory_TEST_SOURCE_FILES}")
+
+ #set(TEST_DEBUG on)
+ set(test_libs llinventory ${LLMESSAGE_LIBRARIES} ${LLVFS_LIBRARIES} ${LLMATH_LIBRARIES} ${LLCOMMON_LIBRARIES} ${WINDOWS_LIBRARIES})
+ LL_ADD_INTEGRATION_TEST(inventorymisc "" "${test_libs}")
+ LL_ADD_INTEGRATION_TEST(llparcel "" "${test_libs}")
+endif (LL_TESTS)
diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp
index bda76eac80..a3caf79519 100644
--- a/indra/llinventory/llinventory.cpp
+++ b/indra/llinventory/llinventory.cpp
@@ -61,8 +61,6 @@ static const std::string INV_FOLDER_ID_LABEL_WS("category_id");
///----------------------------------------------------------------------------
/// Local function declarations, constants, enums, and typedefs
///----------------------------------------------------------------------------
-const U8 TASK_INVENTORY_ITEM_KEY = 0;
-const U8 TASK_INVENTORY_ASSET_KEY = 1;
const LLUUID MAGIC_ID("3c115e51-04f4-523c-9fa6-98aff1034730");
diff --git a/indra/llinventory/llinventorytype.cpp b/indra/llinventory/llinventorytype.cpp
index a99be1420b..d2bba21648 100644
--- a/indra/llinventory/llinventorytype.cpp
+++ b/indra/llinventory/llinventorytype.cpp
@@ -83,6 +83,7 @@ LLInventoryDictionary::LLInventoryDictionary()
addEntry(LLInventoryType::IT_WEARABLE, new InventoryEntry("wearable", "wearable", 2, LLAssetType::AT_CLOTHING, LLAssetType::AT_BODYPART));
addEntry(LLInventoryType::IT_ANIMATION, new InventoryEntry("animation", "animation", 1, LLAssetType::AT_ANIMATION));
addEntry(LLInventoryType::IT_GESTURE, new InventoryEntry("gesture", "gesture", 1, LLAssetType::AT_GESTURE));
+ addEntry(LLInventoryType::IT_MESH, new InventoryEntry("mesh", "mesh", 1, LLAssetType::AT_MESH));
}
@@ -91,32 +92,58 @@ LLInventoryDictionary::LLInventoryDictionary()
static const LLInventoryType::EType
DEFAULT_ASSET_FOR_INV_TYPE[LLAssetType::AT_COUNT] =
{
- LLInventoryType::IT_TEXTURE, // AT_TEXTURE
- LLInventoryType::IT_SOUND, // AT_SOUND
- LLInventoryType::IT_CALLINGCARD, // AT_CALLINGCARD
- LLInventoryType::IT_LANDMARK, // AT_LANDMARK
- LLInventoryType::IT_LSL, // AT_SCRIPT
- LLInventoryType::IT_WEARABLE, // AT_CLOTHING
- LLInventoryType::IT_OBJECT, // AT_OBJECT
- LLInventoryType::IT_NOTECARD, // AT_NOTECARD
- LLInventoryType::IT_CATEGORY, // AT_CATEGORY
- LLInventoryType::IT_NONE, // (null entry)
- LLInventoryType::IT_LSL, // AT_LSL_TEXT
- LLInventoryType::IT_LSL, // AT_LSL_BYTECODE
- LLInventoryType::IT_TEXTURE, // AT_TEXTURE_TGA
- LLInventoryType::IT_WEARABLE, // AT_BODYPART
- LLInventoryType::IT_CATEGORY, // AT_TRASH
- LLInventoryType::IT_CATEGORY, // AT_SNAPSHOT_CATEGORY
- LLInventoryType::IT_CATEGORY, // AT_LOST_AND_FOUND
- LLInventoryType::IT_SOUND, // AT_SOUND_WAV
- LLInventoryType::IT_NONE, // AT_IMAGE_TGA
- LLInventoryType::IT_NONE, // AT_IMAGE_JPEG
- LLInventoryType::IT_ANIMATION, // AT_ANIMATION
- LLInventoryType::IT_GESTURE, // AT_GESTURE
- LLInventoryType::IT_NONE, // AT_SIMSTATE
-
- LLInventoryType::IT_NONE, // AT_LINK
- LLInventoryType::IT_NONE, // AT_LINK_FOLDER
+ LLInventoryType::IT_TEXTURE, // 0 AT_TEXTURE
+ LLInventoryType::IT_SOUND, // 1 AT_SOUND
+ LLInventoryType::IT_CALLINGCARD, // 2 AT_CALLINGCARD
+ LLInventoryType::IT_LANDMARK, // 3 AT_LANDMARK
+ LLInventoryType::IT_LSL, // 4 AT_SCRIPT
+ LLInventoryType::IT_WEARABLE, // 5 AT_CLOTHING
+ LLInventoryType::IT_OBJECT, // 6 AT_OBJECT
+ LLInventoryType::IT_NOTECARD, // 7 AT_NOTECARD
+ LLInventoryType::IT_CATEGORY, // 8 AT_CATEGORY
+ LLInventoryType::IT_NONE, // 9 (null entry)
+ LLInventoryType::IT_LSL, // 10 AT_LSL_TEXT
+ LLInventoryType::IT_LSL, // 11 AT_LSL_BYTECODE
+ LLInventoryType::IT_TEXTURE, // 12 AT_TEXTURE_TGA
+ LLInventoryType::IT_WEARABLE, // 13 AT_BODYPART
+ LLInventoryType::IT_CATEGORY, // 14 AT_TRASH
+ LLInventoryType::IT_CATEGORY, // 15 AT_SNAPSHOT_CATEGORY
+ LLInventoryType::IT_CATEGORY, // 16 AT_LOST_AND_FOUND
+ LLInventoryType::IT_SOUND, // 17 AT_SOUND_WAV
+ LLInventoryType::IT_NONE, // 18 AT_IMAGE_TGA
+ LLInventoryType::IT_NONE, // 19 AT_IMAGE_JPEG
+ LLInventoryType::IT_ANIMATION, // 20 AT_ANIMATION
+ LLInventoryType::IT_GESTURE, // 21 AT_GESTURE
+ LLInventoryType::IT_NONE, // 22 AT_SIMSTATE
+
+ LLInventoryType::IT_NONE, // 23 AT_LINK
+ LLInventoryType::IT_NONE, // 24 AT_LINK_FOLDER
+
+ LLInventoryType::IT_NONE, // 25 AT_NONE
+ LLInventoryType::IT_NONE, // 26 AT_NONE
+ LLInventoryType::IT_NONE, // 27 AT_NONE
+ LLInventoryType::IT_NONE, // 28 AT_NONE
+ LLInventoryType::IT_NONE, // 29 AT_NONE
+ LLInventoryType::IT_NONE, // 30 AT_NONE
+ LLInventoryType::IT_NONE, // 31 AT_NONE
+ LLInventoryType::IT_NONE, // 32 AT_NONE
+ LLInventoryType::IT_NONE, // 33 AT_NONE
+ LLInventoryType::IT_NONE, // 34 AT_NONE
+ LLInventoryType::IT_NONE, // 35 AT_NONE
+ LLInventoryType::IT_NONE, // 36 AT_NONE
+ LLInventoryType::IT_NONE, // 37 AT_NONE
+ LLInventoryType::IT_NONE, // 38 AT_NONE
+ LLInventoryType::IT_NONE, // 39 AT_NONE
+ LLInventoryType::IT_NONE, // 40 AT_NONE
+ LLInventoryType::IT_NONE, // 41 AT_NONE
+ LLInventoryType::IT_NONE, // 42 AT_NONE
+ LLInventoryType::IT_NONE, // 43 AT_NONE
+ LLInventoryType::IT_NONE, // 44 AT_NONE
+ LLInventoryType::IT_NONE, // 45 AT_NONE
+ LLInventoryType::IT_NONE, // 46 AT_NONE
+ LLInventoryType::IT_NONE, // 47 AT_NONE
+ LLInventoryType::IT_NONE, // 48 AT_NONE
+ LLInventoryType::IT_MESH // 49 AT_MESH
};
// static
diff --git a/indra/llinventory/llinventorytype.h b/indra/llinventory/llinventorytype.h
index d9777a73f2..1a24e351ad 100644
--- a/indra/llinventory/llinventorytype.h
+++ b/indra/llinventory/llinventorytype.h
@@ -61,7 +61,8 @@ public:
IT_WEARABLE = 18,
IT_ANIMATION = 19,
IT_GESTURE = 20,
- IT_COUNT = 21,
+ IT_MESH = 22,
+ IT_COUNT = 23,
IT_NONE = -1
};
diff --git a/indra/llinventory/llnotecard.cpp b/indra/llinventory/llnotecard.cpp
index 62829c284f..69152cefe0 100644
--- a/indra/llinventory/llnotecard.cpp
+++ b/indra/llinventory/llnotecard.cpp
@@ -199,7 +199,7 @@ bool LLNotecard::importStream(std::istream& str)
return FALSE;
}
- if(text_len > mMaxText)
+ if(text_len > mMaxText || text_len < 0)
{
llwarns << "Invalid Linden text length: " << text_len << llendl;
return FALSE;
diff --git a/indra/llinventory/llparcel.cpp b/indra/llinventory/llparcel.cpp
index 488bd45d8f..0a4cd51ea0 100644
--- a/indra/llinventory/llparcel.cpp
+++ b/indra/llinventory/llparcel.cpp
@@ -72,6 +72,7 @@ static const std::string PARCEL_CATEGORY_STRING[LLParcel::C_COUNT] =
"shopping",
"stage",
"other",
+ "rental"
};
static const std::string PARCEL_CATEGORY_UI_STRING[LLParcel::C_COUNT + 1] =
{
@@ -89,6 +90,7 @@ static const std::string PARCEL_CATEGORY_UI_STRING[LLParcel::C_COUNT + 1] =
"Shopping",
"Stage",
"Other",
+ "Rental",
"Any", // valid string for parcel searches
};
@@ -188,8 +190,6 @@ void LLParcel::init(const LLUUID &owner_id,
mMediaID.setNull();
mMediaAutoScale = 0;
mMediaLoop = TRUE;
- mObscureMedia = 1;
- mObscureMusic = 1;
mMediaWidth = 0;
mMediaHeight = 0;
setMediaCurrentURL(LLStringUtil::null);
@@ -685,8 +685,8 @@ void LLParcel::packMessage(LLSD& msg)
msg["auto_scale"] = getMediaAutoScale();
msg["media_loop"] = getMediaLoop();
msg["media_current_url"] = getMediaCurrentURL();
- msg["obscure_media"] = getObscureMedia();
- msg["obscure_music"] = getObscureMusic();
+ msg["obscure_media"] = false; // OBSOLETE - no longer used
+ msg["obscure_music"] = false; // OBSOLETE - no longer used
msg["media_id"] = getMediaID();
msg["media_allow_navigate"] = getMediaAllowNavigate();
msg["media_prevent_camera_zoom"] = getMediaPreventCameraZoom();
@@ -750,16 +750,13 @@ void LLParcel::unpackMessage(LLMessageSystem* msg)
msg->getS32("MediaData", "MediaWidth", mMediaWidth);
msg->getS32("MediaData", "MediaHeight", mMediaHeight);
msg->getU8 ( "MediaData", "MediaLoop", mMediaLoop );
- msg->getU8 ( "MediaData", "ObscureMedia", mObscureMedia );
- msg->getU8 ( "MediaData", "ObscureMusic", mObscureMusic );
+ // the ObscureMedia and ObscureMusic flags previously set here are no longer used
}
else
{
setMediaType(std::string("video/vnd.secondlife.qt.legacy"));
setMediaDesc(std::string("No Description available without Server Upgrade"));
mMediaLoop = true;
- mObscureMedia = true;
- mObscureMusic = true;
}
if(msg->getNumberOfBlocks("MediaLinkSharing") > 0)
@@ -1225,8 +1222,6 @@ void LLParcel::clearParcel()
setMediaDesc(LLStringUtil::null);
setMediaAutoScale(0);
setMediaLoop(TRUE);
- mObscureMedia = 1;
- mObscureMusic = 1;
mMediaWidth = 0;
mMediaHeight = 0;
setMediaCurrentURL(LLStringUtil::null);
diff --git a/indra/llinventory/llparcel.h b/indra/llinventory/llparcel.h
index ae301af9f5..71b65d99ce 100644
--- a/indra/llinventory/llparcel.h
+++ b/indra/llinventory/llparcel.h
@@ -165,6 +165,7 @@ public:
C_SHOPPING,
C_STAGE,
C_OTHER,
+ C_RENTAL,
C_COUNT,
C_ANY = -1 // only useful in queries
};
@@ -238,8 +239,6 @@ public:
void setMediaID(const LLUUID& id) { mMediaID = id; }
void setMediaAutoScale ( U8 flagIn ) { mMediaAutoScale = flagIn; }
void setMediaLoop (U8 loop) { mMediaLoop = loop; }
- void setObscureMedia( U8 flagIn ) { mObscureMedia = flagIn; }
- void setObscureMusic( U8 flagIn ) { mObscureMusic = flagIn; }
void setMediaWidth(S32 width);
void setMediaHeight(S32 height);
void setMediaCurrentURL(const std::string& url);
@@ -346,8 +345,6 @@ public:
U8 getMediaAutoScale() const { return mMediaAutoScale; }
U8 getMediaLoop() const { return mMediaLoop; }
const std::string& getMediaCurrentURL() const { return mMediaCurrentURL; }
- U8 getObscureMedia() const { return mObscureMedia; }
- U8 getObscureMusic() const { return mObscureMusic; }
U8 getMediaURLFilterEnable() const { return mMediaURLFilterEnable; }
LLSD getMediaURLFilterList() const { return mMediaURLFilterList; }
U8 getMediaAllowNavigate() const { return mMediaAllowNavigate; }
@@ -636,8 +633,6 @@ protected:
U8 mMediaAutoScale;
U8 mMediaLoop;
std::string mMediaCurrentURL;
- U8 mObscureMedia;
- U8 mObscureMusic;
LLUUID mMediaID;
U8 mMediaURLFilterEnable;
LLSD mMediaURLFilterList;
diff --git a/indra/llkdu/CMakeLists.txt b/indra/llkdu/CMakeLists.txt
new file mode 100644
index 0000000000..046629b514
--- /dev/null
+++ b/indra/llkdu/CMakeLists.txt
@@ -0,0 +1,65 @@
+# -*- cmake -*-
+
+project(llkdu)
+
+# Visual Studio 2005 has a dumb bug that causes it to fail compilation
+# of KDU if building with both optimisation and /WS (treat warnings as
+# errors), even when the specific warnings that make it croak are
+# disabled.
+
+#set(VS_DISABLE_FATAL_WARNINGS ON)
+
+include(00-Common)
+include(LLCommon)
+include(LLImage)
+include(LLKDU)
+include(LLMath)
+
+include_directories(
+ ${LLCOMMON_INCLUDE_DIRS}
+ ${LLIMAGE_INCLUDE_DIRS}
+ ${KDU_INCLUDE_DIR}
+ ${LLKDU_INCLUDE_DIRS}
+ ${LLMATH_INCLUDE_DIRS}
+ )
+
+set(llkdu_SOURCE_FILES
+ llimagej2ckdu.cpp
+ llkdumem.cpp
+ )
+
+set(llkdu_HEADER_FILES
+ CMakeLists.txt
+
+ llimagej2ckdu.h
+ llkdumem.h
+ )
+
+set_source_files_properties(${llkdu_HEADER_FILES}
+ PROPERTIES HEADER_FILE_ONLY TRUE)
+
+list(APPEND llkdu_SOURCE_FILES ${llkdu_HEADER_FILES})
+
+if (USE_KDU)
+ add_library (${LLKDU_LIBRARIES} ${llkdu_SOURCE_FILES})
+
+ # Add tests
+ if (LL_TESTS)
+ include(LLAddBuildTest)
+ include(Tut)
+ SET(llkdu_TEST_SOURCE_FILES
+ llimagej2ckdu.cpp
+ )
+ SET(llkdu_test_additional_HEADER_FILES
+ llimagej2ckdu.h
+ llkdumem.h
+ lltut.h
+ )
+ SET(llkdu_test_additional_INCLUDE_DIRS
+ ${KDU_INCLUDE_DIR}
+ ${LLKDU_INCLUDE_DIRS}
+ )
+ LL_ADD_PROJECT_UNIT_TESTS(llkdu "${llkdu_TEST_SOURCE_FILES}")
+ endif (LL_TESTS)
+
+endif (USE_KDU)
diff --git a/indra/llkdu/llimagej2ckdu.cpp b/indra/llkdu/llimagej2ckdu.cpp
new file mode 100644
index 0000000000..39ae09650e
--- /dev/null
+++ b/indra/llkdu/llimagej2ckdu.cpp
@@ -0,0 +1,1156 @@
+ /**
+ * @file llimagej2ckdu.cpp
+ * @brief This is an implementation of JPEG2000 encode/decode using Kakadu
+ *
+ * $LicenseInfo:firstyear=2010&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 "llimagej2ckdu.h"
+
+#include "lltimer.h"
+#include "llpointer.h"
+#include "llmath.h"
+#include "llkdumem.h"
+
+
+class kdc_flow_control {
+
+public:
+ kdc_flow_control(kdu_image_in_base *img_in, kdu_codestream codestream);
+ ~kdc_flow_control();
+ bool advance_components();
+ void process_components();
+
+private:
+
+ struct kdc_component_flow_control {
+ public:
+ kdu_image_in_base *reader;
+ int vert_subsampling;
+ int ratio_counter; /* Initialized to 0, decremented by `count_delta';
+ when < 0, a new line must be processed, after
+ which it is incremented by `vert_subsampling'. */
+ int initial_lines;
+ int remaining_lines;
+ kdu_line_buf *line;
+ };
+
+ kdu_codestream codestream;
+ kdu_dims valid_tile_indices;
+ kdu_coords tile_idx;
+ kdu_tile tile;
+ int num_components;
+ kdc_component_flow_control *components;
+ int count_delta; // Holds the minimum of the `vert_subsampling' fields
+ kdu_multi_analysis engine;
+ kdu_long max_buffer_memory;
+};
+
+//
+// Kakadu specific implementation
+//
+void set_default_colour_weights(kdu_params *siz);
+
+const char* engineInfoLLImageJ2CKDU()
+{
+ std::string version = llformat("KDU %s", KDU_CORE_VERSION);
+ return version.c_str();
+}
+
+LLImageJ2CKDU* createLLImageJ2CKDU()
+{
+ return new LLImageJ2CKDU();
+}
+
+void destroyLLImageJ2CKDU(LLImageJ2CKDU* kdu)
+{
+ delete kdu;
+ kdu = NULL;
+}
+
+LLImageJ2CImpl* fallbackCreateLLImageJ2CImpl()
+{
+ return new LLImageJ2CKDU();
+}
+
+void fallbackDestroyLLImageJ2CImpl(LLImageJ2CImpl* impl)
+{
+ delete impl;
+ impl = NULL;
+}
+
+const char* fallbackEngineInfoLLImageJ2CImpl()
+{
+ return engineInfoLLImageJ2CKDU();
+}
+
+class LLKDUDecodeState
+{
+public:
+ LLKDUDecodeState(kdu_tile tile, kdu_byte *buf, S32 row_gap);
+ ~LLKDUDecodeState();
+ BOOL processTileDecode(F32 decode_time, BOOL limit_time = TRUE);
+
+private:
+ S32 mNumComponents;
+ BOOL mUseYCC;
+ kdu_dims mDims;
+ kdu_sample_allocator mAllocator;
+ kdu_tile_comp mComps[4];
+ kdu_line_buf mLines[4];
+ kdu_pull_ifc mEngines[4];
+ bool mReversible[4]; // Some components may be reversible and others not
+ int mBitDepths[4]; // Original bit-depth may be quite different from 8
+
+ kdu_tile mTile;
+ kdu_byte *mBuf;
+ S32 mRowGap;
+};
+
+void ll_kdu_error( void )
+{
+ // *FIX: This exception is bad, bad, bad. It gets thrown from a
+ // destructor which can lead to immediate program termination!
+ throw "ll_kdu_error() throwing an exception";
+}
+
+// Stuff for new kdu error handling
+class LLKDUMessageWarning : public kdu_message
+{
+public:
+ /*virtual*/ void put_text(const char *s);
+ /*virtual*/ void put_text(const kdu_uint16 *s);
+
+ static LLKDUMessageWarning sDefaultMessage;
+};
+
+class LLKDUMessageError : public kdu_message
+{
+public:
+ /*virtual*/ void put_text(const char *s);
+ /*virtual*/ void put_text(const kdu_uint16 *s);
+ /*virtual*/ void flush(bool end_of_message = false);
+ static LLKDUMessageError sDefaultMessage;
+};
+
+void LLKDUMessageWarning::put_text(const char *s)
+{
+ llinfos << "KDU Warning: " << s << llendl;
+}
+
+void LLKDUMessageWarning::put_text(const kdu_uint16 *s)
+{
+ llinfos << "KDU Warning: " << s << llendl;
+}
+
+void LLKDUMessageError::put_text(const char *s)
+{
+ llinfos << "KDU Error: " << s << llendl;
+}
+
+void LLKDUMessageError::put_text(const kdu_uint16 *s)
+{
+ llinfos << "KDU Error: " << s << llendl;
+}
+
+void LLKDUMessageError::flush(bool end_of_message)
+{
+ if (end_of_message)
+ {
+ throw "KDU throwing an exception";
+ }
+}
+
+LLKDUMessageWarning LLKDUMessageWarning::sDefaultMessage;
+LLKDUMessageError LLKDUMessageError::sDefaultMessage;
+static bool kdu_message_initialized = false;
+
+LLImageJ2CKDU::LLImageJ2CKDU() : LLImageJ2CImpl(),
+mInputp(NULL),
+mCodeStreamp(NULL),
+mTPosp(NULL),
+mTileIndicesp(NULL),
+mRawImagep(NULL),
+mDecodeState(NULL),
+mBlocksSize(-1),
+mPrecinctsSize(-1),
+mLevels(0)
+{
+}
+
+LLImageJ2CKDU::~LLImageJ2CKDU()
+{
+ cleanupCodeStream(); // in case destroyed before decode completed
+}
+
+// Stuff for new simple decode
+void transfer_bytes(kdu_byte *dest, kdu_line_buf &src, int gap, int precision);
+
+void LLImageJ2CKDU::setupCodeStream(LLImageJ2C &base, BOOL keep_codestream, ECodeStreamMode mode)
+{
+ S32 data_size = base.getDataSize();
+ S32 max_bytes = (base.getMaxBytes() ? base.getMaxBytes() : data_size);
+
+ //
+ // Initialization
+ //
+ if (!kdu_message_initialized)
+ {
+ kdu_message_initialized = true;
+ kdu_customize_errors(&LLKDUMessageError::sDefaultMessage);
+ kdu_customize_warnings(&LLKDUMessageWarning::sDefaultMessage);
+ }
+
+ if (mCodeStreamp)
+ {
+ mCodeStreamp->destroy();
+ delete mCodeStreamp;
+ mCodeStreamp = NULL;
+ }
+
+ if (!mInputp && base.getData())
+ {
+ // The compressed data has been loaded
+ // Setup the source for the codestream
+ mInputp = new LLKDUMemSource(base.getData(), data_size);
+ }
+
+ if (mInputp)
+ {
+ mInputp->reset();
+ }
+ mCodeStreamp = new kdu_codestream;
+
+ mCodeStreamp->create(mInputp);
+
+ // Set the maximum number of bytes to use from the codestream
+ mCodeStreamp->set_max_bytes(max_bytes);
+
+ // If you want to flip or rotate the image for some reason, change
+ // the resolution, or identify a restricted region of interest, this is
+ // the place to do it. You may use "kdu_codestream::change_appearance"
+ // and "kdu_codestream::apply_input_restrictions" for this purpose.
+ // If you wish to truncate the code-stream prior to decompression, you
+ // may use "kdu_codestream::set_max_bytes".
+ // If you wish to retain all compressed data so that the material
+ // can be decompressed multiple times, possibly with different appearance
+ // parameters, you should call "kdu_codestream::set_persistent" here.
+ // There are a variety of other features which must be enabled at
+ // this point if you want to take advantage of them. See the
+ // descriptions appearing with the "kdu_codestream" interface functions
+ // in "kdu_compressed.h" for an itemized account of these capabilities.
+
+ switch (mode)
+ {
+ case MODE_FAST:
+ mCodeStreamp->set_fast();
+ break;
+ case MODE_RESILIENT:
+ mCodeStreamp->set_resilient();
+ break;
+ case MODE_FUSSY:
+ mCodeStreamp->set_fussy();
+ break;
+ default:
+ llassert(0);
+ mCodeStreamp->set_fast();
+ }
+
+ kdu_dims dims;
+ mCodeStreamp->get_dims(0,dims);
+
+ S32 components = mCodeStreamp->get_num_components();
+
+ if (components >= 3)
+ { // Check that components have consistent dimensions (for PPM file)
+ kdu_dims dims1; mCodeStreamp->get_dims(1,dims1);
+ kdu_dims dims2; mCodeStreamp->get_dims(2,dims2);
+ if ((dims1 != dims) || (dims2 != dims))
+ {
+ llerrs << "Components don't have matching dimensions!" << llendl;
+ }
+ }
+
+ base.setSize(dims.size.x, dims.size.y, components);
+
+ if (!keep_codestream)
+ {
+ mCodeStreamp->destroy();
+ delete mCodeStreamp;
+ mCodeStreamp = NULL;
+ delete mInputp;
+ mInputp = NULL;
+ }
+}
+
+void LLImageJ2CKDU::cleanupCodeStream()
+{
+ delete mInputp;
+ mInputp = NULL;
+
+ delete mDecodeState;
+ mDecodeState = NULL;
+
+ if (mCodeStreamp)
+ {
+ mCodeStreamp->destroy();
+ delete mCodeStreamp;
+ mCodeStreamp = NULL;
+ }
+
+ delete mTPosp;
+ mTPosp = NULL;
+
+ delete mTileIndicesp;
+ mTileIndicesp = NULL;
+}
+
+BOOL LLImageJ2CKDU::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, int discard_level, int* region)
+{
+ return initDecode(base,raw_image,0.0f,MODE_FAST,0,4,discard_level,region);
+}
+
+BOOL LLImageJ2CKDU::initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int blocks_size, int precincts_size, int levels)
+{
+ mPrecinctsSize = precincts_size;
+ if (mPrecinctsSize != -1)
+ {
+ mPrecinctsSize = get_lower_power_two(mPrecinctsSize,MAX_PRECINCT_SIZE);
+ mPrecinctsSize = llmax(mPrecinctsSize,MIN_PRECINCT_SIZE);
+ }
+ mBlocksSize = blocks_size;
+ if (mBlocksSize != -1)
+ {
+ mBlocksSize = get_lower_power_two(mBlocksSize,MAX_BLOCK_SIZE);
+ mBlocksSize = llmax(mBlocksSize,MIN_BLOCK_SIZE);
+ if (mPrecinctsSize != -1)
+ {
+ mBlocksSize = llmin(mBlocksSize,mPrecinctsSize); // blocks *must* be smaller than precincts
+ }
+ }
+ mLevels = levels;
+ if (mLevels != 0)
+ {
+ mLevels = llclamp(mLevels,MIN_DECOMPOSITION_LEVELS,MIN_DECOMPOSITION_LEVELS);
+ }
+ return TRUE;
+}
+
+BOOL LLImageJ2CKDU::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, ECodeStreamMode mode, S32 first_channel, S32 max_channel_count, int discard_level, int* region)
+{
+ base.resetLastError();
+
+ // *FIX: kdu calls our callback function if there's an error, and then bombs.
+ // To regain control, we throw an exception, and catch it here.
+ try
+ {
+ base.updateRawDiscardLevel();
+ setupCodeStream(base, TRUE, mode);
+
+ mRawImagep = &raw_image;
+ mCodeStreamp->change_appearance(false, true, false);
+
+ // Apply loading discard level and cropping if required
+ kdu_dims* region_kdu = NULL;
+ if (region != NULL)
+ {
+ region_kdu = new kdu_dims;
+ region_kdu->pos.x = region[0];
+ region_kdu->pos.y = region[1];
+ region_kdu->size.x = region[2] - region[0];
+ region_kdu->size.y = region[3] - region[1];
+ }
+ int discard = (discard_level != -1 ? discard_level : base.getRawDiscardLevel());
+
+ // Apply loading restrictions
+ mCodeStreamp->apply_input_restrictions( first_channel, max_channel_count, discard, 0, region_kdu);
+
+ // Clean-up
+ if (region_kdu)
+ {
+ delete region_kdu;
+ region_kdu = NULL;
+ }
+
+ // Resize raw_image according to the image to be decoded
+ kdu_dims dims; mCodeStreamp->get_dims(0,dims);
+ // *TODO: Use the real number of levels read from the file throughout the code instead of relying on an infered value from dimensions
+ //S32 levels = mCodeStreamp->get_min_dwt_levels();
+ S32 channels = base.getComponents() - first_channel;
+ channels = llmin(channels,max_channel_count);
+ raw_image.resize(dims.size.x, dims.size.y, channels);
+ //llinfos << "j2c image dimension: width = " << dims.size.x << ", height = " << dims.size.y << ", channels = " << channels << ", levels = " << levels << llendl;
+
+ if (!mTileIndicesp)
+ {
+ mTileIndicesp = new kdu_dims;
+ }
+ mCodeStreamp->get_valid_tiles(*mTileIndicesp);
+ if (!mTPosp)
+ {
+ mTPosp = new kdu_coords;
+ mTPosp->y = 0;
+ mTPosp->x = 0;
+ }
+ }
+ catch (const char* msg)
+ {
+ base.setLastError(ll_safe_string(msg));
+ return FALSE;
+ }
+ catch (...)
+ {
+ base.setLastError("Unknown J2C error");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+// Returns TRUE to mean done, whether successful or not.
+BOOL LLImageJ2CKDU::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count)
+{
+ ECodeStreamMode mode = MODE_FAST;
+
+ LLTimer decode_timer;
+
+ if (!mCodeStreamp)
+ {
+ if (!initDecode(base, raw_image, decode_time, mode, first_channel, max_channel_count))
+ {
+ // Initializing the J2C decode failed, bail out.
+ cleanupCodeStream();
+ return TRUE; // done
+ }
+ }
+
+ // These can probably be grabbed from what's saved in the class.
+ kdu_dims dims;
+ mCodeStreamp->get_dims(0,dims);
+
+ // Now we are ready to walk through the tiles processing them one-by-one.
+ kdu_byte *buffer = raw_image.getData();
+
+ while (mTPosp->y < mTileIndicesp->size.y)
+ {
+ while (mTPosp->x < mTileIndicesp->size.x)
+ {
+ try
+ {
+ if (!mDecodeState)
+ {
+ kdu_tile tile = mCodeStreamp->open_tile(*(mTPosp)+mTileIndicesp->pos);
+
+ // Find the region of the buffer occupied by this
+ // tile. Note that we have no control over
+ // sub-sampling factors which might have been used
+ // during compression and so it can happen that tiles
+ // (at the image component level) actually have
+ // different dimensions. For this reason, we cannot
+ // figure out the buffer region occupied by a tile
+ // directly from the tile indices. Instead, we query
+ // the highest resolution of the first tile-component
+ // concerning its location and size on the canvas --
+ // the `dims' object already holds the location and
+ // size of the entire image component on the same
+ // canvas coordinate system. Comparing the two tells
+ // us where the current tile is in the buffer.
+ S32 channels = base.getComponents() - first_channel;
+ if (channels > max_channel_count)
+ {
+ channels = max_channel_count;
+ }
+ kdu_resolution res = tile.access_component(0).access_resolution();
+ kdu_dims tile_dims; res.get_dims(tile_dims);
+ kdu_coords offset = tile_dims.pos - dims.pos;
+ int row_gap = channels*dims.size.x; // inter-row separation
+ kdu_byte *buf = buffer + offset.y*row_gap + offset.x*channels;
+ mDecodeState = new LLKDUDecodeState(tile, buf, row_gap);
+ }
+ // Do the actual processing
+ F32 remaining_time = decode_time - decode_timer.getElapsedTimeF32();
+ // This is where we do the actual decode. If we run out of time, return false.
+ if (mDecodeState->processTileDecode(remaining_time, (decode_time > 0.0f)))
+ {
+ delete mDecodeState;
+ mDecodeState = NULL;
+ }
+ else
+ {
+ // Not finished decoding yet.
+ // setLastError("Ran out of time while decoding");
+ return FALSE;
+ }
+ }
+ catch (const char* msg)
+ {
+ base.setLastError(ll_safe_string(msg));
+ base.decodeFailed();
+ cleanupCodeStream();
+ return TRUE; // done
+ }
+ catch (...)
+ {
+ base.setLastError( "Unknown J2C error" );
+ base.decodeFailed();
+ cleanupCodeStream();
+ return TRUE; // done
+ }
+
+
+ mTPosp->x++;
+ }
+ mTPosp->y++;
+ mTPosp->x = 0;
+ }
+
+ cleanupCodeStream();
+
+ return TRUE;
+}
+
+
+BOOL LLImageJ2CKDU::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text, F32 encode_time, BOOL reversible)
+{
+ // Declare and set simple arguments
+ bool transpose = false;
+ bool vflip = true;
+ bool hflip = false;
+
+ try
+ {
+ // Set up input image files
+ siz_params siz;
+
+ // Should set rate someplace here
+ LLKDUMemIn mem_in(raw_image.getData(),
+ raw_image.getDataSize(),
+ raw_image.getWidth(),
+ raw_image.getHeight(),
+ raw_image.getComponents(),
+ &siz);
+
+ base.setSize(raw_image.getWidth(), raw_image.getHeight(), raw_image.getComponents());
+
+ int num_components = raw_image.getComponents();
+
+ siz.set(Scomponents,0,0,num_components);
+ siz.set(Sdims,0,0,base.getHeight()); // Height of first image component
+ siz.set(Sdims,0,1,base.getWidth()); // Width of first image component
+ siz.set(Sprecision,0,0,8); // Image samples have original bit-depth of 8
+ siz.set(Ssigned,0,0,false); // Image samples are originally unsigned
+
+ kdu_params *siz_ref = &siz;
+ siz_ref->finalize();
+ siz_params transformed_siz; // Use this one to construct code-stream
+ transformed_siz.copy_from(&siz,-1,-1,-1,0,transpose,false,false);
+
+ // Construct the `kdu_codestream' object and parse all remaining arguments
+ U32 max_output_size = base.getWidth()*base.getHeight()*base.getComponents();
+ max_output_size = (max_output_size < 1000 ? 1000 : max_output_size);
+ U8 *output_buffer = new U8[max_output_size];
+ U32 output_size = 0; // Address updated by LLKDUMemTarget to give the final compressed buffer size
+ LLKDUMemTarget output(output_buffer, output_size, max_output_size);
+
+ kdu_codestream codestream;
+ codestream.create(&transformed_siz,&output);
+
+ if (comment_text)
+ {
+ // Set the comments for the codestream
+ kdu_codestream_comment comment = codestream.add_comment();
+ comment.put_text(comment_text);
+ }
+
+ // Set codestream options
+ int num_layer_specs = 0;
+
+ kdu_long layer_bytes[64];
+ U32 max_bytes = 0;
+
+ if (num_components >= 3)
+ {
+ // Note that we always use YCC and not YUV
+ // *TODO: Verify this doesn't screws up reversible textures (like sculpties) as YCC is not reversible but YUV is...
+ set_default_colour_weights(codestream.access_siz());
+ }
+
+ if (reversible)
+ {
+ codestream.access_siz()->parse_string("Creversible=yes");
+ // *TODO: we should use yuv in reversible mode and one level since those images are small.
+ // Don't turn this on now though as both create problems on decoding for the moment
+ //codestream.access_siz()->parse_string("Clevels=1");
+ //codestream.access_siz()->parse_string("Cycc=no");
+ // If we're doing reversible (i.e. lossless compression), assumes we're not using quality layers.
+ // *TODO: this is incorrect and unecessary. Try using the regular layer setting.
+ codestream.access_siz()->parse_string("Clayers=1");
+ num_layer_specs = 1;
+ layer_bytes[0] = 0;
+ }
+ else
+ {
+ // Rate is the argument passed into the LLImageJ2C which
+ // specifies the target compression rate. The default is 8:1.
+ // Possibly if max_bytes < 500, we should just use the default setting?
+ // *TODO: mRate is actually always 8:1 in the viewer. Test different values. Also force to reversible for small (< 500 bytes) textures.
+ if (base.mRate != 0.f)
+ {
+ max_bytes = (U32)(base.mRate*base.getWidth()*base.getHeight()*base.getComponents());
+ }
+ else
+ {
+ max_bytes = (U32)(base.getWidth()*base.getHeight()*base.getComponents()*0.125);
+ }
+
+ const U32 min_bytes = FIRST_PACKET_SIZE;
+ if (max_bytes > min_bytes)
+ {
+ U32 i;
+ // This code is where we specify the target number of bytes for
+ // each layer. Not sure if we should do this for small images
+ // or not. The goal is to have this roughly align with
+ // different quality levels that we decode at.
+ for (i = min_bytes; i < max_bytes; i*=4)
+ {
+ if (i == min_bytes * 4)
+ {
+ i = 2000;
+ }
+ layer_bytes[num_layer_specs] = i;
+ num_layer_specs++;
+ }
+ layer_bytes[num_layer_specs] = max_bytes;
+ num_layer_specs++;
+
+ std::string layer_string = llformat("Clayers=%d",num_layer_specs);
+ codestream.access_siz()->parse_string(layer_string.c_str());
+ }
+ else
+ {
+ layer_bytes[0] = min_bytes;
+ num_layer_specs = 1;
+ std::string layer_string = llformat("Clayers=%d",num_layer_specs);
+ codestream.access_siz()->parse_string(layer_string.c_str());
+ }
+ }
+
+ // Set up data ordering, markers, etc... if precincts or blocks specified
+ if ((mBlocksSize != -1) || (mPrecinctsSize != -1))
+ {
+ if (mPrecinctsSize != -1)
+ {
+ std::string precincts_string = llformat("Cprecincts={%d,%d}",mPrecinctsSize,mPrecinctsSize);
+ codestream.access_siz()->parse_string(precincts_string.c_str());
+ }
+ if (mBlocksSize != -1)
+ {
+ std::string blocks_string = llformat("Cblk={%d,%d}",mBlocksSize,mBlocksSize);
+ codestream.access_siz()->parse_string(blocks_string.c_str());
+ }
+ std::string ordering_string = llformat("Corder=RPCL");
+ codestream.access_siz()->parse_string(ordering_string.c_str());
+ std::string PLT_string = llformat("ORGgen_plt=yes");
+ codestream.access_siz()->parse_string(PLT_string.c_str());
+ std::string Parts_string = llformat("ORGtparts=R");
+ codestream.access_siz()->parse_string(Parts_string.c_str());
+ }
+ if (mLevels != 0)
+ {
+ std::string levels_string = llformat("Clevels=%d",mLevels);
+ codestream.access_siz()->parse_string(levels_string.c_str());
+ }
+
+ codestream.access_siz()->finalize_all();
+ codestream.change_appearance(transpose,vflip,hflip);
+
+ // Now we are ready for sample data processing.
+ kdc_flow_control *tile = new kdc_flow_control(&mem_in,codestream);
+ bool done = false;
+ while (!done)
+ {
+ // Process line by line
+ if (tile->advance_components())
+ {
+ tile->process_components();
+ }
+ else
+ {
+ done = true;
+ }
+ }
+
+ // Produce the compressed output
+ codestream.flush(layer_bytes,num_layer_specs);
+
+ // Cleanup
+ delete tile;
+ codestream.destroy();
+
+ // Now that we're done encoding, create the new data buffer for the compressed
+ // image and stick it there.
+ base.copyData(output_buffer, output_size);
+ base.updateData(); // set width, height
+ delete[] output_buffer;
+ }
+ catch(const char* msg)
+ {
+ base.setLastError(ll_safe_string(msg));
+ return FALSE;
+ }
+ catch( ... )
+ {
+ base.setLastError( "Unknown J2C error" );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOL LLImageJ2CKDU::getMetadata(LLImageJ2C &base)
+{
+ // *FIX: kdu calls our callback function if there's an error, and
+ // then bombs. To regain control, we throw an exception, and
+ // catch it here.
+ try
+ {
+ setupCodeStream(base, FALSE, MODE_FAST);
+ return TRUE;
+ }
+ catch (const char* msg)
+ {
+ base.setLastError(ll_safe_string(msg));
+ return FALSE;
+ }
+ catch (...)
+ {
+ base.setLastError( "Unknown J2C error" );
+ return FALSE;
+ }
+}
+
+void set_default_colour_weights(kdu_params *siz)
+{
+ kdu_params *cod = siz->access_cluster(COD_params);
+ assert(cod != NULL);
+
+ bool can_use_ycc = true;
+ bool rev0 = false;
+ int depth0 = 0, sub_x0 = 1, sub_y0 = 1;
+ for (int c = 0; c < 3; c++)
+ {
+ int depth = 0; siz->get(Sprecision,c,0,depth);
+ int sub_y = 1; siz->get(Ssampling,c,0,sub_y);
+ int sub_x = 1; siz->get(Ssampling,c,1,sub_x);
+ kdu_params *coc = cod->access_relation(-1,c);
+ bool rev = false; coc->get(Creversible,0,0,rev);
+ if (c == 0)
+ {
+ rev0 = rev; depth0 = depth; sub_x0 = sub_x; sub_y0 = sub_y;
+ }
+ else if ((rev != rev0) || (depth != depth0) ||
+ (sub_x != sub_x0) || (sub_y != sub_y0))
+ {
+ can_use_ycc = false;
+ }
+ }
+ if (!can_use_ycc)
+ {
+ return;
+ }
+
+ bool use_ycc;
+ if (!cod->get(Cycc,0,0,use_ycc))
+ {
+ cod->set(Cycc,0,0,use_ycc=true);
+ }
+ if (!use_ycc)
+ {
+ return;
+ }
+ float weight;
+ if (cod->get(Clev_weights,0,0,weight) || cod->get(Cband_weights,0,0,weight))
+ {
+ // Weights already specified explicitly -> nothing to do
+ return;
+ }
+
+ // These example weights are adapted from numbers generated by Marcus Nadenau
+ // at EPFL, for a viewing distance of 15 cm and a display resolution of
+ // 300 DPI.
+
+ cod->parse_string("Cband_weights:C0="
+ "{0.0901},{0.2758},{0.2758},"
+ "{0.7018},{0.8378},{0.8378},{1}");
+ cod->parse_string("Cband_weights:C1="
+ "{0.0263},{0.0863},{0.0863},"
+ "{0.1362},{0.2564},{0.2564},"
+ "{0.3346},{0.4691},{0.4691},"
+ "{0.5444},{0.6523},{0.6523},"
+ "{0.7078},{0.7797},{0.7797},{1}");
+ cod->parse_string("Cband_weights:C2="
+ "{0.0773},{0.1835},{0.1835},"
+ "{0.2598},{0.4130},{0.4130},"
+ "{0.5040},{0.6464},{0.6464},"
+ "{0.7220},{0.8254},{0.8254},"
+ "{0.8769},{0.9424},{0.9424},{1}");
+}
+
+/******************************************************************************/
+/* transfer_bytes */
+/******************************************************************************/
+
+void transfer_bytes(kdu_byte *dest, kdu_line_buf &src, int gap, int precision)
+/* Transfers source samples from the supplied line buffer into the output
+byte buffer, spacing successive output samples apart by `gap' bytes
+(to allow for interleaving of colour components). The function performs
+all necessary level shifting, type conversion, rounding and truncation. */
+{
+ int width = src.get_width();
+ if (src.get_buf32() != NULL)
+ { // Decompressed samples have a 32-bit representation (integer or float)
+ assert(precision >= 8); // Else would have used 16 bit representation
+ kdu_sample32 *sp = src.get_buf32();
+ if (!src.is_absolute())
+ { // Transferring normalized floating point data.
+ float scale16 = (float)(1<<16);
+ kdu_int32 val;
+
+ for (; width > 0; width--, sp++, dest+=gap)
+ {
+ val = (kdu_int32)(sp->fval*scale16);
+ val = (val+128)>>8; // May be faster than true rounding
+ val += 128;
+ if (val & ((-1)<<8))
+ {
+ val = (val < 0 ? 0 : 255);
+ }
+ *dest = (kdu_byte) val;
+ }
+ }
+ else
+ { // Transferring 32-bit absolute integers.
+ kdu_int32 val;
+ kdu_int32 downshift = precision-8;
+ kdu_int32 offset = (1<<downshift)>>1;
+
+ for (; width > 0; width--, sp++, dest+=gap)
+ {
+ val = sp->ival;
+ val = (val+offset)>>downshift;
+ val += 128;
+ if (val & ((-1)<<8))
+ {
+ val = (val < 0 ? 0 : 255);
+ }
+ *dest = (kdu_byte) val;
+ }
+ }
+ }
+ else
+ { // Source data is 16 bits.
+ kdu_sample16 *sp = src.get_buf16();
+ if (!src.is_absolute())
+ { // Transferring 16-bit fixed point quantities
+ kdu_int16 val;
+
+ if (precision >= 8)
+ { // Can essentially ignore the bit-depth.
+ for (; width > 0; width--, sp++, dest+=gap)
+ {
+ val = sp->ival;
+ val += (1<<(KDU_FIX_POINT-8))>>1;
+ val >>= (KDU_FIX_POINT-8);
+ val += 128;
+ if (val & ((-1)<<8))
+ {
+ val = (val < 0 ? 0 : 255);
+ }
+ *dest = (kdu_byte) val;
+ }
+ }
+ else
+ { // Need to force zeros into one or more least significant bits.
+ kdu_int16 downshift = KDU_FIX_POINT-precision;
+ kdu_int16 upshift = 8-precision;
+ kdu_int16 offset = 1<<(downshift-1);
+
+ for (; width > 0; width--, sp++, dest+=gap)
+ {
+ val = sp->ival;
+ val = (val+offset)>>downshift;
+ val <<= upshift;
+ val += 128;
+ if (val & ((-1)<<8))
+ {
+ val = (val < 0 ? 0 : 256 - (1<<upshift));
+ }
+ *dest = (kdu_byte) val;
+ }
+ }
+ }
+ else
+ { // Transferring 16-bit absolute integers.
+ kdu_int16 val;
+
+ if (precision >= 8)
+ {
+ kdu_int16 downshift = precision-8;
+ kdu_int16 offset = (1<<downshift)>>1;
+
+ for (; width > 0; width--, sp++, dest+=gap)
+ {
+ val = sp->ival;
+ val = (val+offset)>>downshift;
+ val += 128;
+ if (val & ((-1)<<8))
+ {
+ val = (val < 0 ? 0 : 255);
+ }
+ *dest = (kdu_byte) val;
+ }
+ }
+ else
+ {
+ kdu_int16 upshift = 8-precision;
+
+ for (; width > 0; width--, sp++, dest+=gap)
+ {
+ val = sp->ival;
+ val <<= upshift;
+ val += 128;
+ if (val & ((-1)<<8))
+ {
+ val = (val < 0 ? 0 : 256 - (1<<upshift));
+ }
+ *dest = (kdu_byte) val;
+ }
+ }
+ }
+ }
+}
+
+LLKDUDecodeState::LLKDUDecodeState(kdu_tile tile, kdu_byte *buf, S32 row_gap)
+{
+ S32 c;
+
+ mTile = tile;
+ mBuf = buf;
+ mRowGap = row_gap;
+
+ mNumComponents = tile.get_num_components();
+
+ llassert(mNumComponents <= 4);
+ mUseYCC = tile.get_ycc();
+
+ for (c = 0; c < 4; ++c)
+ {
+ mReversible[c] = false;
+ mBitDepths[c] = 0;
+ }
+
+ // Open tile-components and create processing engines and resources
+ for (c = 0; c < mNumComponents; c++)
+ {
+ mComps[c] = mTile.access_component(c);
+ mReversible[c] = mComps[c].get_reversible();
+ mBitDepths[c] = mComps[c].get_bit_depth();
+ kdu_resolution res = mComps[c].access_resolution(); // Get top resolution
+ kdu_dims comp_dims; res.get_dims(comp_dims);
+ if (c == 0)
+ {
+ mDims = comp_dims;
+ }
+ else
+ {
+ llassert(mDims == comp_dims); // Safety check; the caller has ensured this
+ }
+ bool use_shorts = (mComps[c].get_bit_depth(true) <= 16);
+ mLines[c].pre_create(&mAllocator,mDims.size.x,mReversible[c],use_shorts);
+ if (res.which() == 0) // No DWT levels used
+ {
+ mEngines[c] = kdu_decoder(res.access_subband(LL_BAND),&mAllocator,use_shorts);
+ }
+ else
+ {
+ mEngines[c] = kdu_synthesis(res,&mAllocator,use_shorts);
+ }
+ }
+ mAllocator.finalize(); // Actually creates buffering resources
+ for (c = 0; c < mNumComponents; c++)
+ {
+ mLines[c].create(); // Grabs resources from the allocator.
+ }
+}
+
+LLKDUDecodeState::~LLKDUDecodeState()
+{
+ // Cleanup
+ for (S32 c = 0; c < mNumComponents; c++)
+ {
+ mEngines[c].destroy(); // engines are interfaces; no default destructors
+ }
+ mTile.close();
+}
+
+BOOL LLKDUDecodeState::processTileDecode(F32 decode_time, BOOL limit_time)
+/* Decompresses a tile, writing the data into the supplied byte buffer.
+The buffer contains interleaved image components, if there are any.
+Although you may think of the buffer as belonging entirely to this tile,
+the `buf' pointer may actually point into a larger buffer representing
+multiple tiles. For this reason, `row_gap' is needed to identify the
+separation between consecutive rows in the real buffer. */
+{
+ S32 c;
+ // Now walk through the lines of the buffer, recovering them from the
+ // relevant tile-component processing engines.
+
+ LLTimer decode_timer;
+ while (mDims.size.y--)
+ {
+ for (c = 0; c < mNumComponents; c++)
+ {
+ mEngines[c].pull(mLines[c],true);
+ }
+ if ((mNumComponents >= 3) && mUseYCC)
+ {
+ kdu_convert_ycc_to_rgb(mLines[0],mLines[1],mLines[2]);
+ }
+ for (c = 0; c < mNumComponents; c++)
+ {
+ transfer_bytes(mBuf+c,mLines[c],mNumComponents,mBitDepths[c]);
+ }
+ mBuf += mRowGap;
+ if (mDims.size.y % 10)
+ {
+ if (limit_time && decode_timer.getElapsedTimeF32() > decode_time)
+ {
+ return FALSE;
+ }
+ }
+ }
+ return TRUE;
+}
+
+// kdc_flow_control
+
+kdc_flow_control::kdc_flow_control (kdu_image_in_base *img_in, kdu_codestream codestream)
+{
+ int n;
+
+ this->codestream = codestream;
+ codestream.get_valid_tiles(valid_tile_indices);
+ tile_idx = valid_tile_indices.pos;
+ tile = codestream.open_tile(tile_idx,NULL);
+
+ // Set up the individual components
+ num_components = codestream.get_num_components(true);
+ components = new kdc_component_flow_control[num_components];
+ count_delta = 0;
+ kdc_component_flow_control *comp = components;
+ for (n = 0; n < num_components; n++, comp++)
+ {
+ comp->line = NULL;
+ comp->reader = img_in;
+ kdu_coords subsampling;
+ codestream.get_subsampling(n,subsampling,true);
+ kdu_dims dims;
+ codestream.get_tile_dims(tile_idx,n,dims,true);
+ comp->vert_subsampling = subsampling.y;
+ if ((n == 0) || (comp->vert_subsampling < count_delta))
+ {
+ count_delta = comp->vert_subsampling;
+ }
+ comp->ratio_counter = 0;
+ comp->remaining_lines = comp->initial_lines = dims.size.y;
+ }
+ assert(num_components >= 0);
+
+ tile.set_components_of_interest(num_components);
+ max_buffer_memory = engine.create(codestream,tile,false,NULL,false,1,NULL,NULL,false);
+}
+
+kdc_flow_control::~kdc_flow_control()
+{
+ if (components != NULL)
+ {
+ delete[] components;
+ }
+ if (engine.exists())
+ {
+ engine.destroy();
+ }
+}
+
+bool kdc_flow_control::advance_components()
+{
+ bool found_line = false;
+ while (!found_line)
+ {
+ bool all_done = true;
+ kdc_component_flow_control *comp = components;
+ for (int n = 0; n < num_components; n++, comp++)
+ {
+ assert(comp->ratio_counter >= 0);
+ if (comp->remaining_lines > 0)
+ {
+ all_done = false;
+ comp->ratio_counter -= count_delta;
+ if (comp->ratio_counter < 0)
+ {
+ found_line = true;
+ comp->line = engine.exchange_line(n,NULL,NULL);
+ assert(comp->line != NULL);
+ if (comp->line->get_width())
+ {
+ comp->reader->get(n,*(comp->line),0);
+ }
+ }
+ }
+ }
+ if (all_done)
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+void kdc_flow_control::process_components()
+{
+ kdc_component_flow_control *comp = components;
+ for (int n = 0; n < num_components; n++, comp++)
+ {
+ if (comp->ratio_counter < 0)
+ {
+ comp->ratio_counter += comp->vert_subsampling;
+ assert(comp->ratio_counter >= 0);
+ assert(comp->remaining_lines > 0);
+ comp->remaining_lines--;
+ assert(comp->line != NULL);
+ engine.exchange_line(n,comp->line,NULL);
+ comp->line = NULL;
+ }
+ }
+}
diff --git a/indra/llkdu/llimagej2ckdu.h b/indra/llkdu/llimagej2ckdu.h
new file mode 100644
index 0000000000..1489dbf704
--- /dev/null
+++ b/indra/llkdu/llimagej2ckdu.h
@@ -0,0 +1,95 @@
+/**
+ * @file llimagej2ckdu.h
+ * @brief This is an implementation of JPEG2000 encode/decode using Kakadu
+ *
+ * $LicenseInfo:firstyear=2010&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_LLIMAGEJ2CKDU_H
+#define LL_LLIMAGEJ2CKDU_H
+
+#include "llimagej2c.h"
+
+//
+// KDU core header files
+//
+#include "kdu_elementary.h"
+#include "kdu_messaging.h"
+#include "kdu_params.h"
+#include "kdu_compressed.h"
+#include "kdu_sample_processing.h"
+
+class LLKDUDecodeState;
+class LLKDUMemSource;
+
+class LLImageJ2CKDU : public LLImageJ2CImpl
+{
+public:
+ enum ECodeStreamMode
+ {
+ MODE_FAST = 0,
+ MODE_RESILIENT = 1,
+ MODE_FUSSY = 2
+ };
+ LLImageJ2CKDU();
+ virtual ~LLImageJ2CKDU();
+
+protected:
+ /*virtual*/ BOOL getMetadata(LLImageJ2C &base);
+ /*virtual*/ BOOL decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count);
+ /*virtual*/ BOOL encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text, F32 encode_time=0.0,
+ BOOL reversible=FALSE);
+ /*virtual*/ BOOL initDecode(LLImageJ2C &base, LLImageRaw &raw_image, int discard_level = -1, int* region = NULL);
+ /*virtual*/ BOOL initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int blocks_size = -1, int precincts_size = -1, int levels = 0);
+
+private:
+ BOOL initDecode(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, ECodeStreamMode mode, S32 first_channel, S32 max_channel_count, int discard_level = -1, int* region = NULL);
+ void setupCodeStream(LLImageJ2C &base, BOOL keep_codestream, ECodeStreamMode mode);
+ void cleanupCodeStream();
+
+ // Encode variable
+ LLKDUMemSource *mInputp;
+ kdu_codestream *mCodeStreamp;
+ kdu_coords *mTPosp; // tile position
+ kdu_dims *mTileIndicesp;
+ int mBlocksSize;
+ int mPrecinctsSize;
+ int mLevels;
+
+ // Temporary variables for in-progress decodes...
+ LLImageRaw *mRawImagep;
+ LLKDUDecodeState *mDecodeState;
+};
+
+#if LL_WINDOWS
+# define LLSYMEXPORT __declspec(dllexport)
+#elif LL_LINUX
+# define LLSYMEXPORT __attribute__ ((visibility("default")))
+#else
+# define LLSYMEXPORT
+#endif
+
+extern "C" LLSYMEXPORT const char* engineInfoLLImageJ2CKDU();
+extern "C" LLSYMEXPORT LLImageJ2CKDU* createLLImageJ2CKDU();
+extern "C" LLSYMEXPORT void destroyLLImageJ2CKDU(LLImageJ2CKDU* kdu);
+
+#endif
diff --git a/indra/llkdu/llkdumem.cpp b/indra/llkdu/llkdumem.cpp
new file mode 100644
index 0000000000..0347475559
--- /dev/null
+++ b/indra/llkdu/llkdumem.cpp
@@ -0,0 +1,196 @@
+ /**
+ * @file llkdumem.cpp
+ * @brief Helper class for kdu memory management
+ *
+ * $LicenseInfo:firstyear=2010&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 "llkdumem.h"
+#include "llerror.h"
+
+#if defined(LL_WINDOWS)
+# pragma warning(disable: 4702) // unreachable code
+#endif
+
+LLKDUMemIn::LLKDUMemIn(const U8 *data,
+ const U32 size,
+ const U16 width,
+ const U16 height,
+ const U8 in_num_components,
+ siz_params *siz)
+{
+ U8 n;
+
+ first_comp_idx = 0;
+ rows = height;
+ cols = width;
+ num_components = in_num_components;
+ alignment_bytes = 0;
+
+ for (n = 0; n < 3; ++n)
+ {
+ precision[n] = 0;
+ }
+
+ for (n = 0; n < num_components; ++n)
+ {
+ siz->set(Sdims,n,0,rows);
+ siz->set(Sdims,n,1,cols);
+ siz->set(Ssigned,n,0,false);
+ siz->set(Sprecision,n,0,8);
+ }
+ incomplete_lines = NULL;
+ free_lines = NULL;
+ num_unread_rows = rows;
+
+ mData = data;
+ mDataSize = size;
+ mCurPos = 0;
+}
+
+LLKDUMemIn::~LLKDUMemIn()
+{
+ if ((num_unread_rows > 0) || (incomplete_lines != NULL))
+ {
+ kdu_warning w;
+ w << "Not all rows of image components "
+ << first_comp_idx << " through "
+ << first_comp_idx+num_components-1
+ << " were consumed!";
+ }
+ image_line_buf *tmp;
+ while ((tmp=incomplete_lines) != NULL)
+ {
+ incomplete_lines = tmp->next;
+ delete tmp;
+ }
+ while ((tmp=free_lines) != NULL)
+ {
+ free_lines = tmp->next;
+ delete tmp;
+ }
+}
+
+
+bool LLKDUMemIn::get(int comp_idx, kdu_line_buf &line, int x_tnum)
+{
+ int idx = comp_idx - this->first_comp_idx;
+ assert((idx >= 0) && (idx < num_components));
+ x_tnum = x_tnum*num_components+idx;
+ image_line_buf *scan, *prev=NULL;
+ for (scan = incomplete_lines; scan != NULL; prev = scan, scan = scan->next)
+ {
+ assert(scan->next_x_tnum >= x_tnum);
+ if (scan->next_x_tnum == x_tnum)
+ {
+ break;
+ }
+ }
+ if (scan == NULL)
+ { // Need to read a new image line.
+ assert(x_tnum == 0); // Must consume in very specific order.
+ if (num_unread_rows == 0)
+ {
+ return false;
+ }
+ if ((scan = free_lines) == NULL)
+ {
+ scan = new image_line_buf(cols+3,num_components);
+ }
+ free_lines = scan->next;
+ if (prev == NULL)
+ {
+ incomplete_lines = scan;
+ }
+ else
+ {
+ prev->next = scan;
+ }
+
+ // Copy from image buffer into scan.
+ memcpy(scan->buf, mData+mCurPos, cols*num_components);
+ mCurPos += cols*num_components;
+
+ num_unread_rows--;
+ scan->accessed_samples = 0;
+ scan->next_x_tnum = 0;
+ }
+
+ assert((cols-scan->accessed_samples) >= line.get_width());
+
+ int comp_offset = idx;
+ kdu_byte *sp = scan->buf+num_components*scan->accessed_samples + comp_offset;
+ int n=line.get_width();
+
+ if (line.get_buf32() != NULL)
+ {
+ kdu_sample32 *dp = line.get_buf32();
+ if (line.is_absolute())
+ { // 32-bit absolute integers
+ for (; n > 0; n--, sp+=num_components, dp++)
+ {
+ dp->ival = ((kdu_int32)(*sp)) - 128;
+ }
+ }
+ else
+ { // true 32-bit floats
+ for (; n > 0; n--, sp+=num_components, dp++)
+ {
+ dp->fval = (((float)(*sp)) / 256.0F) - 0.5F;
+ }
+ }
+ }
+ else
+ {
+ kdu_sample16 *dp = line.get_buf16();
+ if (line.is_absolute())
+ { // 16-bit absolute integers
+ for (; n > 0; n--, sp+=num_components, dp++)
+ {
+ dp->ival = ((kdu_int16)(*sp)) - 128;
+ }
+ }
+ else
+ { // 16-bit normalized representation.
+ for (; n > 0; n--, sp+=num_components, dp++)
+ {
+ dp->ival = (((kdu_int16)(*sp)) - 128) << (KDU_FIX_POINT-8);
+ }
+ }
+ }
+
+ scan->next_x_tnum++;
+ if (idx == (num_components-1))
+ {
+ scan->accessed_samples += line.get_width();
+ }
+ if (scan->accessed_samples == cols)
+ { // Send empty line to free list.
+ assert(scan == incomplete_lines);
+ incomplete_lines = scan->next;
+ scan->next = free_lines;
+ free_lines = scan;
+ }
+
+ return true;
+}
diff --git a/indra/llkdu/llkdumem.h b/indra/llkdu/llkdumem.h
new file mode 100644
index 0000000000..9d923fc367
--- /dev/null
+++ b/indra/llkdu/llkdumem.h
@@ -0,0 +1,145 @@
+/**
+ * @file llkdumem.h
+ * @brief Helper class for kdu memory management
+ *
+ * $LicenseInfo:firstyear=2010&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_LLKDUMEM_H
+#define LL_LLKDUMEM_H
+
+// Support classes for reading and writing from memory buffers in KDU
+#include "kdu_image.h"
+#include "kdu_elementary.h"
+#include "kdu_messaging.h"
+#include "kdu_params.h"
+#include "kdu_compressed.h"
+#include "kdu_sample_processing.h"
+#include "image_local.h"
+#include "stdtypes.h"
+
+class LLKDUMemSource: public kdu_compressed_source
+{
+public:
+ LLKDUMemSource(U8 *input_buffer, U32 size)
+ {
+ mData = input_buffer;
+ mSize = size;
+ mCurPos = 0;
+ }
+
+ ~LLKDUMemSource()
+ {
+ }
+
+ int read(kdu_byte *buf, int num_bytes)
+ {
+ U32 num_out;
+ num_out = num_bytes;
+
+ if ((mSize - mCurPos) < (U32)num_bytes)
+ {
+ num_out = mSize -mCurPos;
+ }
+ memcpy(buf, mData + mCurPos, num_out);
+ mCurPos += num_out;
+ return num_out;
+ }
+
+ void reset()
+ {
+ mCurPos = 0;
+ }
+
+private:
+ U8 *mData;
+ U32 mSize;
+ U32 mCurPos;
+};
+
+class LLKDUMemTarget: public kdu_compressed_target
+{
+public:
+ LLKDUMemTarget(U8 *output_buffer, U32 &output_size, const U32 buffer_size)
+ {
+ mData = output_buffer;
+ mSize = buffer_size;
+ mCurPos = 0;
+ mOutputSize = &output_size;
+ }
+
+ ~LLKDUMemTarget()
+ {
+ }
+
+ bool write(const kdu_byte *buf, int num_bytes)
+ {
+ U32 num_out;
+ num_out = num_bytes;
+
+ if ((mSize - mCurPos) < (U32)num_bytes)
+ {
+ num_out = mSize - mCurPos;
+ memcpy(mData + mCurPos, buf, num_out);
+ return false;
+ }
+ memcpy(mData + mCurPos, buf, num_out);
+ mCurPos += num_out;
+ *mOutputSize = mCurPos;
+ return true;
+ }
+
+private:
+ U8 *mData;
+ U32 mSize;
+ U32 mCurPos;
+ U32 *mOutputSize;
+};
+
+class LLKDUMemIn : public kdu_image_in_base
+{
+public:
+ LLKDUMemIn(const U8 *data,
+ const U32 size,
+ const U16 rows,
+ const U16 cols,
+ U8 in_num_components,
+ siz_params *siz);
+ ~LLKDUMemIn();
+
+ bool get(int comp_idx, kdu_line_buf &line, int x_tnum);
+
+private:
+ const U8 *mData;
+ int first_comp_idx;
+ int num_components;
+ int rows, cols;
+ int alignment_bytes; // Number of 0's at end of each line.
+ int precision[3];
+ image_line_buf *incomplete_lines; // Each "sample" represents a full pixel
+ image_line_buf *free_lines;
+ int num_unread_rows;
+
+ U32 mCurPos;
+ U32 mDataSize;
+};
+#endif
diff --git a/indra/llkdu/tests/llimagej2ckdu_test.cpp b/indra/llkdu/tests/llimagej2ckdu_test.cpp
new file mode 100644
index 0000000000..ab60ab6d50
--- /dev/null
+++ b/indra/llkdu/tests/llimagej2ckdu_test.cpp
@@ -0,0 +1,249 @@
+/**
+ * @file llimagej2ckdu_test.cpp
+ * @author Merov Linden
+ * @date 2010-12-17
+ *
+ * $LicenseInfo:firstyear=2006&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"
+// Class to test
+#include "llimagej2ckdu.h"
+#include "llkdumem.h"
+// Tut header
+#include "lltut.h"
+
+// -------------------------------------------------------------------------------------------
+// Stubbing: Declarations required to link and run the class being tested
+// Notes:
+// * Add here stubbed implementation of the few classes and methods used in the class to be tested
+// * Add as little as possible (let the link errors guide you)
+// * Do not make any assumption as to how those classes or methods work (i.e. don't copy/paste code)
+// * A simulator for a class can be implemented here. Please comment and document thoroughly.
+
+// End Stubbing
+// -------------------------------------------------------------------------------------------
+// Stubb the LL Image Classes
+LLImageRaw::LLImageRaw() { }
+LLImageRaw::~LLImageRaw() { }
+U8* LLImageRaw::allocateData(S32 ) { return NULL; }
+void LLImageRaw::deleteData() { }
+U8* LLImageRaw::reallocateData(S32 ) { return NULL; }
+BOOL LLImageRaw::resize(U16, U16, S8) { return TRUE; } // this method always returns TRUE...
+
+LLImageBase::LLImageBase()
+: mData(NULL),
+mDataSize(0),
+mWidth(0),
+mHeight(0),
+mComponents(0),
+mBadBufferAllocation(false),
+mAllowOverSize(false),
+mMemType(LLMemType::MTYPE_IMAGEBASE)
+{ }
+LLImageBase::~LLImageBase() { }
+U8* LLImageBase::allocateData(S32 ) { return NULL; }
+void LLImageBase::deleteData() { }
+void LLImageBase::dump() { }
+const U8* LLImageBase::getData() const { return NULL; }
+U8* LLImageBase::getData() { return NULL; }
+U8* LLImageBase::reallocateData(S32 ) { return NULL; }
+void LLImageBase::sanityCheck() { }
+void LLImageBase::setSize(S32 , S32 , S32 ) { }
+
+LLImageJ2CImpl::~LLImageJ2CImpl() { }
+
+LLImageFormatted::LLImageFormatted(S8 ) { }
+LLImageFormatted::~LLImageFormatted() { }
+U8* LLImageFormatted::allocateData(S32 ) { return NULL; }
+S32 LLImageFormatted::calcDataSize(S32 ) { return 0; }
+S32 LLImageFormatted::calcDiscardLevelBytes(S32 ) { return 0; }
+BOOL LLImageFormatted::decodeChannels(LLImageRaw*, F32, S32, S32) { return FALSE; }
+BOOL LLImageFormatted::copyData(U8 *, S32) { return TRUE; } // this method always returns TRUE...
+void LLImageFormatted::deleteData() { }
+void LLImageFormatted::dump() { }
+U8* LLImageFormatted::reallocateData(S32 ) { return NULL; }
+void LLImageFormatted::resetLastError() { }
+void LLImageFormatted::sanityCheck() { }
+void LLImageFormatted::setLastError(const std::string& , const std::string& ) { }
+
+LLImageJ2C::LLImageJ2C() : LLImageFormatted(IMG_CODEC_J2C) { }
+LLImageJ2C::~LLImageJ2C() { }
+S32 LLImageJ2C::calcDataSize(S32 ) { return 0; }
+S32 LLImageJ2C::calcDiscardLevelBytes(S32 ) { return 0; }
+S32 LLImageJ2C::calcHeaderSize() { return 0; }
+BOOL LLImageJ2C::decode(LLImageRaw*, F32) { return FALSE; }
+BOOL LLImageJ2C::decodeChannels(LLImageRaw*, F32, S32, S32 ) { return FALSE; }
+void LLImageJ2C::decodeFailed() { }
+BOOL LLImageJ2C::encode(const LLImageRaw*, F32) { return FALSE; }
+S8 LLImageJ2C::getRawDiscardLevel() { return 0; }
+void LLImageJ2C::resetLastError() { }
+void LLImageJ2C::setLastError(const std::string&, const std::string&) { }
+BOOL LLImageJ2C::updateData() { return FALSE; }
+void LLImageJ2C::updateRawDiscardLevel() { }
+
+LLKDUMemIn::LLKDUMemIn(const U8*, const U32, const U16, const U16, const U8, siz_params*) { }
+LLKDUMemIn::~LLKDUMemIn() { }
+bool LLKDUMemIn::get(int, kdu_line_buf&, int) { return false; }
+
+// Stub Kakadu Library calls
+kdu_tile_comp kdu_tile::access_component(int ) { kdu_tile_comp a; return a; }
+void kdu_tile::close(kdu_thread_env* ) { }
+int kdu_tile::get_num_components() { return 0; }
+bool kdu_tile::get_ycc() { return false; }
+void kdu_tile::set_components_of_interest(int , const int* ) { }
+kdu_resolution kdu_tile_comp::access_resolution() { kdu_resolution a; return a; }
+int kdu_tile_comp::get_bit_depth(bool ) { return 8; }
+bool kdu_tile_comp::get_reversible() { return false; }
+kdu_subband kdu_resolution::access_subband(int ) { kdu_subband a; return a; }
+void kdu_resolution::get_dims(kdu_dims& ) { }
+int kdu_resolution::which() { return 0; }
+kdu_decoder::kdu_decoder(kdu_subband , kdu_sample_allocator*, bool , float, int, kdu_thread_env*, kdu_thread_queue*) { }
+kdu_synthesis::kdu_synthesis(kdu_resolution, kdu_sample_allocator*, bool, float, kdu_thread_env*, kdu_thread_queue*) { }
+kdu_params::kdu_params(const char*, bool, bool, bool, bool, bool) { }
+kdu_params::~kdu_params() { }
+void kdu_params::set(const char* , int , int , bool ) { }
+void kdu_params::set(const char* , int , int , int ) { }
+void kdu_params::finalize_all(bool ) { }
+void kdu_params::copy_from(kdu_params*, int, int, int, int, int, bool, bool, bool) { }
+bool kdu_params::parse_string(const char*) { return false; }
+bool kdu_params::get(const char*, int, int, bool&, bool, bool, bool) { return false; }
+bool kdu_params::get(const char*, int, int, float&, bool, bool, bool) { return false; }
+bool kdu_params::get(const char*, int, int, int&, bool, bool, bool) { return false; }
+kdu_params* kdu_params::access_relation(int, int, int, bool) { return NULL; }
+kdu_params* kdu_params::access_cluster(const char*) { return NULL; }
+void kdu_codestream::set_fast() { }
+void kdu_codestream::set_fussy() { }
+void kdu_codestream::get_dims(int, kdu_dims&, bool ) { }
+int kdu_codestream::get_min_dwt_levels() { return 5; }
+void kdu_codestream::change_appearance(bool, bool, bool) { }
+void kdu_codestream::get_tile_dims(kdu_coords, int, kdu_dims&, bool ) { }
+void kdu_codestream::destroy() { }
+void kdu_codestream::collect_timing_stats(int ) { }
+void kdu_codestream::set_max_bytes(kdu_long, bool, bool ) { }
+void kdu_codestream::get_valid_tiles(kdu_dims& ) { }
+void kdu_codestream::create(siz_params*, kdu_compressed_target*, kdu_dims*, int, kdu_long ) { }
+void kdu_codestream::create(kdu_compressed_source*, kdu_thread_env*) { }
+void kdu_codestream::apply_input_restrictions( int, int, int, int, kdu_dims*, kdu_component_access_mode ) { }
+void kdu_codestream::get_subsampling(int , kdu_coords&, bool ) { }
+void kdu_codestream::flush(kdu_long *, int , kdu_uint16 *, bool, bool, double, kdu_thread_env*) { }
+void kdu_codestream::set_resilient(bool ) { }
+int kdu_codestream::get_num_components(bool ) { return 0; }
+siz_params* kdu_codestream::access_siz() { return NULL; }
+kdu_tile kdu_codestream::open_tile(kdu_coords , kdu_thread_env* ) { kdu_tile a; return a; }
+kdu_codestream_comment kdu_codestream::add_comment() { kdu_codestream_comment a; return a; }
+bool kdu_codestream_comment::put_text(const char*) { return false; }
+void kdu_customize_warnings(kdu_message*) { }
+void kdu_customize_errors(kdu_message*) { }
+void kdu_convert_ycc_to_rgb(kdu_line_buf&, kdu_line_buf&, kdu_line_buf&, int) { }
+kdu_long kdu_multi_analysis::create(kdu_codestream, kdu_tile, bool, kdu_roi_image*, bool, int, kdu_thread_env*, kdu_thread_queue*, bool ) { kdu_long a = 0; return a; }
+siz_params::siz_params() : kdu_params(NULL, false, false, false, false, false) { }
+void siz_params::finalize(bool ) { }
+void siz_params::copy_with_xforms(kdu_params*, int, int, bool, bool, bool) { }
+int siz_params::write_marker_segment(kdu_output*, kdu_params*, int) { return 0; }
+bool siz_params::check_marker_segment(kdu_uint16, int, kdu_byte a[], int&) { return false; }
+bool siz_params::read_marker_segment(kdu_uint16, int, kdu_byte a[], int) { return false; }
+
+// -------------------------------------------------------------------------------------------
+// TUT
+// -------------------------------------------------------------------------------------------
+
+namespace tut
+{
+ // Test wrapper declarations
+ struct llimagej2ckdu_test
+ {
+ // Derived test class
+ class LLTestImageJ2CKDU : public LLImageJ2CKDU
+ {
+ public:
+ // Provides public access to some protected methods for testing
+ BOOL callGetMetadata(LLImageJ2C &base) { return getMetadata(base); }
+ BOOL callDecodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count)
+ {
+ return decodeImpl(base, raw_image, decode_time, first_channel, max_channel_count);
+ }
+ BOOL callEncodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text)
+ {
+ return encodeImpl(base, raw_image, comment_text);
+ }
+ };
+ // Instance to be tested
+ LLTestImageJ2CKDU* mImage;
+
+ // Constructor and destructor of the test wrapper
+ llimagej2ckdu_test()
+ {
+ mImage = new LLTestImageJ2CKDU;
+ }
+ ~llimagej2ckdu_test()
+ {
+ delete mImage;
+ }
+ };
+
+ // Tut templating thingamagic: test group, object and test instance
+ typedef test_group<llimagej2ckdu_test> llimagej2ckdu_t;
+ typedef llimagej2ckdu_t::object llimagej2ckdu_object_t;
+ tut::llimagej2ckdu_t tut_llimagej2ckdu("LLImageJ2CKDU");
+
+ // ---------------------------------------------------------------------------------------
+ // Test functions
+ // Notes:
+ // * Test as many as you possibly can without requiring a full blown simulation of everything
+ // * The tests are executed in sequence so the test instance state may change between calls
+ // * Remember that you cannot test private methods with tut
+ // ---------------------------------------------------------------------------------------
+
+ // Test 1 : test getMetadata()
+ template<> template<>
+ void llimagej2ckdu_object_t::test<1>()
+ {
+ LLImageJ2C* image = new LLImageJ2C();
+ BOOL res = mImage->callGetMetadata(*image);
+ // Trying to set up a data stream with all NIL values and stubbed KDU will "work" and return TRUE
+ // Note that is linking with KDU, that call will throw an exception and fail, returning FALSE
+ ensure("getMetadata() test failed", res == TRUE);
+ }
+
+ // Test 2 : test decodeImpl()
+ template<> template<>
+ void llimagej2ckdu_object_t::test<2>()
+ {
+ LLImageJ2C* image = new LLImageJ2C();
+ LLImageRaw* raw = new LLImageRaw();
+ BOOL res = mImage->callDecodeImpl(*image, *raw, 0.0, 0, 0);
+ // Decoding returns TRUE whenever there's nothing else to do, including if decoding failed, so we'll get TRUE here
+ ensure("decodeImpl() test failed", res == TRUE);
+ }
+
+ // Test 3 : test encodeImpl()
+ template<> template<>
+ void llimagej2ckdu_object_t::test<3>()
+ {
+ LLImageJ2C* image = new LLImageJ2C();
+ LLImageRaw* raw = new LLImageRaw();
+ BOOL res = mImage->callEncodeImpl(*image, *raw, NULL);
+ // Encoding returns TRUE unless an exception was raised, so we'll get TRUE here though nothing really was done
+ ensure("encodeImpl() test failed", res == TRUE);
+ }
+}
diff --git a/indra/llmath/CMakeLists.txt b/indra/llmath/CMakeLists.txt
index e93fe90650..9dadad7dd3 100644
--- a/indra/llmath/CMakeLists.txt
+++ b/indra/llmath/CMakeLists.txt
@@ -15,13 +15,16 @@ set(llmath_SOURCE_FILES
llcamera.cpp
llcoordframe.cpp
llline.cpp
+ llmatrix3a.cpp
llmodularmath.cpp
llperlin.cpp
llquaternion.cpp
llrect.cpp
llsphere.cpp
+ llvector4a.cpp
llvolume.cpp
llvolumemgr.cpp
+ llvolumeoctree.cpp
llsdutil_math.cpp
m3math.cpp
m4math.cpp
@@ -49,21 +52,32 @@ set(llmath_HEADER_FILES
llinterp.h
llline.h
llmath.h
+ llmatrix3a.h
+ llmatrix3a.inl
llmodularmath.h
lloctree.h
llperlin.h
llplane.h
llquantize.h
llquaternion.h
+ llquaternion2.h
+ llquaternion2.inl
llrect.h
+ llsimdmath.h
+ llsimdtypes.h
+ llsimdtypes.inl
llsphere.h
lltreenode.h
+ llvector4a.h
+ llvector4a.inl
+ llvector4logical.h
llv4math.h
llv4matrix3.h
llv4matrix4.h
llv4vector3.h
llvolume.h
llvolumemgr.h
+ llvolumeoctree.h
llsdutil_math.h
m3math.h
m4math.h
diff --git a/indra/llmath/llbbox.cpp b/indra/llmath/llbbox.cpp
index b46a6e03d2..3e2c05a6e6 100644
--- a/indra/llmath/llbbox.cpp
+++ b/indra/llmath/llbbox.cpp
@@ -89,6 +89,19 @@ void LLBBox::addBBoxAgent(const LLBBox& b)
}
}
+LLBBox LLBBox::getAxisAligned() const
+{
+ // no rotation = axis aligned rotation
+ LLBBox aligned(mPosAgent, LLQuaternion(), LLVector3(), LLVector3());
+
+ // add the center point so that it's not empty
+ aligned.addPointAgent(mPosAgent);
+
+ // add our BBox
+ aligned.addBBoxAgent(*this);
+
+ return aligned;
+}
void LLBBox::expand( F32 delta )
{
@@ -147,6 +160,15 @@ BOOL LLBBox::containsPointAgent(const LLVector3& p) const
return containsPointLocal(point_local);
}
+LLVector3 LLBBox::getMinAgent() const
+{
+ return localToAgent(mMinLocal);
+}
+
+LLVector3 LLBBox::getMaxAgent() const
+{
+ return localToAgent(mMaxLocal);
+}
/*
LLBBox operator*(const LLBBox &a, const LLMatrix4 &b)
diff --git a/indra/llmath/llbbox.h b/indra/llmath/llbbox.h
index 5b911793f0..28e69b75e1 100644
--- a/indra/llmath/llbbox.h
+++ b/indra/llmath/llbbox.h
@@ -51,9 +51,11 @@ public:
const LLVector3& getPositionAgent() const { return mPosAgent; }
const LLQuaternion& getRotation() const { return mRotation; }
+ LLVector3 getMinAgent() const;
const LLVector3& getMinLocal() const { return mMinLocal; }
void setMinLocal( const LLVector3& min ) { mMinLocal = min; }
+ LLVector3 getMaxAgent() const;
const LLVector3& getMaxLocal() const { return mMaxLocal; }
void setMaxLocal( const LLVector3& max ) { mMaxLocal = max; }
@@ -80,6 +82,8 @@ public:
LLVector3 localToAgentBasis(const LLVector3& v) const;
LLVector3 agentToLocalBasis(const LLVector3& v) const;
+ // Get the smallest possible axis aligned bbox that contains this bbox
+ LLBBox getAxisAligned() const;
// friend LLBBox operator*(const LLBBox& a, const LLMatrix4& b);
diff --git a/indra/llmath/llcamera.cpp b/indra/llmath/llcamera.cpp
index bad4d00fd6..22ba26f99b 100644
--- a/indra/llmath/llcamera.cpp
+++ b/indra/llmath/llcamera.cpp
@@ -45,7 +45,6 @@ LLCamera::LLCamera() :
calculateFrustumPlanes();
}
-
LLCamera::LLCamera(F32 vertical_fov_rads, F32 aspect_ratio, S32 view_height_in_pixels, F32 near_plane, F32 far_plane) :
LLCoordFrame(),
mViewHeightInPixels(view_height_in_pixels),
@@ -61,6 +60,10 @@ LLCamera::LLCamera(F32 vertical_fov_rads, F32 aspect_ratio, S32 view_height_in_p
setView(vertical_fov_rads);
}
+LLCamera::~LLCamera()
+{
+
+}
// ---------------- LLCamera::getFoo() member functions ----------------
@@ -82,11 +85,11 @@ F32 LLCamera::getMaxView() const
// ---------------- LLCamera::setFoo() member functions ----------------
-void LLCamera::setUserClipPlane(LLPlane plane)
+void LLCamera::setUserClipPlane(LLPlane& plane)
{
mPlaneCount = 7;
- mAgentPlanes[6].p = plane;
- mAgentPlanes[6].mask = calcPlaneMask(plane);
+ mAgentPlanes[6] = plane;
+ mPlaneMask[6] = plane.calcPlaneMask();
}
void LLCamera::disableUserClipPlane()
@@ -158,166 +161,91 @@ size_t LLCamera::readFrustumFromBuffer(const char *buffer)
// ---------------- test methods ----------------
-S32 LLCamera::AABBInFrustum(const LLVector3 &center, const LLVector3& radius)
+S32 LLCamera::AABBInFrustum(const LLVector4a &center, const LLVector4a& radius)
{
- static const LLVector3 scaler[] = {
- LLVector3(-1,-1,-1),
- LLVector3( 1,-1,-1),
- LLVector3(-1, 1,-1),
- LLVector3( 1, 1,-1),
- LLVector3(-1,-1, 1),
- LLVector3( 1,-1, 1),
- LLVector3(-1, 1, 1),
- LLVector3( 1, 1, 1)
+ static const LLVector4a scaler[] = {
+ LLVector4a(-1,-1,-1),
+ LLVector4a( 1,-1,-1),
+ LLVector4a(-1, 1,-1),
+ LLVector4a( 1, 1,-1),
+ LLVector4a(-1,-1, 1),
+ LLVector4a( 1,-1, 1),
+ LLVector4a(-1, 1, 1),
+ LLVector4a( 1, 1, 1)
};
U8 mask = 0;
- S32 result = 2;
-
- /*if (mFrustumCornerDist > 0.f && radius.magVecSquared() > mFrustumCornerDist * mFrustumCornerDist)
- { //box is larger than frustum, check frustum quads against box planes
-
- static const LLVector3 dir[] =
- {
- LLVector3(1, 0, 0),
- LLVector3(-1, 0, 0),
- LLVector3(0, 1, 0),
- LLVector3(0, -1, 0),
- LLVector3(0, 0, 1),
- LLVector3(0, 0, -1)
- };
-
- U32 quads[] =
- {
- 0, 1, 2, 3,
- 0, 1, 5, 4,
- 2, 3, 7, 6,
- 3, 0, 7, 4,
- 1, 2, 6, 4,
- 4, 5, 6, 7
- };
-
- result = 0;
-
- BOOL total_inside = TRUE;
- for (U32 i = 0; i < 6; i++)
- {
- LLVector3 p = center + radius.scaledVec(dir[i]);
- F32 d = -p*dir[i];
-
- for (U32 j = 0; j < 6; j++)
- { //for each quad
- F32 dist = mAgentFrustum[quads[j*4+0]]*dir[i] + d;
- if (dist > 0)
- { //at least one frustum point is outside the AABB
- total_inside = FALSE;
- for (U32 k = 1; k < 4; k++)
- { //for each other point on quad
- if ( mAgentFrustum[quads[j*4+k]]*dir[i]+d <= 0.f)
- { //quad is straddling some plane of AABB
- return 1;
- }
- }
- }
- else
- {
- for (U32 k = 1; k < 4; k++)
- {
- if (mAgentFrustum[quads[j*4+k]]*dir[i]+d > 0.f)
- {
- return 1;
- }
- }
- }
- }
- }
-
- if (total_inside)
- {
- result = 1;
- }
- }
- else*/
+ bool result = false;
+ LLVector4a rscale, maxp, minp;
+ LLSimdScalar d;
+ for (U32 i = 0; i < mPlaneCount; i++)
{
- for (U32 i = 0; i < mPlaneCount; i++)
+ mask = mPlaneMask[i];
+ if (mask != 0xff)
{
- mask = mAgentPlanes[i].mask;
- if (mask == 0xff)
- {
- continue;
- }
- LLPlane p = mAgentPlanes[i].p;
- LLVector3 n = LLVector3(p);
- float d = p.mV[3];
- LLVector3 rscale = radius.scaledVec(scaler[mask]);
-
- LLVector3 minp = center - rscale;
- LLVector3 maxp = center + rscale;
-
- if (n * minp > -d)
+ const LLPlane& p(mAgentPlanes[i]);
+ p.getAt<3>(d);
+ rscale.setMul(radius, scaler[mask]);
+ minp.setSub(center, rscale);
+ d = -d;
+ if (p.dot3(minp).getF32() > d)
{
return 0;
}
-
- if (n * maxp > -d)
+
+ if(!result)
{
- result = 1;
+ maxp.setAdd(center, rscale);
+ result = (p.dot3(maxp).getF32() > d);
}
}
}
-
- return result;
+ return result?1:2;
}
-S32 LLCamera::AABBInFrustumNoFarClip(const LLVector3 &center, const LLVector3& radius)
+
+S32 LLCamera::AABBInFrustumNoFarClip(const LLVector4a& center, const LLVector4a& radius)
{
- static const LLVector3 scaler[] = {
- LLVector3(-1,-1,-1),
- LLVector3( 1,-1,-1),
- LLVector3(-1, 1,-1),
- LLVector3( 1, 1,-1),
- LLVector3(-1,-1, 1),
- LLVector3( 1,-1, 1),
- LLVector3(-1, 1, 1),
- LLVector3( 1, 1, 1)
+ static const LLVector4a scaler[] = {
+ LLVector4a(-1,-1,-1),
+ LLVector4a( 1,-1,-1),
+ LLVector4a(-1, 1,-1),
+ LLVector4a( 1, 1,-1),
+ LLVector4a(-1,-1, 1),
+ LLVector4a( 1,-1, 1),
+ LLVector4a(-1, 1, 1),
+ LLVector4a( 1, 1, 1)
};
U8 mask = 0;
- S32 result = 2;
-
+ bool result = false;
+ LLVector4a rscale, maxp, minp;
+ LLSimdScalar d;
for (U32 i = 0; i < mPlaneCount; i++)
{
- if (i == 5)
- {
- continue;
- }
-
- mask = mAgentPlanes[i].mask;
- if (mask == 0xff)
- {
- continue;
- }
- LLPlane p = mAgentPlanes[i].p;
- LLVector3 n = LLVector3(p);
- float d = p.mV[3];
- LLVector3 rscale = radius.scaledVec(scaler[mask]);
-
- LLVector3 minp = center - rscale;
- LLVector3 maxp = center + rscale;
-
- if (n * minp > -d)
+ mask = mPlaneMask[i];
+ if ((i != 5) && (mask != 0xff))
{
- return 0;
- }
-
- if (n * maxp > -d)
- {
- result = 1;
+ const LLPlane& p(mAgentPlanes[i]);
+ p.getAt<3>(d);
+ rscale.setMul(radius, scaler[mask]);
+ minp.setSub(center, rscale);
+ d = -d;
+ if (p.dot3(minp).getF32() > d)
+ {
+ return 0;
+ }
+
+ if(!result)
+ {
+ maxp.setAdd(center, rscale);
+ result = (p.dot3(maxp).getF32() > d);
+ }
}
}
- return result;
+ return result?1:2;
}
int LLCamera::sphereInFrustumQuick(const LLVector3 &sphere_center, const F32 radius)
@@ -438,28 +366,22 @@ int LLCamera::sphereInFrustumOld(const LLVector3 &sphere_center, const F32 radiu
int LLCamera::sphereInFrustum(const LLVector3 &sphere_center, const F32 radius) const
{
// Returns 1 if sphere is in frustum, 0 if not.
- int res = 2;
+ bool res = false;
for (int i = 0; i < 6; i++)
{
- if (mAgentPlanes[i].mask == 0xff)
+ if (mPlaneMask[i] != 0xff)
{
- continue;
- }
-
- float d = mAgentPlanes[i].p.dist(sphere_center);
+ float d = mAgentPlanes[i].dist(sphere_center);
- if (d > radius)
- {
- return 0;
- }
-
- if (d > -radius)
- {
- res = 1;
+ if (d > radius)
+ {
+ return 0;
+ }
+ res = res || (d > -radius);
}
}
- return res;
+ return res?1:2;
}
@@ -611,25 +533,6 @@ LLPlane planeFromPoints(LLVector3 p1, LLVector3 p2, LLVector3 p3)
return LLPlane(p1, n);
}
-U8 LLCamera::calcPlaneMask(const LLPlane& plane)
-{
- U8 mask = 0;
-
- if (plane.mV[0] >= 0)
- {
- mask |= 1;
- }
- if (plane.mV[1] >= 0)
- {
- mask |= 2;
- }
- if (plane.mV[2] >= 0)
- {
- mask |= 4;
- }
-
- return mask;
-}
void LLCamera::ignoreAgentFrustumPlane(S32 idx)
{
@@ -638,12 +541,13 @@ void LLCamera::ignoreAgentFrustumPlane(S32 idx)
return;
}
- mAgentPlanes[idx].mask = 0xff;
- mAgentPlanes[idx].p.clearVec();
+ mPlaneMask[idx] = 0xff;
+ mAgentPlanes[idx].clear();
}
void LLCamera::calcAgentFrustumPlanes(LLVector3* frust)
{
+
for (int i = 0; i < 8; i++)
{
mAgentFrustum[i] = frust[i];
@@ -656,27 +560,27 @@ void LLCamera::calcAgentFrustumPlanes(LLVector3* frust)
//order of planes is important, keep most likely to fail in the front of the list
//near - frust[0], frust[1], frust[2]
- mAgentPlanes[2].p = planeFromPoints(frust[0], frust[1], frust[2]);
+ mAgentPlanes[2] = planeFromPoints(frust[0], frust[1], frust[2]);
//far
- mAgentPlanes[5].p = planeFromPoints(frust[5], frust[4], frust[6]);
+ mAgentPlanes[5] = planeFromPoints(frust[5], frust[4], frust[6]);
//left
- mAgentPlanes[0].p = planeFromPoints(frust[4], frust[0], frust[7]);
+ mAgentPlanes[0] = planeFromPoints(frust[4], frust[0], frust[7]);
//right
- mAgentPlanes[1].p = planeFromPoints(frust[1], frust[5], frust[6]);
+ mAgentPlanes[1] = planeFromPoints(frust[1], frust[5], frust[6]);
//top
- mAgentPlanes[4].p = planeFromPoints(frust[3], frust[2], frust[6]);
+ mAgentPlanes[4] = planeFromPoints(frust[3], frust[2], frust[6]);
//bottom
- mAgentPlanes[3].p = planeFromPoints(frust[1], frust[0], frust[4]);
+ mAgentPlanes[3] = planeFromPoints(frust[1], frust[0], frust[4]);
//cache plane octant facing mask for use in AABBInFrustum
for (U32 i = 0; i < mPlaneCount; i++)
{
- mAgentPlanes[i].mask = calcPlaneMask(mAgentPlanes[i].p);
+ mPlaneMask[i] = mAgentPlanes[i].calcPlaneMask();
}
}
@@ -703,6 +607,7 @@ void LLCamera::calculateFrustumPlanes(F32 left, F32 right, F32 top, F32 bottom)
mLocalPlanes[PLANE_BOTTOM].setVec( a, c, b);
//calculate center and radius squared of frustum in world absolute coordinates
+ static LLVector3 const X_AXIS(1.f, 0.f, 0.f);
mFrustCenter = X_AXIS*mFarPlane*0.5f;
mFrustCenter = transformToAbsolute(mFrustCenter);
mFrustRadiusSquared = mFarPlane*0.5f;
@@ -729,9 +634,10 @@ void LLCamera::calculateWorldFrustumPlanes()
F32 d;
LLVector3 center = mOrigin - mXAxis*mNearPlane;
mWorldPlanePos = center;
+ LLVector3 pnorm;
for (int p=0; p<4; p++)
{
- LLVector3 pnorm = LLVector3(mLocalPlanes[p]);
+ mLocalPlanes[p].getVector3(pnorm);
LLVector3 norm = rotateToAbsolute(pnorm);
norm.normVec();
d = -(center * norm);
@@ -741,13 +647,15 @@ void LLCamera::calculateWorldFrustumPlanes()
LLVector3 zaxis(0, 0, 1.0f);
F32 yaw = getYaw();
{
- LLVector3 tnorm = LLVector3(mLocalPlanes[PLANE_LEFT]);
+ LLVector3 tnorm;
+ mLocalPlanes[PLANE_LEFT].getVector3(tnorm);
tnorm.rotVec(yaw, zaxis);
d = -(mOrigin * tnorm);
mHorizPlanes[HORIZ_PLANE_LEFT] = LLPlane(tnorm, d);
}
{
- LLVector3 tnorm = LLVector3(mLocalPlanes[PLANE_RIGHT]);
+ LLVector3 tnorm;
+ mLocalPlanes[PLANE_RIGHT].getVector3(tnorm);
tnorm.rotVec(yaw, zaxis);
d = -(mOrigin * tnorm);
mHorizPlanes[HORIZ_PLANE_RIGHT] = LLPlane(tnorm, d);
diff --git a/indra/llmath/llcamera.h b/indra/llmath/llcamera.h
index 922d6f9fac..ec67b91d05 100644
--- a/indra/llmath/llcamera.h
+++ b/indra/llmath/llcamera.h
@@ -31,6 +31,7 @@
#include "llmath.h"
#include "llcoordframe.h"
#include "llplane.h"
+#include "llvector4a.h"
const F32 DEFAULT_FIELD_OF_VIEW = 60.f * DEG_TO_RAD;
const F32 DEFAULT_ASPECT_RATIO = 640.f / 480.f;
@@ -50,15 +51,6 @@ const F32 MIN_FAR_PLANE = 0.2f;
static const F32 MIN_FIELD_OF_VIEW = 5.0f * DEG_TO_RAD;
static const F32 MAX_FIELD_OF_VIEW = 175.f * DEG_TO_RAD;
-static const LLVector3 X_AXIS(1.f,0.f,0.f);
-static const LLVector3 Y_AXIS(0.f,1.f,0.f);
-static const LLVector3 Z_AXIS(0.f,0.f,1.f);
-
-static const LLVector3 NEG_X_AXIS(-1.f,0.f,0.f);
-static const LLVector3 NEG_Y_AXIS(0.f,-1.f,0.f);
-static const LLVector3 NEG_Z_AXIS(0.f,0.f,-1.f);
-
-
// An LLCamera is an LLCoorFrame with a view frustum.
// This means that it has several methods for moving it around
// that are inherited from the LLCoordFrame() class :
@@ -73,6 +65,12 @@ class LLCamera
: public LLCoordFrame
{
public:
+
+ LLCamera(const LLCamera& rhs)
+ {
+ *this = rhs;
+ }
+
enum {
PLANE_LEFT = 0,
PLANE_RIGHT = 1,
@@ -110,6 +108,9 @@ public:
};
private:
+ LLPlane mAgentPlanes[7]; //frustum planes in agent space a la gluUnproject (I'm a bastard, I know) - DaveP
+ U8 mPlaneMask[8]; // 8 for alignment
+
F32 mView; // angle between top and bottom frustum planes in radians.
F32 mAspect; // width/height
S32 mViewHeightInPixels; // for ViewHeightInPixels() only
@@ -123,30 +124,22 @@ private:
LLPlane mWorldPlanes[PLANE_NUM];
LLPlane mHorizPlanes[HORIZ_PLANE_NUM];
- struct frustum_plane
- {
- frustum_plane() : mask(0) {}
- LLPlane p;
- U8 mask;
- };
- frustum_plane mAgentPlanes[7]; //frustum planes in agent space a la gluUnproject (I'm a bastard, I know) - DaveP
-
U32 mPlaneCount; //defaults to 6, if setUserClipPlane is called, uses user supplied clip plane in
LLVector3 mWorldPlanePos; // Position of World Planes (may be offset from camera)
public:
LLVector3 mAgentFrustum[8]; //8 corners of 6-plane frustum
F32 mFrustumCornerDist; //distance to corner of frustum against far clip plane
- LLPlane getAgentPlane(U32 idx) { return mAgentPlanes[idx].p; }
+ LLPlane& getAgentPlane(U32 idx) { return mAgentPlanes[idx]; }
public:
LLCamera();
LLCamera(F32 vertical_fov_rads, F32 aspect_ratio, S32 view_height_in_pixels, F32 near_plane, F32 far_plane);
- virtual ~LLCamera(){} // no-op virtual destructor
+ virtual ~LLCamera();
+
- void setUserClipPlane(LLPlane plane);
+ void setUserClipPlane(LLPlane& plane);
void disableUserClipPlane();
- U8 calcPlaneMask(const LLPlane& plane);
virtual void setView(F32 vertical_fov_rads);
void setViewHeightInPixels(S32 height);
void setAspect(F32 new_aspect);
@@ -193,8 +186,8 @@ public:
S32 sphereInFrustum(const LLVector3 &center, const F32 radius) const;
S32 pointInFrustum(const LLVector3 &point) const { return sphereInFrustum(point, 0.0f); }
S32 sphereInFrustumFull(const LLVector3 &center, const F32 radius) const { return sphereInFrustum(center, radius); }
- S32 AABBInFrustum(const LLVector3 &center, const LLVector3& radius);
- S32 AABBInFrustumNoFarClip(const LLVector3 &center, const LLVector3& radius);
+ S32 AABBInFrustum(const LLVector4a& center, const LLVector4a& radius);
+ S32 AABBInFrustumNoFarClip(const LLVector4a& center, const LLVector4a& radius);
//does a quick 'n dirty sphere-sphere check
S32 sphereInFrustumQuick(const LLVector3 &sphere_center, const F32 radius);
diff --git a/indra/llmath/llmath.h b/indra/llmath/llmath.h
index 798f1154d0..eea7c977fb 100644
--- a/indra/llmath/llmath.h
+++ b/indra/llmath/llmath.h
@@ -29,7 +29,7 @@
#include <cmath>
#include <cstdlib>
-#include <complex>
+#include <vector>
#include "lldefs.h"
//#include "llstl.h" // *TODO: Remove when LLString is gone
//#include "llstring.h" // *TODO: Remove when LLString is gone
@@ -55,32 +55,11 @@
#endif
// Single Precision Floating Point Routines
-#ifndef sqrtf
-#define sqrtf(x) ((F32)sqrt((F64)(x)))
-#endif
-#ifndef fsqrtf
-#define fsqrtf(x) sqrtf(x)
-#endif
-
-#ifndef cosf
-#define cosf(x) ((F32)cos((F64)(x)))
-#endif
-#ifndef sinf
-#define sinf(x) ((F32)sin((F64)(x)))
-#endif
-#ifndef tanf
+// (There used to be more defined here, but they appeared to be redundant and
+// were breaking some other includes. Removed by Falcon, reviewed by Andrew, 11/25/09)
+/*#ifndef tanf
#define tanf(x) ((F32)tan((F64)(x)))
-#endif
-#ifndef acosf
-#define acosf(x) ((F32)acos((F64)(x)))
-#endif
-
-#ifndef powf
-#define powf(x,y) ((F32)pow((F64)(x),(F64)(y)))
-#endif
-#ifndef expf
-#define expf(x) ((F32)exp((F64)(x)))
-#endif
+#endif*/
const F32 GRAVITY = -9.8f;
@@ -200,7 +179,7 @@ inline S32 llfloor( F32 f )
}
return result;
#else
- return (S32)floorf(f);
+ return (S32)floor(f);
#endif
}
@@ -378,11 +357,14 @@ inline F32 snap_to_sig_figs(F32 foo, S32 sig_figs)
bar *= 10.f;
}
- foo = (F32)llround(foo * bar);
+ //F32 new_foo = (F32)llround(foo * bar);
+ // the llround() implementation sucks. Don't us it.
- // shift back
- foo /= bar;
- return foo;
+ F32 sign = (foo > 0.f) ? 1.f : -1.f;
+ F32 new_foo = F32( S64(foo * bar + sign * 0.5f));
+ new_foo /= bar;
+
+ return new_foo;
}
inline F32 lerp(F32 a, F32 b, F32 u)
@@ -516,4 +498,45 @@ inline F32 llgaussian(F32 x, F32 o)
return 1.f/(F_SQRT_TWO_PI*o)*powf(F_E, -(x*x)/(2*o*o));
}
+//helper function for removing outliers
+template <class VEC_TYPE>
+inline void ll_remove_outliers(std::vector<VEC_TYPE>& data, F32 k)
+{
+ if (data.size() < 100)
+ { //not enough samples
+ return;
+ }
+
+ VEC_TYPE Q1 = data[data.size()/4];
+ VEC_TYPE Q3 = data[data.size()-data.size()/4-1];
+
+ VEC_TYPE min = (VEC_TYPE) ((F32) Q1-k * (F32) (Q3-Q1));
+ VEC_TYPE max = (VEC_TYPE) ((F32) Q3+k * (F32) (Q3-Q1));
+
+ U32 i = 0;
+ while (i < data.size() && data[i] < min)
+ {
+ i++;
+ }
+
+ S32 j = data.size()-1;
+ while (j > 0 && data[j] > max)
+ {
+ j--;
+ }
+
+ if (j < data.size()-1)
+ {
+ data.erase(data.begin()+j, data.end());
+ }
+
+ if (i > 0)
+ {
+ data.erase(data.begin(), data.begin()+i);
+ }
+}
+
+// Include simd math header
+#include "llsimdmath.h"
+
#endif
diff --git a/indra/llmath/llmatrix3a.cpp b/indra/llmath/llmatrix3a.cpp
new file mode 100644
index 0000000000..ab077abcb0
--- /dev/null
+++ b/indra/llmath/llmatrix3a.cpp
@@ -0,0 +1,134 @@
+/**
+ * @file llvector4a.cpp
+ * @brief SIMD vector implementation
+ *
+ * $LicenseInfo:firstyear=2010&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 "llmath.h"
+
+static LL_ALIGN_16(const F32 M_IDENT_3A[12]) =
+ { 1.f, 0.f, 0.f, 0.f, // Column 1
+ 0.f, 1.f, 0.f, 0.f, // Column 2
+ 0.f, 0.f, 1.f, 0.f }; // Column 3
+
+extern const LLMatrix3a LL_M3A_IDENTITY = *reinterpret_cast<const LLMatrix3a*> (M_IDENT_3A);
+
+void LLMatrix3a::setMul( const LLMatrix3a& lhs, const LLMatrix3a& rhs )
+{
+ const LLVector4a col0 = lhs.getColumn(0);
+ const LLVector4a col1 = lhs.getColumn(1);
+ const LLVector4a col2 = lhs.getColumn(2);
+
+ for ( int i = 0; i < 3; i++ )
+ {
+ LLVector4a xxxx = _mm_load_ss( rhs.mColumns[i].getF32ptr() );
+ xxxx.splat<0>( xxxx );
+ xxxx.mul( col0 );
+
+ {
+ LLVector4a yyyy = _mm_load_ss( rhs.mColumns[i].getF32ptr() + 1 );
+ yyyy.splat<0>( yyyy );
+ yyyy.mul( col1 );
+ xxxx.add( yyyy );
+ }
+
+ {
+ LLVector4a zzzz = _mm_load_ss( rhs.mColumns[i].getF32ptr() + 2 );
+ zzzz.splat<0>( zzzz );
+ zzzz.mul( col2 );
+ xxxx.add( zzzz );
+ }
+
+ xxxx.store4a( mColumns[i].getF32ptr() );
+ }
+
+}
+
+/*static */void LLMatrix3a::batchTransform( const LLMatrix3a& xform, const LLVector4a* src, int numVectors, LLVector4a* dst )
+{
+ const LLVector4a col0 = xform.getColumn(0);
+ const LLVector4a col1 = xform.getColumn(1);
+ const LLVector4a col2 = xform.getColumn(2);
+ const LLVector4a* maxAddr = src + numVectors;
+
+ if ( numVectors & 0x1 )
+ {
+ LLVector4a xxxx = _mm_load_ss( (const F32*)src );
+ LLVector4a yyyy = _mm_load_ss( (const F32*)src + 1 );
+ LLVector4a zzzz = _mm_load_ss( (const F32*)src + 2 );
+ xxxx.splat<0>( xxxx );
+ yyyy.splat<0>( yyyy );
+ zzzz.splat<0>( zzzz );
+ xxxx.mul( col0 );
+ yyyy.mul( col1 );
+ zzzz.mul( col2 );
+ xxxx.add( yyyy );
+ xxxx.add( zzzz );
+ xxxx.store4a( (F32*)dst );
+ src++;
+ dst++;
+ }
+
+
+ numVectors >>= 1;
+ while ( src < maxAddr )
+ {
+ _mm_prefetch( (const char*)(src + 32 ), _MM_HINT_NTA );
+ _mm_prefetch( (const char*)(dst + 32), _MM_HINT_NTA );
+ LLVector4a xxxx = _mm_load_ss( (const F32*)src );
+ LLVector4a xxxx1= _mm_load_ss( (const F32*)(src + 1) );
+
+ xxxx.splat<0>( xxxx );
+ xxxx1.splat<0>( xxxx1 );
+ xxxx.mul( col0 );
+ xxxx1.mul( col0 );
+
+ {
+ LLVector4a yyyy = _mm_load_ss( (const F32*)src + 1 );
+ LLVector4a yyyy1 = _mm_load_ss( (const F32*)(src + 1) + 1);
+ yyyy.splat<0>( yyyy );
+ yyyy1.splat<0>( yyyy1 );
+ yyyy.mul( col1 );
+ yyyy1.mul( col1 );
+ xxxx.add( yyyy );
+ xxxx1.add( yyyy1 );
+ }
+
+ {
+ LLVector4a zzzz = _mm_load_ss( (const F32*)(src) + 2 );
+ LLVector4a zzzz1 = _mm_load_ss( (const F32*)(++src) + 2 );
+ zzzz.splat<0>( zzzz );
+ zzzz1.splat<0>( zzzz1 );
+ zzzz.mul( col2 );
+ zzzz1.mul( col2 );
+ xxxx.add( zzzz );
+ xxxx1.add( zzzz1 );
+ }
+
+ xxxx.store4a(dst->getF32ptr());
+ src++;
+ dst++;
+
+ xxxx1.store4a((F32*)dst++);
+ }
+}
diff --git a/indra/llmath/llmatrix3a.h b/indra/llmath/llmatrix3a.h
new file mode 100644
index 0000000000..adb7e3389d
--- /dev/null
+++ b/indra/llmath/llmatrix3a.h
@@ -0,0 +1,128 @@
+/**
+ * @file llmatrix3a.h
+ * @brief LLMatrix3a class header file - memory aligned and vectorized 3x3 matrix
+ *
+ * $LicenseInfo:firstyear=2010&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_LLMATRIX3A_H
+#define LL_LLMATRIX3A_H
+
+/////////////////////////////
+// LLMatrix3a, LLRotation
+/////////////////////////////
+// This class stores a 3x3 (technically 4x3) matrix in column-major order
+/////////////////////////////
+/////////////////////////////
+// These classes are intentionally minimal right now. If you need additional
+// functionality, please contact someone with SSE experience (e.g., Falcon or
+// Huseby).
+/////////////////////////////
+
+// LLMatrix3a is the base class for LLRotation, which should be used instead any time you're dealing with a
+// rotation matrix.
+class LLMatrix3a
+{
+public:
+
+ // Utility function for quickly transforming an array of LLVector4a's
+ // For transforming a single LLVector4a, see LLVector4a::setRotated
+ static void batchTransform( const LLMatrix3a& xform, const LLVector4a* src, int numVectors, LLVector4a* dst );
+
+ // Utility function to obtain the identity matrix
+ static inline const LLMatrix3a& getIdentity();
+
+ //////////////////////////
+ // Ctors
+ //////////////////////////
+
+ // Ctor
+ LLMatrix3a() {}
+
+ // Ctor for setting by columns
+ inline LLMatrix3a( const LLVector4a& c0, const LLVector4a& c1, const LLVector4a& c2 );
+
+ //////////////////////////
+ // Get/Set
+ //////////////////////////
+
+ // Loads from an LLMatrix3
+ inline void loadu(const LLMatrix3& src);
+
+ // Set rows
+ inline void setRows(const LLVector4a& r0, const LLVector4a& r1, const LLVector4a& r2);
+
+ // Set columns
+ inline void setColumns(const LLVector4a& c0, const LLVector4a& c1, const LLVector4a& c2);
+
+ // Get the read-only access to a specified column. Valid columns are 0-2, but the
+ // function is unchecked. You've been warned.
+ inline const LLVector4a& getColumn(const U32 column) const;
+
+ /////////////////////////
+ // Matrix modification
+ /////////////////////////
+
+ // Set this matrix to the product of lhs and rhs ( this = lhs * rhs )
+ void setMul( const LLMatrix3a& lhs, const LLMatrix3a& rhs );
+
+ // Set this matrix to the transpose of src
+ inline void setTranspose(const LLMatrix3a& src);
+
+ // Set this matrix to a*w + b*(1-w)
+ inline void setLerp(const LLMatrix3a& a, const LLMatrix3a& b, F32 w);
+
+ /////////////////////////
+ // Matrix inspection
+ /////////////////////////
+
+ // Sets all 4 elements in 'dest' to the determinant of this matrix.
+ // If you will be using the determinant in subsequent ops with LLVector4a, use this version
+ inline void getDeterminant( LLVector4a& dest ) const;
+
+ // Returns the determinant as an LLSimdScalar. Use this if you will be using the determinant
+ // primary for scalar operations.
+ inline LLSimdScalar getDeterminant() const;
+
+ // Returns nonzero if rows 0-2 and colums 0-2 contain no NaN or INF values. Row 3 is ignored
+ inline LLBool32 isFinite() const;
+
+ // Returns true if this matrix is equal to 'rhs' up to 'tolerance'
+ inline bool isApproximatelyEqual( const LLMatrix3a& rhs, F32 tolerance = F_APPROXIMATELY_ZERO ) const;
+
+protected:
+
+ LLVector4a mColumns[3];
+
+};
+
+class LLRotation : public LLMatrix3a
+{
+public:
+
+ LLRotation() {}
+
+ // Returns true if this rotation is orthonormal with det ~= 1
+ inline bool isOkRotation() const;
+};
+
+#endif
diff --git a/indra/llmath/llmatrix3a.inl b/indra/llmath/llmatrix3a.inl
new file mode 100644
index 0000000000..37819fea3c
--- /dev/null
+++ b/indra/llmath/llmatrix3a.inl
@@ -0,0 +1,119 @@
+/**
+ * @file llmatrix3a.inl
+ * @brief LLMatrix3a inline definitions
+ *
+ * $LicenseInfo:firstyear=2010&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 "llmatrix3a.h"
+#include "m3math.h"
+
+inline LLMatrix3a::LLMatrix3a( const LLVector4a& c0, const LLVector4a& c1, const LLVector4a& c2 )
+{
+ setColumns( c0, c1, c2 );
+}
+
+inline void LLMatrix3a::loadu(const LLMatrix3& src)
+{
+ mColumns[0].load3(src.mMatrix[0]);
+ mColumns[1].load3(src.mMatrix[1]);
+ mColumns[2].load3(src.mMatrix[2]);
+}
+
+inline void LLMatrix3a::setRows(const LLVector4a& r0, const LLVector4a& r1, const LLVector4a& r2)
+{
+ mColumns[0] = r0;
+ mColumns[1] = r1;
+ mColumns[2] = r2;
+ setTranspose( *this );
+}
+
+inline void LLMatrix3a::setColumns(const LLVector4a& c0, const LLVector4a& c1, const LLVector4a& c2)
+{
+ mColumns[0] = c0;
+ mColumns[1] = c1;
+ mColumns[2] = c2;
+}
+
+inline void LLMatrix3a::setTranspose(const LLMatrix3a& src)
+{
+ const LLQuad srcCol0 = src.mColumns[0];
+ const LLQuad srcCol1 = src.mColumns[1];
+ const LLQuad unpacklo = _mm_unpacklo_ps( srcCol0, srcCol1 );
+ mColumns[0] = _mm_movelh_ps( unpacklo, src.mColumns[2] );
+ mColumns[1] = _mm_shuffle_ps( _mm_movehl_ps( srcCol0, unpacklo ), src.mColumns[2], _MM_SHUFFLE(0, 1, 1, 0) );
+ mColumns[2] = _mm_shuffle_ps( _mm_unpackhi_ps( srcCol0, srcCol1 ), src.mColumns[2], _MM_SHUFFLE(0, 2, 1, 0) );
+}
+
+inline const LLVector4a& LLMatrix3a::getColumn(const U32 column) const
+{
+ llassert( column < 3 );
+ return mColumns[column];
+}
+
+inline void LLMatrix3a::setLerp(const LLMatrix3a& a, const LLMatrix3a& b, F32 w)
+{
+ mColumns[0].setLerp( a.mColumns[0], b.mColumns[0], w );
+ mColumns[1].setLerp( a.mColumns[1], b.mColumns[1], w );
+ mColumns[2].setLerp( a.mColumns[2], b.mColumns[2], w );
+}
+
+inline LLBool32 LLMatrix3a::isFinite() const
+{
+ return mColumns[0].isFinite3() && mColumns[1].isFinite3() && mColumns[2].isFinite3();
+}
+
+inline void LLMatrix3a::getDeterminant( LLVector4a& dest ) const
+{
+ LLVector4a col1xcol2; col1xcol2.setCross3( mColumns[1], mColumns[2] );
+ dest.setAllDot3( col1xcol2, mColumns[0] );
+}
+
+inline LLSimdScalar LLMatrix3a::getDeterminant() const
+{
+ LLVector4a col1xcol2; col1xcol2.setCross3( mColumns[1], mColumns[2] );
+ return col1xcol2.dot3( mColumns[0] );
+}
+
+inline bool LLMatrix3a::isApproximatelyEqual( const LLMatrix3a& rhs, F32 tolerance /*= F_APPROXIMATELY_ZERO*/ ) const
+{
+ return rhs.getColumn(0).equals3(mColumns[0], tolerance)
+ && rhs.getColumn(1).equals3(mColumns[1], tolerance)
+ && rhs.getColumn(2).equals3(mColumns[2], tolerance);
+}
+
+inline const LLMatrix3a& LLMatrix3a::getIdentity()
+{
+ extern const LLMatrix3a LL_M3A_IDENTITY;
+ return LL_M3A_IDENTITY;
+}
+
+inline bool LLRotation::isOkRotation() const
+{
+ LLMatrix3a transpose; transpose.setTranspose( *this );
+ LLMatrix3a product; product.setMul( *this, transpose );
+
+ LLSimdScalar detMinusOne = getDeterminant() - 1.f;
+
+ return product.isApproximatelyEqual( LLMatrix3a::getIdentity() ) && (detMinusOne.getAbs() < F_APPROXIMATELY_ZERO);
+}
+
diff --git a/indra/llmath/llmatrix4a.h b/indra/llmath/llmatrix4a.h
new file mode 100644
index 0000000000..27cf5b79f6
--- /dev/null
+++ b/indra/llmath/llmatrix4a.h
@@ -0,0 +1,143 @@
+/**
+ * @file llmatrix4a.h
+ * @brief LLMatrix4a class header file - memory aligned and vectorized 4x4 matrix
+ *
+ * $LicenseInfo:firstyear=2007&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_LLMATRIX4A_H
+#define LL_LLMATRIX4A_H
+
+#include "llvector4a.h"
+#include "m4math.h"
+#include "m3math.h"
+
+class LLMatrix4a
+{
+public:
+ LLVector4a mMatrix[4];
+
+ inline void clear()
+ {
+ mMatrix[0].clear();
+ mMatrix[1].clear();
+ mMatrix[2].clear();
+ mMatrix[3].clear();
+ }
+
+ inline void loadu(const LLMatrix4& src)
+ {
+ mMatrix[0] = _mm_loadu_ps(src.mMatrix[0]);
+ mMatrix[1] = _mm_loadu_ps(src.mMatrix[1]);
+ mMatrix[2] = _mm_loadu_ps(src.mMatrix[2]);
+ mMatrix[3] = _mm_loadu_ps(src.mMatrix[3]);
+
+ }
+
+ inline void loadu(const LLMatrix3& src)
+ {
+ mMatrix[0].load3(src.mMatrix[0]);
+ mMatrix[1].load3(src.mMatrix[1]);
+ mMatrix[2].load3(src.mMatrix[2]);
+ mMatrix[3].set(0,0,0,1.f);
+ }
+
+ inline void add(const LLMatrix4a& rhs)
+ {
+ mMatrix[0].add(rhs.mMatrix[0]);
+ mMatrix[1].add(rhs.mMatrix[1]);
+ mMatrix[2].add(rhs.mMatrix[2]);
+ mMatrix[3].add(rhs.mMatrix[3]);
+ }
+
+ inline void setRows(const LLVector4a& r0, const LLVector4a& r1, const LLVector4a& r2)
+ {
+ mMatrix[0] = r0;
+ mMatrix[1] = r1;
+ mMatrix[2] = r2;
+ }
+
+ inline void setMul(const LLMatrix4a& m, const F32 s)
+ {
+ mMatrix[0].setMul(m.mMatrix[0], s);
+ mMatrix[1].setMul(m.mMatrix[1], s);
+ mMatrix[2].setMul(m.mMatrix[2], s);
+ mMatrix[3].setMul(m.mMatrix[3], s);
+ }
+
+ inline void setLerp(const LLMatrix4a& a, const LLMatrix4a& b, F32 w)
+ {
+ LLVector4a d0,d1,d2,d3;
+ d0.setSub(b.mMatrix[0], a.mMatrix[0]);
+ d1.setSub(b.mMatrix[1], a.mMatrix[1]);
+ d2.setSub(b.mMatrix[2], a.mMatrix[2]);
+ d3.setSub(b.mMatrix[3], a.mMatrix[3]);
+
+ // this = a + d*w
+
+ d0.mul(w);
+ d1.mul(w);
+ d2.mul(w);
+ d3.mul(w);
+
+ mMatrix[0].setAdd(a.mMatrix[0],d0);
+ mMatrix[1].setAdd(a.mMatrix[1],d1);
+ mMatrix[2].setAdd(a.mMatrix[2],d2);
+ mMatrix[3].setAdd(a.mMatrix[3],d3);
+ }
+
+ inline void rotate(const LLVector4a& v, LLVector4a& res)
+ {
+ res = _mm_shuffle_ps(v, v, _MM_SHUFFLE(0, 0, 0, 0));
+ res.mul(mMatrix[0]);
+
+ LLVector4a y;
+ y = _mm_shuffle_ps(v, v, _MM_SHUFFLE(1, 1, 1, 1));
+ y.mul(mMatrix[1]);
+
+ LLVector4a z;
+ z = _mm_shuffle_ps(v, v, _MM_SHUFFLE(2, 2, 2, 2));
+ z.mul(mMatrix[2]);
+
+ res.add(y);
+ res.add(z);
+ }
+
+ inline void affineTransform(const LLVector4a& v, LLVector4a& res)
+ {
+ LLVector4a x,y,z;
+
+ x = _mm_shuffle_ps(v, v, _MM_SHUFFLE(0, 0, 0, 0));
+ y = _mm_shuffle_ps(v, v, _MM_SHUFFLE(1, 1, 1, 1));
+ z = _mm_shuffle_ps(v, v, _MM_SHUFFLE(2, 2, 2, 2));
+
+ x.mul(mMatrix[0]);
+ y.mul(mMatrix[1]);
+ z.mul(mMatrix[2]);
+
+ x.add(y);
+ z.add(mMatrix[3]);
+ res.setAdd(x,z);
+ }
+};
+
+#endif
diff --git a/indra/llmath/lloctree.h b/indra/llmath/lloctree.h
index 90d4d742c9..fdfc24f8b7 100644
--- a/indra/llmath/lloctree.h
+++ b/indra/llmath/lloctree.h
@@ -29,14 +29,11 @@
#include "lltreenode.h"
#include "v3math.h"
+#include "llvector4a.h"
#include <vector>
#include <set>
-#if LL_RELEASE_WITH_DEBUG_INFO || LL_DEBUG
-#define OCT_ERRS LL_ERRS("OctreeErrors")
-#else
#define OCT_ERRS LL_WARNS("OctreeErrors")
-#endif
#define LL_OCTREE_PARANOIA_CHECK 0
#if LL_DARWIN
@@ -67,6 +64,13 @@ public:
};
template <class T>
+class LLOctreeTravelerDepthFirst : public LLOctreeTraveler<T>
+{
+public:
+ virtual void traverse(const LLOctreeNode<T>* node);
+};
+
+template <class T>
class LLOctreeNode : public LLTreeNode<T>
{
public:
@@ -81,23 +85,30 @@ public:
typedef LLOctreeNode<T> oct_node;
typedef LLOctreeListener<T> oct_listener;
- static const U8 OCTANT_POSITIVE_X = 0x01;
- static const U8 OCTANT_POSITIVE_Y = 0x02;
- static const U8 OCTANT_POSITIVE_Z = 0x04;
-
- LLOctreeNode( LLVector3d center,
- LLVector3d size,
+ /*void* operator new(size_t size)
+ {
+ return ll_aligned_malloc_16(size);
+ }
+
+ void operator delete(void* ptr)
+ {
+ ll_aligned_free_16(ptr);
+ }*/
+
+ LLOctreeNode( const LLVector4a& center,
+ const LLVector4a& size,
BaseType* parent,
U8 octant = 255)
: mParent((oct_node*)parent),
- mCenter(center),
- mSize(size),
mOctant(octant)
{
+ mCenter = center;
+ mSize = size;
+
updateMinMax();
if ((mOctant == 255) && mParent)
{
- mOctant = ((oct_node*) mParent)->getOctant(mCenter.mdV);
+ mOctant = ((oct_node*) mParent)->getOctant(mCenter);
}
clearChildren();
@@ -114,40 +125,24 @@ public:
}
inline const BaseType* getParent() const { return mParent; }
- inline void setParent(BaseType* parent) { mParent = (oct_node*) parent; }
- inline const LLVector3d& getCenter() const { return mCenter; }
- inline const LLVector3d& getSize() const { return mSize; }
- inline void setCenter(LLVector3d center) { mCenter = center; }
- inline void setSize(LLVector3d size) { mSize = size; }
- inline oct_node* getNodeAt(T* data) { return getNodeAt(data->getPositionGroup(), data->getBinRadius()); }
- inline U8 getOctant() const { return mOctant; }
- inline void setOctant(U8 octant) { mOctant = octant; }
+ inline void setParent(BaseType* parent) { mParent = (oct_node*) parent; }
+ inline const LLVector4a& getCenter() const { return mCenter; }
+ inline const LLVector4a& getSize() const { return mSize; }
+ inline void setCenter(const LLVector4a& center) { mCenter = center; }
+ inline void setSize(const LLVector4a& size) { mSize = size; }
+ inline oct_node* getNodeAt(T* data) { return getNodeAt(data->getPositionGroup(), data->getBinRadius()); }
+ inline U8 getOctant() const { return mOctant; }
inline const oct_node* getOctParent() const { return (const oct_node*) getParent(); }
inline oct_node* getOctParent() { return (oct_node*) getParent(); }
- U8 getOctant(const F64 pos[]) const //get the octant pos is in
+ U8 getOctant(const LLVector4a& pos) const //get the octant pos is in
{
- U8 ret = 0;
-
- if (pos[0] > mCenter.mdV[0])
- {
- ret |= OCTANT_POSITIVE_X;
- }
- if (pos[1] > mCenter.mdV[1])
- {
- ret |= OCTANT_POSITIVE_Y;
- }
- if (pos[2] > mCenter.mdV[2])
- {
- ret |= OCTANT_POSITIVE_Z;
- }
-
- return ret;
+ return (U8) (pos.greaterThan(mCenter).getGatheredBits() & 0x7);
}
- inline bool isInside(const LLVector3d& pos, const F64& rad) const
+ inline bool isInside(const LLVector4a& pos, const F32& rad) const
{
- return rad <= mSize.mdV[0]*2.0 && isInside(pos);
+ return rad <= mSize[0]*2.f && isInside(pos);
}
inline bool isInside(T* data) const
@@ -155,29 +150,27 @@ public:
return isInside(data->getPositionGroup(), data->getBinRadius());
}
- bool isInside(const LLVector3d& pos) const
+ bool isInside(const LLVector4a& pos) const
{
- const F64& x = pos.mdV[0];
- const F64& y = pos.mdV[1];
- const F64& z = pos.mdV[2];
-
- if (x > mMax.mdV[0] || x <= mMin.mdV[0] ||
- y > mMax.mdV[1] || y <= mMin.mdV[1] ||
- z > mMax.mdV[2] || z <= mMin.mdV[2])
+ S32 gt = pos.greaterThan(mMax).getGatheredBits() & 0x7;
+ if (gt)
{
return false;
}
-
+
+ S32 lt = pos.lessEqual(mMin).getGatheredBits() & 0x7;
+ if (lt)
+ {
+ return false;
+ }
+
return true;
}
void updateMinMax()
{
- for (U32 i = 0; i < 3; i++)
- {
- mMax.mdV[i] = mCenter.mdV[i] + mSize.mdV[i];
- mMin.mdV[i] = mCenter.mdV[i] - mSize.mdV[i];
- }
+ mMax.setAdd(mCenter, mSize);
+ mMin.setSub(mCenter, mSize);
}
inline oct_listener* getOctListener(U32 index)
@@ -190,34 +183,34 @@ public:
return contains(xform->getBinRadius());
}
- bool contains(F64 radius)
+ bool contains(F32 radius)
{
if (mParent == NULL)
{ //root node contains nothing
return false;
}
- F64 size = mSize.mdV[0];
- F64 p_size = size * 2.0;
+ F32 size = mSize[0];
+ F32 p_size = size * 2.f;
- return (radius <= 0.001 && size <= 0.001) ||
+ return (radius <= 0.001f && size <= 0.001f) ||
(radius <= p_size && radius > size);
}
- static void pushCenter(LLVector3d &center, const LLVector3d &size, const T* data)
+ static void pushCenter(LLVector4a &center, const LLVector4a &size, const T* data)
{
- const LLVector3d& pos = data->getPositionGroup();
- for (U32 i = 0; i < 3; i++)
- {
- if (pos.mdV[i] > center.mdV[i])
- {
- center.mdV[i] += size.mdV[i];
- }
- else
- {
- center.mdV[i] -= size.mdV[i];
- }
- }
+ const LLVector4a& pos = data->getPositionGroup();
+
+ LLVector4Logical gt = pos.greaterThan(center);
+
+ LLVector4a up;
+ up = _mm_and_ps(size, gt);
+
+ LLVector4a down;
+ down = _mm_andnot_ps(gt, size);
+
+ center.add(up);
+ center.sub(down);
}
void accept(oct_traveler* visitor) { visitor->visit(this); }
@@ -236,32 +229,49 @@ public:
void accept(tree_traveler* visitor) const { visitor->visit(this); }
void accept(oct_traveler* visitor) const { visitor->visit(this); }
- oct_node* getNodeAt(const LLVector3d& pos, const F64& rad)
+ void validateChildMap()
+ {
+ for (U32 i = 0; i < 8; i++)
+ {
+ U8 idx = mChildMap[i];
+ if (idx != 255)
+ {
+ LLOctreeNode<T>* child = mChild[idx];
+
+ if (child->getOctant() != i)
+ {
+ llerrs << "Invalid child map, bad octant data." << llendl;
+ }
+
+ if (getOctant(child->getCenter()) != child->getOctant())
+ {
+ llerrs << "Invalid child octant compared to position data." << llendl;
+ }
+ }
+ }
+ }
+
+
+ oct_node* getNodeAt(const LLVector4a& pos, const F32& rad)
{
LLOctreeNode<T>* node = this;
if (node->isInside(pos, rad))
{
//do a quick search by octant
- U8 octant = node->getOctant(pos.mdV);
- BOOL keep_going = TRUE;
-
+ U8 octant = node->getOctant(pos);
+
//traverse the tree until we find a node that has no node
//at the appropriate octant or is smaller than the object.
//by definition, that node is the smallest node that contains
// the data
- while (keep_going && node->getSize().mdV[0] >= rad)
+ U8 next_node = node->mChildMap[octant];
+
+ while (next_node != 255 && node->getSize()[0] >= rad)
{
- keep_going = FALSE;
- for (U32 i = 0; i < node->getChildCount() && !keep_going; i++)
- {
- if (node->getChild(i)->getOctant() == octant)
- {
- node = node->getChild(i);
- octant = node->getOctant(pos.mdV);
- keep_going = TRUE;
- }
- }
+ node = node->getChild(next_node);
+ octant = node->getOctant(pos);
+ next_node = node->mChildMap[octant];
}
}
else if (!node->contains(rad) && node->getParent())
@@ -276,7 +286,7 @@ public:
{
if (data == NULL)
{
- //OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE BRANCH !!!" << llendl;
+ OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE BRANCH !!!" << llendl;
return false;
}
LLOctreeNode<T>* parent = getOctParent();
@@ -284,10 +294,8 @@ public:
//is it here?
if (isInside(data->getPositionGroup()))
{
- if (getElementCount() < LL_OCTREE_MAX_CAPACITY &&
- (contains(data->getBinRadius()) ||
- (data->getBinRadius() > getSize().mdV[0] &&
- parent && parent->getElementCount() >= LL_OCTREE_MAX_CAPACITY)))
+ if ((getElementCount() < LL_OCTREE_MAX_CAPACITY && contains(data->getBinRadius()) ||
+ (data->getBinRadius() > getSize()[0] && parent && parent->getElementCount() >= LL_OCTREE_MAX_CAPACITY)))
{ //it belongs here
#if LL_OCTREE_PARANOIA_CHECK
//if this is a redundant insertion, error out (should never happen)
@@ -317,16 +325,21 @@ public:
}
//it's here, but no kids are in the right place, make a new kid
- LLVector3d center(getCenter());
- LLVector3d size(getSize()*0.5);
+ LLVector4a center = getCenter();
+ LLVector4a size = getSize();
+ size.mul(0.5f);
//push center in direction of data
LLOctreeNode<T>::pushCenter(center, size, data);
// handle case where floating point number gets too small
- if( llabs(center.mdV[0] - getCenter().mdV[0]) < F_APPROXIMATELY_ZERO &&
- llabs(center.mdV[1] - getCenter().mdV[1]) < F_APPROXIMATELY_ZERO &&
- llabs(center.mdV[2] - getCenter().mdV[2]) < F_APPROXIMATELY_ZERO)
+ LLVector4a val;
+ val.setSub(center, getCenter());
+ val.setAbs(val);
+
+ S32 lt = val.lessThan(LLVector4a::getEpsilon()).getGatheredBits() & 0x7;
+
+ if( lt == 0x7 )
{
mData.insert(data);
BaseType::insert(data);
@@ -344,7 +357,7 @@ public:
//make sure no existing node matches this position
for (U32 i = 0; i < getChildCount(); i++)
{
- if (mChild[i]->getCenter() == center)
+ if (mChild[i]->getCenter().equals3(center))
{
OCT_ERRS << "Octree detected duplicate child center and gave up." << llendl;
return false;
@@ -362,7 +375,7 @@ public:
else
{
//it's not in here, give it to the root
- //OCT_ERRS << "Octree insertion failed, starting over from root!" << llendl;
+ OCT_ERRS << "Octree insertion failed, starting over from root!" << llendl;
oct_node* node = this;
@@ -436,6 +449,9 @@ public:
void clearChildren()
{
mChild.clear();
+
+ U32* foo = (U32*) mChildMap;
+ foo[0] = foo[1] = 0xFFFFFFFF;
}
void validate()
@@ -469,13 +485,19 @@ public:
void addChild(oct_node* child, BOOL silent = FALSE)
{
#if LL_OCTREE_PARANOIA_CHECK
+
+ if (child->getSize().equals3(getSize()))
+ {
+ OCT_ERRS << "Child size is same as parent size!" << llendl;
+ }
+
for (U32 i = 0; i < getChildCount(); i++)
{
- if(mChild[i]->getSize() != child->getSize())
+ if(!mChild[i]->getSize().equals3(child->getSize()))
{
OCT_ERRS <<"Invalid octree child size." << llendl;
}
- if (mChild[i]->getCenter() == child->getCenter())
+ if (mChild[i]->getCenter().equals3(child->getCenter()))
{
OCT_ERRS <<"Duplicate octree child position." << llendl;
}
@@ -487,6 +509,8 @@ public:
}
#endif
+ mChildMap[child->getOctant()] = (U8) mChild.size();
+
mChild.push_back(child);
child->setParent(this);
@@ -500,7 +524,7 @@ public:
}
}
- void removeChild(U8 index, BOOL destroy = FALSE)
+ void removeChild(S32 index, BOOL destroy = FALSE)
{
for (U32 i = 0; i < this->getListenerCount(); i++)
{
@@ -508,6 +532,8 @@ public:
listener->handleChildRemoval(this, getChild(index));
}
+
+
if (destroy)
{
mChild[index]->destroy();
@@ -515,6 +541,15 @@ public:
}
mChild.erase(mChild.begin() + index);
+ //rebuild child map
+ U32* foo = (U32*) mChildMap;
+ foo[0] = foo[1] = 0xFFFFFFFF;
+
+ for (U32 i = 0; i < mChild.size(); ++i)
+ {
+ mChildMap[mChild[i]->getOctant()] = i;
+ }
+
checkAlive();
}
@@ -541,19 +576,32 @@ public:
}
}
- //OCT_ERRS << "Octree failed to delete requested child." << llendl;
+ OCT_ERRS << "Octree failed to delete requested child." << llendl;
}
protected:
- child_list mChild;
- element_list mData;
+ typedef enum
+ {
+ CENTER = 0,
+ SIZE = 1,
+ MAX = 2,
+ MIN = 3
+ } eDName;
+
+ LLVector4a mCenter;
+ LLVector4a mSize;
+ LLVector4a mMax;
+ LLVector4a mMin;
+
oct_node* mParent;
- LLVector3d mCenter;
- LLVector3d mSize;
- LLVector3d mMax;
- LLVector3d mMin;
U8 mOctant;
-};
+
+ child_list mChild;
+ U8 mChildMap[8];
+
+ element_list mData;
+
+};
//just like a regular node, except it might expand on insert and compress on balance
template <class T>
@@ -563,9 +611,9 @@ public:
typedef LLOctreeNode<T> BaseType;
typedef LLOctreeNode<T> oct_node;
- LLOctreeRoot( LLVector3d center,
- LLVector3d size,
- BaseType* parent)
+ LLOctreeRoot(const LLVector4a& center,
+ const LLVector4a& size,
+ BaseType* parent)
: BaseType(center, size, parent)
{
}
@@ -596,6 +644,8 @@ public:
//destroy child
child->clearChildren();
delete child;
+
+ return false;
}
return true;
@@ -606,28 +656,33 @@ public:
{
if (data == NULL)
{
- //OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE ROOT !!!" << llendl;
+ OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE ROOT !!!" << llendl;
return false;
}
if (data->getBinRadius() > 4096.0)
{
- //OCT_ERRS << "!!! ELEMENT EXCEEDS MAXIMUM SIZE IN OCTREE ROOT !!!" << llendl;
+ OCT_ERRS << "!!! ELEMENT EXCEEDS MAXIMUM SIZE IN OCTREE ROOT !!!" << llendl;
return false;
}
- const F64 MAX_MAG = 1024.0*1024.0;
+ LLVector4a MAX_MAG;
+ MAX_MAG.splat(1024.f*1024.f);
- const LLVector3d& v = data->getPositionGroup();
- if (!(fabs(v.mdV[0]-this->mCenter.mdV[0]) < MAX_MAG &&
- fabs(v.mdV[1]-this->mCenter.mdV[1]) < MAX_MAG &&
- fabs(v.mdV[2]-this->mCenter.mdV[2]) < MAX_MAG))
+ const LLVector4a& v = data->getPositionGroup();
+
+ LLVector4a val;
+ val.setSub(v, BaseType::mCenter);
+ val.setAbs(val);
+ S32 lt = val.lessThan(MAX_MAG).getGatheredBits() & 0x7;
+
+ if (lt != 0x7)
{
- //OCT_ERRS << "!!! ELEMENT EXCEEDS RANGE OF SPATIAL PARTITION !!!" << llendl;
+ OCT_ERRS << "!!! ELEMENT EXCEEDS RANGE OF SPATIAL PARTITION !!!" << llendl;
return false;
}
- if (this->getSize().mdV[0] > data->getBinRadius() && isInside(data->getPositionGroup()))
+ if (this->getSize()[0] > data->getBinRadius() && isInside(data->getPositionGroup()))
{
//we got it, just act like a branch
oct_node* node = getNodeAt(data);
@@ -643,31 +698,34 @@ public:
else if (this->getChildCount() == 0)
{
//first object being added, just wrap it up
- while (!(this->getSize().mdV[0] > data->getBinRadius() && isInside(data->getPositionGroup())))
+ while (!(this->getSize()[0] > data->getBinRadius() && isInside(data->getPositionGroup())))
{
- LLVector3d center, size;
+ LLVector4a center, size;
center = this->getCenter();
size = this->getSize();
LLOctreeNode<T>::pushCenter(center, size, data);
this->setCenter(center);
- this->setSize(size*2);
+ size.mul(2.f);
+ this->setSize(size);
this->updateMinMax();
}
LLOctreeNode<T>::insert(data);
}
else
{
- while (!(this->getSize().mdV[0] > data->getBinRadius() && isInside(data->getPositionGroup())))
+ while (!(this->getSize()[0] > data->getBinRadius() && isInside(data->getPositionGroup())))
{
//the data is outside the root node, we need to grow
- LLVector3d center(this->getCenter());
- LLVector3d size(this->getSize());
+ LLVector4a center(this->getCenter());
+ LLVector4a size(this->getSize());
//expand this node
- LLVector3d newcenter(center);
+ LLVector4a newcenter(center);
LLOctreeNode<T>::pushCenter(newcenter, size, data);
this->setCenter(newcenter);
- this->setSize(size*2);
+ LLVector4a size2 = size;
+ size2.mul(2.f);
+ this->setSize(size2);
this->updateMinMax();
//copy our children to a new branch
@@ -704,4 +762,15 @@ void LLOctreeTraveler<T>::traverse(const LLOctreeNode<T>* node)
traverse(node->getChild(i));
}
}
+
+template <class T>
+void LLOctreeTravelerDepthFirst<T>::traverse(const LLOctreeNode<T>* node)
+{
+ for (U32 i = 0; i < node->getChildCount(); i++)
+ {
+ traverse(node->getChild(i));
+ }
+ node->accept(this);
+}
+
#endif
diff --git a/indra/llmath/llplane.h b/indra/llmath/llplane.h
index 443f3f46b9..a611894721 100644
--- a/indra/llmath/llplane.h
+++ b/indra/llmath/llplane.h
@@ -36,19 +36,23 @@
// The plane normal = [A, B, C]
// The closest approach = D / sqrt(A*A + B*B + C*C)
-class LLPlane : public LLVector4
+class LLPlane
{
public:
+
+ // Constructors
LLPlane() {}; // no default constructor
LLPlane(const LLVector3 &p0, F32 d) { setVec(p0, d); }
LLPlane(const LLVector3 &p0, const LLVector3 &n) { setVec(p0, n); }
- void setVec(const LLVector3 &p0, F32 d) { LLVector4::setVec(p0[0], p0[1], p0[2], d); }
- void setVec(const LLVector3 &p0, const LLVector3 &n)
+ inline void setVec(const LLVector3 &p0, F32 d) { mV.set(p0[0], p0[1], p0[2], d); }
+
+ // Set
+ inline void setVec(const LLVector3 &p0, const LLVector3 &n)
{
F32 d = -(p0 * n);
setVec(n, d);
}
- void setVec(const LLVector3 &p0, const LLVector3 &p1, const LLVector3 &p2)
+ inline void setVec(const LLVector3 &p0, const LLVector3 &p1, const LLVector3 &p2)
{
LLVector3 u, v, w;
u = p1 - p0;
@@ -58,8 +62,38 @@ public:
F32 d = -(w * p0);
setVec(w, d);
}
- LLPlane& operator=(const LLVector4& v2) { LLVector4::setVec(v2[0],v2[1],v2[2],v2[3]); return *this;}
+
+ inline LLPlane& operator=(const LLVector4& v2) { mV.set(v2[0],v2[1],v2[2],v2[3]); return *this;}
+
+ inline LLPlane& operator=(const LLVector4a& v2) { mV.set(v2[0],v2[1],v2[2],v2[3]); return *this;}
+
+ inline void set(const LLPlane& p2) { mV = p2.mV; }
+
+ //
F32 dist(const LLVector3 &v2) const { return mV[0]*v2[0] + mV[1]*v2[1] + mV[2]*v2[2] + mV[3]; }
+
+ inline LLSimdScalar dot3(const LLVector4a& b) const { return mV.dot3(b); }
+
+ // Read-only access a single float in this vector. Do not use in proximity to any function call that manipulates
+ // the data at the whole vector level or you will incur a substantial penalty. Consider using the splat functions instead
+ inline F32 operator[](const S32 idx) const { return mV[idx]; }
+
+ // preferable when index is known at compile time
+ template <int N> LL_FORCE_INLINE void getAt(LLSimdScalar& v) const { v = mV.getScalarAt<N>(); }
+
+ // reset the vector to 0, 0, 0, 1
+ inline void clear() { mV.set(0, 0, 0, 1); }
+
+ inline void getVector3(LLVector3& vec) const { vec.set(mV[0], mV[1], mV[2]); }
+
+ // Retrieve the mask indicating which of the x, y, or z axis are greater or equal to zero.
+ inline U8 calcPlaneMask()
+ {
+ return mV.greaterEqual(LLVector4a::getZero()).getGatheredBits() & LLVector4Logical::MASK_XYZ;
+ }
+
+private:
+ LLVector4a mV;
};
diff --git a/indra/llmath/llquantize.h b/indra/llmath/llquantize.h
index 7f56ff3448..1595dbecf8 100644
--- a/indra/llmath/llquantize.h
+++ b/indra/llmath/llquantize.h
@@ -29,10 +29,16 @@
#define LL_LLQUANTIZE_H
const U16 U16MAX = 65535;
+LL_ALIGN_16( const F32 F_U16MAX_4A[4] ) = { 65535.f, 65535.f, 65535.f, 65535.f };
+
const F32 OOU16MAX = 1.f/(F32)(U16MAX);
+LL_ALIGN_16( const F32 F_OOU16MAX_4A[4] ) = { OOU16MAX, OOU16MAX, OOU16MAX, OOU16MAX };
const U8 U8MAX = 255;
+LL_ALIGN_16( const F32 F_U8MAX_4A[4] ) = { 255.f, 255.f, 255.f, 255.f };
+
const F32 OOU8MAX = 1.f/(F32)(U8MAX);
+LL_ALIGN_16( const F32 F_OOU8MAX_4A[4] ) = { OOU8MAX, OOU8MAX, OOU8MAX, OOU8MAX };
const U8 FIRSTVALIDCHAR = 54;
const U8 MAXSTRINGVAL = U8MAX - FIRSTVALIDCHAR; //we don't allow newline or null
diff --git a/indra/llmath/llquaternion.cpp b/indra/llmath/llquaternion.cpp
index a51f11072c..7381d5eb99 100644
--- a/indra/llmath/llquaternion.cpp
+++ b/indra/llmath/llquaternion.cpp
@@ -26,9 +26,10 @@
#include "linden_common.h"
+#include "llmath.h" // for F_PI
+
#include "llquaternion.h"
-#include "llmath.h" // for F_PI
//#include "vmath.h"
#include "v3math.h"
#include "v3dmath.h"
diff --git a/indra/llmath/llquaternion.h b/indra/llmath/llquaternion.h
index 26da14ae20..ca0dfe206b 100644
--- a/indra/llmath/llquaternion.h
+++ b/indra/llmath/llquaternion.h
@@ -27,7 +27,11 @@
#ifndef LLQUATERNION_H
#define LLQUATERNION_H
-#include "llmath.h"
+#include <iostream>
+
+#ifndef LLMATH_H //enforce specific include order to avoid tangling inline dependencies
+#error "Please include llmath.h first."
+#endif
class LLVector4;
class LLVector3;
diff --git a/indra/llmath/llquaternion2.h b/indra/llmath/llquaternion2.h
new file mode 100644
index 0000000000..fd9c0cf3ab
--- /dev/null
+++ b/indra/llmath/llquaternion2.h
@@ -0,0 +1,105 @@
+/**
+ * @file llquaternion2.h
+ * @brief LLQuaternion2 class header file - SIMD-enabled quaternion class
+ *
+ * $LicenseInfo:firstyear=2010&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_QUATERNION2_H
+#define LL_QUATERNION2_H
+
+/////////////////////////////
+// LLQuaternion2
+/////////////////////////////
+// This class stores a quaternion x*i + y*j + z*k + w in <x, y, z, w> order
+// (i.e., w in high order element of vector)
+/////////////////////////////
+/////////////////////////////
+// These classes are intentionally minimal right now. If you need additional
+// functionality, please contact someone with SSE experience (e.g., Falcon or
+// Huseby).
+/////////////////////////////
+#include "llquaternion.h"
+
+class LLQuaternion2
+{
+public:
+
+ //////////////////////////
+ // Ctors
+ //////////////////////////
+
+ // Ctor
+ LLQuaternion2() {}
+
+ // Ctor from LLQuaternion
+ explicit LLQuaternion2( const class LLQuaternion& quat );
+
+ //////////////////////////
+ // Get/Set
+ //////////////////////////
+
+ // Load from an LLQuaternion
+ inline void operator=( const LLQuaternion& quat )
+ {
+ mQ.loadua( quat.mQ );
+ }
+
+ // Return the internal LLVector4a representation of the quaternion
+ inline const LLVector4a& getVector4a() const;
+ inline LLVector4a& getVector4aRw();
+
+ /////////////////////////
+ // Quaternion modification
+ /////////////////////////
+
+ // Set this quaternion to the conjugate of src
+ inline void setConjugate(const LLQuaternion2& src);
+
+ // Renormalizes the quaternion. Assumes it has nonzero length.
+ inline void normalize();
+
+ // Quantize this quaternion to 8 bit precision
+ inline void quantize8();
+
+ // Quantize this quaternion to 16 bit precision
+ inline void quantize16();
+
+ /////////////////////////
+ // Quaternion inspection
+ /////////////////////////
+
+ // Return true if this quaternion is equal to 'rhs'.
+ // Note! Quaternions exhibit "double-cover", so any rotation has two equally valid
+ // quaternion representations and they will NOT compare equal.
+ inline bool equals(const LLQuaternion2& rhs, F32 tolerance = F_APPROXIMATELY_ZERO ) const;
+
+ // Return true if all components are finite and the quaternion is normalized
+ inline bool isOkRotation() const;
+
+protected:
+
+ LLVector4a mQ;
+
+};
+
+#endif
diff --git a/indra/llmath/llquaternion2.inl b/indra/llmath/llquaternion2.inl
new file mode 100644
index 0000000000..2a6987552d
--- /dev/null
+++ b/indra/llmath/llquaternion2.inl
@@ -0,0 +1,102 @@
+/**
+ * @file llquaternion2.inl
+ * @brief LLQuaternion2 inline definitions
+ *
+ * $LicenseInfo:firstyear=2010&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 "llquaternion2.h"
+
+static const LLQuad LL_V4A_PLUS_ONE = {1.f, 1.f, 1.f, 1.f};
+static const LLQuad LL_V4A_MINUS_ONE = {-1.f, -1.f, -1.f, -1.f};
+
+// Ctor from LLQuaternion
+inline LLQuaternion2::LLQuaternion2( const LLQuaternion& quat )
+{
+ mQ.set(quat.mQ[VX], quat.mQ[VY], quat.mQ[VZ], quat.mQ[VW]);
+}
+
+//////////////////////////
+// Get/Set
+//////////////////////////
+
+// Return the internal LLVector4a representation of the quaternion
+inline const LLVector4a& LLQuaternion2::getVector4a() const
+{
+ return mQ;
+}
+
+inline LLVector4a& LLQuaternion2::getVector4aRw()
+{
+ return mQ;
+}
+
+/////////////////////////
+// Quaternion modification
+/////////////////////////
+
+// Set this quaternion to the conjugate of src
+inline void LLQuaternion2::setConjugate(const LLQuaternion2& src)
+{
+ static LL_ALIGN_16( const U32 F_QUAT_INV_MASK_4A[4] ) = { 0x80000000, 0x80000000, 0x80000000, 0x00000000 };
+ mQ = _mm_xor_ps(src.mQ, *reinterpret_cast<const LLQuad*>(&F_QUAT_INV_MASK_4A));
+}
+
+// Renormalizes the quaternion. Assumes it has nonzero length.
+inline void LLQuaternion2::normalize()
+{
+ mQ.normalize4();
+}
+
+// Quantize this quaternion to 8 bit precision
+inline void LLQuaternion2::quantize8()
+{
+ mQ.quantize8( LL_V4A_MINUS_ONE, LL_V4A_PLUS_ONE );
+ normalize();
+}
+
+// Quantize this quaternion to 16 bit precision
+inline void LLQuaternion2::quantize16()
+{
+ mQ.quantize16( LL_V4A_MINUS_ONE, LL_V4A_PLUS_ONE );
+ normalize();
+}
+
+
+/////////////////////////
+// Quaternion inspection
+/////////////////////////
+
+// Return true if this quaternion is equal to 'rhs'.
+// Note! Quaternions exhibit "double-cover", so any rotation has two equally valid
+// quaternion representations and they will NOT compare equal.
+inline bool LLQuaternion2::equals(const LLQuaternion2 &rhs, F32 tolerance/* = F_APPROXIMATELY_ZERO*/) const
+{
+ return mQ.equals4(rhs.mQ, tolerance);
+}
+
+// Return true if all components are finite and the quaternion is normalized
+inline bool LLQuaternion2::isOkRotation() const
+{
+ return mQ.isFinite4() && mQ.isNormalized4();
+}
+
diff --git a/indra/llmath/llsimdmath.h b/indra/llmath/llsimdmath.h
new file mode 100644
index 0000000000..c7cdf7b32c
--- /dev/null
+++ b/indra/llmath/llsimdmath.h
@@ -0,0 +1,93 @@
+/**
+ * @file llsimdmath.h
+ * @brief Common header for SIMD-based math library (llvector4a, llmatrix3a, etc.)
+ *
+ * $LicenseInfo:firstyear=2010&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_SIMD_MATH_H
+#define LL_SIMD_MATH_H
+
+#ifndef LLMATH_H
+#error "Please include llmath.h before this file."
+#endif
+
+#if ( ( LL_DARWIN || LL_LINUX ) && !(__SSE2__) ) || ( LL_WINDOWS && ( _M_IX86_FP < 2 ) )
+#error SSE2 not enabled. LLVector4a and related class will not compile.
+#endif
+
+#if !LL_WINDOWS
+#include <stdint.h>
+#endif
+
+template <typename T> T* LL_NEXT_ALIGNED_ADDRESS(T* address)
+{
+ return reinterpret_cast<T*>(
+ (reinterpret_cast<uintptr_t>(address) + 0xF) & ~0xF);
+}
+
+template <typename T> T* LL_NEXT_ALIGNED_ADDRESS_64(T* address)
+{
+ return reinterpret_cast<T*>(
+ (reinterpret_cast<uintptr_t>(address) + 0x3F) & ~0x3F);
+}
+
+#if LL_LINUX || LL_DARWIN
+
+#define LL_ALIGN_PREFIX(x)
+#define LL_ALIGN_POSTFIX(x) __attribute__((aligned(x)))
+
+#elif LL_WINDOWS
+
+#define LL_ALIGN_PREFIX(x) __declspec(align(x))
+#define LL_ALIGN_POSTFIX(x)
+
+#else
+#error "LL_ALIGN_PREFIX and LL_ALIGN_POSTFIX undefined"
+#endif
+
+#define LL_ALIGN_16(var) LL_ALIGN_PREFIX(16) var LL_ALIGN_POSTFIX(16)
+
+
+
+#include <xmmintrin.h>
+#include <emmintrin.h>
+
+#include "llsimdtypes.h"
+#include "llsimdtypes.inl"
+
+class LLMatrix3a;
+class LLRotation;
+class LLMatrix3;
+
+#include "llquaternion.h"
+
+#include "llvector4logical.h"
+#include "llvector4a.h"
+#include "llmatrix3a.h"
+#include "llquaternion2.h"
+#include "llvector4a.inl"
+#include "llmatrix3a.inl"
+#include "llquaternion2.inl"
+
+
+#endif //LL_SIMD_MATH_H
diff --git a/indra/llmath/llsimdtypes.h b/indra/llmath/llsimdtypes.h
new file mode 100644
index 0000000000..bd991d0e71
--- /dev/null
+++ b/indra/llmath/llsimdtypes.h
@@ -0,0 +1,124 @@
+/**
+ * @file llsimdtypes.h
+ * @brief Declaration of basic SIMD math related types
+ *
+ * $LicenseInfo:firstyear=2010&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_SIMD_TYPES_H
+#define LL_SIMD_TYPES_H
+
+#ifndef LL_SIMD_MATH_H
+#error "Please include llmath.h before this file."
+#endif
+
+typedef __m128 LLQuad;
+
+
+#if LL_WINDOWS
+#pragma warning(push)
+#pragma warning( disable : 4800 3 ) // Disable warning about casting int to bool for this class.
+#if defined(_MSC_VER) && (_MSC_VER < 1500)
+// VC++ 2005 is missing these intrinsics
+// __forceinline is MSVC specific and attempts to override compiler inlining judgment. This is so
+// even in debug builds this call is a NOP.
+__forceinline const __m128 _mm_castsi128_ps( const __m128i a ) { return reinterpret_cast<const __m128&>(a); }
+__forceinline const __m128i _mm_castps_si128( const __m128 a ) { return reinterpret_cast<const __m128i&>(a); }
+#endif // _MSC_VER
+
+#endif // LL_WINDOWS
+
+class LLBool32
+{
+public:
+ inline LLBool32() {}
+ inline LLBool32(int rhs) : m_bool(rhs) {}
+ inline LLBool32(unsigned int rhs) : m_bool(rhs) {}
+ inline LLBool32(bool rhs) { m_bool = static_cast<const int>(rhs); }
+ inline LLBool32& operator= (bool rhs) { m_bool = (int)rhs; return *this; }
+ inline bool operator== (bool rhs) const { return static_cast<const bool&>(m_bool) == rhs; }
+ inline bool operator!= (bool rhs) const { return !operator==(rhs); }
+ inline operator bool() const { return static_cast<const bool&>(m_bool); }
+
+private:
+ int m_bool;
+};
+
+#if LL_WINDOWS
+#pragma warning(pop)
+#endif
+
+class LLSimdScalar
+{
+public:
+ inline LLSimdScalar() {}
+ inline LLSimdScalar(LLQuad q)
+ {
+ mQ = q;
+ }
+
+ inline LLSimdScalar(F32 f)
+ {
+ mQ = _mm_set_ss(f);
+ }
+
+ static inline const LLSimdScalar& getZero()
+ {
+ extern const LLQuad F_ZERO_4A;
+ return reinterpret_cast<const LLSimdScalar&>(F_ZERO_4A);
+ }
+
+ inline F32 getF32() const;
+
+ inline LLBool32 isApproximatelyEqual(const LLSimdScalar& rhs, F32 tolerance = F_APPROXIMATELY_ZERO) const;
+
+ inline LLSimdScalar getAbs() const;
+
+ inline void setMax( const LLSimdScalar& a, const LLSimdScalar& b );
+
+ inline void setMin( const LLSimdScalar& a, const LLSimdScalar& b );
+
+ inline LLSimdScalar& operator=(F32 rhs);
+
+ inline LLSimdScalar& operator+=(const LLSimdScalar& rhs);
+
+ inline LLSimdScalar& operator-=(const LLSimdScalar& rhs);
+
+ inline LLSimdScalar& operator*=(const LLSimdScalar& rhs);
+
+ inline LLSimdScalar& operator/=(const LLSimdScalar& rhs);
+
+ inline operator LLQuad() const
+ {
+ return mQ;
+ }
+
+ inline const LLQuad& getQuad() const
+ {
+ return mQ;
+ }
+
+private:
+ LLQuad mQ;
+};
+
+#endif //LL_SIMD_TYPES_H
diff --git a/indra/llmath/llsimdtypes.inl b/indra/llmath/llsimdtypes.inl
new file mode 100644
index 0000000000..712239e425
--- /dev/null
+++ b/indra/llmath/llsimdtypes.inl
@@ -0,0 +1,157 @@
+/**
+ * @file llsimdtypes.inl
+ * @brief Inlined definitions of basic SIMD math related types
+ *
+ * $LicenseInfo:firstyear=2010&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$
+ */
+
+
+
+
+//////////////////
+// LLSimdScalar
+//////////////////
+
+inline LLSimdScalar operator+(const LLSimdScalar& a, const LLSimdScalar& b)
+{
+ LLSimdScalar t(a);
+ t += b;
+ return t;
+}
+
+inline LLSimdScalar operator-(const LLSimdScalar& a, const LLSimdScalar& b)
+{
+ LLSimdScalar t(a);
+ t -= b;
+ return t;
+}
+
+inline LLSimdScalar operator*(const LLSimdScalar& a, const LLSimdScalar& b)
+{
+ LLSimdScalar t(a);
+ t *= b;
+ return t;
+}
+
+inline LLSimdScalar operator/(const LLSimdScalar& a, const LLSimdScalar& b)
+{
+ LLSimdScalar t(a);
+ t /= b;
+ return t;
+}
+
+inline LLSimdScalar operator-(const LLSimdScalar& a)
+{
+ static LL_ALIGN_16(const U32 signMask[4]) = {0x80000000, 0x80000000, 0x80000000, 0x80000000 };
+ return _mm_xor_ps(*reinterpret_cast<const LLQuad*>(signMask), a);
+}
+
+inline LLBool32 operator==(const LLSimdScalar& a, const LLSimdScalar& b)
+{
+ return _mm_comieq_ss(a, b);
+}
+
+inline LLBool32 operator!=(const LLSimdScalar& a, const LLSimdScalar& b)
+{
+ return _mm_comineq_ss(a, b);
+}
+
+inline LLBool32 operator<(const LLSimdScalar& a, const LLSimdScalar& b)
+{
+ return _mm_comilt_ss(a, b);
+}
+
+inline LLBool32 operator<=(const LLSimdScalar& a, const LLSimdScalar& b)
+{
+ return _mm_comile_ss(a, b);
+}
+
+inline LLBool32 operator>(const LLSimdScalar& a, const LLSimdScalar& b)
+{
+ return _mm_comigt_ss(a, b);
+}
+
+inline LLBool32 operator>=(const LLSimdScalar& a, const LLSimdScalar& b)
+{
+ return _mm_comige_ss(a, b);
+}
+
+inline LLBool32 LLSimdScalar::isApproximatelyEqual(const LLSimdScalar& rhs, F32 tolerance /* = F_APPROXIMATELY_ZERO */) const
+{
+ const LLSimdScalar tol( tolerance );
+ const LLSimdScalar diff = _mm_sub_ss( mQ, rhs.mQ );
+ const LLSimdScalar absDiff = diff.getAbs();
+ return absDiff <= tol;
+}
+
+inline void LLSimdScalar::setMax( const LLSimdScalar& a, const LLSimdScalar& b )
+{
+ mQ = _mm_max_ss( a, b );
+}
+
+inline void LLSimdScalar::setMin( const LLSimdScalar& a, const LLSimdScalar& b )
+{
+ mQ = _mm_min_ss( a, b );
+}
+
+inline LLSimdScalar& LLSimdScalar::operator=(F32 rhs)
+{
+ mQ = _mm_set_ss(rhs);
+ return *this;
+}
+
+inline LLSimdScalar& LLSimdScalar::operator+=(const LLSimdScalar& rhs)
+{
+ mQ = _mm_add_ss( mQ, rhs );
+ return *this;
+}
+
+inline LLSimdScalar& LLSimdScalar::operator-=(const LLSimdScalar& rhs)
+{
+ mQ = _mm_sub_ss( mQ, rhs );
+ return *this;
+}
+
+inline LLSimdScalar& LLSimdScalar::operator*=(const LLSimdScalar& rhs)
+{
+ mQ = _mm_mul_ss( mQ, rhs );
+ return *this;
+}
+
+inline LLSimdScalar& LLSimdScalar::operator/=(const LLSimdScalar& rhs)
+{
+ mQ = _mm_div_ss( mQ, rhs );
+ return *this;
+}
+
+inline LLSimdScalar LLSimdScalar::getAbs() const
+{
+ static const LL_ALIGN_16(U32 F_ABS_MASK_4A[4]) = { 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF };
+ return _mm_and_ps( mQ, *reinterpret_cast<const LLQuad*>(F_ABS_MASK_4A));
+}
+
+inline F32 LLSimdScalar::getF32() const
+{
+ F32 ret;
+ _mm_store_ss(&ret, mQ);
+ return ret;
+}
diff --git a/indra/llmath/lltreenode.h b/indra/llmath/lltreenode.h
index a462d1659e..c66bc26176 100644
--- a/indra/llmath/lltreenode.h
+++ b/indra/llmath/lltreenode.h
@@ -28,6 +28,9 @@
#include "stdtypes.h"
#include "xform.h"
+#include "llpointer.h"
+#include "llrefcount.h"
+
#include <vector>
template <class T> class LLTreeNode;
diff --git a/indra/llmath/llvector4a.cpp b/indra/llmath/llvector4a.cpp
new file mode 100644
index 0000000000..b66b7a7076
--- /dev/null
+++ b/indra/llmath/llvector4a.cpp
@@ -0,0 +1,222 @@
+/**
+ * @file llvector4a.cpp
+ * @brief SIMD vector implementation
+ *
+ * $LicenseInfo:firstyear=2010&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 "llmath.h"
+#include "llquantize.h"
+
+extern const LLQuad F_ZERO_4A = { 0, 0, 0, 0 };
+extern const LLQuad F_APPROXIMATELY_ZERO_4A = {
+ F_APPROXIMATELY_ZERO,
+ F_APPROXIMATELY_ZERO,
+ F_APPROXIMATELY_ZERO,
+ F_APPROXIMATELY_ZERO
+};
+
+extern const LLVector4a LL_V4A_ZERO = reinterpret_cast<const LLVector4a&> ( F_ZERO_4A );
+extern const LLVector4a LL_V4A_EPSILON = reinterpret_cast<const LLVector4a&> ( F_APPROXIMATELY_ZERO_4A );
+
+/*static */void LLVector4a::memcpyNonAliased16(F32* __restrict dst, const F32* __restrict src, size_t bytes)
+{
+ assert(src != NULL);
+ assert(dst != NULL);
+ assert(bytes > 0);
+ assert((bytes % sizeof(F32))== 0);
+
+ F32* end = dst + (bytes / sizeof(F32) );
+
+ if (bytes > 64)
+ {
+ F32* begin_64 = LL_NEXT_ALIGNED_ADDRESS_64(dst);
+
+ //at least 64 (16*4) bytes before the end of the destination, switch to 16 byte copies
+ F32* end_64 = end-16;
+
+ _mm_prefetch((char*)begin_64, _MM_HINT_NTA);
+ _mm_prefetch((char*)begin_64 + 64, _MM_HINT_NTA);
+ _mm_prefetch((char*)begin_64 + 128, _MM_HINT_NTA);
+ _mm_prefetch((char*)begin_64 + 192, _MM_HINT_NTA);
+
+ while (dst < begin_64)
+ {
+ copy4a(dst, src);
+ dst += 4;
+ src += 4;
+ }
+
+ while (dst < end_64)
+ {
+ _mm_prefetch((char*)src + 512, _MM_HINT_NTA);
+ _mm_prefetch((char*)dst + 512, _MM_HINT_NTA);
+ copy4a(dst, src);
+ copy4a(dst+4, src+4);
+ copy4a(dst+8, src+8);
+ copy4a(dst+12, src+12);
+
+ dst += 16;
+ src += 16;
+ }
+ }
+
+ while (dst < end)
+ {
+ copy4a(dst, src);
+ dst += 4;
+ src += 4;
+ }
+}
+
+void LLVector4a::setRotated( const LLRotation& rot, const LLVector4a& vec )
+{
+ const LLVector4a col0 = rot.getColumn(0);
+ const LLVector4a col1 = rot.getColumn(1);
+ const LLVector4a col2 = rot.getColumn(2);
+
+ LLVector4a result = _mm_load_ss( vec.getF32ptr() );
+ result.splat<0>( result );
+ result.mul( col0 );
+
+ {
+ LLVector4a yyyy = _mm_load_ss( vec.getF32ptr() + 1 );
+ yyyy.splat<0>( yyyy );
+ yyyy.mul( col1 );
+ result.add( yyyy );
+ }
+
+ {
+ LLVector4a zzzz = _mm_load_ss( vec.getF32ptr() + 2 );
+ zzzz.splat<0>( zzzz );
+ zzzz.mul( col2 );
+ result.add( zzzz );
+ }
+
+ *this = result;
+}
+
+void LLVector4a::setRotated( const LLQuaternion2& quat, const LLVector4a& vec )
+{
+ const LLVector4a& quatVec = quat.getVector4a();
+ LLVector4a temp; temp.setCross3(quatVec, vec);
+ temp.add( temp );
+
+ const LLVector4a realPart( quatVec.getScalarAt<3>() );
+ LLVector4a tempTimesReal; tempTimesReal.setMul( temp, realPart );
+
+ mQ = vec;
+ add( tempTimesReal );
+
+ LLVector4a imagCrossTemp; imagCrossTemp.setCross3( quatVec, temp );
+ add(imagCrossTemp);
+}
+
+void LLVector4a::quantize8( const LLVector4a& low, const LLVector4a& high )
+{
+ LLVector4a val(mQ);
+ LLVector4a delta; delta.setSub( high, low );
+
+ {
+ val.clamp(low, high);
+ val.sub(low);
+
+ // 8-bit quantization means we can do with just 12 bits of reciprocal accuracy
+ const LLVector4a oneOverDelta = _mm_rcp_ps(delta.mQ);
+// {
+// static LL_ALIGN_16( const F32 F_TWO_4A[4] ) = { 2.f, 2.f, 2.f, 2.f };
+// LLVector4a two; two.load4a( F_TWO_4A );
+//
+// // Here we use _mm_rcp_ps plus one round of newton-raphson
+// // We wish to find 'x' such that x = 1/delta
+// // As a first approximation, we take x0 = _mm_rcp_ps(delta)
+// // Then x1 = 2 * x0 - a * x0^2 or x1 = x0 * ( 2 - a * x0 )
+// // See Intel AP-803 http://ompf.org/!/Intel_application_note_AP-803.pdf
+// const LLVector4a recipApprox = _mm_rcp_ps(delta.mQ);
+// oneOverDelta.setMul( delta, recipApprox );
+// oneOverDelta.setSub( two, oneOverDelta );
+// oneOverDelta.mul( recipApprox );
+// }
+
+ val.mul(oneOverDelta);
+ val.mul(*reinterpret_cast<const LLVector4a*>(F_U8MAX_4A));
+ }
+
+ val = _mm_cvtepi32_ps(_mm_cvtps_epi32( val.mQ ));
+
+ {
+ val.mul(*reinterpret_cast<const LLVector4a*>(F_OOU8MAX_4A));
+ val.mul(delta);
+ val.add(low);
+ }
+
+ {
+ LLVector4a maxError; maxError.setMul(delta, *reinterpret_cast<const LLVector4a*>(F_OOU8MAX_4A));
+ LLVector4a absVal; absVal.setAbs( val );
+ setSelectWithMask( absVal.lessThan( maxError ), F_ZERO_4A, val );
+ }
+}
+
+void LLVector4a::quantize16( const LLVector4a& low, const LLVector4a& high )
+{
+ LLVector4a val(mQ);
+ LLVector4a delta; delta.setSub( high, low );
+
+ {
+ val.clamp(low, high);
+ val.sub(low);
+
+ // 16-bit quantization means we need a round of Newton-Raphson
+ LLVector4a oneOverDelta;
+ {
+ static LL_ALIGN_16( const F32 F_TWO_4A[4] ) = { 2.f, 2.f, 2.f, 2.f };
+ LLVector4a two; two.load4a( F_TWO_4A );
+
+ // Here we use _mm_rcp_ps plus one round of newton-raphson
+ // We wish to find 'x' such that x = 1/delta
+ // As a first approximation, we take x0 = _mm_rcp_ps(delta)
+ // Then x1 = 2 * x0 - a * x0^2 or x1 = x0 * ( 2 - a * x0 )
+ // See Intel AP-803 http://ompf.org/!/Intel_application_note_AP-803.pdf
+ const LLVector4a recipApprox = _mm_rcp_ps(delta.mQ);
+ oneOverDelta.setMul( delta, recipApprox );
+ oneOverDelta.setSub( two, oneOverDelta );
+ oneOverDelta.mul( recipApprox );
+ }
+
+ val.mul(oneOverDelta);
+ val.mul(*reinterpret_cast<const LLVector4a*>(F_U16MAX_4A));
+ }
+
+ val = _mm_cvtepi32_ps(_mm_cvtps_epi32( val.mQ ));
+
+ {
+ val.mul(*reinterpret_cast<const LLVector4a*>(F_OOU16MAX_4A));
+ val.mul(delta);
+ val.add(low);
+ }
+
+ {
+ LLVector4a maxError; maxError.setMul(delta, *reinterpret_cast<const LLVector4a*>(F_OOU16MAX_4A));
+ LLVector4a absVal; absVal.setAbs( val );
+ setSelectWithMask( absVal.lessThan( maxError ), F_ZERO_4A, val );
+ }
+}
diff --git a/indra/llmath/llvector4a.h b/indra/llmath/llvector4a.h
new file mode 100644
index 0000000000..596082509d
--- /dev/null
+++ b/indra/llmath/llvector4a.h
@@ -0,0 +1,324 @@
+/**
+ * @file llvector4a.h
+ * @brief LLVector4a class header file - memory aligned and vectorized 4 component vector
+ *
+ * $LicenseInfo:firstyear=2010&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_LLVECTOR4A_H
+#define LL_LLVECTOR4A_H
+
+
+class LLRotation;
+
+#include <assert.h>
+#include "llpreprocessor.h"
+
+///////////////////////////////////
+// FIRST TIME USERS PLEASE READ
+//////////////////////////////////
+// This is just the beginning of LLVector4a. There are many more useful functions
+// yet to be implemented. For example, setNeg to negate a vector, rotate() to apply
+// a matrix rotation, various functions to manipulate only the X, Y, and Z elements
+// and many others (including a whole variety of accessors). So if you don't see a
+// function here that you need, please contact Falcon or someone else with SSE
+// experience (Richard, I think, has some and davep has a little as of the time
+// of this writing, July 08, 2010) about getting it implemented before you resort to
+// LLVector3/LLVector4.
+/////////////////////////////////
+
+class LLVector4a
+{
+public:
+
+ ///////////////////////////////////
+ // STATIC METHODS
+ ///////////////////////////////////
+
+ // Call initClass() at startup to avoid 15,000+ cycle penalties from denormalized numbers
+ static void initClass()
+ {
+ _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
+ _MM_SET_ROUNDING_MODE(_MM_ROUND_NEAREST);
+ }
+
+ // Return a vector of all zeros
+ static inline const LLVector4a& getZero()
+ {
+ extern const LLVector4a LL_V4A_ZERO;
+ return LL_V4A_ZERO;
+ }
+
+ // Return a vector of all epsilon, where epsilon is a small float suitable for approximate equality checks
+ static inline const LLVector4a& getEpsilon()
+ {
+ extern const LLVector4a LL_V4A_EPSILON;
+ return LL_V4A_EPSILON;
+ }
+
+ // Copy 16 bytes from src to dst. Source and destination must be 16-byte aligned
+ static inline void copy4a(F32* dst, const F32* src)
+ {
+ _mm_store_ps(dst, _mm_load_ps(src));
+ }
+
+ // Copy words 16-byte blocks from src to dst. Source and destination must not overlap.
+ static void memcpyNonAliased16(F32* __restrict dst, const F32* __restrict src, size_t bytes);
+
+ ////////////////////////////////////
+ // CONSTRUCTORS
+ ////////////////////////////////////
+
+ LLVector4a()
+ { //DO NOT INITIALIZE -- The overhead is completely unnecessary
+ }
+
+ LLVector4a(F32 x, F32 y, F32 z, F32 w = 0.f)
+ {
+ set(x,y,z,w);
+ }
+
+ LLVector4a(F32 x)
+ {
+ splat(x);
+ }
+
+ LLVector4a(const LLSimdScalar& x)
+ {
+ splat(x);
+ }
+
+ LLVector4a(LLQuad q)
+ {
+ mQ = q;
+ }
+
+ ////////////////////////////////////
+ // LOAD/STORE
+ ////////////////////////////////////
+
+ // Load from 16-byte aligned src array (preferred method of loading)
+ inline void load4a(const F32* src);
+
+ // Load from unaligned src array (NB: Significantly slower than load4a)
+ inline void loadua(const F32* src);
+
+ // Load only three floats beginning at address 'src'. Slowest method.
+ inline void load3(const F32* src);
+
+ // Store to a 16-byte aligned memory address
+ inline void store4a(F32* dst) const;
+
+ ////////////////////////////////////
+ // BASIC GET/SET
+ ////////////////////////////////////
+
+ // Return a "this" as an F32 pointer. Do not use unless you have a very good reason. (Not sure? Ask Falcon)
+ inline F32* getF32ptr();
+
+ // Return a "this" as a const F32 pointer. Do not use unless you have a very good reason. (Not sure? Ask Falcon)
+ inline const F32* const getF32ptr() const;
+
+ // Read-only access a single float in this vector. Do not use in proximity to any function call that manipulates
+ // the data at the whole vector level or you will incur a substantial penalty. Consider using the splat functions instead
+ inline F32 operator[](const S32 idx) const;
+
+ // Prefer this method for read-only access to a single element. Prefer the templated version if the elem is known at compile time.
+ inline LLSimdScalar getScalarAt(const S32 idx) const;
+
+ // Prefer this method for read-only access to a single element. Prefer the templated version if the elem is known at compile time.
+ template <int N> LL_FORCE_INLINE LLSimdScalar getScalarAt() const;
+
+ // Set to an x, y, z and optional w provided
+ inline void set(F32 x, F32 y, F32 z, F32 w = 0.f);
+
+ // Set to all zeros. This is preferred to using ::getZero()
+ inline void clear();
+
+ // Set all elements to 'x'
+ inline void splat(const F32 x);
+
+ // Set all elements to 'x'
+ inline void splat(const LLSimdScalar& x);
+
+ // Set all 4 elements to element N of src, with N known at compile time
+ template <int N> void splat(const LLVector4a& src);
+
+ // Set all 4 elements to element i of v, with i NOT known at compile time
+ inline void splat(const LLVector4a& v, U32 i);
+
+ // Select bits from sourceIfTrue and sourceIfFalse according to bits in mask
+ inline void setSelectWithMask( const LLVector4Logical& mask, const LLVector4a& sourceIfTrue, const LLVector4a& sourceIfFalse );
+
+ ////////////////////////////////////
+ // ALGEBRAIC
+ ////////////////////////////////////
+
+ // Set this to the element-wise (a + b)
+ inline void setAdd(const LLVector4a& a, const LLVector4a& b);
+
+ // Set this to element-wise (a - b)
+ inline void setSub(const LLVector4a& a, const LLVector4a& b);
+
+ // Set this to element-wise multiply (a * b)
+ inline void setMul(const LLVector4a& a, const LLVector4a& b);
+
+ // Set this to element-wise quotient (a / b)
+ inline void setDiv(const LLVector4a& a, const LLVector4a& b);
+
+ // Set this to the element-wise absolute value of src
+ inline void setAbs(const LLVector4a& src);
+
+ // Add to each component in this vector the corresponding component in rhs
+ inline void add(const LLVector4a& rhs);
+
+ // Subtract from each component in this vector the corresponding component in rhs
+ inline void sub(const LLVector4a& rhs);
+
+ // Multiply each component in this vector by the corresponding component in rhs
+ inline void mul(const LLVector4a& rhs);
+
+ // Divide each component in this vector by the corresponding component in rhs
+ inline void div(const LLVector4a& rhs);
+
+ // Multiply this vector by x in a scalar fashion
+ inline void mul(const F32 x);
+
+ // Set this to (a x b) (geometric cross-product)
+ inline void setCross3(const LLVector4a& a, const LLVector4a& b);
+
+ // Set all elements to the dot product of the x, y, and z elements in a and b
+ inline void setAllDot3(const LLVector4a& a, const LLVector4a& b);
+
+ // Set all elements to the dot product of the x, y, z, and w elements in a and b
+ inline void setAllDot4(const LLVector4a& a, const LLVector4a& b);
+
+ // Return the 3D dot product of this vector and b
+ inline LLSimdScalar dot3(const LLVector4a& b) const;
+
+ // Return the 4D dot product of this vector and b
+ inline LLSimdScalar dot4(const LLVector4a& b) const;
+
+ // Normalize this vector with respect to the x, y, and z components only. Accurate to 22 bites of precision. W component is destroyed
+ // Note that this does not consider zero length vectors!
+ inline void normalize3();
+
+ // Same as normalize3() but with respect to all 4 components
+ inline void normalize4();
+
+ // Same as normalize3(), but returns length as a SIMD scalar
+ inline LLSimdScalar normalize3withLength();
+
+ // Normalize this vector with respect to the x, y, and z components only. Accurate only to 10-12 bits of precision. W component is destroyed
+ // Note that this does not consider zero length vectors!
+ inline void normalize3fast();
+
+ // Return true if this vector is normalized with respect to x,y,z up to tolerance
+ inline LLBool32 isNormalized3( F32 tolerance = 1e-3 ) const;
+
+ // Return true if this vector is normalized with respect to all components up to tolerance
+ inline LLBool32 isNormalized4( F32 tolerance = 1e-3 ) const;
+
+ // Set all elements to the length of vector 'v'
+ inline void setAllLength3( const LLVector4a& v );
+
+ // Get this vector's length
+ inline LLSimdScalar getLength3() const;
+
+ // Set the components of this vector to the minimum of the corresponding components of lhs and rhs
+ inline void setMin(const LLVector4a& lhs, const LLVector4a& rhs);
+
+ // Set the components of this vector to the maximum of the corresponding components of lhs and rhs
+ inline void setMax(const LLVector4a& lhs, const LLVector4a& rhs);
+
+ // Clamps this vector to be within the component-wise range low to high (inclusive)
+ inline void clamp( const LLVector4a& low, const LLVector4a& high );
+
+ // Set this to (c * lhs) + rhs * ( 1 - c)
+ inline void setLerp(const LLVector4a& lhs, const LLVector4a& rhs, F32 c);
+
+ // Return true (nonzero) if x, y, z (and w for Finite4) are all finite floats
+ inline LLBool32 isFinite3() const;
+ inline LLBool32 isFinite4() const;
+
+ // Set this vector to 'vec' rotated by the LLRotation or LLQuaternion2 provided
+ void setRotated( const LLRotation& rot, const LLVector4a& vec );
+ void setRotated( const class LLQuaternion2& quat, const LLVector4a& vec );
+
+ // Set this vector to 'vec' rotated by the INVERSE of the LLRotation or LLQuaternion2 provided
+ inline void setRotatedInv( const LLRotation& rot, const LLVector4a& vec );
+ inline void setRotatedInv( const class LLQuaternion2& quat, const LLVector4a& vec );
+
+ // Quantize this vector to 8 or 16 bit precision
+ void quantize8( const LLVector4a& low, const LLVector4a& high );
+ void quantize16( const LLVector4a& low, const LLVector4a& high );
+
+ ////////////////////////////////////
+ // LOGICAL
+ ////////////////////////////////////
+ // The functions in this section will compare the elements in this vector
+ // to those in rhs and return an LLVector4Logical with all bits set in elements
+ // where the comparison was true and all bits unset in elements where the comparison
+ // was false. See llvector4logica.h
+ ////////////////////////////////////
+ // WARNING: Other than equals3 and equals4, these functions do NOT account
+ // for floating point tolerance. You should include the appropriate tolerance
+ // in the inputs.
+ ////////////////////////////////////
+
+ inline LLVector4Logical greaterThan(const LLVector4a& rhs) const;
+
+ inline LLVector4Logical lessThan(const LLVector4a& rhs) const;
+
+ inline LLVector4Logical greaterEqual(const LLVector4a& rhs) const;
+
+ inline LLVector4Logical lessEqual(const LLVector4a& rhs) const;
+
+ inline LLVector4Logical equal(const LLVector4a& rhs) const;
+
+ // Returns true if this and rhs are componentwise equal up to the specified absolute tolerance
+ inline bool equals4(const LLVector4a& rhs, F32 tolerance = F_APPROXIMATELY_ZERO ) const;
+
+ inline bool equals3(const LLVector4a& rhs, F32 tolerance = F_APPROXIMATELY_ZERO ) const;
+
+ ////////////////////////////////////
+ // OPERATORS
+ ////////////////////////////////////
+
+ // Do NOT add aditional operators without consulting someone with SSE experience
+ inline const LLVector4a& operator= ( const LLVector4a& rhs );
+
+ inline const LLVector4a& operator= ( const LLQuad& rhs );
+
+ inline operator LLQuad() const;
+
+private:
+ LLQuad mQ;
+};
+
+inline void update_min_max(LLVector4a& min, LLVector4a& max, const LLVector4a& p)
+{
+ min.setMin(min, p);
+ max.setMax(max, p);
+}
+
+#endif
diff --git a/indra/llmath/llvector4a.inl b/indra/llmath/llvector4a.inl
new file mode 100644
index 0000000000..7ad22a5631
--- /dev/null
+++ b/indra/llmath/llvector4a.inl
@@ -0,0 +1,593 @@
+/**
+ * @file llvector4a.inl
+ * @brief LLVector4a inline function implementations
+ *
+ * $LicenseInfo:firstyear=2010&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$
+ */
+
+////////////////////////////////////
+// LOAD/STORE
+////////////////////////////////////
+
+// Load from 16-byte aligned src array (preferred method of loading)
+inline void LLVector4a::load4a(const F32* src)
+{
+ mQ = _mm_load_ps(src);
+}
+
+// Load from unaligned src array (NB: Significantly slower than load4a)
+inline void LLVector4a::loadua(const F32* src)
+{
+ mQ = _mm_loadu_ps(src);
+}
+
+// Load only three floats beginning at address 'src'. Slowest method.
+inline void LLVector4a::load3(const F32* src)
+{
+ // mQ = { 0.f, src[2], src[1], src[0] } = { W, Z, Y, X }
+ // NB: This differs from the convention of { Z, Y, X, W }
+ mQ = _mm_set_ps(0.f, src[2], src[1], src[0]);
+}
+
+// Store to a 16-byte aligned memory address
+inline void LLVector4a::store4a(F32* dst) const
+{
+ _mm_store_ps(dst, mQ);
+}
+
+////////////////////////////////////
+// BASIC GET/SET
+////////////////////////////////////
+
+// Return a "this" as an F32 pointer. Do not use unless you have a very good reason. (Not sure? Ask Falcon)
+F32* LLVector4a::getF32ptr()
+{
+ return (F32*) &mQ;
+}
+
+// Return a "this" as a const F32 pointer. Do not use unless you have a very good reason. (Not sure? Ask Falcon)
+const F32* const LLVector4a::getF32ptr() const
+{
+ return (const F32* const) &mQ;
+}
+
+// Read-only access a single float in this vector. Do not use in proximity to any function call that manipulates
+// the data at the whole vector level or you will incur a substantial penalty. Consider using the splat functions instead
+inline F32 LLVector4a::operator[](const S32 idx) const
+{
+ return ((F32*)&mQ)[idx];
+}
+
+// Prefer this method for read-only access to a single element. Prefer the templated version if the elem is known at compile time.
+inline LLSimdScalar LLVector4a::getScalarAt(const S32 idx) const
+{
+ // Return appropriate LLQuad. It will be cast to LLSimdScalar automatically (should be effectively a nop)
+ switch (idx)
+ {
+ case 0:
+ return mQ;
+ case 1:
+ return _mm_shuffle_ps(mQ, mQ, _MM_SHUFFLE(1, 1, 1, 1));
+ case 2:
+ return _mm_shuffle_ps(mQ, mQ, _MM_SHUFFLE(2, 2, 2, 2));
+ case 3:
+ default:
+ return _mm_shuffle_ps(mQ, mQ, _MM_SHUFFLE(3, 3, 3, 3));
+ }
+}
+
+// Prefer this method for read-only access to a single element. Prefer the templated version if the elem is known at compile time.
+template <int N> LL_FORCE_INLINE LLSimdScalar LLVector4a::getScalarAt() const
+{
+ return _mm_shuffle_ps(mQ, mQ, _MM_SHUFFLE(N, N, N, N));
+}
+
+template<> LL_FORCE_INLINE LLSimdScalar LLVector4a::getScalarAt<0>() const
+{
+ return mQ;
+}
+
+// Set to an x, y, z and optional w provided
+inline void LLVector4a::set(F32 x, F32 y, F32 z, F32 w)
+{
+ mQ = _mm_set_ps(w, z, y, x);
+}
+
+// Set to all zeros
+inline void LLVector4a::clear()
+{
+ mQ = LLVector4a::getZero().mQ;
+}
+
+inline void LLVector4a::splat(const F32 x)
+{
+ mQ = _mm_set1_ps(x);
+}
+
+inline void LLVector4a::splat(const LLSimdScalar& x)
+{
+ mQ = _mm_shuffle_ps( x.getQuad(), x.getQuad(), _MM_SHUFFLE(0,0,0,0) );
+}
+
+// Set all 4 elements to element N of src, with N known at compile time
+template <int N> void LLVector4a::splat(const LLVector4a& src)
+{
+ mQ = _mm_shuffle_ps(src.mQ, src.mQ, _MM_SHUFFLE(N, N, N, N) );
+}
+
+// Set all 4 elements to element i of v, with i NOT known at compile time
+inline void LLVector4a::splat(const LLVector4a& v, U32 i)
+{
+ switch (i)
+ {
+ case 0:
+ mQ = _mm_shuffle_ps(v.mQ, v.mQ, _MM_SHUFFLE(0, 0, 0, 0));
+ break;
+ case 1:
+ mQ = _mm_shuffle_ps(v.mQ, v.mQ, _MM_SHUFFLE(1, 1, 1, 1));
+ break;
+ case 2:
+ mQ = _mm_shuffle_ps(v.mQ, v.mQ, _MM_SHUFFLE(2, 2, 2, 2));
+ break;
+ case 3:
+ mQ = _mm_shuffle_ps(v.mQ, v.mQ, _MM_SHUFFLE(3, 3, 3, 3));
+ break;
+ }
+}
+
+// Select bits from sourceIfTrue and sourceIfFalse according to bits in mask
+inline void LLVector4a::setSelectWithMask( const LLVector4Logical& mask, const LLVector4a& sourceIfTrue, const LLVector4a& sourceIfFalse )
+{
+ // ((( sourceIfTrue ^ sourceIfFalse ) & mask) ^ sourceIfFalse )
+ // E.g., sourceIfFalse = 1010b, sourceIfTrue = 0101b, mask = 1100b
+ // (sourceIfTrue ^ sourceIfFalse) = 1111b --> & mask = 1100b --> ^ sourceIfFalse = 0110b,
+ // as expected (01 from sourceIfTrue, 10 from sourceIfFalse)
+ // Courtesy of Mark++, http://markplusplus.wordpress.com/2007/03/14/fast-sse-select-operation/
+ mQ = _mm_xor_ps( sourceIfFalse, _mm_and_ps( mask, _mm_xor_ps( sourceIfTrue, sourceIfFalse ) ) );
+}
+
+////////////////////////////////////
+// ALGEBRAIC
+////////////////////////////////////
+
+// Set this to the element-wise (a + b)
+inline void LLVector4a::setAdd(const LLVector4a& a, const LLVector4a& b)
+{
+ mQ = _mm_add_ps(a.mQ, b.mQ);
+}
+
+// Set this to element-wise (a - b)
+inline void LLVector4a::setSub(const LLVector4a& a, const LLVector4a& b)
+{
+ mQ = _mm_sub_ps(a.mQ, b.mQ);
+}
+
+// Set this to element-wise multiply (a * b)
+inline void LLVector4a::setMul(const LLVector4a& a, const LLVector4a& b)
+{
+ mQ = _mm_mul_ps(a.mQ, b.mQ);
+}
+
+// Set this to element-wise quotient (a / b)
+inline void LLVector4a::setDiv(const LLVector4a& a, const LLVector4a& b)
+{
+ mQ = _mm_div_ps( a.mQ, b.mQ );
+}
+
+// Set this to the element-wise absolute value of src
+inline void LLVector4a::setAbs(const LLVector4a& src)
+{
+ static const LL_ALIGN_16(U32 F_ABS_MASK_4A[4]) = { 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF };
+ mQ = _mm_and_ps(src.mQ, *reinterpret_cast<const LLQuad*>(F_ABS_MASK_4A));
+}
+
+// Add to each component in this vector the corresponding component in rhs
+inline void LLVector4a::add(const LLVector4a& rhs)
+{
+ mQ = _mm_add_ps(mQ, rhs.mQ);
+}
+
+// Subtract from each component in this vector the corresponding component in rhs
+inline void LLVector4a::sub(const LLVector4a& rhs)
+{
+ mQ = _mm_sub_ps(mQ, rhs.mQ);
+}
+
+// Multiply each component in this vector by the corresponding component in rhs
+inline void LLVector4a::mul(const LLVector4a& rhs)
+{
+ mQ = _mm_mul_ps(mQ, rhs.mQ);
+}
+
+// Divide each component in this vector by the corresponding component in rhs
+inline void LLVector4a::div(const LLVector4a& rhs)
+{
+ // TODO: Check accuracy, maybe add divFast
+ mQ = _mm_div_ps(mQ, rhs.mQ);
+}
+
+// Multiply this vector by x in a scalar fashion
+inline void LLVector4a::mul(const F32 x)
+{
+ LLVector4a t;
+ t.splat(x);
+
+ mQ = _mm_mul_ps(mQ, t.mQ);
+}
+
+// Set this to (a x b) (geometric cross-product)
+inline void LLVector4a::setCross3(const LLVector4a& a, const LLVector4a& b)
+{
+ // Vectors are stored in memory in w, z, y, x order from high to low
+ // Set vector1 = { a[W], a[X], a[Z], a[Y] }
+ const LLQuad vector1 = _mm_shuffle_ps( a.mQ, a.mQ, _MM_SHUFFLE( 3, 0, 2, 1 ));
+ // Set vector2 = { b[W], b[Y], b[X], b[Z] }
+ const LLQuad vector2 = _mm_shuffle_ps( b.mQ, b.mQ, _MM_SHUFFLE( 3, 1, 0, 2 ));
+ // mQ = { a[W]*b[W], a[X]*b[Y], a[Z]*b[X], a[Y]*b[Z] }
+ mQ = _mm_mul_ps( vector1, vector2 );
+ // vector3 = { a[W], a[Y], a[X], a[Z] }
+ const LLQuad vector3 = _mm_shuffle_ps( a.mQ, a.mQ, _MM_SHUFFLE( 3, 1, 0, 2 ));
+ // vector4 = { b[W], b[X], b[Z], b[Y] }
+ const LLQuad vector4 = _mm_shuffle_ps( b.mQ, b.mQ, _MM_SHUFFLE( 3, 0, 2, 1 ));
+ // mQ = { 0, a[X]*b[Y] - a[Y]*b[X], a[Z]*b[X] - a[X]*b[Z], a[Y]*b[Z] - a[Z]*b[Y] }
+ mQ = _mm_sub_ps( mQ, _mm_mul_ps( vector3, vector4 ));
+}
+
+/* This function works, but may be slightly slower than the one below on older machines
+ inline void LLVector4a::setAllDot3(const LLVector4a& a, const LLVector4a& b)
+ {
+ // ab = { a[W]*b[W], a[Z]*b[Z], a[Y]*b[Y], a[X]*b[X] }
+ const LLQuad ab = _mm_mul_ps( a.mQ, b.mQ );
+ // yzxw = { a[W]*b[W], a[Z]*b[Z], a[X]*b[X], a[Y]*b[Y] }
+ const LLQuad wzxy = _mm_shuffle_ps( ab, ab, _MM_SHUFFLE(3, 2, 0, 1 ));
+ // xPlusY = { 2*a[W]*b[W], 2 * a[Z] * b[Z], a[Y]*b[Y] + a[X] * b[X], a[X] * b[X] + a[Y] * b[Y] }
+ const LLQuad xPlusY = _mm_add_ps(ab, wzxy);
+ // xPlusYSplat = { a[Y]*b[Y] + a[X] * b[X], a[X] * b[X] + a[Y] * b[Y], a[Y]*b[Y] + a[X] * b[X], a[X] * b[X] + a[Y] * b[Y] }
+ const LLQuad xPlusYSplat = _mm_movelh_ps(xPlusY, xPlusY);
+ // zSplat = { a[Z]*b[Z], a[Z]*b[Z], a[Z]*b[Z], a[Z]*b[Z] }
+ const LLQuad zSplat = _mm_shuffle_ps( ab, ab, _MM_SHUFFLE( 2, 2, 2, 2 ));
+ // mQ = { a[Z] * b[Z] + a[Y] * b[Y] + a[X] * b[X], same, same, same }
+ mQ = _mm_add_ps(zSplat, xPlusYSplat);
+ }*/
+
+// Set all elements to the dot product of the x, y, and z elements in a and b
+inline void LLVector4a::setAllDot3(const LLVector4a& a, const LLVector4a& b)
+{
+ // ab = { a[W]*b[W], a[Z]*b[Z], a[Y]*b[Y], a[X]*b[X] }
+ const LLQuad ab = _mm_mul_ps( a.mQ, b.mQ );
+ // yzxw = { a[W]*b[W], a[Z]*b[Z], a[X]*b[X], a[Y]*b[Y] }
+ const __m128i wzxy = _mm_shuffle_epi32(_mm_castps_si128(ab), _MM_SHUFFLE(3, 2, 0, 1 ));
+ // xPlusY = { 2*a[W]*b[W], 2 * a[Z] * b[Z], a[Y]*b[Y] + a[X] * b[X], a[X] * b[X] + a[Y] * b[Y] }
+ const LLQuad xPlusY = _mm_add_ps(ab, _mm_castsi128_ps(wzxy));
+ // xPlusYSplat = { a[Y]*b[Y] + a[X] * b[X], a[X] * b[X] + a[Y] * b[Y], a[Y]*b[Y] + a[X] * b[X], a[X] * b[X] + a[Y] * b[Y] }
+ const LLQuad xPlusYSplat = _mm_movelh_ps(xPlusY, xPlusY);
+ // zSplat = { a[Z]*b[Z], a[Z]*b[Z], a[Z]*b[Z], a[Z]*b[Z] }
+ const __m128i zSplat = _mm_shuffle_epi32(_mm_castps_si128(ab), _MM_SHUFFLE( 2, 2, 2, 2 ));
+ // mQ = { a[Z] * b[Z] + a[Y] * b[Y] + a[X] * b[X], same, same, same }
+ mQ = _mm_add_ps(_mm_castsi128_ps(zSplat), xPlusYSplat);
+}
+
+// Set all elements to the dot product of the x, y, z, and w elements in a and b
+inline void LLVector4a::setAllDot4(const LLVector4a& a, const LLVector4a& b)
+{
+ // ab = { a[W]*b[W], a[Z]*b[Z], a[Y]*b[Y], a[X]*b[X] }
+ const LLQuad ab = _mm_mul_ps( a.mQ, b.mQ );
+ // yzxw = { a[W]*b[W], a[Z]*b[Z], a[X]*b[X], a[Y]*b[Y] }
+ const __m128i zwxy = _mm_shuffle_epi32(_mm_castps_si128(ab), _MM_SHUFFLE(2, 3, 0, 1 ));
+ // zPlusWandXplusY = { a[W]*b[W] + a[Z]*b[Z], a[Z] * b[Z] + a[W]*b[W], a[Y]*b[Y] + a[X] * b[X], a[X] * b[X] + a[Y] * b[Y] }
+ const LLQuad zPlusWandXplusY = _mm_add_ps(ab, _mm_castsi128_ps(zwxy));
+ // xPlusYSplat = { a[Y]*b[Y] + a[X] * b[X], a[X] * b[X] + a[Y] * b[Y], a[Y]*b[Y] + a[X] * b[X], a[X] * b[X] + a[Y] * b[Y] }
+ const LLQuad xPlusYSplat = _mm_movelh_ps(zPlusWandXplusY, zPlusWandXplusY);
+ const LLQuad zPlusWSplat = _mm_movehl_ps(zPlusWandXplusY, zPlusWandXplusY);
+
+ // mQ = { a[W]*b[W] + a[Z] * b[Z] + a[Y] * b[Y] + a[X] * b[X], same, same, same }
+ mQ = _mm_add_ps(xPlusYSplat, zPlusWSplat);
+}
+
+// Return the 3D dot product of this vector and b
+inline LLSimdScalar LLVector4a::dot3(const LLVector4a& b) const
+{
+ const LLQuad ab = _mm_mul_ps( mQ, b.mQ );
+ const LLQuad splatY = _mm_castsi128_ps( _mm_shuffle_epi32( _mm_castps_si128(ab), _MM_SHUFFLE(1, 1, 1, 1) ) );
+ const LLQuad splatZ = _mm_castsi128_ps( _mm_shuffle_epi32( _mm_castps_si128(ab), _MM_SHUFFLE(2, 2, 2, 2) ) );
+ const LLQuad xPlusY = _mm_add_ps( ab, splatY );
+ return _mm_add_ps( xPlusY, splatZ );
+}
+
+// Return the 4D dot product of this vector and b
+inline LLSimdScalar LLVector4a::dot4(const LLVector4a& b) const
+{
+ // ab = { w, z, y, x }
+ const LLQuad ab = _mm_mul_ps( mQ, b.mQ );
+ // upperProdsInLowerElems = { y, x, y, x }
+ const LLQuad upperProdsInLowerElems = _mm_movehl_ps( ab, ab );
+ // sumOfPairs = { w+y, z+x, 2y, 2x }
+ const LLQuad sumOfPairs = _mm_add_ps( upperProdsInLowerElems, ab );
+ // shuffled = { z+x, z+x, z+x, z+x }
+ const LLQuad shuffled = _mm_castsi128_ps( _mm_shuffle_epi32( _mm_castps_si128( sumOfPairs ), _MM_SHUFFLE(1, 1, 1, 1) ) );
+ return _mm_add_ss( sumOfPairs, shuffled );
+}
+
+// Normalize this vector with respect to the x, y, and z components only. Accurate to 22 bites of precision. W component is destroyed
+// Note that this does not consider zero length vectors!
+inline void LLVector4a::normalize3()
+{
+ // lenSqrd = a dot a
+ LLVector4a lenSqrd; lenSqrd.setAllDot3( *this, *this );
+ // rsqrt = approximate reciprocal square (i.e., { ~1/len(a)^2, ~1/len(a)^2, ~1/len(a)^2, ~1/len(a)^2 }
+ const LLQuad rsqrt = _mm_rsqrt_ps(lenSqrd.mQ);
+ static const LLQuad half = { 0.5f, 0.5f, 0.5f, 0.5f };
+ static const LLQuad three = {3.f, 3.f, 3.f, 3.f };
+ // Now we do one round of Newton-Raphson approximation to get full accuracy
+ // According to the Newton-Raphson method, given a first 'w' for the root of f(x) = 1/x^2 - a (i.e., x = 1/sqrt(a))
+ // the next better approximation w[i+1] = w - f(w)/f'(w) = w - (1/w^2 - a)/(-2*w^(-3))
+ // w[i+1] = w + 0.5 * (1/w^2 - a) * w^3 = w + 0.5 * (w - a*w^3) = 1.5 * w - 0.5 * a * w^3
+ // = 0.5 * w * (3 - a*w^2)
+ // Our first approx is w = rsqrt. We need out = a * w[i+1] (this is the input vector 'a', not the 'a' from the above formula
+ // which is actually lenSqrd). So out = a * [0.5*rsqrt * (3 - lenSqrd*rsqrt*rsqrt)]
+ const LLQuad AtimesRsqrt = _mm_mul_ps( lenSqrd.mQ, rsqrt );
+ const LLQuad AtimesRsqrtTimesRsqrt = _mm_mul_ps( AtimesRsqrt, rsqrt );
+ const LLQuad threeMinusAtimesRsqrtTimesRsqrt = _mm_sub_ps(three, AtimesRsqrtTimesRsqrt );
+ const LLQuad nrApprox = _mm_mul_ps(half, _mm_mul_ps(rsqrt, threeMinusAtimesRsqrtTimesRsqrt));
+ mQ = _mm_mul_ps( mQ, nrApprox );
+}
+
+// Normalize this vector with respect to all components. Accurate to 22 bites of precision.
+// Note that this does not consider zero length vectors!
+inline void LLVector4a::normalize4()
+{
+ // lenSqrd = a dot a
+ LLVector4a lenSqrd; lenSqrd.setAllDot4( *this, *this );
+ // rsqrt = approximate reciprocal square (i.e., { ~1/len(a)^2, ~1/len(a)^2, ~1/len(a)^2, ~1/len(a)^2 }
+ const LLQuad rsqrt = _mm_rsqrt_ps(lenSqrd.mQ);
+ static const LLQuad half = { 0.5f, 0.5f, 0.5f, 0.5f };
+ static const LLQuad three = {3.f, 3.f, 3.f, 3.f };
+ // Now we do one round of Newton-Raphson approximation to get full accuracy
+ // According to the Newton-Raphson method, given a first 'w' for the root of f(x) = 1/x^2 - a (i.e., x = 1/sqrt(a))
+ // the next better approximation w[i+1] = w - f(w)/f'(w) = w - (1/w^2 - a)/(-2*w^(-3))
+ // w[i+1] = w + 0.5 * (1/w^2 - a) * w^3 = w + 0.5 * (w - a*w^3) = 1.5 * w - 0.5 * a * w^3
+ // = 0.5 * w * (3 - a*w^2)
+ // Our first approx is w = rsqrt. We need out = a * w[i+1] (this is the input vector 'a', not the 'a' from the above formula
+ // which is actually lenSqrd). So out = a * [0.5*rsqrt * (3 - lenSqrd*rsqrt*rsqrt)]
+ const LLQuad AtimesRsqrt = _mm_mul_ps( lenSqrd.mQ, rsqrt );
+ const LLQuad AtimesRsqrtTimesRsqrt = _mm_mul_ps( AtimesRsqrt, rsqrt );
+ const LLQuad threeMinusAtimesRsqrtTimesRsqrt = _mm_sub_ps(three, AtimesRsqrtTimesRsqrt );
+ const LLQuad nrApprox = _mm_mul_ps(half, _mm_mul_ps(rsqrt, threeMinusAtimesRsqrtTimesRsqrt));
+ mQ = _mm_mul_ps( mQ, nrApprox );
+}
+
+// Normalize this vector with respect to the x, y, and z components only. Accurate to 22 bites of precision. W component is destroyed
+// Note that this does not consider zero length vectors!
+inline LLSimdScalar LLVector4a::normalize3withLength()
+{
+ // lenSqrd = a dot a
+ LLVector4a lenSqrd; lenSqrd.setAllDot3( *this, *this );
+ // rsqrt = approximate reciprocal square (i.e., { ~1/len(a)^2, ~1/len(a)^2, ~1/len(a)^2, ~1/len(a)^2 }
+ const LLQuad rsqrt = _mm_rsqrt_ps(lenSqrd.mQ);
+ static const LLQuad half = { 0.5f, 0.5f, 0.5f, 0.5f };
+ static const LLQuad three = {3.f, 3.f, 3.f, 3.f };
+ // Now we do one round of Newton-Raphson approximation to get full accuracy
+ // According to the Newton-Raphson method, given a first 'w' for the root of f(x) = 1/x^2 - a (i.e., x = 1/sqrt(a))
+ // the next better approximation w[i+1] = w - f(w)/f'(w) = w - (1/w^2 - a)/(-2*w^(-3))
+ // w[i+1] = w + 0.5 * (1/w^2 - a) * w^3 = w + 0.5 * (w - a*w^3) = 1.5 * w - 0.5 * a * w^3
+ // = 0.5 * w * (3 - a*w^2)
+ // Our first approx is w = rsqrt. We need out = a * w[i+1] (this is the input vector 'a', not the 'a' from the above formula
+ // which is actually lenSqrd). So out = a * [0.5*rsqrt * (3 - lenSqrd*rsqrt*rsqrt)]
+ const LLQuad AtimesRsqrt = _mm_mul_ps( lenSqrd.mQ, rsqrt );
+ const LLQuad AtimesRsqrtTimesRsqrt = _mm_mul_ps( AtimesRsqrt, rsqrt );
+ const LLQuad threeMinusAtimesRsqrtTimesRsqrt = _mm_sub_ps(three, AtimesRsqrtTimesRsqrt );
+ const LLQuad nrApprox = _mm_mul_ps(half, _mm_mul_ps(rsqrt, threeMinusAtimesRsqrtTimesRsqrt));
+ mQ = _mm_mul_ps( mQ, nrApprox );
+ return _mm_sqrt_ss(lenSqrd);
+}
+
+// Normalize this vector with respect to the x, y, and z components only. Accurate only to 10-12 bits of precision. W component is destroyed
+// Note that this does not consider zero length vectors!
+inline void LLVector4a::normalize3fast()
+{
+ LLVector4a lenSqrd; lenSqrd.setAllDot3( *this, *this );
+ const LLQuad approxRsqrt = _mm_rsqrt_ps(lenSqrd.mQ);
+ mQ = _mm_mul_ps( mQ, approxRsqrt );
+}
+
+// Return true if this vector is normalized with respect to x,y,z up to tolerance
+inline LLBool32 LLVector4a::isNormalized3( F32 tolerance ) const
+{
+ static LL_ALIGN_16(const U32 ones[4]) = { 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000 };
+ LLSimdScalar tol = _mm_load_ss( &tolerance );
+ tol = _mm_mul_ss( tol, tol );
+ LLVector4a lenSquared; lenSquared.setAllDot3( *this, *this );
+ lenSquared.sub( *reinterpret_cast<const LLVector4a*>(ones) );
+ lenSquared.setAbs(lenSquared);
+ return _mm_comile_ss( lenSquared, tol );
+}
+
+// Return true if this vector is normalized with respect to all components up to tolerance
+inline LLBool32 LLVector4a::isNormalized4( F32 tolerance ) const
+{
+ static LL_ALIGN_16(const U32 ones[4]) = { 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000 };
+ LLSimdScalar tol = _mm_load_ss( &tolerance );
+ tol = _mm_mul_ss( tol, tol );
+ LLVector4a lenSquared; lenSquared.setAllDot4( *this, *this );
+ lenSquared.sub( *reinterpret_cast<const LLVector4a*>(ones) );
+ lenSquared.setAbs(lenSquared);
+ return _mm_comile_ss( lenSquared, tol );
+}
+
+// Set all elements to the length of vector 'v'
+inline void LLVector4a::setAllLength3( const LLVector4a& v )
+{
+ LLVector4a lenSqrd;
+ lenSqrd.setAllDot3(v, v);
+
+ mQ = _mm_sqrt_ps(lenSqrd.mQ);
+}
+
+// Get this vector's length
+inline LLSimdScalar LLVector4a::getLength3() const
+{
+ return _mm_sqrt_ss( dot3( (const LLVector4a)mQ ) );
+}
+
+// Set the components of this vector to the minimum of the corresponding components of lhs and rhs
+inline void LLVector4a::setMin(const LLVector4a& lhs, const LLVector4a& rhs)
+{
+ mQ = _mm_min_ps(lhs.mQ, rhs.mQ);
+}
+
+// Set the components of this vector to the maximum of the corresponding components of lhs and rhs
+inline void LLVector4a::setMax(const LLVector4a& lhs, const LLVector4a& rhs)
+{
+ mQ = _mm_max_ps(lhs.mQ, rhs.mQ);
+}
+
+// Set this to (c * lhs) + rhs * ( 1 - c)
+inline void LLVector4a::setLerp(const LLVector4a& lhs, const LLVector4a& rhs, F32 c)
+{
+ LLVector4a a = lhs;
+ a.mul(c);
+
+ LLVector4a b = rhs;
+ b.mul(1.f-c);
+
+ setAdd(a, b);
+}
+
+inline LLBool32 LLVector4a::isFinite3() const
+{
+ static LL_ALIGN_16(const U32 nanOrInfMask[4]) = { 0x7f800000, 0x7f800000, 0x7f800000, 0x7f800000 };
+ const __m128i nanOrInfMaskV = *reinterpret_cast<const __m128i*> (nanOrInfMask);
+ const __m128i maskResult = _mm_and_si128( _mm_castps_si128(mQ), nanOrInfMaskV );
+ const LLVector4Logical equalityCheck = _mm_castsi128_ps(_mm_cmpeq_epi32( maskResult, nanOrInfMaskV ));
+ return !equalityCheck.areAnySet( LLVector4Logical::MASK_XYZ );
+}
+
+inline LLBool32 LLVector4a::isFinite4() const
+{
+ static LL_ALIGN_16(const U32 nanOrInfMask[4]) = { 0x7f800000, 0x7f800000, 0x7f800000, 0x7f800000 };
+ const __m128i nanOrInfMaskV = *reinterpret_cast<const __m128i*> (nanOrInfMask);
+ const __m128i maskResult = _mm_and_si128( _mm_castps_si128(mQ), nanOrInfMaskV );
+ const LLVector4Logical equalityCheck = _mm_castsi128_ps(_mm_cmpeq_epi32( maskResult, nanOrInfMaskV ));
+ return !equalityCheck.areAnySet( LLVector4Logical::MASK_XYZW );
+}
+
+inline void LLVector4a::setRotatedInv( const LLRotation& rot, const LLVector4a& vec )
+{
+ LLRotation inv; inv.setTranspose( rot );
+ setRotated( inv, vec );
+}
+
+inline void LLVector4a::setRotatedInv( const LLQuaternion2& quat, const LLVector4a& vec )
+{
+ LLQuaternion2 invRot; invRot.setConjugate( quat );
+ setRotated(invRot, vec);
+}
+
+inline void LLVector4a::clamp( const LLVector4a& low, const LLVector4a& high )
+{
+ const LLVector4Logical highMask = greaterThan( high );
+ const LLVector4Logical lowMask = lessThan( low );
+
+ setSelectWithMask( highMask, high, *this );
+ setSelectWithMask( lowMask, low, *this );
+}
+
+
+////////////////////////////////////
+// LOGICAL
+////////////////////////////////////
+// The functions in this section will compare the elements in this vector
+// to those in rhs and return an LLVector4Logical with all bits set in elements
+// where the comparison was true and all bits unset in elements where the comparison
+// was false. See llvector4logica.h
+////////////////////////////////////
+// WARNING: Other than equals3 and equals4, these functions do NOT account
+// for floating point tolerance. You should include the appropriate tolerance
+// in the inputs.
+////////////////////////////////////
+
+inline LLVector4Logical LLVector4a::greaterThan(const LLVector4a& rhs) const
+{
+ return _mm_cmpgt_ps(mQ, rhs.mQ);
+}
+
+inline LLVector4Logical LLVector4a::lessThan(const LLVector4a& rhs) const
+{
+ return _mm_cmplt_ps(mQ, rhs.mQ);
+}
+
+inline LLVector4Logical LLVector4a::greaterEqual(const LLVector4a& rhs) const
+{
+ return _mm_cmpge_ps(mQ, rhs.mQ);
+}
+
+inline LLVector4Logical LLVector4a::lessEqual(const LLVector4a& rhs) const
+{
+ return _mm_cmple_ps(mQ, rhs.mQ);
+}
+
+inline LLVector4Logical LLVector4a::equal(const LLVector4a& rhs) const
+{
+ return _mm_cmpeq_ps(mQ, rhs.mQ);
+}
+
+// Returns true if this and rhs are componentwise equal up to the specified absolute tolerance
+inline bool LLVector4a::equals4(const LLVector4a& rhs, F32 tolerance ) const
+{
+ LLVector4a diff; diff.setSub( *this, rhs );
+ diff.setAbs( diff );
+ const LLQuad tol = _mm_set1_ps( tolerance );
+ const LLQuad cmp = _mm_cmplt_ps( diff, tol );
+ return (_mm_movemask_ps( cmp ) & LLVector4Logical::MASK_XYZW) == LLVector4Logical::MASK_XYZW;
+}
+
+inline bool LLVector4a::equals3(const LLVector4a& rhs, F32 tolerance ) const
+{
+ LLVector4a diff; diff.setSub( *this, rhs );
+ diff.setAbs( diff );
+ const LLQuad tol = _mm_set1_ps( tolerance );
+ const LLQuad t = _mm_cmplt_ps( diff, tol );
+ return (_mm_movemask_ps( t ) & LLVector4Logical::MASK_XYZ) == LLVector4Logical::MASK_XYZ;
+
+}
+
+////////////////////////////////////
+// OPERATORS
+////////////////////////////////////
+
+// Do NOT add aditional operators without consulting someone with SSE experience
+inline const LLVector4a& LLVector4a::operator= ( const LLVector4a& rhs )
+{
+ mQ = rhs.mQ;
+ return *this;
+}
+
+inline const LLVector4a& LLVector4a::operator= ( const LLQuad& rhs )
+{
+ mQ = rhs;
+ return *this;
+}
+
+inline LLVector4a::operator LLQuad() const
+{
+ return mQ;
+}
diff --git a/indra/llmath/llvector4logical.h b/indra/llmath/llvector4logical.h
new file mode 100644
index 0000000000..dd66b09d43
--- /dev/null
+++ b/indra/llmath/llvector4logical.h
@@ -0,0 +1,124 @@
+/**
+ * @file llvector4logical.h
+ * @brief LLVector4Logical class header file - Companion class to LLVector4a for logical and bit-twiddling operations
+ *
+ * $LicenseInfo:firstyear=2010&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_VECTOR4LOGICAL_H
+#define LL_VECTOR4LOGICAL_H
+
+
+////////////////////////////
+// LLVector4Logical
+////////////////////////////
+// This class is incomplete. If you need additional functionality,
+// for example setting/unsetting particular elements or performing
+// other boolean operations, feel free to implement. If you need
+// assistance in determining the most optimal implementation,
+// contact someone with SSE experience (Falcon, Richard, Davep, e.g.)
+////////////////////////////
+
+static LL_ALIGN_16(const U32 S_V4LOGICAL_MASK_TABLE[4*4]) =
+{
+ 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF
+};
+
+class LLVector4Logical
+{
+public:
+
+ enum {
+ MASK_X = 1,
+ MASK_Y = 1 << 1,
+ MASK_Z = 1 << 2,
+ MASK_W = 1 << 3,
+ MASK_XYZ = MASK_X | MASK_Y | MASK_Z,
+ MASK_XYZW = MASK_XYZ | MASK_W
+ };
+
+ // Empty default ctor
+ LLVector4Logical() {}
+
+ LLVector4Logical( const LLQuad& quad )
+ {
+ mQ = quad;
+ }
+
+ // Create and return a mask consisting of the lowest order bit of each element
+ inline U32 getGatheredBits() const
+ {
+ return _mm_movemask_ps(mQ);
+ };
+
+ // Invert this mask
+ inline LLVector4Logical& invert()
+ {
+ static const LL_ALIGN_16(U32 allOnes[4]) = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+ mQ = _mm_andnot_ps( mQ, *(LLQuad*)(allOnes) );
+ return *this;
+ }
+
+ inline LLBool32 areAllSet( U32 mask ) const
+ {
+ return ( getGatheredBits() & mask) == mask;
+ }
+
+ inline LLBool32 areAllSet() const
+ {
+ return areAllSet( MASK_XYZW );
+ }
+
+ inline LLBool32 areAnySet( U32 mask ) const
+ {
+ return getGatheredBits() & mask;
+ }
+
+ inline LLBool32 areAnySet() const
+ {
+ return areAnySet( MASK_XYZW );
+ }
+
+ inline operator LLQuad() const
+ {
+ return mQ;
+ }
+
+ inline void clear()
+ {
+ mQ = _mm_setzero_ps();
+ }
+
+ template<int N> void setElement()
+ {
+ mQ = _mm_or_ps( mQ, *reinterpret_cast<const LLQuad*>(S_V4LOGICAL_MASK_TABLE + 4*N) );
+ }
+
+private:
+
+ LLQuad mQ;
+};
+
+#endif //LL_VECTOR4ALOGICAL_H
diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index 14e1ca8d43..c504215ee5 100644
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -1,4 +1,5 @@
/**
+
* @file llvolume.cpp
*
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
@@ -24,9 +25,13 @@
*/
#include "linden_common.h"
+#include "llmemory.h"
#include "llmath.h"
#include <set>
+#if !LL_WINDOWS
+#include <stdint.h>
+#endif
#include "llerror.h"
#include "llmemtype.h"
@@ -37,9 +42,16 @@
#include "v4math.h"
#include "m4math.h"
#include "m3math.h"
+#include "llmatrix3a.h"
+#include "lloctree.h"
#include "lldarray.h"
#include "llvolume.h"
+#include "llvolumeoctree.h"
#include "llstl.h"
+#include "llsdserialize.h"
+#include "llvector4a.h"
+#include "llmatrix4a.h"
+#include "lltimer.h"
#define DEBUG_SILHOUETTE_BINORMALS 0
#define DEBUG_SILHOUETTE_NORMALS 0 // TomY: Use this to display normals using the silhouette
@@ -80,7 +92,18 @@ const F32 SKEW_MAX = 0.95f;
const F32 SCULPT_MIN_AREA = 0.002f;
const S32 SCULPT_MIN_AREA_DETAIL = 1;
-#define GEN_TRI_STRIP 0
+extern BOOL gDebugGL;
+
+void assert_aligned(void* ptr, uintptr_t alignment)
+{
+#if 0
+ uintptr_t t = (uintptr_t) ptr;
+ if (t%alignment != 0)
+ {
+ llerrs << "WTF?" << llendl;
+ }
+#endif
+}
BOOL check_same_clock_dir( const LLVector3& pt1, const LLVector3& pt2, const LLVector3& pt3, const LLVector3& norm)
{
@@ -99,128 +122,262 @@ BOOL check_same_clock_dir( const LLVector3& pt1, const LLVector3& pt2, const LLV
BOOL LLLineSegmentBoxIntersect(const LLVector3& start, const LLVector3& end, const LLVector3& center, const LLVector3& size)
{
- float fAWdU[3];
- LLVector3 dir;
- LLVector3 diff;
+ return LLLineSegmentBoxIntersect(start.mV, end.mV, center.mV, size.mV);
+}
+
+BOOL LLLineSegmentBoxIntersect(const F32* start, const F32* end, const F32* center, const F32* size)
+{
+ F32 fAWdU[3];
+ F32 dir[3];
+ F32 diff[3];
for (U32 i = 0; i < 3; i++)
{
- dir.mV[i] = 0.5f * (end.mV[i] - start.mV[i]);
- diff.mV[i] = (0.5f * (end.mV[i] + start.mV[i])) - center.mV[i];
- fAWdU[i] = fabsf(dir.mV[i]);
- if(fabsf(diff.mV[i])>size.mV[i] + fAWdU[i]) return false;
+ dir[i] = 0.5f * (end[i] - start[i]);
+ diff[i] = (0.5f * (end[i] + start[i])) - center[i];
+ fAWdU[i] = fabsf(dir[i]);
+ if(fabsf(diff[i])>size[i] + fAWdU[i]) return false;
}
float f;
- f = dir.mV[1] * diff.mV[2] - dir.mV[2] * diff.mV[1]; if(fabsf(f)>size.mV[1]*fAWdU[2] + size.mV[2]*fAWdU[1]) return false;
- f = dir.mV[2] * diff.mV[0] - dir.mV[0] * diff.mV[2]; if(fabsf(f)>size.mV[0]*fAWdU[2] + size.mV[2]*fAWdU[0]) return false;
- f = dir.mV[0] * diff.mV[1] - dir.mV[1] * diff.mV[0]; if(fabsf(f)>size.mV[0]*fAWdU[1] + size.mV[1]*fAWdU[0]) return false;
+ f = dir[1] * diff[2] - dir[2] * diff[1]; if(fabsf(f)>size[1]*fAWdU[2] + size[2]*fAWdU[1]) return false;
+ f = dir[2] * diff[0] - dir[0] * diff[2]; if(fabsf(f)>size[0]*fAWdU[2] + size[2]*fAWdU[0]) return false;
+ f = dir[0] * diff[1] - dir[1] * diff[0]; if(fabsf(f)>size[0]*fAWdU[1] + size[1]*fAWdU[0]) return false;
return true;
}
+
// intersect test between triangle vert0, vert1, vert2 and a ray from orig in direction dir.
// returns TRUE if intersecting and returns barycentric coordinates in intersection_a, intersection_b,
// and returns the intersection point along dir in intersection_t.
// Moller-Trumbore algorithm
-BOOL LLTriangleRayIntersect(const LLVector3& vert0, const LLVector3& vert1, const LLVector3& vert2, const LLVector3& orig, const LLVector3& dir,
- F32* intersection_a, F32* intersection_b, F32* intersection_t, BOOL two_sided)
+BOOL LLTriangleRayIntersect(const LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir,
+ F32& intersection_a, F32& intersection_b, F32& intersection_t)
{
- F32 u, v, t;
/* find vectors for two edges sharing vert0 */
- LLVector3 edge1 = vert1 - vert0;
+ LLVector4a edge1;
+ edge1.setSub(vert1, vert0);
- LLVector3 edge2 = vert2 - vert0;;
+ LLVector4a edge2;
+ edge2.setSub(vert2, vert0);
/* begin calculating determinant - also used to calculate U parameter */
- LLVector3 pvec = dir % edge2;
-
- /* if determinant is near zero, ray lies in plane of triangle */
- F32 det = edge1 * pvec;
+ LLVector4a pvec;
+ pvec.setCross3(dir, edge2);
- if (!two_sided)
+ /* if determinant is near zero, ray lies in plane of triangle */
+ LLVector4a det;
+ det.setAllDot3(edge1, pvec);
+
+ if (det.greaterEqual(LLVector4a::getEpsilon()).getGatheredBits() & 0x7)
{
- if (det < F_APPROXIMATELY_ZERO)
- {
- return FALSE;
- }
-
/* calculate distance from vert0 to ray origin */
- LLVector3 tvec = orig - vert0;
+ LLVector4a tvec;
+ tvec.setSub(orig, vert0);
/* calculate U parameter and test bounds */
- u = tvec * pvec;
+ LLVector4a u;
+ u.setAllDot3(tvec,pvec);
- if (u < 0.f || u > det)
+ if ((u.greaterEqual(LLVector4a::getZero()).getGatheredBits() & 0x7) &&
+ (u.lessEqual(det).getGatheredBits() & 0x7))
{
- return FALSE;
+ /* prepare to test V parameter */
+ LLVector4a qvec;
+ qvec.setCross3(tvec, edge1);
+
+ /* calculate V parameter and test bounds */
+ LLVector4a v;
+ v.setAllDot3(dir, qvec);
+
+
+ //if (!(v < 0.f || u + v > det))
+
+ LLVector4a sum_uv;
+ sum_uv.setAdd(u, v);
+
+ S32 v_gequal = v.greaterEqual(LLVector4a::getZero()).getGatheredBits() & 0x7;
+ S32 sum_lequal = sum_uv.lessEqual(det).getGatheredBits() & 0x7;
+
+ if (v_gequal && sum_lequal)
+ {
+ /* calculate t, scale parameters, ray intersects triangle */
+ LLVector4a t;
+ t.setAllDot3(edge2,qvec);
+
+ t.div(det);
+ u.div(det);
+ v.div(det);
+
+ intersection_a = u[0];
+ intersection_b = v[0];
+ intersection_t = t[0];
+ return TRUE;
+ }
}
-
- /* prepare to test V parameter */
- LLVector3 qvec = tvec % edge1;
+ }
- /* calculate V parameter and test bounds */
- v = dir * qvec;
- if (v < 0.f || u + v > det)
- {
- return FALSE;
- }
+ return FALSE;
+}
- /* calculate t, scale parameters, ray intersects triangle */
- t = edge2 * qvec;
- F32 inv_det = 1.0 / det;
- t *= inv_det;
- u *= inv_det;
- v *= inv_det;
- }
+BOOL LLTriangleRayIntersectTwoSided(const LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir,
+ F32& intersection_a, F32& intersection_b, F32& intersection_t)
+{
+ F32 u, v, t;
- else // two sided
- {
- if (det > -F_APPROXIMATELY_ZERO && det < F_APPROXIMATELY_ZERO)
- {
- return FALSE;
- }
- F32 inv_det = 1.0 / det;
+ /* find vectors for two edges sharing vert0 */
+ LLVector4a edge1;
+ edge1.setSub(vert1, vert0);
+
+
+ LLVector4a edge2;
+ edge2.setSub(vert2, vert0);
- /* calculate distance from vert0 to ray origin */
- LLVector3 tvec = orig - vert0;
-
- /* calculate U parameter and test bounds */
- u = (tvec * pvec) * inv_det;
- if (u < 0.f || u > 1.f)
- {
- return FALSE;
- }
+ /* begin calculating determinant - also used to calculate U parameter */
+ LLVector4a pvec;
+ pvec.setCross3(dir, edge2);
- /* prepare to test V parameter */
- LLVector3 qvec = tvec - edge1;
-
- /* calculate V parameter and test bounds */
- v = (dir * qvec) * inv_det;
-
- if (v < 0.f || u + v > 1.f)
- {
- return FALSE;
- }
+ /* if determinant is near zero, ray lies in plane of triangle */
+ F32 det = edge1.dot3(pvec).getF32();
- /* calculate t, ray intersects triangle */
- t = (edge2 * qvec) * inv_det;
+
+ if (det > -F_APPROXIMATELY_ZERO && det < F_APPROXIMATELY_ZERO)
+ {
+ return FALSE;
+ }
+
+ F32 inv_det = 1.f / det;
+
+ /* calculate distance from vert0 to ray origin */
+ LLVector4a tvec;
+ tvec.setSub(orig, vert0);
+
+ /* calculate U parameter and test bounds */
+ u = (tvec.dot3(pvec).getF32()) * inv_det;
+ if (u < 0.f || u > 1.f)
+ {
+ return FALSE;
}
+
+ /* prepare to test V parameter */
+ tvec.sub(edge1);
+
+ /* calculate V parameter and test bounds */
+ v = (dir.dot3(tvec).getF32()) * inv_det;
+
+ if (v < 0.f || u + v > 1.f)
+ {
+ return FALSE;
+ }
+
+ /* calculate t, ray intersects triangle */
+ t = (edge2.dot3(tvec).getF32()) * inv_det;
- if (intersection_a != NULL)
- *intersection_a = u;
- if (intersection_b != NULL)
- *intersection_b = v;
- if (intersection_t != NULL)
- *intersection_t = t;
+ intersection_a = u;
+ intersection_b = v;
+ intersection_t = t;
return TRUE;
}
+//helper for non-aligned vectors
+BOOL LLTriangleRayIntersect(const LLVector3& vert0, const LLVector3& vert1, const LLVector3& vert2, const LLVector3& orig, const LLVector3& dir,
+ F32& intersection_a, F32& intersection_b, F32& intersection_t, BOOL two_sided)
+{
+ LLVector4a vert0a, vert1a, vert2a, origa, dira;
+ vert0a.load3(vert0.mV);
+ vert1a.load3(vert1.mV);
+ vert2a.load3(vert2.mV);
+ origa.load3(orig.mV);
+ dira.load3(dir.mV);
+
+ if (two_sided)
+ {
+ return LLTriangleRayIntersectTwoSided(vert0a, vert1a, vert2a, origa, dira,
+ intersection_a, intersection_b, intersection_t);
+ }
+ else
+ {
+ return LLTriangleRayIntersect(vert0a, vert1a, vert2a, origa, dira,
+ intersection_a, intersection_b, intersection_t);
+ }
+}
+
+class LLVolumeOctreeRebound : public LLOctreeTravelerDepthFirst<LLVolumeTriangle>
+{
+public:
+ const LLVolumeFace* mFace;
+
+ LLVolumeOctreeRebound(const LLVolumeFace* face)
+ {
+ mFace = face;
+ }
+
+ virtual void visit(const LLOctreeNode<LLVolumeTriangle>* branch)
+ { //this is a depth first traversal, so it's safe to assum all children have complete
+ //bounding data
+
+ LLVolumeOctreeListener* node = (LLVolumeOctreeListener*) branch->getListener(0);
+
+ LLVector4a& min = node->mExtents[0];
+ LLVector4a& max = node->mExtents[1];
+
+ if (!branch->getData().empty())
+ { //node has data, find AABB that binds data set
+ const LLVolumeTriangle* tri = *(branch->getData().begin());
+
+ //initialize min/max to first available vertex
+ min = *(tri->mV[0]);
+ max = *(tri->mV[0]);
+
+ for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter =
+ branch->getData().begin(); iter != branch->getData().end(); ++iter)
+ { //for each triangle in node
+
+ //stretch by triangles in node
+ tri = *iter;
+
+ min.setMin(min, *tri->mV[0]);
+ min.setMin(min, *tri->mV[1]);
+ min.setMin(min, *tri->mV[2]);
+
+ max.setMax(max, *tri->mV[0]);
+ max.setMax(max, *tri->mV[1]);
+ max.setMax(max, *tri->mV[2]);
+ }
+ }
+ else if (!branch->getChildren().empty())
+ { //no data, but child nodes exist
+ LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(0)->getListener(0);
+
+ //initialize min/max to extents of first child
+ min = child->mExtents[0];
+ max = child->mExtents[1];
+ }
+ else
+ {
+ llerrs << "WTF? Empty leaf" << llendl;
+ }
+
+ for (S32 i = 0; i < branch->getChildCount(); ++i)
+ { //stretch by child extents
+ LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(i)->getListener(0);
+ min.setMin(min, child->mExtents[0]);
+ max.setMax(max, child->mExtents[1]);
+ }
+
+ node->mBounds[0].setAdd(min, max);
+ node->mBounds[0].mul(0.5f);
+
+ node->mBounds[1].setSub(max,min);
+ node->mBounds[1].mul(0.5f);
+ }
+};
//-------------------------------------------------------------------
// statics
@@ -1669,7 +1826,13 @@ LLVolume::LLVolume(const LLVolumeParams &params, const F32 detail, const BOOL ge
mFaceMask = 0x0;
mDetail = detail;
mSculptLevel = -2;
-
+ mIsTetrahedron = FALSE;
+ mLODScaleBias.setVec(1,1,1);
+ mHullPoints = NULL;
+ mHullIndices = NULL;
+ mNumHullPoints = 0;
+ mNumHullIndices = 0;
+
// set defaults
if (mParams.getPathParams().getCurveType() == LL_PCODE_PATH_FLEXIBLE)
{
@@ -1684,7 +1847,8 @@ LLVolume::LLVolume(const LLVolumeParams &params, const F32 detail, const BOOL ge
mGenerateSingleFace = generate_single_face;
generate();
- if (mParams.getSculptID().isNull() && params.getSculptType() == LL_SCULPT_TYPE_NONE)
+
+ if (mParams.getSculptID().isNull() && mParams.getSculptType() == LL_SCULPT_TYPE_NONE)
{
createVolumeFaces();
}
@@ -1719,6 +1883,11 @@ LLVolume::~LLVolume()
mPathp = NULL;
mProfilep = NULL;
mVolumeFaces.clear();
+
+ ll_aligned_free_16(mHullPoints);
+ mHullPoints = NULL;
+ ll_aligned_free_16(mHullIndices);
+ mHullIndices = NULL;
}
BOOL LLVolume::generate()
@@ -1835,6 +2004,577 @@ BOOL LLVolume::generate()
return FALSE;
}
+void LLVolumeFace::VertexData::init()
+{
+ if (!mData)
+ {
+ mData = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*2);
+ }
+}
+
+LLVolumeFace::VertexData::VertexData()
+{
+ mData = NULL;
+ init();
+}
+
+LLVolumeFace::VertexData::VertexData(const VertexData& rhs)
+{
+ mData = NULL;
+ *this = rhs;
+}
+
+const LLVolumeFace::VertexData& LLVolumeFace::VertexData::operator=(const LLVolumeFace::VertexData& rhs)
+{
+ if (this != &rhs)
+ {
+ init();
+ LLVector4a::memcpyNonAliased16((F32*) mData, (F32*) rhs.mData, 2*sizeof(LLVector4a));
+ mTexCoord = rhs.mTexCoord;
+ }
+ return *this;
+}
+
+LLVolumeFace::VertexData::~VertexData()
+{
+ ll_aligned_free_16(mData);
+ mData = NULL;
+}
+
+LLVector4a& LLVolumeFace::VertexData::getPosition()
+{
+ return mData[POSITION];
+}
+
+LLVector4a& LLVolumeFace::VertexData::getNormal()
+{
+ return mData[NORMAL];
+}
+
+const LLVector4a& LLVolumeFace::VertexData::getPosition() const
+{
+ return mData[POSITION];
+}
+
+const LLVector4a& LLVolumeFace::VertexData::getNormal() const
+{
+ return mData[NORMAL];
+}
+
+
+void LLVolumeFace::VertexData::setPosition(const LLVector4a& pos)
+{
+ mData[POSITION] = pos;
+}
+
+void LLVolumeFace::VertexData::setNormal(const LLVector4a& norm)
+{
+ mData[NORMAL] = norm;
+}
+
+bool LLVolumeFace::VertexData::operator<(const LLVolumeFace::VertexData& rhs)const
+{
+ const F32* lp = this->getPosition().getF32ptr();
+ const F32* rp = rhs.getPosition().getF32ptr();
+
+ if (lp[0] != rp[0])
+ {
+ return lp[0] < rp[0];
+ }
+
+ if (rp[1] != lp[1])
+ {
+ return lp[1] < rp[1];
+ }
+
+ if (rp[2] != lp[2])
+ {
+ return lp[2] < rp[2];
+ }
+
+ lp = getNormal().getF32ptr();
+ rp = rhs.getNormal().getF32ptr();
+
+ if (lp[0] != rp[0])
+ {
+ return lp[0] < rp[0];
+ }
+
+ if (rp[1] != lp[1])
+ {
+ return lp[1] < rp[1];
+ }
+
+ if (rp[2] != lp[2])
+ {
+ return lp[2] < rp[2];
+ }
+
+ if (mTexCoord.mV[0] != rhs.mTexCoord.mV[0])
+ {
+ return mTexCoord.mV[0] < rhs.mTexCoord.mV[0];
+ }
+
+ return mTexCoord.mV[1] < rhs.mTexCoord.mV[1];
+}
+
+bool LLVolumeFace::VertexData::operator==(const LLVolumeFace::VertexData& rhs)const
+{
+ return mData[POSITION].equals3(rhs.getPosition()) &&
+ mData[NORMAL].equals3(rhs.getNormal()) &&
+ mTexCoord == rhs.mTexCoord;
+}
+
+bool LLVolumeFace::VertexData::compareNormal(const LLVolumeFace::VertexData& rhs, F32 angle_cutoff) const
+{
+ bool retval = false;
+ if (rhs.mData[POSITION].equals3(mData[POSITION]) && rhs.mTexCoord == mTexCoord)
+ {
+ if (angle_cutoff > 1.f)
+ {
+ retval = (mData[NORMAL].equals3(rhs.mData[NORMAL]));
+ }
+ else
+ {
+ F32 cur_angle = rhs.mData[NORMAL].dot3(mData[NORMAL]).getF32();
+ retval = cur_angle > angle_cutoff;
+ }
+ }
+
+ return retval;
+}
+
+bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
+{
+ //input stream is now pointing at a zlib compressed block of LLSD
+ //decompress block
+ LLSD mdl;
+ if (!unzip_llsd(mdl, is, size))
+ {
+ llwarns << "not a valid mesh asset!" << llendl;
+ return false;
+ }
+
+ {
+ U32 face_count = mdl.size();
+
+ if (face_count == 0)
+ {
+ llerrs << "WTF?" << llendl;
+ }
+
+ mVolumeFaces.resize(face_count);
+
+ for (U32 i = 0; i < face_count; ++i)
+ {
+ LLSD::Binary pos = mdl[i]["Position"];
+ LLSD::Binary norm = mdl[i]["Normal"];
+ LLSD::Binary tc = mdl[i]["TexCoord0"];
+ LLSD::Binary idx = mdl[i]["TriangleList"];
+
+ LLVolumeFace& face = mVolumeFaces[i];
+
+ //copy out indices
+ face.resizeIndices(idx.size()/2);
+
+ if (idx.empty() || face.mNumIndices < 3)
+ { //why is there an empty index list?
+ llerrs <<"WTF?" << llendl;
+ continue;
+ }
+
+ U16* indices = (U16*) &(idx[0]);
+ U32 count = idx.size()/2;
+ for (U32 j = 0; j < count; ++j)
+ {
+ face.mIndices[j] = indices[j];
+ }
+
+ //copy out vertices
+ U32 num_verts = pos.size()/(3*2);
+ face.resizeVertices(num_verts);
+
+ LLVector3 minp;
+ LLVector3 maxp;
+ LLVector2 min_tc;
+ LLVector2 max_tc;
+
+ minp.setValue(mdl[i]["PositionDomain"]["Min"]);
+ maxp.setValue(mdl[i]["PositionDomain"]["Max"]);
+ LLVector4a min_pos, max_pos;
+ min_pos.load3(minp.mV);
+ max_pos.load3(maxp.mV);
+
+ min_tc.setValue(mdl[i]["TexCoord0Domain"]["Min"]);
+ max_tc.setValue(mdl[i]["TexCoord0Domain"]["Max"]);
+
+ LLVector4a pos_range;
+ pos_range.setSub(max_pos, min_pos);
+ LLVector2 tc_range2 = max_tc - min_tc;
+ LLVector4a tc_range;
+ tc_range.set(tc_range2[0], tc_range2[1], tc_range2[0], tc_range2[1]);
+ LLVector4a min_tc4(min_tc[0], min_tc[1], min_tc[0], min_tc[1]);
+
+ LLVector4a* pos_out = face.mPositions;
+ LLVector4a* norm_out = face.mNormals;
+ LLVector4a* tc_out = (LLVector4a*) face.mTexCoords;
+
+ {
+ U16* v = (U16*) &(pos[0]);
+ for (U32 j = 0; j < num_verts; ++j)
+ {
+ pos_out->set((F32) v[0], (F32) v[1], (F32) v[2]);
+ pos_out->div(65535.f);
+ pos_out->mul(pos_range);
+ pos_out->add(min_pos);
+ pos_out++;
+ v += 3;
+ }
+
+ }
+
+ {
+ U16* n = (U16*) &(norm[0]);
+ for (U32 j = 0; j < num_verts; ++j)
+ {
+ norm_out->set((F32) n[0], (F32) n[1], (F32) n[2]);
+ norm_out->div(65535.f);
+ norm_out->mul(2.f);
+ norm_out->sub(1.f);
+ norm_out++;
+ n += 3;
+ }
+ }
+
+ {
+ U16* t = (U16*) &(tc[0]);
+ for (U32 j = 0; j < num_verts; j+=2)
+ {
+ if (j < num_verts-1)
+ {
+ tc_out->set((F32) t[0], (F32) t[1], (F32) t[2], (F32) t[3]);
+ }
+ else
+ {
+ tc_out->set((F32) t[0], (F32) t[1], 0.f, 0.f);
+ }
+
+ t += 4;
+
+ tc_out->div(65535.f);
+ tc_out->mul(tc_range);
+ tc_out->add(min_tc4);
+
+ tc_out++;
+ }
+ }
+
+ if (mdl[i].has("Weights"))
+ {
+ face.allocateWeights(num_verts);
+
+ LLSD::Binary weights = mdl[i]["Weights"];
+
+ U32 idx = 0;
+
+ U32 cur_vertex = 0;
+ while (idx < weights.size() && cur_vertex < num_verts)
+ {
+ const U8 END_INFLUENCES = 0xFF;
+ U8 joint = weights[idx++];
+
+ U32 cur_influence = 0;
+ LLVector4 wght(0,0,0,0);
+
+ while (joint != END_INFLUENCES && idx < weights.size())
+ {
+ U16 influence = weights[idx++];
+ influence |= ((U16) weights[idx++] << 8);
+
+ F32 w = llclamp((F32) influence / 65535.f, 0.f, 0.99999f);
+ wght.mV[cur_influence++] = (F32) joint + w;
+
+ if (cur_influence >= 4)
+ {
+ joint = END_INFLUENCES;
+ }
+ else
+ {
+ joint = weights[idx++];
+ }
+ }
+
+ face.mWeights[cur_vertex].loadua(wght.mV);
+
+ cur_vertex++;
+ }
+
+ if (cur_vertex != num_verts || idx != weights.size())
+ {
+ llwarns << "Vertex weight count does not match vertex count!" << llendl;
+ }
+
+ }
+
+ // modifier flags?
+ bool do_mirror = (mParams.getSculptType() & LL_SCULPT_FLAG_MIRROR);
+ bool do_invert = (mParams.getSculptType() &LL_SCULPT_FLAG_INVERT);
+
+
+ // translate to actions:
+ bool do_reflect_x = false;
+ bool do_reverse_triangles = false;
+ bool do_invert_normals = false;
+
+ if (do_mirror)
+ {
+ do_reflect_x = true;
+ do_reverse_triangles = !do_reverse_triangles;
+ }
+
+ if (do_invert)
+ {
+ do_invert_normals = true;
+ do_reverse_triangles = !do_reverse_triangles;
+ }
+
+ // now do the work
+
+ if (do_reflect_x)
+ {
+ LLVector4a* p = (LLVector4a*) face.mPositions;
+ LLVector4a* n = (LLVector4a*) face.mNormals;
+
+ for (S32 i = 0; i < face.mNumVertices; i++)
+ {
+ p[i].mul(-1.0f);
+ n[i].mul(-1.0f);
+ }
+ }
+
+ if (do_invert_normals)
+ {
+ LLVector4a* n = (LLVector4a*) face.mNormals;
+
+ for (S32 i = 0; i < face.mNumVertices; i++)
+ {
+ n[i].mul(-1.0f);
+ }
+ }
+
+ if (do_reverse_triangles)
+ {
+ for (U32 j = 0; j < face.mNumIndices; j += 3)
+ {
+ // swap the 2nd and 3rd index
+ S32 swap = face.mIndices[j+1];
+ face.mIndices[j+1] = face.mIndices[j+2];
+ face.mIndices[j+2] = swap;
+ }
+ }
+
+ //calculate bounding box
+ LLVector4a& min = face.mExtents[0];
+ LLVector4a& max = face.mExtents[1];
+
+ min.clear();
+ max.clear();
+ min = max = face.mPositions[0];
+
+ for (S32 i = 1; i < face.mNumVertices; ++i)
+ {
+ min.setMin(min, face.mPositions[i]);
+ max.setMax(max, face.mPositions[i]);
+ }
+ }
+ }
+
+ mSculptLevel = 0; // success!
+
+ cacheOptimize();
+
+ return true;
+}
+
+void tetrahedron_set_normal(LLVolumeFace::VertexData* cv)
+{
+ LLVector4a v0;
+ v0.setSub(cv[1].getPosition(), cv[0].getNormal());
+ LLVector4a v1;
+ v1.setSub(cv[2].getNormal(), cv[0].getPosition());
+
+ cv[0].getNormal().setCross3(v0,v1);
+ cv[0].getNormal().normalize3fast();
+ cv[1].setNormal(cv[0].getNormal());
+ cv[2].setNormal(cv[1].getNormal());
+}
+
+BOOL LLVolume::isTetrahedron()
+{
+ return mIsTetrahedron;
+}
+
+void LLVolume::makeTetrahedron()
+{
+ mVolumeFaces.clear();
+
+ LLVolumeFace face;
+
+ F32 x = 0.25f;
+ LLVector4a p[] =
+ { //unit tetrahedron corners
+ LLVector4a(x,x,x),
+ LLVector4a(-x,-x,x),
+ LLVector4a(-x,x,-x),
+ LLVector4a(x,-x,-x)
+ };
+
+ face.mExtents[0].splat(-x);
+ face.mExtents[1].splat(x);
+
+ LLVolumeFace::VertexData cv[3];
+
+ //set texture coordinates
+ cv[0].mTexCoord = LLVector2(0,0);
+ cv[1].mTexCoord = LLVector2(1,0);
+ cv[2].mTexCoord = LLVector2(0.5f, 0.5f*F_SQRT3);
+
+
+ //side 1
+ cv[0].setPosition(p[1]);
+ cv[1].setPosition(p[0]);
+ cv[2].setPosition(p[2]);
+
+ tetrahedron_set_normal(cv);
+
+ face.resizeVertices(12);
+ face.resizeIndices(12);
+
+ LLVector4a* v = (LLVector4a*) face.mPositions;
+ LLVector4a* n = (LLVector4a*) face.mNormals;
+ LLVector2* tc = (LLVector2*) face.mTexCoords;
+
+ v[0] = cv[0].getPosition();
+ v[1] = cv[1].getPosition();
+ v[2] = cv[2].getPosition();
+ v += 3;
+
+ n[0] = cv[0].getNormal();
+ n[1] = cv[1].getNormal();
+ n[2] = cv[2].getNormal();
+ n += 3;
+
+ tc[0] = cv[0].mTexCoord;
+ tc[1] = cv[1].mTexCoord;
+ tc[2] = cv[2].mTexCoord;
+ tc += 3;
+
+
+ //side 2
+ cv[0].setPosition(p[3]);
+ cv[1].setPosition(p[0]);
+ cv[2].setPosition(p[1]);
+
+ tetrahedron_set_normal(cv);
+
+ v[0] = cv[0].getPosition();
+ v[1] = cv[1].getPosition();
+ v[2] = cv[2].getPosition();
+ v += 3;
+
+ n[0] = cv[0].getNormal();
+ n[1] = cv[1].getNormal();
+ n[2] = cv[2].getNormal();
+ n += 3;
+
+ tc[0] = cv[0].mTexCoord;
+ tc[1] = cv[1].mTexCoord;
+ tc[2] = cv[2].mTexCoord;
+ tc += 3;
+
+ //side 3
+ cv[0].setPosition(p[3]);
+ cv[1].setPosition(p[1]);
+ cv[2].setPosition(p[2]);
+
+ tetrahedron_set_normal(cv);
+
+ v[0] = cv[0].getPosition();
+ v[1] = cv[1].getPosition();
+ v[2] = cv[2].getPosition();
+ v += 3;
+
+ n[0] = cv[0].getNormal();
+ n[1] = cv[1].getNormal();
+ n[2] = cv[2].getNormal();
+ n += 3;
+
+ tc[0] = cv[0].mTexCoord;
+ tc[1] = cv[1].mTexCoord;
+ tc[2] = cv[2].mTexCoord;
+ tc += 3;
+
+ //side 4
+ cv[0].setPosition(p[2]);
+ cv[1].setPosition(p[0]);
+ cv[2].setPosition(p[3]);
+
+ tetrahedron_set_normal(cv);
+
+ v[0] = cv[0].getPosition();
+ v[1] = cv[1].getPosition();
+ v[2] = cv[2].getPosition();
+ v += 3;
+
+ n[0] = cv[0].getNormal();
+ n[1] = cv[1].getNormal();
+ n[2] = cv[2].getNormal();
+ n += 3;
+
+ tc[0] = cv[0].mTexCoord;
+ tc[1] = cv[1].mTexCoord;
+ tc[2] = cv[2].mTexCoord;
+ tc += 3;
+
+ //set index buffer
+ for (U16 i = 0; i < 12; i++)
+ {
+ face.mIndices[i] = i;
+ }
+
+ mVolumeFaces.push_back(face);
+ mSculptLevel = 0;
+ mIsTetrahedron = TRUE;
+}
+
+void LLVolume::copyVolumeFaces(const LLVolume* volume)
+{
+ mVolumeFaces = volume->mVolumeFaces;
+ mSculptLevel = 0;
+ mIsTetrahedron = FALSE;
+}
+
+void LLVolume::cacheOptimize()
+{
+ for (S32 i = 0; i < mVolumeFaces.size(); ++i)
+ {
+ mVolumeFaces[i].cacheOptimize();
+ }
+}
+
+
+S32 LLVolume::getNumFaces() const
+{
+ U8 sculpt_type = (mParams.getSculptType() & LL_SCULPT_TYPE_MASK);
+
+ if (sculpt_type == LL_SCULPT_TYPE_MESH)
+ {
+ return LL_SCULPT_MESH_MAX_FACES;
+ }
+
+ return (S32)mProfilep->mFaces.size();
+}
+
void LLVolume::createVolumeFaces()
{
@@ -2188,7 +2928,7 @@ void sculpt_calc_mesh_resolution(U16 width, U16 height, U8 type, F32 detail, S32
ratio = (F32) width / (F32) height;
- s = (S32)fsqrtf(((F32)vertices / ratio));
+ s = (S32)(F32) sqrt(((F32)vertices / ratio));
s = llmax(s, 4); // no degenerate sizes, please
t = vertices / s;
@@ -2281,6 +3021,16 @@ BOOL LLVolume::isFlat(S32 face)
}
+bool LLVolumeParams::isSculpt() const
+{
+ return mSculptID.notNull();
+}
+
+bool LLVolumeParams::isMeshSculpt() const
+{
+ return isSculpt() && ((mSculptType & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH);
+}
+
bool LLVolumeParams::operator==(const LLVolumeParams &params) const
{
return ( (getPathParams() == params.getPathParams()) &&
@@ -2314,7 +3064,6 @@ bool LLVolumeParams::operator<(const LLVolumeParams &params) const
return mSculptID < params.mSculptID;
}
-
return mSculptType < params.mSculptType;
@@ -3372,34 +4121,62 @@ S32 LLVolume::getNumTriangleIndices() const
return count;
}
+
+S32 LLVolume::getNumTriangles() const
+{
+ U32 triangle_count = 0;
+
+ for (S32 i = 0; i < getNumVolumeFaces(); ++i)
+ {
+ triangle_count += getVolumeFace(i).mNumIndices/3;
+ }
+
+ return triangle_count;
+}
+
+
//-----------------------------------------------------------------------------
// generateSilhouetteVertices()
//-----------------------------------------------------------------------------
void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
std::vector<LLVector3> &normals,
- std::vector<S32> &segments,
- const LLVector3& obj_cam_vec,
- const LLMatrix4& mat,
- const LLMatrix3& norm_mat,
+ const LLVector3& obj_cam_vec_in,
+ const LLMatrix4& mat_in,
+ const LLMatrix3& norm_mat_in,
S32 face_mask)
{
LLMemType m1(LLMemType::MTYPE_VOLUME);
-
+
+ LLMatrix4a mat;
+ mat.loadu(mat_in);
+
+ LLMatrix4a norm_mat;
+ norm_mat.loadu(norm_mat_in);
+
+ LLVector4a obj_cam_vec;
+ obj_cam_vec.load3(obj_cam_vec_in.mV);
+
vertices.clear();
normals.clear();
- segments.clear();
+ if ((mParams.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH)
+ {
+ return;
+ }
+
S32 cur_index = 0;
//for each face
for (face_list_t::iterator iter = mVolumeFaces.begin();
iter != mVolumeFaces.end(); ++iter)
{
- const LLVolumeFace& face = *iter;
+ LLVolumeFace& face = *iter;
- if (!(face_mask & (0x1 << cur_index++)))
+ if (!(face_mask & (0x1 << cur_index++)) ||
+ face.mNumIndices == 0 || face.mEdge.empty())
{
continue;
}
+
if (face.mTypeMask & (LLVolumeFace::CAP_MASK)) {
}
@@ -3412,7 +4189,7 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
#if DEBUG_SILHOUETTE_EDGE_MAP
//for each triangle
- U32 count = face.mIndices.size();
+ U32 count = face.mNumIndices;
for (U32 j = 0; j < count/3; j++) {
//get vertices
S32 v1 = face.mIndices[j*3+0];
@@ -3420,9 +4197,9 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
S32 v3 = face.mIndices[j*3+2];
//get current face center
- LLVector3 cCenter = (face.mVertices[v1].mPosition +
- face.mVertices[v2].mPosition +
- face.mVertices[v3].mPosition) / 3.0f;
+ LLVector3 cCenter = (face.mVertices[v1].getPosition() +
+ face.mVertices[v2].getPosition() +
+ face.mVertices[v3].getPosition()) / 3.0f;
//for each edge
for (S32 k = 0; k < 3; k++) {
@@ -3440,9 +4217,9 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
v3 = face.mIndices[nIndex*3+2];
//get neighbor face center
- LLVector3 nCenter = (face.mVertices[v1].mPosition +
- face.mVertices[v2].mPosition +
- face.mVertices[v3].mPosition) / 3.0f;
+ LLVector3 nCenter = (face.mVertices[v1].getPosition() +
+ face.mVertices[v2].getPosition() +
+ face.mVertices[v3].getPosition()) / 3.0f;
//draw line
vertices.push_back(cCenter);
@@ -3465,15 +4242,15 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
#elif DEBUG_SILHOUETTE_NORMALS
//for each vertex
- for (U32 j = 0; j < face.mVertices.size(); j++) {
- vertices.push_back(face.mVertices[j].mPosition);
- vertices.push_back(face.mVertices[j].mPosition + face.mVertices[j].mNormal*0.1f);
+ for (U32 j = 0; j < face.mNumVertices; j++) {
+ vertices.push_back(face.mVertices[j].getPosition());
+ vertices.push_back(face.mVertices[j].getPosition() + face.mVertices[j].getNormal()*0.1f);
normals.push_back(LLVector3(0,0,1));
normals.push_back(LLVector3(0,0,1));
segments.push_back(vertices.size());
#if DEBUG_SILHOUETTE_BINORMALS
- vertices.push_back(face.mVertices[j].mPosition);
- vertices.push_back(face.mVertices[j].mPosition + face.mVertices[j].mBinormal*0.1f);
+ vertices.push_back(face.mVertices[j].getPosition());
+ vertices.push_back(face.mVertices[j].getPosition() + face.mVertices[j].mBinormal*0.1f);
normals.push_back(LLVector3(0,0,1));
normals.push_back(LLVector3(0,0,1));
segments.push_back(vertices.size());
@@ -3491,26 +4268,36 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
//for each triangle
std::vector<U8> fFacing;
- vector_append(fFacing, face.mIndices.size()/3);
- for (U32 j = 0; j < face.mIndices.size()/3; j++)
+ vector_append(fFacing, face.mNumIndices/3);
+
+ LLVector4a* v = (LLVector4a*) face.mPositions;
+ LLVector4a* n = (LLVector4a*) face.mNormals;
+
+ for (U32 j = 0; j < face.mNumIndices/3; j++)
{
//approximate normal
S32 v1 = face.mIndices[j*3+0];
S32 v2 = face.mIndices[j*3+1];
S32 v3 = face.mIndices[j*3+2];
- LLVector3 norm = (face.mVertices[v1].mPosition - face.mVertices[v2].mPosition) %
- (face.mVertices[v2].mPosition - face.mVertices[v3].mPosition);
-
- if (norm.magVecSquared() < 0.00000001f)
+ LLVector4a c1,c2;
+ c1.setSub(v[v1], v[v2]);
+ c2.setSub(v[v2], v[v3]);
+
+ LLVector4a norm;
+
+ norm.setCross3(c1, c2);
+
+ if (norm.dot3(norm) < 0.00000001f)
{
fFacing[j] = AWAY | TOWARDS;
}
else
{
//get view vector
- LLVector3 view = (obj_cam_vec-face.mVertices[v1].mPosition);
- bool away = view * norm > 0.0f;
+ LLVector4a view;
+ view.setSub(obj_cam_vec, v[v1]);
+ bool away = view.dot3(norm) > 0.0f;
if (away)
{
fFacing[j] = AWAY;
@@ -3523,7 +4310,7 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
}
//for each triangle
- for (U32 j = 0; j < face.mIndices.size()/3; j++)
+ for (U32 j = 0; j < face.mNumIndices/3; j++)
{
if (fFacing[j] == (AWAY | TOWARDS))
{ //this is a degenerate triangle
@@ -3556,17 +4343,21 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
S32 v1 = face.mIndices[j*3+k];
S32 v2 = face.mIndices[j*3+((k+1)%3)];
- vertices.push_back(face.mVertices[v1].mPosition*mat);
- LLVector3 norm1 = face.mVertices[v1].mNormal * norm_mat;
- norm1.normVec();
- normals.push_back(norm1);
+ LLVector4a t;
+ mat.affineTransform(v[v1], t);
+ vertices.push_back(LLVector3(t[0], t[1], t[2]));
- vertices.push_back(face.mVertices[v2].mPosition*mat);
- LLVector3 norm2 = face.mVertices[v2].mNormal * norm_mat;
- norm2.normVec();
- normals.push_back(norm2);
+ norm_mat.rotate(n[v1], t);
- segments.push_back(vertices.size());
+ t.normalize3fast();
+ normals.push_back(LLVector3(t[0], t[1], t[2]));
+
+ mat.affineTransform(v[v2], t);
+ vertices.push_back(LLVector3(t[0], t[1], t[2]));
+
+ norm_mat.rotate(n[v2], t);
+ t.normalize3fast();
+ normals.push_back(LLVector3(t[0], t[1], t[2]));
}
}
}
@@ -3579,6 +4370,19 @@ S32 LLVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& end,
S32 face,
LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal)
{
+ LLVector4a starta, enda;
+ starta.load3(start.mV);
+ enda.load3(end.mV);
+
+ return lineSegmentIntersect(starta, enda, face, intersection, tex_coord, normal, bi_normal);
+
+}
+
+
+S32 LLVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end,
+ S32 face,
+ LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal)
+{
S32 hit_face = -1;
S32 start_face;
@@ -3595,16 +4399,23 @@ S32 LLVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& end,
end_face = face;
}
- LLVector3 dir = end - start;
+ LLVector4a dir;
+ dir.setSub(end, start);
F32 closest_t = 2.f; // must be larger than 1
+ end_face = llmin(end_face, getNumVolumeFaces()-1);
+
for (S32 i = start_face; i <= end_face; i++)
{
- const LLVolumeFace &face = getVolumeFace((U32)i);
+ LLVolumeFace &face = mVolumeFaces[i];
+
+ LLVector4a box_center;
+ box_center.setAdd(face.mExtents[0], face.mExtents[1]);
+ box_center.mul(0.5f);
- LLVector3 box_center = (face.mExtents[0] + face.mExtents[1]) / 2.f;
- LLVector3 box_size = face.mExtents[1] - face.mExtents[0];
+ LLVector4a box_size;
+ box_size.setSub(face.mExtents[1], face.mExtents[0]);
if (LLLineSegmentBoxIntersect(start, end, box_center, box_size))
{
@@ -3612,56 +4423,19 @@ S32 LLVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& end,
{
genBinormals(i);
}
-
- for (U32 tri = 0; tri < face.mIndices.size()/3; tri++)
- {
- S32 index1 = face.mIndices[tri*3+0];
- S32 index2 = face.mIndices[tri*3+1];
- S32 index3 = face.mIndices[tri*3+2];
- F32 a, b, t;
+ if (!face.mOctree)
+ {
+ face.createOctree();
+ }
- if (LLTriangleRayIntersect(face.mVertices[index1].mPosition,
- face.mVertices[index2].mPosition,
- face.mVertices[index3].mPosition,
- start, dir, &a, &b, &t, FALSE))
- {
- if ((t >= 0.f) && // if hit is after start
- (t <= 1.f) && // and before end
- (t < closest_t)) // and this hit is closer
- {
- closest_t = t;
- hit_face = i;
+ //LLVector4a* p = (LLVector4a*) face.mPositions;
- if (intersection != NULL)
- {
- *intersection = start + dir * closest_t;
- }
-
- if (tex_coord != NULL)
+ LLOctreeTriangleRayIntersect intersect(start, dir, &face, &closest_t, intersection, tex_coord, normal, bi_normal);
+ intersect.traverse(face.mOctree);
+ if (intersect.mHitFace)
{
- *tex_coord = ((1.f - a - b) * face.mVertices[index1].mTexCoord +
- a * face.mVertices[index2].mTexCoord +
- b * face.mVertices[index3].mTexCoord);
-
- }
-
- if (normal != NULL)
- {
- *normal = ((1.f - a - b) * face.mVertices[index1].mNormal +
- a * face.mVertices[index2].mNormal +
- b * face.mVertices[index3].mNormal);
- }
-
- if (bi_normal != NULL)
- {
- *bi_normal = ((1.f - a - b) * face.mVertices[index1].mBinormal +
- a * face.mVertices[index2].mBinormal +
- b * face.mVertices[index3].mBinormal);
- }
-
- }
- }
+ hit_face = i;
}
}
}
@@ -4109,11 +4883,28 @@ BOOL LLVolumeParams::exportLegacyStream(std::ostream& output_stream) const
return TRUE;
}
+LLSD LLVolumeParams::sculptAsLLSD() const
+{
+ LLSD sd = LLSD();
+ sd["id"] = getSculptID();
+ sd["type"] = getSculptType();
+
+ return sd;
+}
+
+bool LLVolumeParams::sculptFromLLSD(LLSD& sd)
+{
+ setSculptID(sd["id"].asUUID(), (U8)sd["type"].asInteger());
+ return true;
+}
+
LLSD LLVolumeParams::asLLSD() const
{
LLSD sd = LLSD();
sd["path"] = mPathParams;
sd["profile"] = mProfileParams;
+ sd["sculpt"] = sculptAsLLSD();
+
return sd;
}
@@ -4121,6 +4912,8 @@ bool LLVolumeParams::fromLLSD(LLSD& sd)
{
mPathParams.fromLLSD(sd["path"]);
mProfileParams.fromLLSD(sd["profile"]);
+ sculptFromLLSD(sd["sculpt"]);
+
return true;
}
@@ -4163,6 +4956,12 @@ const F32 MIN_CONCAVE_PATH_WEDGE = 0.111111f; // 1/9 unity
// for collison purposes
BOOL LLVolumeParams::isConvex() const
{
+ if (!getSculptID().isNull())
+ {
+ // can't determine, be safe and say no:
+ return FALSE;
+ }
+
F32 path_length = mPathParams.getEnd() - mPathParams.getBegin();
F32 hollow = mProfileParams.getHollow();
@@ -4403,22 +5202,805 @@ std::ostream& operator<<(std::ostream &s, const LLVolume *volumep)
return s;
}
+LLVolumeFace::LLVolumeFace() :
+ mID(0),
+ mTypeMask(0),
+ mBeginS(0),
+ mBeginT(0),
+ mNumS(0),
+ mNumT(0),
+ mNumVertices(0),
+ mNumIndices(0),
+ mPositions(NULL),
+ mNormals(NULL),
+ mBinormals(NULL),
+ mTexCoords(NULL),
+ mIndices(NULL),
+ mWeights(NULL),
+ mOctree(NULL)
+{
+ mExtents = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*3);
+ mCenter = mExtents+2;
+}
+
+LLVolumeFace::LLVolumeFace(const LLVolumeFace& src)
+: mID(0),
+ mTypeMask(0),
+ mBeginS(0),
+ mBeginT(0),
+ mNumS(0),
+ mNumT(0),
+ mNumVertices(0),
+ mNumIndices(0),
+ mPositions(NULL),
+ mNormals(NULL),
+ mBinormals(NULL),
+ mTexCoords(NULL),
+ mIndices(NULL),
+ mWeights(NULL),
+ mOctree(NULL)
+{
+ mExtents = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*3);
+ mCenter = mExtents+2;
+ *this = src;
+}
+
+LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src)
+{
+ if (&src == this)
+ { //self assignment, do nothing
+ return *this;
+ }
+
+ mID = src.mID;
+ mTypeMask = src.mTypeMask;
+ mBeginS = src.mBeginS;
+ mBeginT = src.mBeginT;
+ mNumS = src.mNumS;
+ mNumT = src.mNumT;
+
+ mExtents[0] = src.mExtents[0];
+ mExtents[1] = src.mExtents[1];
+ *mCenter = *src.mCenter;
+
+ mNumVertices = 0;
+ mNumIndices = 0;
+
+ freeData();
+
+ LLVector4a::memcpyNonAliased16((F32*) mExtents, (F32*) src.mExtents, 3*sizeof(LLVector4a));
+
+ resizeVertices(src.mNumVertices);
+ resizeIndices(src.mNumIndices);
+
+ if (mNumVertices)
+ {
+ S32 vert_size = mNumVertices*sizeof(LLVector4a);
+ S32 tc_size = (mNumVertices*sizeof(LLVector2)+0xF) & ~0xF;
+
+ LLVector4a::memcpyNonAliased16((F32*) mPositions, (F32*) src.mPositions, vert_size);
+ LLVector4a::memcpyNonAliased16((F32*) mNormals, (F32*) src.mNormals, vert_size);
+ LLVector4a::memcpyNonAliased16((F32*) mTexCoords, (F32*) src.mTexCoords, tc_size);
+
+
+ if (src.mBinormals)
+ {
+ allocateBinormals(src.mNumVertices);
+ LLVector4a::memcpyNonAliased16((F32*) mBinormals, (F32*) src.mBinormals, vert_size);
+ }
+ else
+ {
+ ll_aligned_free_16(mBinormals);
+ mBinormals = NULL;
+ }
+
+ if (src.mWeights)
+ {
+ allocateWeights(src.mNumVertices);
+ LLVector4a::memcpyNonAliased16((F32*) mWeights, (F32*) src.mWeights, vert_size);
+ }
+ else
+ {
+ ll_aligned_free_16(mWeights);
+ mWeights = NULL;
+ }
+ }
+
+ if (mNumIndices)
+ {
+ S32 idx_size = (mNumIndices*sizeof(U16)+0xF) & ~0xF;
+
+ LLVector4a::memcpyNonAliased16((F32*) mIndices, (F32*) src.mIndices, idx_size);
+ }
+
+ //delete
+ return *this;
+}
+
+LLVolumeFace::~LLVolumeFace()
+{
+ ll_aligned_free_16(mExtents);
+ mExtents = NULL;
+
+ freeData();
+}
+
+void LLVolumeFace::freeData()
+{
+ ll_aligned_free_16(mPositions);
+ mPositions = NULL;
+ ll_aligned_free_16( mNormals);
+ mNormals = NULL;
+ ll_aligned_free_16(mTexCoords);
+ mTexCoords = NULL;
+ ll_aligned_free_16(mIndices);
+ mIndices = NULL;
+ ll_aligned_free_16(mBinormals);
+ mBinormals = NULL;
+ ll_aligned_free_16(mWeights);
+ mWeights = NULL;
+
+ delete mOctree;
+ mOctree = NULL;
+}
BOOL LLVolumeFace::create(LLVolume* volume, BOOL partial_build)
{
+ //tree for this face is no longer valid
+ delete mOctree;
+ mOctree = NULL;
+
+ BOOL ret = FALSE ;
if (mTypeMask & CAP_MASK)
{
- return createCap(volume, partial_build);
+ ret = createCap(volume, partial_build);
}
else if ((mTypeMask & END_MASK) || (mTypeMask & SIDE_MASK))
{
- return createSide(volume, partial_build);
+ ret = createSide(volume, partial_build);
}
else
{
llerrs << "Unknown/uninitialized face type!" << llendl;
- return FALSE;
}
+
+ //update the range of the texture coordinates
+ if(ret)
+ {
+ mTexCoordExtents[0].setVec(1.f, 1.f) ;
+ mTexCoordExtents[1].setVec(0.f, 0.f) ;
+
+ for(U32 i = 0 ; i < mNumVertices ; i++)
+ {
+ if(mTexCoordExtents[0].mV[0] > mTexCoords[i].mV[0])
+ {
+ mTexCoordExtents[0].mV[0] = mTexCoords[i].mV[0] ;
+ }
+ if(mTexCoordExtents[1].mV[0] < mTexCoords[i].mV[0])
+ {
+ mTexCoordExtents[1].mV[0] = mTexCoords[i].mV[0] ;
+ }
+
+ if(mTexCoordExtents[0].mV[1] > mTexCoords[i].mV[1])
+ {
+ mTexCoordExtents[0].mV[1] = mTexCoords[i].mV[1] ;
+ }
+ if(mTexCoordExtents[1].mV[1] < mTexCoords[i].mV[1])
+ {
+ mTexCoordExtents[1].mV[1] = mTexCoords[i].mV[1] ;
+ }
+ }
+ mTexCoordExtents[0].mV[0] = llmax(0.f, mTexCoordExtents[0].mV[0]) ;
+ mTexCoordExtents[0].mV[1] = llmax(0.f, mTexCoordExtents[0].mV[1]) ;
+ mTexCoordExtents[1].mV[0] = llmin(1.f, mTexCoordExtents[1].mV[0]) ;
+ mTexCoordExtents[1].mV[1] = llmin(1.f, mTexCoordExtents[1].mV[1]) ;
+ }
+
+ return ret ;
+}
+
+void LLVolumeFace::getVertexData(U16 index, LLVolumeFace::VertexData& cv)
+{
+ cv.setPosition(mPositions[index]);
+ cv.setNormal(mNormals[index]);
+ cv.mTexCoord = mTexCoords[index];
+}
+
+bool LLVolumeFace::VertexMapData::operator==(const LLVolumeFace::VertexData& rhs) const
+{
+ return getPosition().equals3(rhs.getPosition()) &&
+ mTexCoord == rhs.mTexCoord &&
+ getNormal().equals3(rhs.getNormal());
+}
+
+bool LLVolumeFace::VertexMapData::ComparePosition::operator()(const LLVector3& a, const LLVector3& b) const
+{
+ if (a.mV[0] != b.mV[0])
+ {
+ return a.mV[0] < b.mV[0];
+ }
+
+ if (a.mV[1] != b.mV[1])
+ {
+ return a.mV[1] < b.mV[1];
+ }
+
+ return a.mV[2] < b.mV[2];
+}
+
+void LLVolumeFace::optimize(F32 angle_cutoff)
+{
+ LLVolumeFace new_face;
+
+ //map of points to vector of vertices at that point
+ VertexMapData::PointMap point_map;
+
+ //remove redundant vertices
+ for (U32 i = 0; i < mNumIndices; ++i)
+ {
+ U16 index = mIndices[i];
+
+ LLVolumeFace::VertexData cv;
+ getVertexData(index, cv);
+
+ BOOL found = FALSE;
+ VertexMapData::PointMap::iterator point_iter = point_map.find(LLVector3(cv.getPosition().getF32ptr()));
+ if (point_iter != point_map.end())
+ { //duplicate point might exist
+ for (U32 j = 0; j < point_iter->second.size(); ++j)
+ {
+ LLVolumeFace::VertexData& tv = (point_iter->second)[j];
+ if (tv.compareNormal(cv, angle_cutoff))
+ {
+ found = TRUE;
+ new_face.pushIndex((point_iter->second)[j].mIndex);
+ break;
+ }
+ }
+ }
+
+ if (!found)
+ {
+ new_face.pushVertex(cv);
+ U16 index = (U16) new_face.mNumVertices-1;
+ new_face.pushIndex(index);
+
+ VertexMapData d;
+ d.setPosition(cv.getPosition());
+ d.mTexCoord = cv.mTexCoord;
+ d.setNormal(cv.getNormal());
+ d.mIndex = index;
+ if (point_iter != point_map.end())
+ {
+ point_iter->second.push_back(d);
+ }
+ else
+ {
+ point_map[LLVector3(d.getPosition().getF32ptr())].push_back(d);
+ }
+ }
+ }
+
+ swapData(new_face);
+}
+
+class LLVCacheTriangleData;
+
+class LLVCacheVertexData
+{
+public:
+ S32 mIdx;
+ S32 mCacheTag;
+ F32 mScore;
+ U32 mActiveTriangles;
+ std::vector<LLVCacheTriangleData*> mTriangles;
+
+ LLVCacheVertexData()
+ {
+ mCacheTag = -1;
+ mScore = 0.f;
+ mActiveTriangles = 0;
+ mIdx = -1;
+ }
+};
+
+class LLVCacheTriangleData
+{
+public:
+ bool mActive;
+ F32 mScore;
+ LLVCacheVertexData* mVertex[3];
+
+ LLVCacheTriangleData()
+ {
+ mActive = true;
+ mScore = 0.f;
+ mVertex[0] = mVertex[1] = mVertex[2] = NULL;
+ }
+
+ void complete()
+ {
+ mActive = false;
+ for (S32 i = 0; i < 3; ++i)
+ {
+ if (mVertex[i])
+ {
+ llassert_always(mVertex[i]->mActiveTriangles > 0);
+ mVertex[i]->mActiveTriangles--;
+ }
+ }
+ }
+
+ bool operator<(const LLVCacheTriangleData& rhs) const
+ { //highest score first
+ return rhs.mScore < mScore;
+ }
+};
+
+const F32 FindVertexScore_CacheDecayPower = 1.5f;
+const F32 FindVertexScore_LastTriScore = 0.75f;
+const F32 FindVertexScore_ValenceBoostScale = 2.0f;
+const F32 FindVertexScore_ValenceBoostPower = 0.5f;
+const U32 MaxSizeVertexCache = 32;
+
+F32 find_vertex_score(LLVCacheVertexData& data)
+{
+ if (data.mActiveTriangles == 0)
+ { //no triangle references this vertex
+ return -1.f;
+ }
+
+ F32 score = 0.f;
+
+ S32 cache_idx = data.mCacheTag;
+
+ if (cache_idx < 0)
+ {
+ //not in cache
+ }
+ else
+ {
+ if (cache_idx < 3)
+ { //vertex was in the last triangle
+ score = FindVertexScore_LastTriScore;
+ }
+ else
+ { //more points for being higher in the cache
+ F32 scaler = 1.f/(MaxSizeVertexCache-3);
+ score = 1.f-((cache_idx-3)*scaler);
+ score = powf(score, FindVertexScore_CacheDecayPower);
+ }
+ }
+
+ //bonus points for having low valence
+ F32 valence_boost = powf(data.mActiveTriangles, -FindVertexScore_ValenceBoostPower);
+ score += FindVertexScore_ValenceBoostScale * valence_boost;
+
+ return score;
+}
+
+class LLVCacheFIFO
+{
+public:
+ LLVCacheVertexData* mCache[MaxSizeVertexCache];
+ U32 mMisses;
+
+ LLVCacheFIFO()
+ {
+ mMisses = 0;
+ for (U32 i = 0; i < MaxSizeVertexCache; ++i)
+ {
+ mCache[i] = NULL;
+ }
+ }
+
+ void addVertex(LLVCacheVertexData* data)
+ {
+ if (data->mCacheTag == -1)
+ {
+ mMisses++;
+
+ S32 end = MaxSizeVertexCache-1;
+
+ if (mCache[end])
+ {
+ mCache[end]->mCacheTag = -1;
+ }
+
+ for (S32 i = end; i > 0; --i)
+ {
+ mCache[i] = mCache[i-1];
+ if (mCache[i])
+ {
+ mCache[i]->mCacheTag = i;
+ }
+ }
+
+ mCache[0] = data;
+ data->mCacheTag = 0;
+ }
+ }
+};
+
+class LLVCacheLRU
+{
+public:
+ LLVCacheVertexData* mCache[MaxSizeVertexCache+3];
+
+ LLVCacheTriangleData* mBestTriangle;
+
+ U32 mMisses;
+
+ LLVCacheLRU()
+ {
+ for (U32 i = 0; i < MaxSizeVertexCache+3; ++i)
+ {
+ mCache[i] = NULL;
+ }
+
+ mBestTriangle = NULL;
+ mMisses = 0;
+ }
+
+ void addVertex(LLVCacheVertexData* data)
+ {
+ S32 end = MaxSizeVertexCache+2;
+ if (data->mCacheTag != -1)
+ { //just moving a vertex to the front of the cache
+ end = data->mCacheTag;
+ }
+ else
+ {
+ mMisses++;
+ if (mCache[end])
+ { //adding a new vertex, vertex at end of cache falls off
+ mCache[end]->mCacheTag = -1;
+ }
+ }
+
+ for (S32 i = end; i > 0; --i)
+ { //adjust cache pointers and tags
+ mCache[i] = mCache[i-1];
+
+ if (mCache[i])
+ {
+ mCache[i]->mCacheTag = i;
+ }
+ }
+
+ mCache[0] = data;
+ mCache[0]->mCacheTag = 0;
+ }
+
+ void addTriangle(LLVCacheTriangleData* data)
+ {
+ addVertex(data->mVertex[0]);
+ addVertex(data->mVertex[1]);
+ addVertex(data->mVertex[2]);
+ }
+
+ void updateScores()
+ {
+ for (U32 i = MaxSizeVertexCache; i < MaxSizeVertexCache+3; ++i)
+ { //trailing 3 vertices aren't actually in the cache for scoring purposes
+ if (mCache[i])
+ {
+ mCache[i]->mCacheTag = -1;
+ }
+ }
+
+ for (U32 i = 0; i < MaxSizeVertexCache; ++i)
+ { //update scores of vertices in cache
+ if (mCache[i])
+ {
+ mCache[i]->mScore = find_vertex_score(*(mCache[i]));
+ llassert_always(mCache[i]->mCacheTag == i);
+ }
+ }
+
+ mBestTriangle = NULL;
+ //update triangle scores
+ for (U32 i = 0; i < MaxSizeVertexCache+3; ++i)
+ {
+ if (mCache[i])
+ {
+ for (U32 j = 0; j < mCache[i]->mTriangles.size(); ++j)
+ {
+ LLVCacheTriangleData* tri = mCache[i]->mTriangles[j];
+ if (tri->mActive)
+ {
+ tri->mScore = tri->mVertex[0]->mScore;
+ tri->mScore += tri->mVertex[1]->mScore;
+ tri->mScore += tri->mVertex[2]->mScore;
+
+ if (!mBestTriangle || mBestTriangle->mScore < tri->mScore)
+ {
+ mBestTriangle = tri;
+ }
+ }
+ }
+ }
+ }
+
+ //knock trailing 3 vertices off the cache
+ for (U32 i = MaxSizeVertexCache; i < MaxSizeVertexCache+3; ++i)
+ {
+ if (mCache[i])
+ {
+ llassert_always(mCache[i]->mCacheTag == -1);
+ mCache[i] = NULL;
+ }
+ }
+ }
+};
+
+
+void LLVolumeFace::cacheOptimize()
+{ //optimize for vertex cache according to Forsyth method:
+ // http://home.comcast.net/~tom_forsyth/papers/fast_vert_cache_opt.html
+
+ LLVCacheLRU cache;
+
+ //mapping of vertices to triangles and indices
+ std::vector<LLVCacheVertexData> vertex_data;
+
+ //mapping of triangles do vertices
+ std::vector<LLVCacheTriangleData> triangle_data;
+
+ triangle_data.resize(mNumIndices/3);
+ vertex_data.resize(mNumVertices);
+
+ for (U32 i = 0; i < mNumIndices; i++)
+ { //populate vertex data and triangle data arrays
+ U16 idx = mIndices[i];
+ U32 tri_idx = i/3;
+
+ vertex_data[idx].mTriangles.push_back(&(triangle_data[tri_idx]));
+ vertex_data[idx].mIdx = idx;
+ triangle_data[tri_idx].mVertex[i%3] = &(vertex_data[idx]);
+ }
+
+ /*F32 pre_acmr = 1.f;
+ //measure cache misses from before rebuild
+ {
+ LLVCacheFIFO test_cache;
+ for (U32 i = 0; i < mNumIndices; ++i)
+ {
+ test_cache.addVertex(&vertex_data[mIndices[i]]);
+ }
+
+ for (U32 i = 0; i < mNumVertices; i++)
+ {
+ vertex_data[i].mCacheTag = -1;
+ }
+
+ pre_acmr = (F32) test_cache.mMisses/(mNumIndices/3);
+ }*/
+
+ for (U32 i = 0; i < mNumVertices; i++)
+ { //initialize score values (no cache -- might try a fifo cache here)
+ vertex_data[i].mScore = find_vertex_score(vertex_data[i]);
+ vertex_data[i].mActiveTriangles = vertex_data[i].mTriangles.size();
+
+ for (U32 j = 0; j < vertex_data[i].mTriangles.size(); ++j)
+ {
+ vertex_data[i].mTriangles[j]->mScore += vertex_data[i].mScore;
+ }
+ }
+
+ //sort triangle data by score
+ std::sort(triangle_data.begin(), triangle_data.end());
+
+ std::vector<U16> new_indices;
+
+ LLVCacheTriangleData* tri;
+
+ //prime pump by adding first triangle to cache;
+ tri = &(triangle_data[0]);
+ cache.addTriangle(tri);
+ new_indices.push_back(tri->mVertex[0]->mIdx);
+ new_indices.push_back(tri->mVertex[1]->mIdx);
+ new_indices.push_back(tri->mVertex[2]->mIdx);
+ tri->complete();
+
+ U32 breaks = 0;
+ for (U32 i = 1; i < mNumIndices/3; ++i)
+ {
+ cache.updateScores();
+ tri = cache.mBestTriangle;
+ if (!tri)
+ {
+ breaks++;
+ for (U32 j = 0; j < triangle_data.size(); ++j)
+ {
+ if (triangle_data[j].mActive)
+ {
+ tri = &(triangle_data[j]);
+ break;
+ }
+ }
+ }
+
+ cache.addTriangle(tri);
+ new_indices.push_back(tri->mVertex[0]->mIdx);
+ new_indices.push_back(tri->mVertex[1]->mIdx);
+ new_indices.push_back(tri->mVertex[2]->mIdx);
+ tri->complete();
+ }
+
+ for (U32 i = 0; i < mNumIndices; ++i)
+ {
+ mIndices[i] = new_indices[i];
+ }
+
+ /*F32 post_acmr = 1.f;
+ //measure cache misses from after rebuild
+ {
+ LLVCacheFIFO test_cache;
+ for (U32 i = 0; i < mNumVertices; i++)
+ {
+ vertex_data[i].mCacheTag = -1;
+ }
+
+ for (U32 i = 0; i < mNumIndices; ++i)
+ {
+ test_cache.addVertex(&vertex_data[mIndices[i]]);
+ }
+
+ post_acmr = (F32) test_cache.mMisses/(mNumIndices/3);
+ }*/
+
+ //optimize for pre-TnL cache
+
+ //allocate space for new buffer
+ S32 num_verts = mNumVertices;
+ LLVector4a* pos = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
+ LLVector4a* norm = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
+ S32 size = ((num_verts*sizeof(LLVector2)) + 0xF) & ~0xF;
+ LLVector2* tc = (LLVector2*) ll_aligned_malloc_16(size);
+
+ LLVector4a* wght = NULL;
+ if (mWeights)
+ {
+ wght = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
+ }
+
+ LLVector4a* binorm = NULL;
+ if (mBinormals)
+ {
+ binorm = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
+ }
+
+ //allocate mapping of old indices to new indices
+ std::vector<S32> new_idx;
+ new_idx.resize(mNumVertices, -1);
+
+ S32 cur_idx = 0;
+ for (U32 i = 0; i < mNumIndices; ++i)
+ {
+ U16 idx = mIndices[i];
+ if (new_idx[idx] == -1)
+ { //this vertex hasn't been added yet
+ new_idx[idx] = cur_idx;
+
+ //copy vertex data
+ pos[cur_idx] = mPositions[idx];
+ norm[cur_idx] = mNormals[idx];
+ tc[cur_idx] = mTexCoords[idx];
+ if (mWeights)
+ {
+ wght[cur_idx] = mWeights[idx];
+ }
+ if (mBinormals)
+ {
+ binorm[cur_idx] = mBinormals[idx];
+ }
+
+ cur_idx++;
+ }
+ }
+
+ for (U32 i = 0; i < mNumIndices; ++i)
+ {
+ mIndices[i] = new_idx[mIndices[i]];
+ }
+
+ ll_aligned_free_16(mPositions);
+ ll_aligned_free_16(mNormals);
+ ll_aligned_free_16(mTexCoords);
+ ll_aligned_free_16(mWeights);
+ ll_aligned_free_16(mBinormals);
+
+ mPositions = pos;
+ mNormals = norm;
+ mTexCoords = tc;
+ mWeights = wght;
+ mBinormals = binorm;
+
+ //std::string result = llformat("ACMR pre/post: %.3f/%.3f -- %d triangles %d breaks", pre_acmr, post_acmr, mNumIndices/3, breaks);
+ //llinfos << result << llendl;
+
+}
+
+void LLVolumeFace::createOctree(F32 scaler, const LLVector4a& center, const LLVector4a& size)
+{
+ if (mOctree)
+ {
+ return;
+ }
+
+ mOctree = new LLOctreeRoot<LLVolumeTriangle>(center, size, NULL);
+ new LLVolumeOctreeListener(mOctree);
+
+ for (U32 i = 0; i < mNumIndices; i+= 3)
+ { //for each triangle
+ LLPointer<LLVolumeTriangle> tri = new LLVolumeTriangle();
+
+ const LLVector4a& v0 = mPositions[mIndices[i]];
+ const LLVector4a& v1 = mPositions[mIndices[i+1]];
+ const LLVector4a& v2 = mPositions[mIndices[i+2]];
+
+ //store pointers to vertex data
+ tri->mV[0] = &v0;
+ tri->mV[1] = &v1;
+ tri->mV[2] = &v2;
+
+ //store indices
+ tri->mIndex[0] = mIndices[i];
+ tri->mIndex[1] = mIndices[i+1];
+ tri->mIndex[2] = mIndices[i+2];
+
+ //get minimum point
+ LLVector4a min = v0;
+ min.setMin(min, v1);
+ min.setMin(min, v2);
+
+ //get maximum point
+ LLVector4a max = v0;
+ max.setMax(max, v1);
+ max.setMax(max, v2);
+
+ //compute center
+ LLVector4a center;
+ center.setAdd(min, max);
+ center.mul(0.5f);
+
+ tri->mPositionGroup = center;
+
+ //compute "radius"
+ LLVector4a size;
+ size.setSub(max,min);
+
+ tri->mRadius = size.getLength3().getF32() * scaler;
+
+ //insert
+ mOctree->insert(tri);
+ }
+
+ //remove unneeded octree layers
+ while (!mOctree->balance()) { }
+
+ //calculate AABB for each node
+ LLVolumeOctreeRebound rebound(this);
+ rebound.traverse(mOctree);
+
+ if (gDebugGL)
+ {
+ LLVolumeOctreeValidate validate;
+ validate.traverse(mOctree);
+ }
+}
+
+
+void LLVolumeFace::swapData(LLVolumeFace& rhs)
+{
+ llswap(rhs.mPositions, mPositions);
+ llswap(rhs.mNormals, mNormals);
+ llswap(rhs.mBinormals, mBinormals);
+ llswap(rhs.mTexCoords, mTexCoords);
+ llswap(rhs.mIndices,mIndices);
+ llswap(rhs.mNumVertices, mNumVertices);
+ llswap(rhs.mNumIndices, mNumIndices);
}
void LerpPlanarVertex(LLVolumeFace::VertexData& v0,
@@ -4428,10 +6010,21 @@ void LerpPlanarVertex(LLVolumeFace::VertexData& v0,
F32 coef01,
F32 coef02)
{
- vout.mPosition = v0.mPosition + ((v1.mPosition-v0.mPosition)*coef01)+((v2.mPosition-v0.mPosition)*coef02);
+
+ LLVector4a lhs;
+ lhs.setSub(v1.getPosition(), v0.getPosition());
+ lhs.mul(coef01);
+ LLVector4a rhs;
+ rhs.setSub(v2.getPosition(), v0.getPosition());
+ rhs.mul(coef02);
+
+ rhs.add(lhs);
+ rhs.add(v0.getPosition());
+
+ vout.setPosition(rhs);
+
vout.mTexCoord = v0.mTexCoord + ((v1.mTexCoord-v0.mTexCoord)*coef01)+((v2.mTexCoord-v0.mTexCoord)*coef02);
- vout.mNormal = v0.mNormal;
- vout.mBinormal = v0.mBinormal;
+ vout.setNormal(v0.getNormal());
}
BOOL LLVolumeFace::createUnCutCubeCap(LLVolume* volume, BOOL partial_build)
@@ -4451,84 +6044,113 @@ BOOL LLVolumeFace::createUnCutCubeCap(LLVolume* volume, BOOL partial_build)
num_vertices = (grid_size+1)*(grid_size+1);
num_indices = quad_count * 4;
- LLVector3& min = mExtents[0];
- LLVector3& max = mExtents[1];
+ LLVector4a& min = mExtents[0];
+ LLVector4a& max = mExtents[1];
S32 offset = 0;
if (mTypeMask & TOP_MASK)
+ {
offset = (max_t-1) * max_s;
+ }
else
+ {
offset = mBeginS;
+ }
- VertexData corners[4];
- VertexData baseVert;
- for(int t = 0; t < 4; t++){
- corners[t].mPosition = mesh[offset + (grid_size*t)].mPos;
- corners[t].mTexCoord.mV[0] = profile[grid_size*t].mV[0]+0.5f;
- corners[t].mTexCoord.mV[1] = 0.5f - profile[grid_size*t].mV[1];
- }
- baseVert.mNormal =
- ((corners[1].mPosition-corners[0].mPosition) %
- (corners[2].mPosition-corners[1].mPosition));
- baseVert.mNormal.normVec();
- if(!(mTypeMask & TOP_MASK)){
- baseVert.mNormal *= -1.0f;
- }else{
- //Swap the UVs on the U(X) axis for top face
- LLVector2 swap;
- swap = corners[0].mTexCoord;
- corners[0].mTexCoord=corners[3].mTexCoord;
- corners[3].mTexCoord=swap;
- swap = corners[1].mTexCoord;
- corners[1].mTexCoord=corners[2].mTexCoord;
- corners[2].mTexCoord=swap;
- }
- baseVert.mBinormal = calc_binormal_from_triangle(
- corners[0].mPosition, corners[0].mTexCoord,
- corners[1].mPosition, corners[1].mTexCoord,
- corners[2].mPosition, corners[2].mTexCoord);
- for(int t = 0; t < 4; t++){
- corners[t].mBinormal = baseVert.mBinormal;
- corners[t].mNormal = baseVert.mNormal;
- }
- mHasBinormals = TRUE;
-
- if (partial_build)
{
- mVertices.clear();
- }
+ VertexData corners[4];
+ VertexData baseVert;
+ for(S32 t = 0; t < 4; t++)
+ {
+ corners[t].getPosition().load3( mesh[offset + (grid_size*t)].mPos.mV);
+ corners[t].mTexCoord.mV[0] = profile[grid_size*t].mV[0]+0.5f;
+ corners[t].mTexCoord.mV[1] = 0.5f - profile[grid_size*t].mV[1];
+ }
- S32 vtop = mVertices.size();
- for(int gx = 0;gx<grid_size+1;gx++){
- for(int gy = 0;gy<grid_size+1;gy++){
- VertexData newVert;
- LerpPlanarVertex(
- corners[0],
- corners[1],
- corners[3],
- newVert,
- (F32)gx/(F32)grid_size,
- (F32)gy/(F32)grid_size);
- mVertices.push_back(newVert);
+ {
+ LLVector4a lhs;
+ lhs.setSub(corners[1].getPosition(), corners[0].getPosition());
+ LLVector4a rhs;
+ rhs.setSub(corners[2].getPosition(), corners[1].getPosition());
+ baseVert.getNormal().setCross3(lhs, rhs);
+ baseVert.getNormal().normalize3fast();
+ }
- if (gx == 0 && gy == 0)
- {
- min = max = newVert.mPosition;
- }
- else
+ if(!(mTypeMask & TOP_MASK))
+ {
+ baseVert.getNormal().mul(-1.0f);
+ }
+ else
+ {
+ //Swap the UVs on the U(X) axis for top face
+ LLVector2 swap;
+ swap = corners[0].mTexCoord;
+ corners[0].mTexCoord=corners[3].mTexCoord;
+ corners[3].mTexCoord=swap;
+ swap = corners[1].mTexCoord;
+ corners[1].mTexCoord=corners[2].mTexCoord;
+ corners[2].mTexCoord=swap;
+ }
+
+ LLVector4a binormal;
+
+ calc_binormal_from_triangle( binormal,
+ corners[0].getPosition(), corners[0].mTexCoord,
+ corners[1].getPosition(), corners[1].mTexCoord,
+ corners[2].getPosition(), corners[2].mTexCoord);
+
+ binormal.normalize3fast();
+
+ S32 size = (grid_size+1)*(grid_size+1);
+ resizeVertices(size);
+ allocateBinormals(size);
+
+ LLVector4a* pos = (LLVector4a*) mPositions;
+ LLVector4a* norm = (LLVector4a*) mNormals;
+ LLVector4a* binorm = (LLVector4a*) mBinormals;
+ LLVector2* tc = (LLVector2*) mTexCoords;
+
+ for(int gx = 0;gx<grid_size+1;gx++)
+ {
+ for(int gy = 0;gy<grid_size+1;gy++)
{
- update_min_max(min,max,newVert.mPosition);
+ VertexData newVert;
+ LerpPlanarVertex(
+ corners[0],
+ corners[1],
+ corners[3],
+ newVert,
+ (F32)gx/(F32)grid_size,
+ (F32)gy/(F32)grid_size);
+
+ *pos++ = newVert.getPosition();
+ *norm++ = baseVert.getNormal();
+ *tc++ = newVert.mTexCoord;
+ *binorm++ = binormal;
+
+ if (gx == 0 && gy == 0)
+ {
+ min = newVert.getPosition();
+ max = min;
+ }
+ else
+ {
+ min.setMin(min, newVert.getPosition());
+ max.setMax(max, newVert.getPosition());
+ }
}
}
- }
- mCenter = (min + max) * 0.5f;
+ mCenter->setAdd(min, max);
+ mCenter->mul(0.5f);
+ }
if (!partial_build)
{
-#if GEN_TRI_STRIP
- mTriStrip.clear();
-#endif
+ resizeIndices(grid_size*grid_size*6);
+
+ U16* out = mIndices;
+
S32 idxs[] = {0,1,(grid_size+1)+1,(grid_size+1)+1,(grid_size+1),0};
for(S32 gx = 0;gx<grid_size;gx++)
{
@@ -4539,61 +6161,18 @@ BOOL LLVolumeFace::createUnCutCubeCap(LLVolume* volume, BOOL partial_build)
{
for(S32 i=5;i>=0;i--)
{
- mIndices.push_back(vtop+(gy*(grid_size+1))+gx+idxs[i]);
- }
-
-#if GEN_TRI_STRIP
- if (gy == 0)
- {
- mTriStrip.push_back((gx+1)*(grid_size+1));
- mTriStrip.push_back((gx+1)*(grid_size+1));
- mTriStrip.push_back(gx*(grid_size+1));
- }
-
- mTriStrip.push_back(gy+1+(gx+1)*(grid_size+1));
- mTriStrip.push_back(gy+1+gx*(grid_size+1));
-
-
- if (gy == grid_size-1)
- {
- mTriStrip.push_back(gy+1+gx*(grid_size+1));
- }
-#endif
+ *out++ = ((gy*(grid_size+1))+gx+idxs[i]);
+ }
}
else
{
for(S32 i=0;i<6;i++)
{
- mIndices.push_back(vtop+(gy*(grid_size+1))+gx+idxs[i]);
- }
-
-#if GEN_TRI_STRIP
- if (gy == 0)
- {
- mTriStrip.push_back(gx*(grid_size+1));
- mTriStrip.push_back(gx*(grid_size+1));
- mTriStrip.push_back((gx+1)*(grid_size+1));
- }
-
- mTriStrip.push_back(gy+1+gx*(grid_size+1));
- mTriStrip.push_back(gy+1+(gx+1)*(grid_size+1));
-
- if (gy == grid_size-1)
- {
- mTriStrip.push_back(gy+1+(gx+1)*(grid_size+1));
+ *out++ = ((gy*(grid_size+1))+gx+idxs[i]);
}
-#endif
}
- }
-
- }
-
-#if GEN_TRI_STRIP
- if (mTriStrip.size()%2 == 1)
- {
- mTriStrip.push_back(mTriStrip[mTriStrip.size()-1]);
+ }
}
-#endif
}
return TRUE;
@@ -4623,17 +6202,31 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
num_vertices = profile.size();
num_indices = (profile.size() - 2)*3;
- mVertices.resize(num_vertices);
+ if (!(mTypeMask & HOLLOW_MASK) && !(mTypeMask & OPEN_MASK))
+ {
+ resizeVertices(num_vertices+1);
+ allocateBinormals(num_vertices+1);
- if (!partial_build)
+ if (!partial_build)
+ {
+ resizeIndices(num_indices+3);
+ }
+ }
+ else
{
- mIndices.resize(num_indices);
+ resizeVertices(num_vertices);
+ allocateBinormals(num_vertices);
+
+ if (!partial_build)
+ {
+ resizeIndices(num_indices);
+ }
}
S32 max_s = volume->getProfile().getTotal();
S32 max_t = volume->getPath().mPath.size();
- mCenter.clearVec();
+ mCenter->clear();
S32 offset = 0;
if (mTypeMask & TOP_MASK)
@@ -4651,82 +6244,91 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
LLVector2 cuv;
LLVector2 min_uv, max_uv;
- LLVector3& min = mExtents[0];
- LLVector3& max = mExtents[1];
+ LLVector4a& min = mExtents[0];
+ LLVector4a& max = mExtents[1];
+
+ LLVector2* tc = (LLVector2*) mTexCoords;
+ LLVector4a* pos = (LLVector4a*) mPositions;
+ LLVector4a* norm = (LLVector4a*) mNormals;
+ LLVector4a* binorm = (LLVector4a*) mBinormals;
// Copy the vertices into the array
for (S32 i = 0; i < num_vertices; i++)
{
if (mTypeMask & TOP_MASK)
{
- mVertices[i].mTexCoord.mV[0] = profile[i].mV[0]+0.5f;
- mVertices[i].mTexCoord.mV[1] = profile[i].mV[1]+0.5f;
+ tc[i].mV[0] = profile[i].mV[0]+0.5f;
+ tc[i].mV[1] = profile[i].mV[1]+0.5f;
}
else
{
// Mirror for underside.
- mVertices[i].mTexCoord.mV[0] = profile[i].mV[0]+0.5f;
- mVertices[i].mTexCoord.mV[1] = 0.5f - profile[i].mV[1];
+ tc[i].mV[0] = profile[i].mV[0]+0.5f;
+ tc[i].mV[1] = 0.5f - profile[i].mV[1];
}
- mVertices[i].mPosition = mesh[i + offset].mPos;
+ pos[i].load3(mesh[i + offset].mPos.mV);
if (i == 0)
{
- min = max = mVertices[i].mPosition;
- min_uv = max_uv = mVertices[i].mTexCoord;
+ max = pos[i];
+ min = max;
+ min_uv = max_uv = tc[i];
}
else
{
- update_min_max(min,max, mVertices[i].mPosition);
- update_min_max(min_uv, max_uv, mVertices[i].mTexCoord);
+ update_min_max(min,max,pos[i]);
+ update_min_max(min_uv, max_uv, tc[i]);
}
}
- mCenter = (min+max)*0.5f;
+ mCenter->setAdd(min, max);
+ mCenter->mul(0.5f);
+
cuv = (min_uv + max_uv)*0.5f;
- LLVector3 binormal = calc_binormal_from_triangle(
- mCenter, cuv,
- mVertices[0].mPosition, mVertices[0].mTexCoord,
- mVertices[1].mPosition, mVertices[1].mTexCoord);
- binormal.normVec();
+ LLVector4a binormal;
+ calc_binormal_from_triangle(binormal,
+ *mCenter, cuv,
+ pos[0], tc[0],
+ pos[1], tc[1]);
+ binormal.normalize3fast();
+
+ LLVector4a normal;
+ LLVector4a d0, d1;
+
- LLVector3 d0;
- LLVector3 d1;
- LLVector3 normal;
+ d0.setSub(*mCenter, pos[0]);
+ d1.setSub(*mCenter, pos[1]);
- d0 = mCenter-mVertices[0].mPosition;
- d1 = mCenter-mVertices[1].mPosition;
+ if (mTypeMask & TOP_MASK)
+ {
+ normal.setCross3(d0, d1);
+ }
+ else
+ {
+ normal.setCross3(d1, d0);
+ }
- normal = (mTypeMask & TOP_MASK) ? (d0%d1) : (d1%d0);
- normal.normVec();
+ normal.normalize3fast();
VertexData vd;
- vd.mPosition = mCenter;
- vd.mNormal = normal;
- vd.mBinormal = binormal;
+ vd.setPosition(*mCenter);
vd.mTexCoord = cuv;
if (!(mTypeMask & HOLLOW_MASK) && !(mTypeMask & OPEN_MASK))
{
- mVertices.push_back(vd);
+ pos[num_vertices] = *mCenter;
+ tc[num_vertices] = cuv;
num_vertices++;
- if (!partial_build)
- {
- vector_append(mIndices, 3);
- }
}
-
for (S32 i = 0; i < num_vertices; i++)
{
- mVertices[i].mBinormal = binormal;
- mVertices[i].mNormal = normal;
+ binorm[i].load4a(binormal.getF32ptr());
+ norm[i].load4a(normal.getF32ptr());
}
- mHasBinormals = TRUE;
-
if (partial_build)
{
return TRUE;
@@ -4834,8 +6436,6 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
pt2--;
}
}
-
- makeTriStrip();
}
else
{
@@ -4940,8 +6540,6 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
pt2--;
}
}
-
- makeTriStrip();
}
}
else
@@ -4963,131 +6561,277 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
mIndices[3*i+v2] = i + 1;
}
-#if GEN_TRI_STRIP
- //make tri strip
- if (mTypeMask & OPEN_MASK)
- {
- makeTriStrip();
- }
- else
- {
- S32 j = num_vertices-2;
- if (mTypeMask & TOP_MASK)
- {
- mTriStrip.push_back(0);
- for (S32 i = 0; i <= j; ++i)
- {
- mTriStrip.push_back(i);
- if (i != j)
- {
- mTriStrip.push_back(j);
- }
- --j;
- }
- }
- else
- {
- mTriStrip.push_back(j);
- for (S32 i = 0; i <= j; ++i)
- {
- if (i != j)
- {
- mTriStrip.push_back(j);
- }
- mTriStrip.push_back(i);
- --j;
- }
- }
-
- mTriStrip.push_back(mTriStrip[mTriStrip.size()-1]);
- if (mTriStrip.size()%2 == 1)
- {
- mTriStrip.push_back(mTriStrip[mTriStrip.size()-1]);
- }
- }
-#endif
}
return TRUE;
}
-void LLVolumeFace::makeTriStrip()
+void LLVolumeFace::createBinormals()
{
-#if GEN_TRI_STRIP
- for (U32 i = 0; i < mIndices.size(); i+=3)
+ LLMemType m1(LLMemType::MTYPE_VOLUME);
+
+ if (!mBinormals)
{
- U16 i0 = mIndices[i];
- U16 i1 = mIndices[i+1];
- U16 i2 = mIndices[i+2];
+ allocateBinormals(mNumVertices);
- if ((i/3)%2 == 1)
- {
- mTriStrip.push_back(i0);
- mTriStrip.push_back(i0);
- mTriStrip.push_back(i1);
- mTriStrip.push_back(i2);
- mTriStrip.push_back(i2);
- }
- else
+ //generate binormals
+ LLVector4a* pos = mPositions;
+ LLVector2* tc = (LLVector2*) mTexCoords;
+ LLVector4a* binorm = (LLVector4a*) mBinormals;
+
+ LLVector4a* end = mBinormals+mNumVertices;
+ while (binorm < end)
{
- mTriStrip.push_back(i2);
- mTriStrip.push_back(i2);
- mTriStrip.push_back(i1);
- mTriStrip.push_back(i0);
- mTriStrip.push_back(i0);
+ (*binorm++).clear();
}
- }
- if (mTriStrip.size()%2 == 1)
- {
- mTriStrip.push_back(mTriStrip[mTriStrip.size()-1]);
- }
-#endif
-}
+ binorm = mBinormals;
-void LLVolumeFace::createBinormals()
-{
- LLMemType m1(LLMemType::MTYPE_VOLUME);
-
- if (!mHasBinormals)
- {
- //generate binormals
- for (U32 i = 0; i < mIndices.size()/3; i++)
+ for (U32 i = 0; i < mNumIndices/3; i++)
{ //for each triangle
- const VertexData& v0 = mVertices[mIndices[i*3+0]];
- const VertexData& v1 = mVertices[mIndices[i*3+1]];
- const VertexData& v2 = mVertices[mIndices[i*3+2]];
+ const U16& i0 = mIndices[i*3+0];
+ const U16& i1 = mIndices[i*3+1];
+ const U16& i2 = mIndices[i*3+2];
//calculate binormal
- LLVector3 binorm = calc_binormal_from_triangle(v0.mPosition, v0.mTexCoord,
- v1.mPosition, v1.mTexCoord,
- v2.mPosition, v2.mTexCoord);
+ LLVector4a binormal;
+ calc_binormal_from_triangle(binormal,
+ pos[i0], tc[i0],
+ pos[i1], tc[i1],
+ pos[i2], tc[i2]);
- for (U32 j = 0; j < 3; j++)
- { //add triangle normal to vertices
- mVertices[mIndices[i*3+j]].mBinormal += binorm; // * (weight_sum - d[j])/weight_sum;
- }
+
+ //add triangle normal to vertices
+ binorm[i0].add(binormal);
+ binorm[i1].add(binormal);
+ binorm[i2].add(binormal);
//even out quad contributions
if (i % 2 == 0)
{
- mVertices[mIndices[i*3+2]].mBinormal += binorm;
+ binorm[i2].add(binormal);
}
else
{
- mVertices[mIndices[i*3+1]].mBinormal += binorm;
+ binorm[i1].add(binormal);
}
}
//normalize binormals
- for (U32 i = 0; i < mVertices.size(); i++)
+ for (U32 i = 0; i < mNumVertices; i++)
+ {
+ binorm[i].normalize3fast();
+ //bump map/planar projection code requires normals to be normalized
+ mNormals[i].normalize3fast();
+ }
+ }
+}
+
+void LLVolumeFace::resizeVertices(S32 num_verts)
+{
+ ll_aligned_free_16(mPositions);
+ ll_aligned_free_16(mNormals);
+ ll_aligned_free_16(mBinormals);
+ ll_aligned_free_16(mTexCoords);
+
+ mBinormals = NULL;
+
+ if (num_verts)
+ {
+ mPositions = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
+ assert_aligned(mPositions, 16);
+ mNormals = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
+ assert_aligned(mNormals, 16);
+
+ //pad texture coordinate block end to allow for QWORD reads
+ S32 size = ((num_verts*sizeof(LLVector2)) + 0xF) & ~0xF;
+ mTexCoords = (LLVector2*) ll_aligned_malloc_16(size);
+ assert_aligned(mTexCoords, 16);
+ }
+ else
+ {
+ mPositions = NULL;
+ mNormals = NULL;
+ mTexCoords = NULL;
+ }
+
+ mNumVertices = num_verts;
+}
+
+void LLVolumeFace::pushVertex(const LLVolumeFace::VertexData& cv)
+{
+ pushVertex(cv.getPosition(), cv.getNormal(), cv.mTexCoord);
+}
+
+void LLVolumeFace::pushVertex(const LLVector4a& pos, const LLVector4a& norm, const LLVector2& tc)
+{
+ S32 new_verts = mNumVertices+1;
+ S32 new_size = new_verts*16;
+// S32 old_size = mNumVertices*16;
+
+ //positions
+ mPositions = (LLVector4a*) realloc(mPositions, new_size);
+
+ //normals
+ mNormals = (LLVector4a*) realloc(mNormals, new_size);
+
+ //tex coords
+ new_size = ((new_verts*8)+0xF) & ~0xF;
+ mTexCoords = (LLVector2*) realloc(mTexCoords, new_size);
+
+
+ //just clear binormals
+ ll_aligned_free_16(mBinormals);
+ mBinormals = NULL;
+
+ mPositions[mNumVertices] = pos;
+ mNormals[mNumVertices] = norm;
+ mTexCoords[mNumVertices] = tc;
+
+ mNumVertices++;
+}
+
+void LLVolumeFace::allocateBinormals(S32 num_verts)
+{
+ ll_aligned_free_16(mBinormals);
+ mBinormals = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
+}
+
+void LLVolumeFace::allocateWeights(S32 num_verts)
+{
+ ll_aligned_free_16(mWeights);
+ mWeights = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
+}
+
+void LLVolumeFace::resizeIndices(S32 num_indices)
+{
+ ll_aligned_free_16(mIndices);
+
+ if (num_indices)
+ {
+ //pad index block end to allow for QWORD reads
+ S32 size = ((num_indices*sizeof(U16)) + 0xF) & ~0xF;
+
+ mIndices = (U16*) ll_aligned_malloc_16(size);
+ }
+ else
+ {
+ mIndices = NULL;
+ }
+
+ mNumIndices = num_indices;
+}
+
+void LLVolumeFace::pushIndex(const U16& idx)
+{
+ S32 new_count = mNumIndices + 1;
+ S32 new_size = ((new_count*2)+0xF) & ~0xF;
+
+ S32 old_size = ((mNumIndices*2)+0xF) & ~0xF;
+ if (new_size != old_size)
+ {
+ mIndices = (U16*) realloc(mIndices, new_size);
+ }
+
+ mIndices[mNumIndices++] = idx;
+}
+
+void LLVolumeFace::fillFromLegacyData(std::vector<LLVolumeFace::VertexData>& v, std::vector<U16>& idx)
+{
+ resizeVertices(v.size());
+ resizeIndices(idx.size());
+
+ for (U32 i = 0; i < v.size(); ++i)
+ {
+ mPositions[i] = v[i].getPosition();
+ mNormals[i] = v[i].getNormal();
+ mTexCoords[i] = v[i].mTexCoord;
+ }
+
+ for (U32 i = 0; i < idx.size(); ++i)
+ {
+ mIndices[i] = idx[i];
+ }
+}
+
+void LLVolumeFace::appendFace(const LLVolumeFace& face, LLMatrix4& mat_in, LLMatrix4& norm_mat_in)
+{
+ U16 offset = mNumVertices;
+
+ S32 new_count = face.mNumVertices + mNumVertices;
+
+ if (new_count > 65536)
+ {
+ llerrs << "Cannot append face -- 16-bit overflow will occur." << llendl;
+ }
+
+ if (face.mNumVertices == 0)
+ {
+ llerrs << "Cannot append empty face." << llendl;
+ }
+
+ //allocate new buffer space
+ mPositions = (LLVector4a*) realloc(mPositions, new_count*sizeof(LLVector4a));
+ assert_aligned(mPositions, 16);
+ mNormals = (LLVector4a*) realloc(mNormals, new_count*sizeof(LLVector4a));
+ assert_aligned(mNormals, 16);
+ mTexCoords = (LLVector2*) realloc(mTexCoords, (new_count*sizeof(LLVector2)+0xF) & ~0xF);
+ assert_aligned(mTexCoords, 16);
+
+ mNumVertices = new_count;
+
+ //get destination address of appended face
+ LLVector4a* dst_pos = mPositions+offset;
+ LLVector2* dst_tc = mTexCoords+offset;
+ LLVector4a* dst_norm = mNormals+offset;
+
+ //get source addresses of appended face
+ const LLVector4a* src_pos = face.mPositions;
+ const LLVector2* src_tc = face.mTexCoords;
+ const LLVector4a* src_norm = face.mNormals;
+
+ //load aligned matrices
+ LLMatrix4a mat, norm_mat;
+ mat.loadu(mat_in);
+ norm_mat.loadu(norm_mat_in);
+
+ for (U32 i = 0; i < face.mNumVertices; ++i)
+ {
+ //transform appended face position and store
+ mat.affineTransform(src_pos[i], dst_pos[i]);
+
+ //transform appended face normal and store
+ norm_mat.rotate(src_norm[i], dst_norm[i]);
+ dst_norm[i].normalize3fast();
+
+ //copy appended face texture coordinate
+ dst_tc[i] = src_tc[i];
+
+ if (offset == 0 && i == 0)
+ { //initialize bounding box
+ mExtents[0] = mExtents[1] = dst_pos[i];
+ }
+ else
{
- mVertices[i].mBinormal.normVec();
- mVertices[i].mNormal.normVec();
+ //stretch bounding box
+ update_min_max(mExtents[0], mExtents[1], dst_pos[i]);
}
+ }
+
- mHasBinormals = TRUE;
+ new_count = mNumIndices + face.mNumIndices;
+
+ //allocate new index buffer
+ mIndices = (U16*) realloc(mIndices, (new_count*sizeof(U16)+0xF) & ~0xF);
+
+ //get destination address into new index buffer
+ U16* dst_idx = mIndices+mNumIndices;
+ mNumIndices = new_count;
+
+ for (U32 i = 0; i < face.mNumIndices; ++i)
+ { //copy indices, offsetting by old vertex count
+ dst_idx[i] = face.mIndices[i]+offset;
}
}
@@ -5117,18 +6861,20 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
num_vertices = mNumS*mNumT;
num_indices = (mNumS-1)*(mNumT-1)*6;
- mVertices.resize(num_vertices);
-
if (!partial_build)
{
- mIndices.resize(num_indices);
- mEdge.resize(num_indices);
- }
- else
- {
- mHasBinormals = FALSE;
+ resizeVertices(num_vertices);
+ resizeIndices(num_indices);
+
+ if ((volume->getParams().getSculptType() & LL_SCULPT_TYPE_MASK) != LL_SCULPT_TYPE_MESH)
+ {
+ mEdge.resize(num_indices);
+ }
}
+ LLVector4a* pos = (LLVector4a*) mPositions;
+ LLVector4a* norm = (LLVector4a*) mNormals;
+ LLVector2* tc = (LLVector2*) mTexCoords;
S32 begin_stex = llfloor( profile[mBeginS].mV[2] );
S32 num_s = ((mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2) ? mNumS/2 : mNumS;
@@ -5179,21 +6925,20 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
i = mBeginS + s + max_s*t;
}
- mVertices[cur_vertex].mPosition = mesh[i].mPos;
- mVertices[cur_vertex].mTexCoord = LLVector2(ss,tt);
+ pos[cur_vertex].load3(mesh[i].mPos.mV);
+ tc[cur_vertex] = LLVector2(ss,tt);
- mVertices[cur_vertex].mNormal = LLVector3(0,0,0);
- mVertices[cur_vertex].mBinormal = LLVector3(0,0,0);
-
+ norm[cur_vertex].clear();
cur_vertex++;
if ((mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2 && s > 0)
{
- mVertices[cur_vertex].mPosition = mesh[i].mPos;
- mVertices[cur_vertex].mTexCoord = LLVector2(ss,tt);
+
+ pos[cur_vertex].load3(mesh[i].mPos.mV);
+ tc[cur_vertex] = LLVector2(ss,tt);
- mVertices[cur_vertex].mNormal = LLVector3(0,0,0);
- mVertices[cur_vertex].mBinormal = LLVector3(0,0,0);
+ norm[cur_vertex].clear();
+
cur_vertex++;
}
}
@@ -5211,29 +6956,29 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
i = mBeginS + s + max_s*t;
ss = profile[mBeginS + s].mV[2] - begin_stex;
- mVertices[cur_vertex].mPosition = mesh[i].mPos;
- mVertices[cur_vertex].mTexCoord = LLVector2(ss,tt);
-
- mVertices[cur_vertex].mNormal = LLVector3(0,0,0);
- mVertices[cur_vertex].mBinormal = LLVector3(0,0,0);
-
+ pos[cur_vertex].load3(mesh[i].mPos.mV);
+ tc[cur_vertex] = LLVector2(ss,tt);
+ norm[cur_vertex].clear();
+
cur_vertex++;
}
}
//get bounding box for this side
- LLVector3& face_min = mExtents[0];
- LLVector3& face_max = mExtents[1];
- mCenter.clearVec();
+ LLVector4a& face_min = mExtents[0];
+ LLVector4a& face_max = mExtents[1];
+ mCenter->clear();
- face_min = face_max = mVertices[0].mPosition;
- for (U32 i = 1; i < mVertices.size(); ++i)
+ face_min = face_max = pos[0];
+
+ for (U32 i = 1; i < mNumVertices; ++i)
{
- update_min_max(face_min, face_max, mVertices[i].mPosition);
+ update_min_max(face_min, face_max, pos[i]);
}
- mCenter = (face_min + face_max) * 0.5f;
+ mCenter->setAdd(face_min, face_max);
+ mCenter->mul(0.5f);
S32 cur_index = 0;
S32 cur_edge = 0;
@@ -5241,18 +6986,9 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
if (!partial_build)
{
-#if GEN_TRI_STRIP
- mTriStrip.clear();
-#endif
-
// Now we generate the indices.
for (t = 0; t < (mNumT-1); t++)
{
-#if GEN_TRI_STRIP
- //prepend terminating index to strip
- mTriStrip.push_back(mNumS*t);
-#endif
-
for (s = 0; s < (mNumS-1); s++)
{
mIndices[cur_index++] = s + mNumS*t; //bottom left
@@ -5262,16 +6998,6 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
mIndices[cur_index++] = s+1 + mNumS*t; //bottom right
mIndices[cur_index++] = s+1 + mNumS*(t+1); //top right
-#if GEN_TRI_STRIP
- if (s == 0)
- {
- mTriStrip.push_back(s+mNumS*t);
- mTriStrip.push_back(s+mNumS*(t+1));
- }
- mTriStrip.push_back(s+1+mNumS*t);
- mTriStrip.push_back(s+1+mNumS*(t+1));
-#endif
-
mEdge[cur_edge++] = (mNumS-1)*2*t+s*2+1; //bottom left/top right neighbor face
if (t < mNumT-2) { //top right/top left neighbor face
mEdge[cur_edge++] = (mNumS-1)*2*(t+1)+s*2+1;
@@ -5312,52 +7038,61 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
}
mEdge[cur_edge++] = (mNumS-1)*2*t+s*2; //top right/bottom left neighbor face
}
-#if GEN_TRI_STRIP
- //append terminating vertex to strip
- mTriStrip.push_back(mNumS-1+mNumS*(t+1));
-#endif
}
+ }
-#if GEN_TRI_STRIP
- if (mTriStrip.size()%2 == 1)
- {
- mTriStrip.push_back(mTriStrip[mTriStrip.size()-1]);
- }
-#endif
+ //clear normals
+ for (U32 i = 0; i < mNumVertices; i++)
+ {
+ mNormals[i].clear();
}
//generate normals
- for (U32 i = 0; i < mIndices.size()/3; i++) //for each triangle
+ for (U32 i = 0; i < mNumIndices/3; i++) //for each triangle
{
const U16* idx = &(mIndices[i*3]);
-
- VertexData* v[] =
- { &mVertices[idx[0]], &mVertices[idx[1]], &mVertices[idx[2]] };
-
- //calculate triangle normal
- LLVector3 norm = (v[0]->mPosition-v[1]->mPosition) % (v[0]->mPosition-v[2]->mPosition);
+
- v[0]->mNormal += norm;
- v[1]->mNormal += norm;
- v[2]->mNormal += norm;
+ LLVector4a* v[] =
+ { pos+idx[0], pos+idx[1], pos+idx[2] };
+
+ LLVector4a* n[] =
+ { norm+idx[0], norm+idx[1], norm+idx[2] };
+
+ //calculate triangle normal
+ LLVector4a a, b, c;
+
+ a.setSub(*v[0], *v[1]);
+ b.setSub(*v[0], *v[2]);
+ c.setCross3(a,b);
+ n[0]->add(c);
+ n[1]->add(c);
+ n[2]->add(c);
+
//even out quad contributions
- v[i%2+1]->mNormal += norm;
+ n[i%2+1]->add(c);
}
// adjust normals based on wrapping and stitching
- BOOL s_bottom_converges = ((mVertices[0].mPosition - mVertices[mNumS*(mNumT-2)].mPosition).magVecSquared() < 0.000001f);
- BOOL s_top_converges = ((mVertices[mNumS-1].mPosition - mVertices[mNumS*(mNumT-2)+mNumS-1].mPosition).magVecSquared() < 0.000001f);
+ LLVector4a top;
+ top.setSub(pos[0], pos[mNumS*(mNumT-2)]);
+ BOOL s_bottom_converges = (top.dot3(top) < 0.000001f);
+
+ top.setSub(pos[mNumS-1], pos[mNumS*(mNumT-2)+mNumS-1]);
+ BOOL s_top_converges = (top.dot3(top) < 0.000001f);
+
if (sculpt_stitching == LL_SCULPT_TYPE_NONE) // logic for non-sculpt volumes
{
if (volume->getPath().isOpen() == FALSE)
{ //wrap normals on T
for (S32 i = 0; i < mNumS; i++)
{
- LLVector3 norm = mVertices[i].mNormal + mVertices[mNumS*(mNumT-1)+i].mNormal;
- mVertices[i].mNormal = norm;
- mVertices[mNumS*(mNumT-1)+i].mNormal = norm;
+ LLVector4a n;
+ n.setAdd(norm[i], norm[mNumS*(mNumT-1)+i]);
+ norm[i] = n;
+ norm[mNumS*(mNumT-1)+i] = n;
}
}
@@ -5365,9 +7100,10 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
{ //wrap normals on S
for (S32 i = 0; i < mNumT; i++)
{
- LLVector3 norm = mVertices[mNumS*i].mNormal + mVertices[mNumS*i+mNumS-1].mNormal;
- mVertices[mNumS * i].mNormal = norm;
- mVertices[mNumS * i+mNumS-1].mNormal = norm;
+ LLVector4a n;
+ n.setAdd(norm[mNumS*i], norm[mNumS*i+mNumS-1]);
+ norm[mNumS * i] = n;
+ norm[mNumS * i+mNumS-1] = n;
}
}
@@ -5378,7 +7114,7 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
{ //all lower S have same normal
for (S32 i = 0; i < mNumT; i++)
{
- mVertices[mNumS*i].mNormal = LLVector3(1,0,0);
+ norm[mNumS*i].set(1,0,0);
}
}
@@ -5386,12 +7122,11 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
{ //all upper S have same normal
for (S32 i = 0; i < mNumT; i++)
{
- mVertices[mNumS*i+mNumS-1].mNormal = LLVector3(-1,0,0);
+ norm[mNumS*i+mNumS-1].set(-1,0,0);
}
}
}
}
-
else // logic for sculpt volumes
{
BOOL average_poles = FALSE;
@@ -5414,30 +7149,33 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
{
// average normals for north pole
- LLVector3 average(0.0, 0.0, 0.0);
+ LLVector4a average;
+ average.clear();
+
for (S32 i = 0; i < mNumS; i++)
{
- average += mVertices[i].mNormal;
+ average.add(norm[i]);
}
// set average
for (S32 i = 0; i < mNumS; i++)
{
- mVertices[i].mNormal = average;
+ norm[i] = average;
}
// average normals for south pole
- average = LLVector3(0.0, 0.0, 0.0);
+ average.clear();
+
for (S32 i = 0; i < mNumS; i++)
{
- average += mVertices[i + mNumS * (mNumT - 1)].mNormal;
+ average.add(norm[i + mNumS * (mNumT - 1)]);
}
// set average
for (S32 i = 0; i < mNumS; i++)
{
- mVertices[i + mNumS * (mNumT - 1)].mNormal = average;
+ norm[i + mNumS * (mNumT - 1)] = average;
}
}
@@ -5447,23 +7185,22 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
{
for (S32 i = 0; i < mNumT; i++)
{
- LLVector3 norm = mVertices[mNumS*i].mNormal + mVertices[mNumS*i+mNumS-1].mNormal;
- mVertices[mNumS * i].mNormal = norm;
- mVertices[mNumS * i+mNumS-1].mNormal = norm;
+ LLVector4a n;
+ n.setAdd(norm[mNumS*i], norm[mNumS*i+mNumS-1]);
+ norm[mNumS * i] = n;
+ norm[mNumS * i+mNumS-1] = n;
}
}
-
-
if (wrap_t)
{
for (S32 i = 0; i < mNumS; i++)
{
- LLVector3 norm = mVertices[i].mNormal + mVertices[mNumS*(mNumT-1)+i].mNormal;
- mVertices[i].mNormal = norm;
- mVertices[mNumS*(mNumT-1)+i].mNormal = norm;
+ LLVector4a n;
+ n.setAdd(norm[i], norm[mNumS*(mNumT-1)+i]);
+ norm[i] = n;
+ norm[mNumS*(mNumT-1)+i] = n;
}
-
}
}
@@ -5473,41 +7210,51 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
// Finds binormal based on three vertices with texture coordinates.
// Fills in dummy values if the triangle has degenerate texture coordinates.
-LLVector3 calc_binormal_from_triangle(
- const LLVector3& pos0,
+void calc_binormal_from_triangle(LLVector4a& binormal,
+
+ const LLVector4a& pos0,
const LLVector2& tex0,
- const LLVector3& pos1,
+ const LLVector4a& pos1,
const LLVector2& tex1,
- const LLVector3& pos2,
+ const LLVector4a& pos2,
const LLVector2& tex2)
{
- LLVector3 rx0( pos0.mV[VX], tex0.mV[VX], tex0.mV[VY] );
- LLVector3 rx1( pos1.mV[VX], tex1.mV[VX], tex1.mV[VY] );
- LLVector3 rx2( pos2.mV[VX], tex2.mV[VX], tex2.mV[VY] );
+ LLVector4a rx0( pos0[VX], tex0.mV[VX], tex0.mV[VY] );
+ LLVector4a rx1( pos1[VX], tex1.mV[VX], tex1.mV[VY] );
+ LLVector4a rx2( pos2[VX], tex2.mV[VX], tex2.mV[VY] );
- LLVector3 ry0( pos0.mV[VY], tex0.mV[VX], tex0.mV[VY] );
- LLVector3 ry1( pos1.mV[VY], tex1.mV[VX], tex1.mV[VY] );
- LLVector3 ry2( pos2.mV[VY], tex2.mV[VX], tex2.mV[VY] );
+ LLVector4a ry0( pos0[VY], tex0.mV[VX], tex0.mV[VY] );
+ LLVector4a ry1( pos1[VY], tex1.mV[VX], tex1.mV[VY] );
+ LLVector4a ry2( pos2[VY], tex2.mV[VX], tex2.mV[VY] );
- LLVector3 rz0( pos0.mV[VZ], tex0.mV[VX], tex0.mV[VY] );
- LLVector3 rz1( pos1.mV[VZ], tex1.mV[VX], tex1.mV[VY] );
- LLVector3 rz2( pos2.mV[VZ], tex2.mV[VX], tex2.mV[VY] );
+ LLVector4a rz0( pos0[VZ], tex0.mV[VX], tex0.mV[VY] );
+ LLVector4a rz1( pos1[VZ], tex1.mV[VX], tex1.mV[VY] );
+ LLVector4a rz2( pos2[VZ], tex2.mV[VX], tex2.mV[VY] );
- LLVector3 r0 = (rx0 - rx1) % (rx0 - rx2);
- LLVector3 r1 = (ry0 - ry1) % (ry0 - ry2);
- LLVector3 r2 = (rz0 - rz1) % (rz0 - rz2);
+ LLVector4a lhs, rhs;
+
+ LLVector4a r0;
+ lhs.setSub(rx0, rx1); rhs.setSub(rx0, rx2);
+ r0.setCross3(lhs, rhs);
+
+ LLVector4a r1;
+ lhs.setSub(ry0, ry1); rhs.setSub(ry0, ry2);
+ r1.setCross3(lhs, rhs);
+
+ LLVector4a r2;
+ lhs.setSub(rz0, rz1); rhs.setSub(rz0, rz2);
+ r2.setCross3(lhs, rhs);
- if( r0.mV[VX] && r1.mV[VX] && r2.mV[VX] )
+ if( r0[VX] && r1[VX] && r2[VX] )
{
- LLVector3 binormal(
- -r0.mV[VZ] / r0.mV[VX],
- -r1.mV[VZ] / r1.mV[VX],
- -r2.mV[VZ] / r2.mV[VX]);
+ binormal.set(
+ -r0[VZ] / r0[VX],
+ -r1[VZ] / r1[VX],
+ -r2[VZ] / r2[VX]);
// binormal.normVec();
- return binormal;
}
else
{
- return LLVector3( 0, 1 , 0 );
+ binormal.set( 0, 1 , 0 );
}
}
diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h
index d48a79ee46..01bfbd858b 100644
--- a/indra/llmath/llvolume.h
+++ b/indra/llmath/llvolume.h
@@ -34,8 +34,13 @@ class LLPathParams;
class LLVolumeParams;
class LLProfile;
class LLPath;
+
+template <class T> class LLOctreeNode;
+
+class LLVector4a;
class LLVolumeFace;
class LLVolume;
+class LLVolumeTriangle;
#include "lldarray.h"
#include "lluuid.h"
@@ -43,6 +48,8 @@ class LLVolume;
//#include "vmath.h"
#include "v2math.h"
#include "v3math.h"
+#include "v3dmath.h"
+#include "v4math.h"
#include "llquaternion.h"
#include "llstrider.h"
#include "v4coloru.h"
@@ -177,12 +184,14 @@ const U8 LL_SCULPT_TYPE_SPHERE = 1;
const U8 LL_SCULPT_TYPE_TORUS = 2;
const U8 LL_SCULPT_TYPE_PLANE = 3;
const U8 LL_SCULPT_TYPE_CYLINDER = 4;
-
-const U8 LL_SCULPT_TYPE_MASK = LL_SCULPT_TYPE_SPHERE | LL_SCULPT_TYPE_TORUS | LL_SCULPT_TYPE_PLANE | LL_SCULPT_TYPE_CYLINDER;
+const U8 LL_SCULPT_TYPE_MESH = 5;
+const U8 LL_SCULPT_TYPE_MASK = LL_SCULPT_TYPE_SPHERE | LL_SCULPT_TYPE_TORUS | LL_SCULPT_TYPE_PLANE |
+ LL_SCULPT_TYPE_CYLINDER | LL_SCULPT_TYPE_MESH;
const U8 LL_SCULPT_FLAG_INVERT = 64;
const U8 LL_SCULPT_FLAG_MIRROR = 128;
+const S32 LL_SCULPT_MESH_MAX_FACES = 8;
class LLProfileParams
{
@@ -569,6 +578,9 @@ public:
BOOL importLegacyStream(std::istream& input_stream);
BOOL exportLegacyStream(std::ostream& output_stream) const;
+ LLSD sculptAsLLSD() const;
+ bool sculptFromLLSD(LLSD& sd);
+
LLSD asLLSD() const;
operator LLSD() const { return asLLSD(); }
bool fromLLSD(LLSD& sd);
@@ -628,7 +640,8 @@ public:
const F32& getSkew() const { return mPathParams.getSkew(); }
const LLUUID& getSculptID() const { return mSculptID; }
const U8& getSculptType() const { return mSculptType; }
-
+ bool isSculpt() const;
+ bool isMeshSculpt() const;
BOOL isConvex() const;
// 'begin' and 'end' should be in range [0, 1] (they will be clamped)
@@ -779,30 +792,88 @@ public:
class LLVolumeFace
{
public:
- LLVolumeFace() :
- mID(0),
- mTypeMask(0),
- mHasBinormals(FALSE),
- mBeginS(0),
- mBeginT(0),
- mNumS(0),
- mNumT(0)
+ class VertexData
{
- }
+ enum
+ {
+ POSITION = 0,
+ NORMAL = 1
+ };
+
+ private:
+ void init();
+ public:
+ VertexData();
+ VertexData(const VertexData& rhs);
+ const VertexData& operator=(const VertexData& rhs);
+
+ ~VertexData();
+ LLVector4a& getPosition();
+ LLVector4a& getNormal();
+ const LLVector4a& getPosition() const;
+ const LLVector4a& getNormal() const;
+ void setPosition(const LLVector4a& pos);
+ void setNormal(const LLVector4a& norm);
+
+
+ LLVector2 mTexCoord;
+
+ bool operator<(const VertexData& rhs) const;
+ bool operator==(const VertexData& rhs) const;
+ bool compareNormal(const VertexData& rhs, F32 angle_cutoff) const;
+
+ private:
+ LLVector4a* mData;
+ };
+
+ LLVolumeFace();
+ LLVolumeFace(const LLVolumeFace& src);
+ LLVolumeFace& operator=(const LLVolumeFace& rhs);
+
+ ~LLVolumeFace();
+private:
+ void freeData();
+public:
BOOL create(LLVolume* volume, BOOL partial_build = FALSE);
void createBinormals();
- void makeTriStrip();
- class VertexData
+ void appendFace(const LLVolumeFace& face, LLMatrix4& transform, LLMatrix4& normal_tranform);
+
+ void resizeVertices(S32 num_verts);
+ void allocateBinormals(S32 num_verts);
+ void allocateWeights(S32 num_verts);
+ void resizeIndices(S32 num_indices);
+ void fillFromLegacyData(std::vector<LLVolumeFace::VertexData>& v, std::vector<U16>& idx);
+
+ void pushVertex(const VertexData& cv);
+ void pushVertex(const LLVector4a& pos, const LLVector4a& norm, const LLVector2& tc);
+ void pushIndex(const U16& idx);
+
+ void swapData(LLVolumeFace& rhs);
+
+ void getVertexData(U16 indx, LLVolumeFace::VertexData& cv);
+
+ class VertexMapData : public LLVolumeFace::VertexData
{
public:
- LLVector3 mPosition;
- LLVector3 mNormal;
- LLVector3 mBinormal;
- LLVector2 mTexCoord;
+ U16 mIndex;
+
+ bool operator==(const LLVolumeFace::VertexData& rhs) const;
+
+ struct ComparePosition
+ {
+ bool operator()(const LLVector3& a, const LLVector3& b) const;
+ };
+
+ typedef std::map<LLVector3, std::vector<VertexMapData>, VertexMapData::ComparePosition > PointMap;
};
+ void optimize(F32 angle_cutoff = 2.f);
+ void cacheOptimize();
+
+ void createOctree(F32 scaler = 0.25f, const LLVector4a& center = LLVector4a(0,0,0), const LLVector4a& size = LLVector4a(0.5f,0.5f,0.5f));
+
enum
{
SINGLE_MASK = 0x0001,
@@ -821,22 +892,35 @@ public:
public:
S32 mID;
U32 mTypeMask;
- LLVector3 mCenter;
- BOOL mHasBinormals;
-
+
// Only used for INNER/OUTER faces
S32 mBeginS;
S32 mBeginT;
S32 mNumS;
S32 mNumT;
- LLVector3 mExtents[2]; //minimum and maximum point of face
+ LLVector4a* mExtents; //minimum and maximum point of face
+ LLVector4a* mCenter;
+ LLVector2 mTexCoordExtents[2]; //minimum and maximum of texture coordinates of the face.
+
+ S32 mNumVertices;
+ S32 mNumIndices;
+
+ LLVector4a* mPositions;
+ LLVector4a* mNormals;
+ LLVector4a* mBinormals;
+ LLVector2* mTexCoords;
+ U16* mIndices;
- std::vector<VertexData> mVertices;
- std::vector<U16> mIndices;
- std::vector<U16> mTriStrip;
std::vector<S32> mEdge;
+ //list of skin weights for rigged volumes
+ // format is mWeights[vertex_index].mV[influence] = <joint_index>.<weight>
+ // mWeights.size() should be empty or match mVertices.size()
+ LLVector4a* mWeights;
+
+ LLOctreeNode<LLVolumeTriangle>* mOctree;
+
private:
BOOL createUnCutCubeCap(LLVolume* volume, BOOL partial_build = FALSE);
BOOL createCap(LLVolume* volume, BOOL partial_build = FALSE);
@@ -847,8 +931,7 @@ class LLVolume : public LLRefCount
{
friend class LLVolumeLODGroup;
-private:
- LLVolume(const LLVolume&); // Don't implement
+protected:
~LLVolume(); // use unref
public:
@@ -870,7 +953,7 @@ public:
U8 getProfileType() const { return mParams.getProfileParams().getCurveType(); }
U8 getPathType() const { return mParams.getPathParams().getCurveType(); }
- S32 getNumFaces() const { return (S32)mProfilep->mFaces.size(); }
+ S32 getNumFaces() const;
S32 getNumVolumeFaces() const { return mVolumeFaces.size(); }
F32 getDetail() const { return mDetail; }
const LLVolumeParams& getParams() const { return mParams; }
@@ -892,15 +975,17 @@ public:
BOOL isUnique() const { return mUnique; }
S32 getSculptLevel() const { return mSculptLevel; }
-
+ void setSculptLevel(S32 level) { mSculptLevel = level; }
+
S32 *getTriangleIndices(U32 &num_indices) const;
// returns number of triangle indeces required for path/profile mesh
S32 getNumTriangleIndices() const;
+ S32 getNumTriangles() const;
+
void generateSilhouetteVertices(std::vector<LLVector3> &vertices,
std::vector<LLVector3> &normals,
- std::vector<S32> &segments,
const LLVector3& view_vec,
const LLMatrix4& mat,
const LLMatrix3& norm_mat,
@@ -916,6 +1001,13 @@ public:
LLVector3* normal = NULL, // return the surface normal at the intersection point
LLVector3* bi_normal = NULL // return the surface bi-normal at the intersection point
);
+
+ S32 lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end,
+ S32 face = 1,
+ LLVector3* intersection = NULL,
+ LLVector2* tex_coord = NULL,
+ LLVector3* normal = NULL,
+ LLVector3* bi_normal = NULL);
// The following cleans up vertices and triangles,
// getting rid of degenerate triangles and duplicate vertices,
@@ -937,11 +1029,14 @@ public:
friend std::ostream& operator<<(std::ostream &s, const LLVolume *volumep); // HACK to bypass Windoze confusion over
// conversion if *(LLVolume*) to LLVolume&
const LLVolumeFace &getVolumeFace(const S32 f) const {return mVolumeFaces[f];} // DO NOT DELETE VOLUME WHILE USING THIS REFERENCE, OR HOLD A POINTER TO THIS VOLUMEFACE
-
+
U32 mFaceMask; // bit array of which faces exist in this volume
LLVector3 mLODScaleBias; // vector for biasing LOD based on scale
void sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, S32 sculpt_level);
+ void copyVolumeFaces(const LLVolume* volume);
+ void cacheOptimize();
+
private:
void sculptGenerateMapVertices(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, U8 sculpt_type);
F32 sculptGetSurfaceArea();
@@ -952,35 +1047,56 @@ private:
protected:
BOOL generate();
void createVolumeFaces();
+public:
+ virtual bool unpackVolumeFaces(std::istream& is, S32 size);
+
+ virtual void makeTetrahedron();
+ virtual BOOL isTetrahedron();
protected:
BOOL mUnique;
F32 mDetail;
S32 mSculptLevel;
+ BOOL mIsTetrahedron;
LLVolumeParams mParams;
LLPath *mPathp;
LLProfile *mProfilep;
std::vector<Point> mMesh;
-
+
BOOL mGenerateSingleFace;
typedef std::vector<LLVolumeFace> face_list_t;
face_list_t mVolumeFaces;
+
+public:
+ LLVector4a* mHullPoints;
+ U16* mHullIndices;
+ S32 mNumHullPoints;
+ S32 mNumHullIndices;
};
std::ostream& operator<<(std::ostream &s, const LLVolumeParams &volume_params);
-LLVector3 calc_binormal_from_triangle(
- const LLVector3& pos0,
+void calc_binormal_from_triangle(
+ LLVector4a& binormal,
+ const LLVector4a& pos0,
const LLVector2& tex0,
- const LLVector3& pos1,
+ const LLVector4a& pos1,
const LLVector2& tex1,
- const LLVector3& pos2,
+ const LLVector4a& pos2,
const LLVector2& tex2);
+BOOL LLLineSegmentBoxIntersect(const F32* start, const F32* end, const F32* center, const F32* size);
BOOL LLLineSegmentBoxIntersect(const LLVector3& start, const LLVector3& end, const LLVector3& center, const LLVector3& size);
+BOOL LLLineSegmentBoxIntersect(const LLVector4a& start, const LLVector4a& end, const LLVector4a& center, const LLVector4a& size);
+
BOOL LLTriangleRayIntersect(const LLVector3& vert0, const LLVector3& vert1, const LLVector3& vert2, const LLVector3& orig, const LLVector3& dir,
- F32* intersection_a, F32* intersection_b, F32* intersection_t, BOOL two_sided);
+ F32& intersection_a, F32& intersection_b, F32& intersection_t, BOOL two_sided);
+
+BOOL LLTriangleRayIntersect(const LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir,
+ F32& intersection_a, F32& intersection_b, F32& intersection_t);
+BOOL LLTriangleRayIntersectTwoSided(const LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir,
+ F32& intersection_a, F32& intersection_b, F32& intersection_t);
diff --git a/indra/llmath/llvolumemgr.cpp b/indra/llmath/llvolumemgr.cpp
index 88c195936c..c60b750088 100644
--- a/indra/llmath/llvolumemgr.cpp
+++ b/indra/llmath/llvolumemgr.cpp
@@ -314,7 +314,7 @@ BOOL LLVolumeLODGroup::derefLOD(LLVolume *volumep)
{
llassert_always(mLODRefs[i] > 0);
mLODRefs[i]--;
-#if 1 // SJB: Possible opt: keep other lods around
+#if 0 // SJB: Possible opt: keep other lods around
if (!mLODRefs[i])
{
mVolumeLODs[i] = NULL;
@@ -369,6 +369,19 @@ F32 LLVolumeLODGroup::getVolumeScaleFromDetail(const S32 detail)
return mDetailScales[detail];
}
+S32 LLVolumeLODGroup::getVolumeDetailFromScale(const F32 detail)
+{
+ for (S32 i = 1; i < 4; i++)
+ {
+ if (mDetailScales[i] > detail)
+ {
+ return i-1;
+ }
+ }
+
+ return 3;
+}
+
F32 LLVolumeLODGroup::dump()
{
F32 usage = 0.f;
diff --git a/indra/llmath/llvolumemgr.h b/indra/llmath/llvolumemgr.h
index 5257da2693..c75906f675 100644
--- a/indra/llmath/llvolumemgr.h
+++ b/indra/llmath/llvolumemgr.h
@@ -53,6 +53,7 @@ public:
static S32 getDetailFromTan(const F32 tan_angle);
static void getDetailProximity(const F32 tan_angle, F32 &to_lower, F32& to_higher);
static F32 getVolumeScaleFromDetail(const S32 detail);
+ static S32 getVolumeDetailFromScale(F32 scale);
LLVolume* refLOD(const S32 detail);
BOOL derefLOD(LLVolume *volumep);
diff --git a/indra/llmath/llvolumeoctree.cpp b/indra/llmath/llvolumeoctree.cpp
new file mode 100644
index 0000000000..b5a935c2b5
--- /dev/null
+++ b/indra/llmath/llvolumeoctree.cpp
@@ -0,0 +1,256 @@
+/**
+
+ * @file llvolumeoctree.cpp
+ *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llvolumeoctree.h"
+#include "llvector4a.h"
+
+BOOL LLLineSegmentBoxIntersect(const LLVector4a& start, const LLVector4a& end, const LLVector4a& center, const LLVector4a& size)
+{
+ LLVector4a fAWdU;
+ LLVector4a dir;
+ LLVector4a diff;
+
+ dir.setSub(end, start);
+ dir.mul(0.5f);
+
+ diff.setAdd(end,start);
+ diff.mul(0.5f);
+ diff.sub(center);
+ fAWdU.setAbs(dir);
+
+ LLVector4a rhs;
+ rhs.setAdd(size, fAWdU);
+
+ LLVector4a lhs;
+ lhs.setAbs(diff);
+
+ U32 grt = lhs.greaterThan(rhs).getGatheredBits();
+
+ if (grt & 0x7)
+ {
+ return false;
+ }
+
+ LLVector4a f;
+ f.setCross3(dir, diff);
+ f.setAbs(f);
+
+ LLVector4a v0, v1;
+
+ v0 = _mm_shuffle_ps(size, size,_MM_SHUFFLE(3,0,0,1));
+ v1 = _mm_shuffle_ps(fAWdU, fAWdU, _MM_SHUFFLE(3,1,2,2));
+ lhs.setMul(v0, v1);
+
+ v0 = _mm_shuffle_ps(size, size, _MM_SHUFFLE(3,1,2,2));
+ v1 = _mm_shuffle_ps(fAWdU, fAWdU, _MM_SHUFFLE(3,0,0,1));
+ rhs.setMul(v0, v1);
+ rhs.add(lhs);
+
+ grt = f.greaterThan(rhs).getGatheredBits();
+
+ return (grt & 0x7) ? false : true;
+}
+
+
+LLVolumeOctreeListener::LLVolumeOctreeListener(LLOctreeNode<LLVolumeTriangle>* node)
+{
+ node->addListener(this);
+}
+
+LLVolumeOctreeListener::~LLVolumeOctreeListener()
+{
+
+}
+
+void LLVolumeOctreeListener::handleChildAddition(const LLOctreeNode<LLVolumeTriangle>* parent,
+ LLOctreeNode<LLVolumeTriangle>* child)
+{
+ new LLVolumeOctreeListener(child);
+}
+
+
+LLOctreeTriangleRayIntersect::LLOctreeTriangleRayIntersect(const LLVector4a& start, const LLVector4a& dir,
+ const LLVolumeFace* face, F32* closest_t,
+ LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal)
+ : mFace(face),
+ mStart(start),
+ mDir(dir),
+ mIntersection(intersection),
+ mTexCoord(tex_coord),
+ mNormal(normal),
+ mBinormal(bi_normal),
+ mClosestT(closest_t),
+ mHitFace(false)
+{
+ mEnd.setAdd(mStart, mDir);
+}
+
+void LLOctreeTriangleRayIntersect::traverse(const LLOctreeNode<LLVolumeTriangle>* node)
+{
+ LLVolumeOctreeListener* vl = (LLVolumeOctreeListener*) node->getListener(0);
+
+ /*const F32* start = mStart.getF32();
+ const F32* end = mEnd.getF32();
+ const F32* center = vl->mBounds[0].getF32();
+ const F32* size = vl->mBounds[1].getF32();*/
+
+ //if (LLLineSegmentBoxIntersect(mStart, mEnd, vl->mBounds[0], vl->mBounds[1]))
+ if (LLLineSegmentBoxIntersect(mStart.getF32ptr(), mEnd.getF32ptr(), vl->mBounds[0].getF32ptr(), vl->mBounds[1].getF32ptr()))
+ {
+ node->accept(this);
+ for (S32 i = 0; i < node->getChildCount(); ++i)
+ {
+ traverse(node->getChild(i));
+ }
+ }
+}
+
+void LLOctreeTriangleRayIntersect::visit(const LLOctreeNode<LLVolumeTriangle>* node)
+{
+ for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter =
+ node->getData().begin(); iter != node->getData().end(); ++iter)
+ {
+ const LLVolumeTriangle* tri = *iter;
+
+ F32 a, b, t;
+
+ if (LLTriangleRayIntersect(*tri->mV[0], *tri->mV[1], *tri->mV[2],
+ mStart, mDir, a, b, t))
+ {
+ if ((t >= 0.f) && // if hit is after start
+ (t <= 1.f) && // and before end
+ (t < *mClosestT)) // and this hit is closer
+ {
+ *mClosestT = t;
+ mHitFace = true;
+
+ if (mIntersection != NULL)
+ {
+ LLVector4a intersect = mDir;
+ intersect.mul(*mClosestT);
+ intersect.add(mStart);
+ mIntersection->set(intersect.getF32ptr());
+ }
+
+
+ if (mTexCoord != NULL)
+ {
+ LLVector2* tc = (LLVector2*) mFace->mTexCoords;
+ *mTexCoord = ((1.f - a - b) * tc[tri->mIndex[0]] +
+ a * tc[tri->mIndex[1]] +
+ b * tc[tri->mIndex[2]]);
+
+ }
+
+ if (mNormal != NULL)
+ {
+ LLVector4* norm = (LLVector4*) mFace->mNormals;
+
+ *mNormal = ((1.f - a - b) * LLVector3(norm[tri->mIndex[0]]) +
+ a * LLVector3(norm[tri->mIndex[1]]) +
+ b * LLVector3(norm[tri->mIndex[2]]));
+ }
+
+ if (mBinormal != NULL)
+ {
+ LLVector4* binormal = (LLVector4*) mFace->mBinormals;
+ *mBinormal = ((1.f - a - b) * LLVector3(binormal[tri->mIndex[0]]) +
+ a * LLVector3(binormal[tri->mIndex[1]]) +
+ b * LLVector3(binormal[tri->mIndex[2]]));
+ }
+ }
+ }
+ }
+}
+
+const LLVector4a& LLVolumeTriangle::getPositionGroup() const
+{
+ return mPositionGroup;
+}
+
+const F32& LLVolumeTriangle::getBinRadius() const
+{
+ return mRadius;
+}
+
+
+//TEST CODE
+
+void LLVolumeOctreeValidate::visit(const LLOctreeNode<LLVolumeTriangle>* branch)
+{
+ LLVolumeOctreeListener* node = (LLVolumeOctreeListener*) branch->getListener(0);
+
+ //make sure bounds matches extents
+ LLVector4a& min = node->mExtents[0];
+ LLVector4a& max = node->mExtents[1];
+
+ LLVector4a& center = node->mBounds[0];
+ LLVector4a& size = node->mBounds[1];
+
+ LLVector4a test_min, test_max;
+ test_min.setSub(center, size);
+ test_max.setAdd(center, size);
+
+ if (!test_min.equals3(min, 0.001f) ||
+ !test_max.equals3(max, 0.001f))
+ {
+ llerrs << "Bad bounding box data found." << llendl;
+ }
+
+ test_min.sub(LLVector4a(0.001f));
+ test_max.add(LLVector4a(0.001f));
+
+ for (U32 i = 0; i < branch->getChildCount(); ++i)
+ {
+ LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(i)->getListener(0);
+
+ //make sure all children fit inside this node
+ if (child->mExtents[0].lessThan(test_min).areAnySet(LLVector4Logical::MASK_XYZ) ||
+ child->mExtents[1].greaterThan(test_max).areAnySet(LLVector4Logical::MASK_XYZ))
+ {
+ llerrs << "Child protrudes from bounding box." << llendl;
+ }
+ }
+
+ //children fit, check data
+ for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter = branch->getData().begin();
+ iter != branch->getData().end(); ++iter)
+ {
+ const LLVolumeTriangle* tri = *iter;
+
+ //validate triangle
+ for (U32 i = 0; i < 3; i++)
+ {
+ if (tri->mV[i]->greaterThan(test_max).areAnySet(LLVector4Logical::MASK_XYZ) ||
+ tri->mV[i]->lessThan(test_min).areAnySet(LLVector4Logical::MASK_XYZ))
+ {
+ llerrs << "Triangle protrudes from node." << llendl;
+ }
+ }
+ }
+}
+
+
diff --git a/indra/llmath/llvolumeoctree.h b/indra/llmath/llvolumeoctree.h
new file mode 100644
index 0000000000..688d91dc40
--- /dev/null
+++ b/indra/llmath/llvolumeoctree.h
@@ -0,0 +1,134 @@
+/**
+ * @file llvolumeoctree.h
+ * @brief LLVolume octree classes.
+ *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLVOLUME_OCTREE_H
+#define LL_LLVOLUME_OCTREE_H
+
+#include "linden_common.h"
+#include "llmemory.h"
+
+#include "lloctree.h"
+#include "llvolume.h"
+#include "llvector4a.h"
+
+class LLVolumeTriangle : public LLRefCount
+{
+public:
+ LLVolumeTriangle()
+ {
+
+ }
+
+ LLVolumeTriangle(const LLVolumeTriangle& rhs)
+ {
+ *this = rhs;
+ }
+
+ const LLVolumeTriangle& operator=(const LLVolumeTriangle& rhs)
+ {
+ llerrs << "Illegal operation!" << llendl;
+ return *this;
+ }
+
+ ~LLVolumeTriangle()
+ {
+
+ }
+
+ LLVector4a mPositionGroup;
+
+ const LLVector4a* mV[3];
+ U16 mIndex[3];
+
+ F32 mRadius;
+
+ virtual const LLVector4a& getPositionGroup() const;
+ virtual const F32& getBinRadius() const;
+};
+
+class LLVolumeOctreeListener : public LLOctreeListener<LLVolumeTriangle>
+{
+public:
+
+ LLVolumeOctreeListener(LLOctreeNode<LLVolumeTriangle>* node);
+ ~LLVolumeOctreeListener();
+
+ LLVolumeOctreeListener(const LLVolumeOctreeListener& rhs)
+ {
+ *this = rhs;
+ }
+
+ const LLVolumeOctreeListener& operator=(const LLVolumeOctreeListener& rhs)
+ {
+ llerrs << "Illegal operation!" << llendl;
+ return *this;
+ }
+
+ //LISTENER FUNCTIONS
+ virtual void handleChildAddition(const LLOctreeNode<LLVolumeTriangle>* parent,
+ LLOctreeNode<LLVolumeTriangle>* child);
+ virtual void handleStateChange(const LLTreeNode<LLVolumeTriangle>* node) { }
+ virtual void handleChildRemoval(const LLOctreeNode<LLVolumeTriangle>* parent,
+ const LLOctreeNode<LLVolumeTriangle>* child) { }
+ virtual void handleInsertion(const LLTreeNode<LLVolumeTriangle>* node, LLVolumeTriangle* tri) { }
+ virtual void handleRemoval(const LLTreeNode<LLVolumeTriangle>* node, LLVolumeTriangle* tri) { }
+ virtual void handleDestruction(const LLTreeNode<LLVolumeTriangle>* node) { }
+
+
+public:
+ LLVector4a mBounds[2]; // bounding box (center, size) of this node and all its children (tight fit to objects)
+ LLVector4a mExtents[2]; // extents (min, max) of this node and all its children
+};
+
+class LLOctreeTriangleRayIntersect : public LLOctreeTraveler<LLVolumeTriangle>
+{
+public:
+ const LLVolumeFace* mFace;
+ LLVector4a mStart;
+ LLVector4a mDir;
+ LLVector4a mEnd;
+ LLVector3* mIntersection;
+ LLVector2* mTexCoord;
+ LLVector3* mNormal;
+ LLVector3* mBinormal;
+ F32* mClosestT;
+ bool mHitFace;
+
+ LLOctreeTriangleRayIntersect(const LLVector4a& start, const LLVector4a& dir,
+ const LLVolumeFace* face, F32* closest_t,
+ LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal);
+
+ void traverse(const LLOctreeNode<LLVolumeTriangle>* node);
+
+ virtual void visit(const LLOctreeNode<LLVolumeTriangle>* node);
+};
+
+class LLVolumeOctreeValidate : public LLOctreeTraveler<LLVolumeTriangle>
+{
+ virtual void visit(const LLOctreeNode<LLVolumeTriangle>* branch);
+};
+
+#endif
diff --git a/indra/llmath/m4math.cpp b/indra/llmath/m4math.cpp
index 946b1553fe..bad4deb4de 100644
--- a/indra/llmath/m4math.cpp
+++ b/indra/llmath/m4math.cpp
@@ -215,8 +215,33 @@ const LLMatrix4& LLMatrix4::transpose()
F32 LLMatrix4::determinant() const
{
- llerrs << "Not implemented!" << llendl;
- return 0.f;
+ F32 value =
+ mMatrix[0][3] * mMatrix[1][2] * mMatrix[2][1] * mMatrix[3][0] -
+ mMatrix[0][2] * mMatrix[1][3] * mMatrix[2][1] * mMatrix[3][0] -
+ mMatrix[0][3] * mMatrix[1][1] * mMatrix[2][2] * mMatrix[3][0] +
+ mMatrix[0][1] * mMatrix[1][3] * mMatrix[2][2] * mMatrix[3][0] +
+ mMatrix[0][2] * mMatrix[1][1] * mMatrix[2][3] * mMatrix[3][0] -
+ mMatrix[0][1] * mMatrix[1][2] * mMatrix[2][3] * mMatrix[3][0] -
+ mMatrix[0][3] * mMatrix[1][2] * mMatrix[2][0] * mMatrix[3][1] +
+ mMatrix[0][2] * mMatrix[1][3] * mMatrix[2][0] * mMatrix[3][1] +
+ mMatrix[0][3] * mMatrix[1][0] * mMatrix[2][2] * mMatrix[3][1] -
+ mMatrix[0][0] * mMatrix[1][3] * mMatrix[2][2] * mMatrix[3][1] -
+ mMatrix[0][2] * mMatrix[1][0] * mMatrix[2][3] * mMatrix[3][1] +
+ mMatrix[0][0] * mMatrix[1][2] * mMatrix[2][3] * mMatrix[3][1] +
+ mMatrix[0][3] * mMatrix[1][1] * mMatrix[2][0] * mMatrix[3][2] -
+ mMatrix[0][1] * mMatrix[1][3] * mMatrix[2][0] * mMatrix[3][2] -
+ mMatrix[0][3] * mMatrix[1][0] * mMatrix[2][1] * mMatrix[3][2] +
+ mMatrix[0][0] * mMatrix[1][3] * mMatrix[2][1] * mMatrix[3][2] +
+ mMatrix[0][1] * mMatrix[1][0] * mMatrix[2][3] * mMatrix[3][2] -
+ mMatrix[0][0] * mMatrix[1][1] * mMatrix[2][3] * mMatrix[3][2] -
+ mMatrix[0][2] * mMatrix[1][1] * mMatrix[2][0] * mMatrix[3][3] +
+ mMatrix[0][1] * mMatrix[1][2] * mMatrix[2][0] * mMatrix[3][3] +
+ mMatrix[0][2] * mMatrix[1][0] * mMatrix[2][1] * mMatrix[3][3] -
+ mMatrix[0][0] * mMatrix[1][2] * mMatrix[2][1] * mMatrix[3][3] -
+ mMatrix[0][1] * mMatrix[1][0] * mMatrix[2][2] * mMatrix[3][3] +
+ mMatrix[0][0] * mMatrix[1][1] * mMatrix[2][2] * mMatrix[3][3];
+
+ return value;
}
// Only works for pure orthonormal, homogeneous transform matrices.
@@ -422,6 +447,17 @@ const LLMatrix4& LLMatrix4::initRotTrans(const LLQuaternion &q, const LLVector
return (*this);
}
+const LLMatrix4& LLMatrix4::initScale(const LLVector3 &scale)
+{
+ setIdentity();
+
+ mMatrix[VX][VX] = scale.mV[VX];
+ mMatrix[VY][VY] = scale.mV[VY];
+ mMatrix[VZ][VZ] = scale.mV[VZ];
+
+ return (*this);
+}
+
const LLMatrix4& LLMatrix4::initAll(const LLVector3 &scale, const LLQuaternion &q, const LLVector3 &pos)
{
F32 sx, sy, sz;
@@ -642,37 +678,6 @@ const LLMatrix4& LLMatrix4::initMatrix(const LLMatrix3 &mat, const LLVector4 &
// LLMatrix4 Operators
-
-/* Not implemented to help enforce code consistency with the syntax of
- row-major notation. This is a Good Thing.
-LLVector4 operator*(const LLMatrix4 &a, const LLVector4 &b)
-{
- // Operate "to the right" on column-vector b
- LLVector4 vec;
- vec.mV[VX] = a.mMatrix[VX][VX] * b.mV[VX] +
- a.mMatrix[VY][VX] * b.mV[VY] +
- a.mMatrix[VZ][VX] * b.mV[VZ] +
- a.mMatrix[VW][VX] * b.mV[VW];
-
- vec.mV[VY] = a.mMatrix[VX][VY] * b.mV[VX] +
- a.mMatrix[VY][VY] * b.mV[VY] +
- a.mMatrix[VZ][VY] * b.mV[VZ] +
- a.mMatrix[VW][VY] * b.mV[VW];
-
- vec.mV[VZ] = a.mMatrix[VX][VZ] * b.mV[VX] +
- a.mMatrix[VY][VZ] * b.mV[VY] +
- a.mMatrix[VZ][VZ] * b.mV[VZ] +
- a.mMatrix[VW][VZ] * b.mV[VW];
-
- vec.mV[VW] = a.mMatrix[VX][VW] * b.mV[VX] +
- a.mMatrix[VY][VW] * b.mV[VY] +
- a.mMatrix[VZ][VW] * b.mV[VZ] +
- a.mMatrix[VW][VW] * b.mV[VW];
- return vec;
-}
-*/
-
-
LLVector4 operator*(const LLVector4 &a, const LLMatrix4 &b)
{
// Operate "to the left" on row-vector a
@@ -768,6 +773,23 @@ bool operator!=(const LLMatrix4 &a, const LLMatrix4 &b)
return FALSE;
}
+bool operator<(const LLMatrix4& a, const LLMatrix4 &b)
+{
+ U32 i, j;
+ for (i = 0; i < NUM_VALUES_IN_MAT4; i++)
+ {
+ for (j = 0; j < NUM_VALUES_IN_MAT4; j++)
+ {
+ if (a.mMatrix[i][j] != b.mMatrix[i][j])
+ {
+ return a.mMatrix[i][j] < b.mMatrix[i][j];
+ }
+ }
+ }
+
+ return false;
+}
+
const LLMatrix4& operator*=(LLMatrix4 &a, F32 k)
{
U32 i, j;
@@ -807,4 +829,54 @@ std::ostream& operator<<(std::ostream& s, const LLMatrix4 &a)
return s;
}
+LLSD LLMatrix4::getValue() const
+{
+ LLSD ret;
+
+ ret[0] = mMatrix[0][0];
+ ret[1] = mMatrix[0][1];
+ ret[2] = mMatrix[0][2];
+ ret[3] = mMatrix[0][3];
+
+ ret[4] = mMatrix[1][0];
+ ret[5] = mMatrix[1][1];
+ ret[6] = mMatrix[1][2];
+ ret[7] = mMatrix[1][3];
+
+ ret[8] = mMatrix[2][0];
+ ret[9] = mMatrix[2][1];
+ ret[10] = mMatrix[2][2];
+ ret[11] = mMatrix[2][3];
+
+ ret[12] = mMatrix[3][0];
+ ret[13] = mMatrix[3][1];
+ ret[14] = mMatrix[3][2];
+ ret[15] = mMatrix[3][3];
+
+ return ret;
+}
+
+void LLMatrix4::setValue(const LLSD& data)
+{
+ mMatrix[0][0] = data[0].asReal();
+ mMatrix[0][1] = data[1].asReal();
+ mMatrix[0][2] = data[2].asReal();
+ mMatrix[0][3] = data[3].asReal();
+
+ mMatrix[1][0] = data[4].asReal();
+ mMatrix[1][1] = data[5].asReal();
+ mMatrix[1][2] = data[6].asReal();
+ mMatrix[1][3] = data[7].asReal();
+
+ mMatrix[2][0] = data[8].asReal();
+ mMatrix[2][1] = data[9].asReal();
+ mMatrix[2][2] = data[10].asReal();
+ mMatrix[2][3] = data[11].asReal();
+
+ mMatrix[3][0] = data[12].asReal();
+ mMatrix[3][1] = data[13].asReal();
+ mMatrix[3][2] = data[14].asReal();
+ mMatrix[3][3] = data[15].asReal();
+}
+
diff --git a/indra/llmath/m4math.h b/indra/llmath/m4math.h
index 6ec9958491..a7dce10397 100644
--- a/indra/llmath/m4math.h
+++ b/indra/llmath/m4math.h
@@ -119,6 +119,8 @@ public:
~LLMatrix4(void); // Destructor
+ LLSD getValue() const;
+ void setValue(const LLSD&);
//////////////////////////////
//
@@ -132,6 +134,7 @@ public:
// various useful matrix functions
const LLMatrix4& setIdentity(); // Load identity matrix
+ bool isIdentity() const;
const LLMatrix4& setZero(); // Clears matrix to all zeros.
const LLMatrix4& initRotation(const F32 angle, const F32 x, const F32 y, const F32 z); // Calculate rotation matrix by rotating angle radians about (x, y, z)
@@ -153,6 +156,7 @@ public:
const LLMatrix4& initRotTrans(const F32 roll, const F32 pitch, const F32 yaw, const LLVector4 &pos); // Rotation from Euler + translation
const LLMatrix4& initRotTrans(const LLQuaternion &q, const LLVector4 &pos); // Set with Quaternion and position
+ const LLMatrix4& initScale(const LLVector3 &scale);
// Set all
const LLMatrix4& initAll(const LLVector3 &scale, const LLQuaternion &q, const LLVector3 &pos);
@@ -219,10 +223,7 @@ public:
// Operators
//
-// Not implemented to enforce code that agrees with symbolic syntax
-// friend LLVector4 operator*(const LLMatrix4 &a, const LLVector4 &b); // Apply rotation a to vector b
-
-// friend inline LLMatrix4 operator*(const LLMatrix4 &a, const LLMatrix4 &b); // Return a * b
+ // friend inline LLMatrix4 operator*(const LLMatrix4 &a, const LLMatrix4 &b); // Return a * b
friend LLVector4 operator*(const LLVector4 &a, const LLMatrix4 &b); // Return transform of vector a by matrix b
friend const LLVector3 operator*(const LLVector3 &a, const LLMatrix4 &b); // Return full transform of a by matrix b
friend LLVector4 rotate_vector(const LLVector4 &a, const LLMatrix4 &b); // Rotates a but does not translate
@@ -230,6 +231,7 @@ public:
friend bool operator==(const LLMatrix4 &a, const LLMatrix4 &b); // Return a == b
friend bool operator!=(const LLMatrix4 &a, const LLMatrix4 &b); // Return a != b
+ friend bool operator<(const LLMatrix4 &a, const LLMatrix4& b); // Return a < b
friend const LLMatrix4& operator+=(LLMatrix4 &a, const LLMatrix4 &b); // Return a + b
friend const LLMatrix4& operator-=(LLMatrix4 &a, const LLMatrix4 &b); // Return a - b
@@ -263,6 +265,30 @@ inline const LLMatrix4& LLMatrix4::setIdentity()
return (*this);
}
+inline bool LLMatrix4::isIdentity() const
+{
+ return
+ mMatrix[0][0] == 1.f &&
+ mMatrix[0][1] == 0.f &&
+ mMatrix[0][2] == 0.f &&
+ mMatrix[0][3] == 0.f &&
+
+ mMatrix[1][0] == 0.f &&
+ mMatrix[1][1] == 1.f &&
+ mMatrix[1][2] == 0.f &&
+ mMatrix[1][3] == 0.f &&
+
+ mMatrix[2][0] == 0.f &&
+ mMatrix[2][1] == 0.f &&
+ mMatrix[2][2] == 1.f &&
+ mMatrix[2][3] == 0.f &&
+
+ mMatrix[3][0] == 0.f &&
+ mMatrix[3][1] == 0.f &&
+ mMatrix[3][2] == 0.f &&
+ mMatrix[3][3] == 1.f;
+}
+
/*
inline LLMatrix4 operator*(const LLMatrix4 &a, const LLMatrix4 &b)
diff --git a/indra/llmath/tests/llbbox_test.cpp b/indra/llmath/tests/llbbox_test.cpp
index 8064ab217d..fd0dbb58fc 100644
--- a/indra/llmath/tests/llbbox_test.cpp
+++ b/indra/llmath/tests/llbbox_test.cpp
@@ -34,7 +34,7 @@
#define ANGLE (3.14159265f / 2.0f)
-#define APPROX_EQUAL(a, b) dist_vec((a),(b)) < 1e-5
+#define APPROX_EQUAL(a, b) (dist_vec_squared((a),(b)) < 1e-10)
namespace tut
{
diff --git a/indra/llmath/tests/llquaternion_test.cpp b/indra/llmath/tests/llquaternion_test.cpp
index 9e79b299ff..e69010b2d6 100644
--- a/indra/llmath/tests/llquaternion_test.cpp
+++ b/indra/llmath/tests/llquaternion_test.cpp
@@ -29,12 +29,12 @@
#include "linden_common.h"
#include "../test/lltut.h"
-#include "../llquaternion.h"
#include "../v4math.h"
#include "../v3math.h"
#include "../v3dmath.h"
#include "../m4math.h"
#include "../m3math.h"
+#include "../llquaternion.h"
namespace tut
{
diff --git a/indra/llmath/tests/m3math_test.cpp b/indra/llmath/tests/m3math_test.cpp
index 8abf61b740..1ca2b005d9 100644
--- a/indra/llmath/tests/m3math_test.cpp
+++ b/indra/llmath/tests/m3math_test.cpp
@@ -37,6 +37,16 @@
#include "../test/lltut.h"
+#if LL_WINDOWS
+// disable unreachable code warnings caused by usage of skip.
+#pragma warning(disable: 4702)
+#endif
+
+#if LL_WINDOWS
+// disable unreachable code warnings caused by usage of skip.
+#pragma warning(disable: 4702)
+#endif
+
namespace tut
{
struct m3math_test
@@ -277,20 +287,21 @@ namespace tut
LLVector3 llvec2(1, 2, 0);
LLVector3 llvec3(2, 4, 2);
+ skip("This test fails depending on architecture. Need to fix comparison operation, is_approx_equal, to work on more than one platform.");
+
llmat_obj.setRows(llvec1, llvec2, llvec3);
llmat_obj.orthogonalize();
- skip("Grr, LLMatrix3::orthogonalize test is failing. Has it ever worked?");
ensure("LLMatrix3::orthogonalize failed ",
- is_approx_equal(0.19611613f, llmat_obj.mMatrix[0][0]) &&
+ is_approx_equal(0.19611614f, llmat_obj.mMatrix[0][0]) &&
is_approx_equal(0.78446454f, llmat_obj.mMatrix[0][1]) &&
- is_approx_equal(0.58834839f, llmat_obj.mMatrix[0][2]) &&
- is_approx_equal(0.47628206f, llmat_obj.mMatrix[1][0]) &&
- is_approx_equal(0.44826555f, llmat_obj.mMatrix[1][1]) &&
- is_approx_equal(-0.75644791f, llmat_obj.mMatrix[1][2]) &&
- is_approx_equal(-0.85714287f, llmat_obj.mMatrix[2][0]) &&
+ is_approx_equal(0.58834841f, llmat_obj.mMatrix[0][2]) &&
+ is_approx_equal(0.47628204f, llmat_obj.mMatrix[1][0]) &&
+ is_approx_equal(0.44826545f, llmat_obj.mMatrix[1][1]) &&
+ is_approx_equal(-0.75644795f, llmat_obj.mMatrix[1][2]) &&
+ is_approx_equal(-0.85714286f, llmat_obj.mMatrix[2][0]) &&
is_approx_equal(0.42857143f, llmat_obj.mMatrix[2][1]) &&
- is_approx_equal(-0.28571427f, llmat_obj.mMatrix[2][2]));
+ is_approx_equal(-0.28571429f, llmat_obj.mMatrix[2][2]));
}
//test case for adjointTranspose() fn.
diff --git a/indra/llmath/tests/v2math_test.cpp b/indra/llmath/tests/v2math_test.cpp
index 9747996b25..4d6a2eca93 100644
--- a/indra/llmath/tests/v2math_test.cpp
+++ b/indra/llmath/tests/v2math_test.cpp
@@ -85,7 +85,7 @@ namespace tut
F32 x = 2.2345f, y = 3.5678f ;
LLVector2 vec2(x,y);
ensure("magVecSquared:Fail ", is_approx_equal(vec2.magVecSquared(), (x*x + y*y)));
- ensure("magVec:Fail ", is_approx_equal(vec2.magVec(), fsqrtf(x*x + y*y)));
+ ensure("magVec:Fail ", is_approx_equal(vec2.magVec(), (F32) sqrt(x*x + y*y)));
}
template<> template<>
@@ -407,7 +407,7 @@ namespace tut
ensure_equals("dist_vec_squared values are not equal",val2, val1);
val1 = dist_vec(vec2, vec3);
- val2 = fsqrtf((x1 - x2)*(x1 - x2) + (y1 - y2)* (y1 - y2));
+ val2 = (F32) sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)* (y1 - y2));
ensure_equals("dist_vec values are not equal",val2, val1);
}
@@ -431,7 +431,7 @@ namespace tut
LLVector2 vec2(x1, y1);
F32 vecMag = vec2.normVec();
- F32 mag = fsqrtf(x1*x1 + y1*y1);
+ F32 mag = (F32) sqrt(x1*x1 + y1*y1);
F32 oomag = 1.f / mag;
val1 = x1 * oomag;
diff --git a/indra/llmath/tests/v3color_test.cpp b/indra/llmath/tests/v3color_test.cpp
index 2c00f00ab3..29d1c483ab 100644
--- a/indra/llmath/tests/v3color_test.cpp
+++ b/indra/llmath/tests/v3color_test.cpp
@@ -93,7 +93,7 @@ namespace tut
F32 r = 2.3436212f, g = 1231.f, b = 4.7849321232f;
LLColor3 llcolor3(r,g,b);
ensure("magVecSquared:Fail ", is_approx_equal(llcolor3.magVecSquared(), (r*r + g*g + b*b)));
- ensure("magVec:Fail ", is_approx_equal(llcolor3.magVec(), fsqrtf(r*r + g*g + b*b)));
+ ensure("magVec:Fail ", is_approx_equal(llcolor3.magVec(), (F32) sqrt(r*r + g*g + b*b)));
}
template<> template<>
@@ -103,7 +103,7 @@ namespace tut
F32 val1, val2,val3;
LLColor3 llcolor3(r,g,b);
F32 vecMag = llcolor3.normVec();
- F32 mag = fsqrtf(r*r + g*g + b*b);
+ F32 mag = (F32) sqrt(r*r + g*g + b*b);
F32 oomag = 1.f / mag;
val1 = r * oomag;
val2 = g * oomag;
@@ -286,7 +286,7 @@ namespace tut
F32 r1 =1.f, g1 = 2.f,b1 = 1.2f, r2 = -2.3f, g2 = 1.11f, b2 = 1234.234f;
LLColor3 llcolor3(r1,g1,b1),llcolor3a(r2,g2,b2);
F32 val = distVec(llcolor3,llcolor3a);
- ensure("distVec failed ", is_approx_equal(fsqrtf((r1-r2)*(r1-r2) + (g1-g2)*(g1-g2) + (b1-b2)*(b1-b2)) ,val));
+ ensure("distVec failed ", is_approx_equal((F32) sqrt((r1-r2)*(r1-r2) + (g1-g2)*(g1-g2) + (b1-b2)*(b1-b2)) ,val));
F32 val1 = distVec_squared(llcolor3,llcolor3a);
ensure("distVec_squared failed ", is_approx_equal(((r1-r2)*(r1-r2) + (g1-g2)*(g1-g2) + (b1-b2)*(b1-b2)) ,val1));
diff --git a/indra/llmath/tests/v3dmath_test.cpp b/indra/llmath/tests/v3dmath_test.cpp
index b67346f4e5..20b26faa12 100644
--- a/indra/llmath/tests/v3dmath_test.cpp
+++ b/indra/llmath/tests/v3dmath_test.cpp
@@ -30,11 +30,11 @@
#include "llsd.h"
#include "../test/lltut.h"
-#include "../llquaternion.h"
#include "../m3math.h"
#include "../v4math.h"
#include "../v3dmath.h"
#include "../v3dmath.h"
+#include "../llquaternion.h"
namespace tut
{
@@ -403,7 +403,7 @@ namespace tut
LLVector3d vec3D(x,y,z);
F64 res = (x*x + y*y + z*z) - vec3D.magVecSquared();
ensure("1:magVecSquared:Fail ", ((-F_APPROXIMATELY_ZERO <= res)&& (res <=F_APPROXIMATELY_ZERO)));
- res = fsqrtf(x*x + y*y + z*z) - vec3D.magVec();
+ res = (F32) sqrt(x*x + y*y + z*z) - vec3D.magVec();
ensure("2:magVec: Fail ", ((-F_APPROXIMATELY_ZERO <= res)&& (res <=F_APPROXIMATELY_ZERO)));
}
diff --git a/indra/llmath/tests/v3math_test.cpp b/indra/llmath/tests/v3math_test.cpp
index e4732bf861..df7a77002f 100644
--- a/indra/llmath/tests/v3math_test.cpp
+++ b/indra/llmath/tests/v3math_test.cpp
@@ -30,12 +30,12 @@
#include "../test/lltut.h"
#include "llsd.h"
-#include "../llquaternion.h"
-#include "../llquantize.h"
#include "../v3dmath.h"
#include "../m3math.h"
#include "../v4math.h"
#include "../v3math.h"
+#include "../llquaternion.h"
+#include "../llquantize.h"
namespace tut
@@ -149,7 +149,7 @@ namespace tut
F32 x = 2.32f, y = 1.212f, z = -.12f;
LLVector3 vec3(x,y,z);
ensure("1:magVecSquared:Fail ", is_approx_equal(vec3.magVecSquared(), (x*x + y*y + z*z)));
- ensure("2:magVec:Fail ", is_approx_equal(vec3.magVec(), fsqrtf(x*x + y*y + z*z)));
+ ensure("2:magVec:Fail ", is_approx_equal(vec3.magVec(), (F32) sqrt(x*x + y*y + z*z)));
}
template<> template<>
@@ -509,7 +509,7 @@ namespace tut
F32 val1,val2;
LLVector3 vec3(x1,y1,z1),vec3a(x2,y2,z2);
val1 = dist_vec(vec3,vec3a);
- val2 = fsqrtf((x1 - x2)*(x1 - x2) + (y1 - y2)* (y1 - y2) + (z1 - z2)* (z1 -z2));
+ val2 = (F32) sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)* (y1 - y2) + (z1 - z2)* (z1 -z2));
ensure_equals("1:dist_vec: Fail ",val2, val1);
val1 = dist_vec_squared(vec3,vec3a);
val2 =((x1 - x2)*(x1 - x2) + (y1 - y2)* (y1 - y2) + (z1 - z2)* (z1 -z2));
diff --git a/indra/llmath/tests/v4color_test.cpp b/indra/llmath/tests/v4color_test.cpp
index fbd43625d1..d7eec3c87f 100644
--- a/indra/llmath/tests/v4color_test.cpp
+++ b/indra/llmath/tests/v4color_test.cpp
@@ -155,7 +155,7 @@ namespace tut
F32 r = 0x20, g = 0xFFFF, b = 0xFF;
LLColor4 llcolor4(r,g,b);
ensure("magVecSquared:Fail ", is_approx_equal(llcolor4.magVecSquared(), (r*r + g*g + b*b)));
- ensure("magVec:Fail ", is_approx_equal(llcolor4.magVec(), fsqrtf(r*r + g*g + b*b)));
+ ensure("magVec:Fail ", is_approx_equal(llcolor4.magVec(), (F32) sqrt(r*r + g*g + b*b)));
}
template<> template<>
@@ -164,7 +164,7 @@ namespace tut
F32 r = 0x20, g = 0xFFFF, b = 0xFF;
LLColor4 llcolor4(r,g,b);
F32 vecMag = llcolor4.normVec();
- F32 mag = fsqrtf(r*r + g*g + b*b);
+ F32 mag = (F32) sqrt(r*r + g*g + b*b);
F32 oomag = 1.f / mag;
F32 val1 = r * oomag, val2 = g * oomag, val3 = b * oomag;
ensure("1:normVec failed ", (is_approx_equal(val1, llcolor4.mV[0]) && is_approx_equal(val2, llcolor4.mV[1]) && is_approx_equal(val3, llcolor4.mV[2]) && is_approx_equal(vecMag, mag)));
diff --git a/indra/llmath/tests/v4coloru_test.cpp b/indra/llmath/tests/v4coloru_test.cpp
index 6d84ba41ef..128f6f3564 100644
--- a/indra/llmath/tests/v4coloru_test.cpp
+++ b/indra/llmath/tests/v4coloru_test.cpp
@@ -135,7 +135,7 @@ namespace tut
U8 r = 0x12, g = 0xFF, b = 0xAF;
LLColor4U llcolor4u(r,g,b);
ensure("magVecSquared:Fail ", is_approx_equal(llcolor4u.magVecSquared(), (F32)(r*r + g*g + b*b)));
- ensure("magVec:Fail ", is_approx_equal(llcolor4u.magVec(), fsqrtf(r*r + g*g + b*b)));
+ ensure("magVec:Fail ", is_approx_equal(llcolor4u.magVec(), (F32) sqrt((F32) (r*r + g*g + b*b))));
}
template<> template<>
diff --git a/indra/llmath/tests/v4math_test.cpp b/indra/llmath/tests/v4math_test.cpp
index b1f934e555..191ac864df 100644
--- a/indra/llmath/tests/v4math_test.cpp
+++ b/indra/llmath/tests/v4math_test.cpp
@@ -30,9 +30,9 @@
#include "../test/lltut.h"
#include "llsd.h"
-#include "../llquaternion.h"
#include "../m4math.h"
#include "../v4math.h"
+#include "../llquaternion.h"
namespace tut
{
@@ -96,7 +96,7 @@ namespace tut
{
F32 x = 10.f, y = -2.3f, z = -.023f;
LLVector4 vec4(x,y,z);
- ensure("magVec:Fail ", is_approx_equal(vec4.magVec(), fsqrtf(x*x + y*y + z*z)));
+ ensure("magVec:Fail ", is_approx_equal(vec4.magVec(), (F32) sqrt(x*x + y*y + z*z)));
ensure("magVecSquared:Fail ", is_approx_equal(vec4.magVecSquared(), (x*x + y*y + z*z)));
}
@@ -337,7 +337,7 @@ namespace tut
F32 val1,val2;
LLVector4 vec4(x1,y1,z1),vec4a(x2,y2,z2);
val1 = dist_vec(vec4,vec4a);
- val2 = fsqrtf((x1 - x2)*(x1 - x2) + (y1 - y2)* (y1 - y2) + (z1 - z2)* (z1 -z2));
+ val2 = (F32) sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)* (y1 - y2) + (z1 - z2)* (z1 -z2));
ensure_equals("dist_vec: Fail ",val2, val1);
val1 = dist_vec_squared(vec4,vec4a);
val2 =((x1 - x2)*(x1 - x2) + (y1 - y2)* (y1 - y2) + (z1 - z2)* (z1 -z2));
diff --git a/indra/llmath/v2math.cpp b/indra/llmath/v2math.cpp
index 0180049b5d..a0cd642853 100644
--- a/indra/llmath/v2math.cpp
+++ b/indra/llmath/v2math.cpp
@@ -86,7 +86,7 @@ F32 dist_vec(const LLVector2 &a, const LLVector2 &b)
{
F32 x = a.mV[0] - b.mV[0];
F32 y = a.mV[1] - b.mV[1];
- return fsqrtf( x*x + y*y );
+ return (F32) sqrt( x*x + y*y );
}
F32 dist_vec_squared(const LLVector2 &a, const LLVector2 &b)
@@ -109,3 +109,18 @@ LLVector2 lerp(const LLVector2 &a, const LLVector2 &b, F32 u)
a.mV[VX] + (b.mV[VX] - a.mV[VX]) * u,
a.mV[VY] + (b.mV[VY] - a.mV[VY]) * u );
}
+
+LLSD LLVector2::getValue() const
+{
+ LLSD ret;
+ ret[0] = mV[0];
+ ret[1] = mV[1];
+ return ret;
+}
+
+void LLVector2::setValue(LLSD& sd)
+{
+ mV[0] = (F32) sd[0].asReal();
+ mV[1] = (F32) sd[1].asReal();
+}
+
diff --git a/indra/llmath/v2math.h b/indra/llmath/v2math.h
index f50a5e6633..8d5db96f5e 100644
--- a/indra/llmath/v2math.h
+++ b/indra/llmath/v2math.h
@@ -60,6 +60,9 @@ class LLVector2
void set(const LLVector2 &vec); // Sets LLVector2 to vec
void set(const F32 *vec); // Sets LLVector2 to vec
+ LLSD getValue() const;
+ void setValue(LLSD& sd);
+
void setVec(F32 x, F32 y); // deprecated
void setVec(const LLVector2 &vec); // deprecated
void setVec(const F32 *vec); // deprecated
@@ -216,7 +219,7 @@ inline void LLVector2::setVec(const F32 *vec)
inline F32 LLVector2::length(void) const
{
- return fsqrtf(mV[0]*mV[0] + mV[1]*mV[1]);
+ return (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1]);
}
inline F32 LLVector2::lengthSquared(void) const
@@ -226,7 +229,7 @@ inline F32 LLVector2::lengthSquared(void) const
inline F32 LLVector2::normalize(void)
{
- F32 mag = fsqrtf(mV[0]*mV[0] + mV[1]*mV[1]);
+ F32 mag = (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1]);
F32 oomag;
if (mag > FP_MAG_THRESHOLD)
@@ -253,7 +256,7 @@ inline bool LLVector2::isFinite() const
// deprecated
inline F32 LLVector2::magVec(void) const
{
- return fsqrtf(mV[0]*mV[0] + mV[1]*mV[1]);
+ return (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1]);
}
// deprecated
@@ -265,7 +268,7 @@ inline F32 LLVector2::magVecSquared(void) const
// deprecated
inline F32 LLVector2::normVec(void)
{
- F32 mag = fsqrtf(mV[0]*mV[0] + mV[1]*mV[1]);
+ F32 mag = (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1]);
F32 oomag;
if (mag > FP_MAG_THRESHOLD)
diff --git a/indra/llmath/v3color.h b/indra/llmath/v3color.h
index 327e452bf7..56cb2ae73e 100644
--- a/indra/llmath/v3color.h
+++ b/indra/llmath/v3color.h
@@ -278,7 +278,7 @@ inline F32 LLColor3::brightness(void) const
inline F32 LLColor3::length(void) const
{
- return fsqrtf(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]);
+ return (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]);
}
inline F32 LLColor3::lengthSquared(void) const
@@ -288,7 +288,7 @@ inline F32 LLColor3::lengthSquared(void) const
inline F32 LLColor3::normalize(void)
{
- F32 mag = fsqrtf(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]);
+ F32 mag = (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]);
F32 oomag;
if (mag)
@@ -304,7 +304,7 @@ inline F32 LLColor3::normalize(void)
// deprecated
inline F32 LLColor3::magVec(void) const
{
- return fsqrtf(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]);
+ return (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]);
}
// deprecated
@@ -316,7 +316,7 @@ inline F32 LLColor3::magVecSquared(void) const
// deprecated
inline F32 LLColor3::normVec(void)
{
- F32 mag = fsqrtf(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]);
+ F32 mag = (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]);
F32 oomag;
if (mag)
@@ -438,7 +438,7 @@ inline F32 distVec(const LLColor3 &a, const LLColor3 &b)
F32 x = a.mV[0] - b.mV[0];
F32 y = a.mV[1] - b.mV[1];
F32 z = a.mV[2] - b.mV[2];
- return fsqrtf( x*x + y*y + z*z );
+ return (F32) sqrt( x*x + y*y + z*z );
}
inline F32 distVec_squared(const LLColor3 &a, const LLColor3 &b)
diff --git a/indra/llmath/v3dmath.h b/indra/llmath/v3dmath.h
index 664c986ad0..578dcdc8ea 100644
--- a/indra/llmath/v3dmath.h
+++ b/indra/llmath/v3dmath.h
@@ -234,7 +234,7 @@ inline const LLVector3d& LLVector3d::setVec(const F64 *vec)
inline F64 LLVector3d::normVec(void)
{
- F64 mag = fsqrtf(mdV[0]*mdV[0] + mdV[1]*mdV[1] + mdV[2]*mdV[2]);
+ F64 mag = (F32) sqrt(mdV[0]*mdV[0] + mdV[1]*mdV[1] + mdV[2]*mdV[2]);
F64 oomag;
if (mag > FP_MAG_THRESHOLD)
@@ -256,7 +256,7 @@ inline F64 LLVector3d::normVec(void)
inline F64 LLVector3d::normalize(void)
{
- F64 mag = fsqrtf(mdV[0]*mdV[0] + mdV[1]*mdV[1] + mdV[2]*mdV[2]);
+ F64 mag = (F32) sqrt(mdV[0]*mdV[0] + mdV[1]*mdV[1] + mdV[2]*mdV[2]);
F64 oomag;
if (mag > FP_MAG_THRESHOLD)
@@ -280,7 +280,7 @@ inline F64 LLVector3d::normalize(void)
inline F64 LLVector3d::magVec(void) const
{
- return fsqrtf(mdV[0]*mdV[0] + mdV[1]*mdV[1] + mdV[2]*mdV[2]);
+ return (F32) sqrt(mdV[0]*mdV[0] + mdV[1]*mdV[1] + mdV[2]*mdV[2]);
}
inline F64 LLVector3d::magVecSquared(void) const
@@ -290,7 +290,7 @@ inline F64 LLVector3d::magVecSquared(void) const
inline F64 LLVector3d::length(void) const
{
- return fsqrtf(mdV[0]*mdV[0] + mdV[1]*mdV[1] + mdV[2]*mdV[2]);
+ return (F32) sqrt(mdV[0]*mdV[0] + mdV[1]*mdV[1] + mdV[2]*mdV[2]);
}
inline F64 LLVector3d::lengthSquared(void) const
@@ -400,7 +400,7 @@ inline F64 dist_vec(const LLVector3d &a, const LLVector3d &b)
F64 x = a.mdV[0] - b.mdV[0];
F64 y = a.mdV[1] - b.mdV[1];
F64 z = a.mdV[2] - b.mdV[2];
- return fsqrtf( x*x + y*y + z*z );
+ return (F32) sqrt( x*x + y*y + z*z );
}
inline F64 dist_vec_squared(const LLVector3d &a, const LLVector3d &b)
diff --git a/indra/llmath/v3math.cpp b/indra/llmath/v3math.cpp
index fd08df02d8..e7107dee16 100644
--- a/indra/llmath/v3math.cpp
+++ b/indra/llmath/v3math.cpp
@@ -134,6 +134,21 @@ BOOL LLVector3::clampLength( F32 length_limit )
return changed;
}
+BOOL LLVector3::clamp(const LLVector3 &min_vec, const LLVector3 &max_vec)
+{
+ BOOL ret = FALSE;
+
+ if (mV[0] < min_vec[0]) { mV[0] = min_vec[0]; ret = TRUE; }
+ if (mV[1] < min_vec[1]) { mV[1] = min_vec[1]; ret = TRUE; }
+ if (mV[2] < min_vec[2]) { mV[2] = min_vec[2]; ret = TRUE; }
+
+ if (mV[0] > max_vec[0]) { mV[0] = max_vec[0]; ret = TRUE; }
+ if (mV[1] > max_vec[1]) { mV[1] = max_vec[1]; ret = TRUE; }
+ if (mV[2] > max_vec[2]) { mV[2] = max_vec[2]; ret = TRUE; }
+
+ return ret;
+}
+
// Sets all values to absolute value of their original values
// Returns TRUE if data changed
@@ -191,6 +206,28 @@ const LLVector3& LLVector3::rotVec(const LLQuaternion &q)
return *this;
}
+const LLVector3& LLVector3::transVec(const LLMatrix4& mat)
+{
+ setVec(
+ mV[VX] * mat.mMatrix[VX][VX] +
+ mV[VY] * mat.mMatrix[VX][VY] +
+ mV[VZ] * mat.mMatrix[VX][VZ] +
+ mat.mMatrix[VX][VW],
+
+ mV[VX] * mat.mMatrix[VY][VX] +
+ mV[VY] * mat.mMatrix[VY][VY] +
+ mV[VZ] * mat.mMatrix[VY][VZ] +
+ mat.mMatrix[VY][VW],
+
+ mV[VX] * mat.mMatrix[VZ][VX] +
+ mV[VY] * mat.mMatrix[VZ][VY] +
+ mV[VZ] * mat.mMatrix[VZ][VZ] +
+ mat.mMatrix[VZ][VW]);
+
+ return *this;
+}
+
+
const LLVector3& LLVector3::rotVec(F32 angle, const LLVector3 &vec)
{
if ( !vec.isExactlyZero() && angle )
diff --git a/indra/llmath/v3math.h b/indra/llmath/v3math.h
index dbd38c1c3f..0432aeba4c 100644
--- a/indra/llmath/v3math.h
+++ b/indra/llmath/v3math.h
@@ -34,6 +34,7 @@
class LLVector2;
class LLVector4;
class LLMatrix3;
+class LLMatrix4;
class LLVector3d;
class LLQuaternion;
@@ -69,6 +70,7 @@ class LLVector3
inline BOOL isFinite() const; // checks to see if all values of LLVector3 are finite
BOOL clamp(F32 min, F32 max); // Clamps all values to (min,max), returns TRUE if data changed
+ BOOL clamp(const LLVector3 &min_vec, const LLVector3 &max_vec); // Scales vector by another vector
BOOL clampLength( F32 length_limit ); // Scales vector to limit length to a value
void quantize16(F32 lowerxy, F32 upperxy, F32 lowerz, F32 upperz); // changes the vector to reflect quatization
@@ -109,6 +111,7 @@ class LLVector3
const LLVector3& rotVec(F32 angle, F32 x, F32 y, F32 z); // Rotates about x,y,z by angle radians
const LLVector3& rotVec(const LLMatrix3 &mat); // Rotates by LLMatrix4 mat
const LLVector3& rotVec(const LLQuaternion &q); // Rotates by LLQuaternion q
+ const LLVector3& transVec(const LLMatrix4& mat); // Transforms by LLMatrix4 mat (mat * v)
const LLVector3& scaleVec(const LLVector3& vec); // scales per component by vec
LLVector3 scaledVec(const LLVector3& vec) const; // get a copy of this vector scaled by vec
@@ -156,6 +159,8 @@ F32 dist_vec(const LLVector3 &a, const LLVector3 &b); // Returns distance betwe
F32 dist_vec_squared(const LLVector3 &a, const LLVector3 &b);// Returns distance squared between a and b
F32 dist_vec_squared2D(const LLVector3 &a, const LLVector3 &b);// Returns distance squared between a and b ignoring Z component
LLVector3 projected_vec(const LLVector3 &a, const LLVector3 &b); // Returns vector a projected on vector b
+LLVector3 parallel_component(const LLVector3 &a, const LLVector3 &b); // Returns vector a projected on vector b (same as projected_vec)
+LLVector3 orthogonal_component(const LLVector3 &a, const LLVector3 &b); // Returns component of vector a not parallel to vector b (same as projected_vec)
LLVector3 lerp(const LLVector3 &a, const LLVector3 &b, F32 u); // Returns a vector that is a linear interpolation between a and b
inline LLVector3::LLVector3(void)
@@ -274,7 +279,7 @@ inline void LLVector3::setVec(const F32 *vec)
inline F32 LLVector3::normalize(void)
{
- F32 mag = fsqrtf(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]);
+ F32 mag = (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]);
F32 oomag;
if (mag > FP_MAG_THRESHOLD)
@@ -297,7 +302,7 @@ inline F32 LLVector3::normalize(void)
// deprecated
inline F32 LLVector3::normVec(void)
{
- F32 mag = fsqrtf(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]);
+ F32 mag = (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]);
F32 oomag;
if (mag > FP_MAG_THRESHOLD)
@@ -321,7 +326,7 @@ inline F32 LLVector3::normVec(void)
inline F32 LLVector3::length(void) const
{
- return fsqrtf(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]);
+ return (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]);
}
inline F32 LLVector3::lengthSquared(void) const
@@ -331,7 +336,7 @@ inline F32 LLVector3::lengthSquared(void) const
inline F32 LLVector3::magVec(void) const
{
- return fsqrtf(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]);
+ return (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]);
}
inline F32 LLVector3::magVecSquared(void) const
@@ -465,7 +470,7 @@ inline F32 dist_vec(const LLVector3 &a, const LLVector3 &b)
F32 x = a.mV[0] - b.mV[0];
F32 y = a.mV[1] - b.mV[1];
F32 z = a.mV[2] - b.mV[2];
- return fsqrtf( x*x + y*y + z*z );
+ return (F32) sqrt( x*x + y*y + z*z );
}
inline F32 dist_vec_squared(const LLVector3 &a, const LLVector3 &b)
@@ -490,6 +495,17 @@ inline LLVector3 projected_vec(const LLVector3 &a, const LLVector3 &b)
return project_axis * (a * project_axis);
}
+inline LLVector3 parallel_component(const LLVector3 &a, const LLVector3 &b)
+{
+ return projected_vec(a, b);
+}
+
+inline LLVector3 orthogonal_component(const LLVector3 &a, const LLVector3 &b)
+{
+ return a - projected_vec(a, b);
+}
+
+
inline LLVector3 lerp(const LLVector3 &a, const LLVector3 &b, F32 u)
{
return LLVector3(
@@ -523,6 +539,21 @@ inline void update_min_max(LLVector3& min, LLVector3& max, const LLVector3& pos)
}
}
+inline void update_min_max(LLVector3& min, LLVector3& max, const F32* pos)
+{
+ for (U32 i = 0; i < 3; i++)
+ {
+ if (min.mV[i] > pos[i])
+ {
+ min.mV[i] = pos[i];
+ }
+ if (max.mV[i] < pos[i])
+ {
+ max.mV[i] = pos[i];
+ }
+ }
+}
+
inline F32 angle_between(const LLVector3& a, const LLVector3& b)
{
LLVector3 an = a;
diff --git a/indra/llmath/v4color.h b/indra/llmath/v4color.h
index 60d24e2e11..b047f86e6e 100644
--- a/indra/llmath/v4color.h
+++ b/indra/llmath/v4color.h
@@ -108,6 +108,7 @@ class LLColor4
const LLColor4& operator=(const LLColor3 &a); // Assigns vec3 to vec4 and returns vec4
+ bool operator<(const LLColor4& rhs) const;
friend std::ostream& operator<<(std::ostream& s, const LLColor4 &a); // Print a
friend LLColor4 operator+(const LLColor4 &a, const LLColor4 &b); // Return vector a + b
friend LLColor4 operator-(const LLColor4 &a, const LLColor4 &b); // Return vector a minus b
@@ -385,7 +386,7 @@ inline const LLColor4& LLColor4::setAlpha(F32 a)
inline F32 LLColor4::length(void) const
{
- return fsqrtf(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
+ return (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
}
inline F32 LLColor4::lengthSquared(void) const
@@ -395,7 +396,7 @@ inline F32 LLColor4::lengthSquared(void) const
inline F32 LLColor4::normalize(void)
{
- F32 mag = fsqrtf(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
+ F32 mag = (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
F32 oomag;
if (mag)
@@ -411,7 +412,7 @@ inline F32 LLColor4::normalize(void)
// deprecated
inline F32 LLColor4::magVec(void) const
{
- return fsqrtf(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
+ return (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
}
// deprecated
@@ -423,7 +424,7 @@ inline F32 LLColor4::magVecSquared(void) const
// deprecated
inline F32 LLColor4::normVec(void)
{
- F32 mag = fsqrtf(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
+ F32 mag = (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
F32 oomag;
if (mag)
@@ -589,6 +590,23 @@ inline LLColor4 lerp(const LLColor4 &a, const LLColor4 &b, F32 u)
a.mV[VW] + (b.mV[VW] - a.mV[VW]) * u);
}
+inline bool LLColor4::operator<(const LLColor4& rhs) const
+{
+ if (mV[0] != rhs.mV[0])
+ {
+ return mV[0] < rhs.mV[0];
+ }
+ if (mV[1] != rhs.mV[1])
+ {
+ return mV[1] < rhs.mV[1];
+ }
+ if (mV[2] != rhs.mV[2])
+ {
+ return mV[2] < rhs.mV[2];
+ }
+
+ return mV[3] < rhs.mV[3];
+}
void LLColor4::clamp()
{
diff --git a/indra/llmath/v4coloru.h b/indra/llmath/v4coloru.h
index 7471aebe02..12da7e2dd7 100644
--- a/indra/llmath/v4coloru.h
+++ b/indra/llmath/v4coloru.h
@@ -294,7 +294,7 @@ inline const LLColor4U& LLColor4U::setAlpha(U8 a)
inline F32 LLColor4U::length(void) const
{
- return fsqrtf( ((F32)mV[VX]) * mV[VX] + ((F32)mV[VY]) * mV[VY] + ((F32)mV[VZ]) * mV[VZ] );
+ return (F32) sqrt( ((F32)mV[VX]) * mV[VX] + ((F32)mV[VY]) * mV[VY] + ((F32)mV[VZ]) * mV[VZ] );
}
inline F32 LLColor4U::lengthSquared(void) const
@@ -305,7 +305,7 @@ inline F32 LLColor4U::lengthSquared(void) const
// deprecated
inline F32 LLColor4U::magVec(void) const
{
- return fsqrtf( ((F32)mV[VX]) * mV[VX] + ((F32)mV[VY]) * mV[VY] + ((F32)mV[VZ]) * mV[VZ] );
+ return (F32) sqrt( ((F32)mV[VX]) * mV[VX] + ((F32)mV[VY]) * mV[VY] + ((F32)mV[VZ]) * mV[VZ] );
}
// deprecated
diff --git a/indra/llmath/v4math.h b/indra/llmath/v4math.h
index e7028626f9..623c8b2003 100644
--- a/indra/llmath/v4math.h
+++ b/indra/llmath/v4math.h
@@ -315,7 +315,7 @@ inline void LLVector4::setVec(const F32 *vec)
inline F32 LLVector4::length(void) const
{
- return fsqrtf(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
+ return (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
}
inline F32 LLVector4::lengthSquared(void) const
@@ -325,7 +325,7 @@ inline F32 LLVector4::lengthSquared(void) const
inline F32 LLVector4::magVec(void) const
{
- return fsqrtf(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
+ return (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
}
inline F32 LLVector4::magVecSquared(void) const
@@ -457,7 +457,7 @@ inline LLVector4 lerp(const LLVector4 &a, const LLVector4 &b, F32 u)
inline F32 LLVector4::normalize(void)
{
- F32 mag = fsqrtf(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
+ F32 mag = (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
F32 oomag;
if (mag > FP_MAG_THRESHOLD)
@@ -480,7 +480,7 @@ inline F32 LLVector4::normalize(void)
// deprecated
inline F32 LLVector4::normVec(void)
{
- F32 mag = fsqrtf(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
+ F32 mag = (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
F32 oomag;
if (mag > FP_MAG_THRESHOLD)
diff --git a/indra/llmath/xform.h b/indra/llmath/xform.h
index 5159c1cbfe..1b50749b3e 100644
--- a/indra/llmath/xform.h
+++ b/indra/llmath/xform.h
@@ -32,11 +32,11 @@
const F32 MAX_OBJECT_Z = 4096.f; // should match REGION_HEIGHT_METERS, Pre-havok4: 768.f
const F32 MIN_OBJECT_Z = -256.f;
-const F32 DEFAULT_MAX_PRIM_SCALE = 10.f;
+const F32 DEFAULT_MAX_PRIM_SCALE = 64.f;
+const F32 DEFAULT_MAX_PRIM_SCALE_NO_MESH = 10.f;
const F32 MIN_PRIM_SCALE = 0.01f;
const F32 MAX_PRIM_SCALE = 65536.f; // something very high but not near FLT_MAX
-
class LLXform
{
protected:
diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt
index 1cad0f6d22..c5f82cf052 100644
--- a/indra/llmessage/CMakeLists.txt
+++ b/indra/llmessage/CMakeLists.txt
@@ -10,7 +10,9 @@ include(LLMath)
include(LLMessage)
include(LLVFS)
include(LLAddBuildTest)
+include(Python)
include(Tut)
+include(Python)
include_directories (${CMAKE_CURRENT_SOURCE_DIR})
diff --git a/indra/llmessage/llassetstorage.cpp b/indra/llmessage/llassetstorage.cpp
index b26d412e9f..31cdb1219b 100644
--- a/indra/llmessage/llassetstorage.cpp
+++ b/indra/llmessage/llassetstorage.cpp
@@ -398,6 +398,12 @@ BOOL LLAssetStorage::hasLocalAsset(const LLUUID &uuid, const LLAssetType::EType
bool LLAssetStorage::findInStaticVFSAndInvokeCallback(const LLUUID& uuid, LLAssetType::EType type,
LLGetAssetCallback callback, void *user_data)
{
+ if (user_data)
+ {
+ // The *user_data should not be passed without a callback to clean it up.
+ llassert(callback != NULL)
+ }
+
BOOL exists = mStaticVFS->getExists(uuid, type);
if (exists)
{
@@ -432,15 +438,26 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, LL
llinfos << "ASSET_TRACE requesting " << uuid << " type " << LLAssetType::lookup(type) << llendl;
+ if (user_data)
+ {
+ // The *user_data should not be passed without a callback to clean it up.
+ llassert(callback != NULL)
+ }
+
if (mShutDown)
{
llinfos << "ASSET_TRACE cancelled " << uuid << " type " << LLAssetType::lookup(type) << " shutting down" << llendl;
- return; // don't get the asset or do any callbacks, we are shutting down
+
+ if (callback)
+ {
+ callback(mVFS, uuid, type, user_data, LL_ERR_ASSET_REQUEST_FAILED, LL_EXSTAT_NONE);
+ }
+ return;
}
-
+
if (uuid.isNull())
{
- // Special case early out for NULL uuid
+ // Special case early out for NULL uuid and for shutting down
if (callback)
{
callback(mVFS, uuid, type, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE, LL_EXSTAT_NULL_UUID);
@@ -513,6 +530,10 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, LL
}
+//
+// *NOTE: Logic here is replicated in LLViewerAssetStorage::_queueDataRequest.
+// Changes here may need to be replicated in the viewer's derived class.
+//
void LLAssetStorage::_queueDataRequest(const LLUUID& uuid, LLAssetType::EType atype,
LLGetAssetCallback callback,
void *user_data, BOOL duplicate,
@@ -540,7 +561,7 @@ void LLAssetStorage::_queueDataRequest(const LLUUID& uuid, LLAssetType::EType at
tpvf.setAsset(uuid, atype);
tpvf.setCallback(downloadCompleteCallback, req);
- llinfos << "Starting transfer for " << uuid << llendl;
+ //llinfos << "Starting transfer for " << uuid << llendl;
LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(mUpstreamHost, LLTCT_ASSET);
ttcp->requestTransfer(spa, tpvf, 100.f + (is_priority ? 1.f : 0.f));
}
diff --git a/indra/llmessage/llavatarnamecache.cpp b/indra/llmessage/llavatarnamecache.cpp
index 2f2d9099a3..97f2792686 100644
--- a/indra/llmessage/llavatarnamecache.cpp
+++ b/indra/llmessage/llavatarnamecache.cpp
@@ -81,8 +81,11 @@ namespace LLAvatarNameCache
// only need per-frame timing resolution
LLFrameTimer sRequestTimer;
- // Periodically clean out expired entries from the cache
- //LLFrameTimer sEraseExpiredTimer;
+ /// Maximum time an unrefreshed cache entry is allowed
+ const F64 MAX_UNREFRESHED_TIME = 20.0 * 60.0;
+
+ /// Time when unrefreshed cached names were checked last
+ static F64 sLastExpireCheck;
//-----------------------------------------------------------------------
// Internal methods
@@ -99,8 +102,9 @@ namespace LLAvatarNameCache
// Legacy name system callback
void legacyNameCallback(const LLUUID& agent_id,
- const std::string& full_name,
- bool is_group);
+ const std::string& full_name,
+ bool is_group
+ );
void requestNamesViaLegacy();
@@ -117,7 +121,7 @@ namespace LLAvatarNameCache
bool isRequestPending(const LLUUID& agent_id);
// Erase expired names from cache
- void eraseExpired();
+ void eraseUnrefreshed();
bool expirationFromCacheControl(LLSD headers, F64 *expires);
}
@@ -187,6 +191,7 @@ public:
{
// Pull expiration out of headers if available
F64 expires = LLAvatarNameCache::nameExpirationFromHeaders(mHeaders);
+ F64 now = LLFrameTimer::getTotalSeconds();
LLSD agents = content["agents"];
LLSD::array_const_iterator it = agents.beginArray();
@@ -207,100 +212,91 @@ public:
av_name.mDisplayName = av_name.mUsername;
}
+ LL_DEBUGS("AvNameCache") << "LLAvatarNameResponder::result for " << agent_id << " "
+ << "user '" << av_name.mUsername << "' "
+ << "display '" << av_name.mDisplayName << "' "
+ << "expires in " << expires - now << " seconds"
+ << LL_ENDL;
+
// cache it and fire signals
LLAvatarNameCache::processName(agent_id, av_name, true);
}
// Same logic as error response case
LLSD unresolved_agents = content["bad_ids"];
- if (unresolved_agents.size() > 0)
+ S32 num_unresolved = unresolved_agents.size();
+ if (num_unresolved > 0)
{
- const std::string DUMMY_NAME("\?\?\?");
- LLAvatarName av_name;
- av_name.mUsername = DUMMY_NAME;
- av_name.mDisplayName = DUMMY_NAME;
- av_name.mIsDisplayNameDefault = false;
- av_name.mIsDummy = true;
- av_name.mExpires = expires;
-
+ LL_WARNS("AvNameCache") << "LLAvatarNameResponder::result " << num_unresolved << " unresolved ids; "
+ << "expires in " << expires - now << " seconds"
+ << LL_ENDL;
it = unresolved_agents.beginArray();
for ( ; it != unresolved_agents.endArray(); ++it)
{
const LLUUID& agent_id = *it;
- // cache it and fire signals
- LLAvatarNameCache::processName(agent_id, av_name, true);
+
+ LL_WARNS("AvNameCache") << "LLAvatarNameResponder::result "
+ << "failed id " << agent_id
+ << LL_ENDL;
+
+ LLAvatarNameCache::handleAgentError(agent_id);
}
}
- }
+ LL_DEBUGS("AvNameCache") << "LLAvatarNameResponder::result "
+ << LLAvatarNameCache::sCache.size() << " cached names"
+ << LL_ENDL;
+ }
/*virtual*/ void error(U32 status, const std::string& reason)
{
- // We're going to construct a dummy record and cache it for a while,
- // either briefly for a 503 Service Unavailable, or longer for other
- // errors.
- F64 retry_timestamp = errorRetryTimestamp(status);
-
- // *NOTE: "??" starts trigraphs in C/C++, escape the question marks.
- const std::string DUMMY_NAME("\?\?\?");
- LLAvatarName av_name;
- av_name.mUsername = DUMMY_NAME;
- av_name.mDisplayName = DUMMY_NAME;
- av_name.mIsDisplayNameDefault = false;
- av_name.mIsDummy = true;
- av_name.mExpires = retry_timestamp;
-
- // Add dummy records for all agent IDs in this request
+ // If there's an error, it might be caused by PeopleApi,
+ // or when loading textures on startup and using a very slow
+ // network, this query may time out.
+ // What we should do depends on whether or not we have a cached name
+ LL_WARNS("AvNameCache") << "LLAvatarNameResponder::error " << status << " " << reason
+ << LL_ENDL;
+
+ // Add dummy records for any agent IDs in this request that we do not have cached already
std::vector<LLUUID>::const_iterator it = mAgentIDs.begin();
for ( ; it != mAgentIDs.end(); ++it)
{
const LLUUID& agent_id = *it;
- // cache it and fire signals
- LLAvatarNameCache::processName(agent_id, av_name, true);
- }
- }
-
- // Return time to retry a request that generated an error, based on
- // error type and headers. Return value is seconds-since-epoch.
- F64 errorRetryTimestamp(S32 status)
- {
- F64 now = LLFrameTimer::getTotalSeconds();
-
- // Retry-After takes priority
- LLSD retry_after = mHeaders["retry-after"];
- if (retry_after.isDefined())
- {
- // We only support the delta-seconds type
- S32 delta_seconds = retry_after.asInteger();
- if (delta_seconds > 0)
- {
- // ...valid delta-seconds
- return now + F64(delta_seconds);
- }
- }
-
- // If no Retry-After, look for Cache-Control max-age
- F64 expires = 0.0;
- if (LLAvatarNameCache::expirationFromCacheControl(mHeaders, &expires))
- {
- return expires;
- }
-
- // No information in header, make a guess
- if (status == 503)
- {
- // ...service unavailable, retry soon
- const F64 SERVICE_UNAVAILABLE_DELAY = 600.0; // 10 min
- return now + SERVICE_UNAVAILABLE_DELAY;
- }
- else
- {
- // ...other unexpected error
- const F64 DEFAULT_DELAY = 3600.0; // 1 hour
- return now + DEFAULT_DELAY;
+ LLAvatarNameCache::handleAgentError(agent_id);
}
}
};
+// Provide some fallback for agents that return errors
+void LLAvatarNameCache::handleAgentError(const LLUUID& agent_id)
+{
+ std::map<LLUUID,LLAvatarName>::iterator existing = sCache.find(agent_id);
+ if (existing == sCache.end())
+ {
+ // there is no existing cache entry, so make a temporary name from legacy
+ LL_WARNS("AvNameCache") << "LLAvatarNameCache get legacy for agent "
+ << agent_id << LL_ENDL;
+ gCacheName->get(agent_id, false, // legacy compatibility
+ boost::bind(&LLAvatarNameCache::legacyNameCallback,
+ _1, _2, _3));
+ }
+ else
+ {
+ // we have a chached (but probably expired) entry - since that would have
+ // been returned by the get method, there is no need to signal anyone
+
+ // Clear this agent from the pending list
+ LLAvatarNameCache::sPendingQueue.erase(agent_id);
+
+ const LLAvatarName& av_name = existing->second;
+ LL_DEBUGS("AvNameCache") << "LLAvatarNameCache use cache for agent "
+ << agent_id
+ << "user '" << av_name.mUsername << "' "
+ << "display '" << av_name.mDisplayName << "' "
+ << "expires in " << av_name.mExpires - LLFrameTimer::getTotalSeconds() << " seconds"
+ << LL_ENDL;
+ }
+}
+
void LLAvatarNameCache::processName(const LLUUID& agent_id,
const LLAvatarName& av_name,
bool add_to_cache)
@@ -342,6 +338,7 @@ void LLAvatarNameCache::requestNamesViaCapability()
std::vector<LLUUID> agent_ids;
agent_ids.reserve(128);
+ U32 ids = 0;
ask_queue_t::const_iterator it = sAskQueue.begin();
for ( ; it != sAskQueue.end(); ++it)
{
@@ -352,11 +349,13 @@ void LLAvatarNameCache::requestNamesViaCapability()
// ...starting new request
url += sNameLookupURL;
url += "?ids=";
+ ids = 1;
}
else
{
// ...continuing existing request
url += "&ids=";
+ ids++;
}
url += agent_id.asString();
agent_ids.push_back(agent_id);
@@ -366,7 +365,9 @@ void LLAvatarNameCache::requestNamesViaCapability()
if (url.size() > NAME_URL_SEND_THRESHOLD)
{
- //llinfos << "requestNames " << url << llendl;
+ LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::requestNamesViaCapability first "
+ << ids << " ids"
+ << LL_ENDL;
LLHTTPClient::get(url, new LLAvatarNameResponder(agent_ids));
url.clear();
agent_ids.clear();
@@ -375,7 +376,9 @@ void LLAvatarNameCache::requestNamesViaCapability()
if (!url.empty())
{
- //llinfos << "requestNames " << url << llendl;
+ LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::requestNamesViaCapability all "
+ << ids << " ids"
+ << LL_ENDL;
LLHTTPClient::get(url, new LLAvatarNameResponder(agent_ids));
url.clear();
agent_ids.clear();
@@ -392,6 +395,11 @@ void LLAvatarNameCache::legacyNameCallback(const LLUUID& agent_id,
// Construct a dummy record for this name. By convention, SLID is blank
// Never expires, but not written to disk, so lasts until end of session.
LLAvatarName av_name;
+ LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::legacyNameCallback "
+ << "agent " << agent_id << " "
+ << "full name '" << full_name << "'"
+ << ( is_group ? " [group]" : "" )
+ << LL_ENDL;
buildLegacyName(full_name, &av_name);
// Don't add to cache, the data already exists in the legacy name system
@@ -413,6 +421,8 @@ void LLAvatarNameCache::requestNamesViaLegacy()
// invoked below. This should never happen in practice.
sPendingQueue[agent_id] = now;
+ LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::requestNamesViaLegacy agent " << agent_id << LL_ENDL;
+
gCacheName->get(agent_id, false, // legacy compatibility
boost::bind(&LLAvatarNameCache::legacyNameCallback,
_1, _2, _3));
@@ -451,21 +461,24 @@ void LLAvatarNameCache::importFile(std::istream& istr)
av_name.fromLLSD( it->second );
sCache[agent_id] = av_name;
}
- // entries may have expired since we last ran the viewer, just
- // clean them out now
- eraseExpired();
- llinfos << "loaded " << sCache.size() << llendl;
+ LL_INFOS("AvNameCache") << "loaded " << sCache.size() << LL_ENDL;
+
+ // Some entries may have expired since the cache was stored,
+ // but they will be flushed in the first call to eraseUnrefreshed
+ // from LLAvatarNameResponder::idle
}
void LLAvatarNameCache::exportFile(std::ostream& ostr)
{
LLSD agents;
+ F64 max_unrefreshed = LLFrameTimer::getTotalSeconds() - MAX_UNREFRESHED_TIME;
cache_t::const_iterator it = sCache.begin();
for ( ; it != sCache.end(); ++it)
{
const LLUUID& agent_id = it->first;
const LLAvatarName& av_name = it->second;
- if (!av_name.mIsDummy)
+ // Do not write temporary or expired entries to the stored cache
+ if (!av_name.mIsTemporaryName && av_name.mExpires >= max_unrefreshed)
{
// key must be a string
agents[agent_id.asString()] = av_name.asLLSD();
@@ -500,62 +513,65 @@ void LLAvatarNameCache::idle()
// return;
//}
- // Must be large relative to above
-
- // No longer deleting expired entries, just re-requesting in the get
- // this way first synchronous get call on an expired entry won't return
- // legacy name. LF
-
- //const F32 ERASE_EXPIRED_TIMEOUT = 60.f; // seconds
- //if (sEraseExpiredTimer.checkExpirationAndReset(ERASE_EXPIRED_TIMEOUT))
- //{
- // eraseExpired();
- //}
-
- if (sAskQueue.empty())
+ if (!sAskQueue.empty())
{
- return;
+ if (useDisplayNames())
+ {
+ requestNamesViaCapability();
+ }
+ else
+ {
+ // ...fall back to legacy name cache system
+ requestNamesViaLegacy();
+ }
}
- if (useDisplayNames())
- {
- requestNamesViaCapability();
- }
- else
- {
- // ...fall back to legacy name cache system
- requestNamesViaLegacy();
- }
+ // erase anything that has not been refreshed for more than MAX_UNREFRESHED_TIME
+ eraseUnrefreshed();
}
bool LLAvatarNameCache::isRequestPending(const LLUUID& agent_id)
{
+ bool isPending = false;
const F64 PENDING_TIMEOUT_SECS = 5.0 * 60.0;
- F64 now = LLFrameTimer::getTotalSeconds();
- F64 expire_time = now - PENDING_TIMEOUT_SECS;
pending_queue_t::const_iterator it = sPendingQueue.find(agent_id);
if (it != sPendingQueue.end())
{
- bool request_expired = (it->second < expire_time);
- return !request_expired;
+ // in the list of requests in flight, retry if too old
+ F64 expire_time = LLFrameTimer::getTotalSeconds() - PENDING_TIMEOUT_SECS;
+ isPending = (it->second > expire_time);
}
- return false;
+ return isPending;
}
-void LLAvatarNameCache::eraseExpired()
+void LLAvatarNameCache::eraseUnrefreshed()
{
F64 now = LLFrameTimer::getTotalSeconds();
- cache_t::iterator it = sCache.begin();
- while (it != sCache.end())
- {
- cache_t::iterator cur = it;
- ++it;
- const LLAvatarName& av_name = cur->second;
- if (av_name.mExpires < now)
- {
- sCache.erase(cur);
- }
+ F64 max_unrefreshed = now - MAX_UNREFRESHED_TIME;
+
+ if (!sLastExpireCheck || sLastExpireCheck < max_unrefreshed)
+ {
+ sLastExpireCheck = now;
+
+ for (cache_t::iterator it = sCache.begin(); it != sCache.end();)
+ {
+ const LLAvatarName& av_name = it->second;
+ if (av_name.mExpires < max_unrefreshed)
+ {
+ const LLUUID& agent_id = it->first;
+ LL_DEBUGS("AvNameCache") << agent_id
+ << " user '" << av_name.mUsername << "' "
+ << "expired " << now - av_name.mExpires << " secs ago"
+ << LL_ENDL;
+ sCache.erase(it++);
+ }
+ else
+ {
+ ++it;
+ }
+ }
+ LL_INFOS("AvNameCache") << sCache.size() << " cached avatar names" << LL_ENDL;
}
}
@@ -566,8 +582,11 @@ void LLAvatarNameCache::buildLegacyName(const std::string& full_name,
av_name->mUsername = "";
av_name->mDisplayName = full_name;
av_name->mIsDisplayNameDefault = true;
- av_name->mIsDummy = true;
- av_name->mExpires = F64_MAX;
+ av_name->mIsTemporaryName = true;
+ av_name->mExpires = F64_MAX; // not used because these are not cached
+ LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::buildLegacyName "
+ << full_name
+ << LL_ENDL;
}
// fills in av_name if it has it in the cache, even if expired (can check expiry time)
@@ -590,6 +609,9 @@ bool LLAvatarNameCache::get(const LLUUID& agent_id, LLAvatarName *av_name)
{
if (!isRequestPending(agent_id))
{
+ LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::get "
+ << "refresh agent " << agent_id
+ << LL_ENDL;
sAskQueue.insert(agent_id);
}
}
@@ -611,6 +633,9 @@ bool LLAvatarNameCache::get(const LLUUID& agent_id, LLAvatarName *av_name)
if (!isRequestPending(agent_id))
{
+ LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::get "
+ << "queue request for agent " << agent_id
+ << LL_ENDL;
sAskQueue.insert(agent_id);
}
@@ -643,7 +668,6 @@ void LLAvatarNameCache::get(const LLUUID& agent_id, callback_slot_t slot)
{
// ...name already exists in cache, fire callback now
fireSignal(agent_id, slot, av_name);
-
return;
}
}
@@ -739,6 +763,9 @@ F64 LLAvatarNameCache::nameExpirationFromHeaders(LLSD headers)
bool LLAvatarNameCache::expirationFromCacheControl(LLSD headers, F64 *expires)
{
+ bool fromCacheControl = false;
+ F64 now = LLFrameTimer::getTotalSeconds();
+
// Allow the header to override the default
LLSD cache_control_header = headers["cache-control"];
if (cache_control_header.isDefined())
@@ -747,12 +774,16 @@ bool LLAvatarNameCache::expirationFromCacheControl(LLSD headers, F64 *expires)
std::string cache_control = cache_control_header.asString();
if (max_age_from_cache_control(cache_control, &max_age))
{
- F64 now = LLFrameTimer::getTotalSeconds();
*expires = now + (F64)max_age;
- return true;
+ fromCacheControl = true;
}
}
- return false;
+ LL_DEBUGS("AvNameCache")
+ << ( fromCacheControl ? "expires based on cache control " : "default expiration " )
+ << "in " << *expires - now << " seconds"
+ << LL_ENDL;
+
+ return fromCacheControl;
}
diff --git a/indra/llmessage/llavatarnamecache.h b/indra/llmessage/llavatarnamecache.h
index 8f21ace96a..59c1329ffa 100644
--- a/indra/llmessage/llavatarnamecache.h
+++ b/indra/llmessage/llavatarnamecache.h
@@ -82,6 +82,9 @@ namespace LLAvatarNameCache
void erase(const LLUUID& agent_id);
+ /// Provide some fallback for agents that return errors
+ void handleAgentError(const LLUUID& agent_id);
+
// Force a re-fetch of the most recent data, but keep the current
// data in cache
void fetch(const LLUUID& agent_id);
diff --git a/indra/llmessage/llcachename.cpp b/indra/llmessage/llcachename.cpp
index 4ab6bd2438..479efabb5f 100644
--- a/indra/llmessage/llcachename.cpp
+++ b/indra/llmessage/llcachename.cpp
@@ -556,35 +556,43 @@ std::string LLCacheName::buildUsername(const std::string& full_name)
//static
std::string LLCacheName::buildLegacyName(const std::string& complete_name)
{
- // regexp doesn't play nice with unicode, chop off the display name
+ //boost::regexp was showing up in the crashreporter, so doing
+ //painfully manual parsing using substr. LF
S32 open_paren = complete_name.rfind(" (");
+ S32 close_paren = complete_name.rfind(')');
- if (open_paren == std::string::npos)
+ if (open_paren != std::string::npos &&
+ close_paren == complete_name.length()-1)
{
- return complete_name;
- }
+ S32 length = close_paren - open_paren - 2;
+ std::string legacy_name = complete_name.substr(open_paren+2, length);
+
+ if (legacy_name.length() > 0)
+ {
+ std::string cap_letter = legacy_name.substr(0, 1);
+ LLStringUtil::toUpper(cap_letter);
+ legacy_name = cap_letter + legacy_name.substr(1);
+
+ S32 separator = legacy_name.find('.');
- std::string username = complete_name.substr(open_paren);
- boost::regex complete_name_regex("( \\()([a-z0-9]+)(.[a-z]+)*(\\))");
- boost::match_results<std::string::const_iterator> name_results;
- if (!boost::regex_match(username, name_results, complete_name_regex)) return complete_name;
+ if (separator != std::string::npos)
+ {
+ std::string last_name = legacy_name.substr(separator+1);
+ legacy_name = legacy_name.substr(0, separator);
- std::string legacy_name = name_results[2];
- // capitalize the first letter
- std::string cap_letter = legacy_name.substr(0, 1);
- LLStringUtil::toUpper(cap_letter);
- legacy_name = cap_letter + legacy_name.substr(1);
+ if (last_name.length() > 0)
+ {
+ cap_letter = last_name.substr(0, 1);
+ LLStringUtil::toUpper(cap_letter);
+ legacy_name = legacy_name + " " + cap_letter + last_name.substr(1);
+ }
+ }
- if (name_results[3].matched)
- {
- std::string last_name = name_results[3];
- std::string cap_letter = last_name.substr(1, 1);
- LLStringUtil::toUpper(cap_letter);
- last_name = cap_letter + last_name.substr(2);
- legacy_name = legacy_name + " " + last_name;
+ return legacy_name;
+ }
}
- return legacy_name;
+ return complete_name;
}
// This is a little bit kludgy. LLCacheNameCallback is a slot instead of a function pointer.
@@ -967,6 +975,10 @@ void LLCacheName::Impl::processUUIDReply(LLMessageSystem* msg, bool isGroup)
if (entry->mLastName.empty())
{
full_name = cleanFullName(entry->mFirstName);
+
+ //fix what we are putting in the cache
+ entry->mFirstName = full_name;
+ entry->mLastName = "Resident";
}
else
{
diff --git a/indra/llmessage/llcircuit.cpp b/indra/llmessage/llcircuit.cpp
index 3ba2dfb104..e0410906fb 100644
--- a/indra/llmessage/llcircuit.cpp
+++ b/indra/llmessage/llcircuit.cpp
@@ -87,6 +87,7 @@ LLCircuitData::LLCircuitData(const LLHost &host, TPACKETID in_id,
mPingDelayAveraged((F32)INITIAL_PING_VALUE_MSEC),
mUnackedPacketCount(0),
mUnackedPacketBytes(0),
+ mLastPacketInTime(0.0),
mLocalEndPointID(),
mPacketsOut(0),
mPacketsIn(0),
@@ -667,6 +668,8 @@ void LLCircuitData::checkPacketInID(TPACKETID id, BOOL receive_resent)
mHighestPacketID = llmax(mHighestPacketID, id);
}
+ // Save packet arrival time
+ mLastPacketInTime = LLMessageSystem::getMessageTimeSeconds();
// Have we received anything on this circuit yet?
if (0 == mPacketsIn)
diff --git a/indra/llmessage/llcircuit.h b/indra/llmessage/llcircuit.h
index 874c0c0bee..d1c400c6a2 100644
--- a/indra/llmessage/llcircuit.h
+++ b/indra/llmessage/llcircuit.h
@@ -122,7 +122,7 @@ public:
U32 getPacketsLost() const;
TPACKETID getPacketOutID() const;
BOOL getTrusted() const;
- F32 getAgeInSeconds() const;
+ F32 getAgeInSeconds() const;
S32 getUnackedPacketCount() const { return mUnackedPacketCount; }
S32 getUnackedPacketBytes() const { return mUnackedPacketBytes; }
F64 getNextPingSendTime() const { return mNextPingSendTime; }
@@ -130,6 +130,7 @@ public:
{ return mOutOfOrderRate.meanValue(scale); }
U32 getLastPacketGap() const { return mLastPacketGap; }
LLHost getHost() const { return mHost; }
+ F64 getLastPacketInTime() const { return mLastPacketInTime; }
LLThrottleGroup &getThrottleGroup() { return mThrottles; }
@@ -248,6 +249,7 @@ protected:
S32 mUnackedPacketCount;
S32 mUnackedPacketBytes;
+ F64 mLastPacketInTime; // Time of last packet arrival
LLUUID mLocalEndPointID;
diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp
index a485fa0160..7c8b7e3584 100644
--- a/indra/llmessage/llcurl.cpp
+++ b/indra/llmessage/llcurl.cpp
@@ -49,6 +49,7 @@
#include "llstl.h"
#include "llsdserialize.h"
#include "llthread.h"
+#include "lltimer.h"
//////////////////////////////////////////////////////////////////////////////
/*
@@ -84,6 +85,26 @@ std::vector<LLMutex*> LLCurl::sSSLMutex;
std::string LLCurl::sCAPath;
std::string LLCurl::sCAFile;
+void check_curl_code(CURLcode code)
+{
+ if (code != CURLE_OK)
+ {
+ // linux appears to throw a curl error once per session for a bad initialization
+ // at a pretty random time (when enabling cookies).
+ llinfos << "curl error detected: " << curl_easy_strerror(code) << llendl;
+ }
+}
+
+void check_curl_multi_code(CURLMcode code)
+{
+ if (code != CURLM_OK)
+ {
+ // linux appears to throw a curl error once per session for a bad initialization
+ // at a pretty random time (when enabling cookies).
+ llinfos << "curl multi error detected: " << curl_multi_strerror(code) << llendl;
+ }
+}
+
//static
void LLCurl::setCAPath(const std::string& path)
{
@@ -234,7 +255,12 @@ public:
void resetState();
+ static CURL* allocEasyHandle();
+ static void releaseEasyHandle(CURL* handle);
+
private:
+ friend class LLCurl;
+
CURL* mCurlEasyHandle;
struct curl_slist* mHeaders;
@@ -249,8 +275,62 @@ private:
std::vector<char*> mStrings;
ResponderPtr mResponder;
+
+ static std::set<CURL*> sFreeHandles;
+ static std::set<CURL*> sActiveHandles;
+ static LLMutex* sHandleMutex;
};
+std::set<CURL*> LLCurl::Easy::sFreeHandles;
+std::set<CURL*> LLCurl::Easy::sActiveHandles;
+LLMutex* LLCurl::Easy::sHandleMutex = NULL;
+
+
+//static
+CURL* LLCurl::Easy::allocEasyHandle()
+{
+ CURL* ret = NULL;
+ LLMutexLock lock(sHandleMutex);
+ if (sFreeHandles.empty())
+ {
+ ret = curl_easy_init();
+ }
+ else
+ {
+ ret = *(sFreeHandles.begin());
+ sFreeHandles.erase(ret);
+ curl_easy_reset(ret);
+ }
+
+ if (ret)
+ {
+ sActiveHandles.insert(ret);
+ }
+
+ return ret;
+}
+
+//static
+void LLCurl::Easy::releaseEasyHandle(CURL* handle)
+{
+ if (!handle)
+ {
+ llerrs << "handle cannot be NULL!" << llendl;
+ }
+
+ LLMutexLock lock(sHandleMutex);
+
+ if (sActiveHandles.find(handle) != sActiveHandles.end())
+ {
+ sActiveHandles.erase(handle);
+ sFreeHandles.insert(handle);
+ }
+ else
+ {
+ llerrs << "Invalid handle." << llendl;
+ }
+}
+
LLCurl::Easy::Easy()
: mHeaders(NULL),
mCurlEasyHandle(NULL)
@@ -261,25 +341,28 @@ LLCurl::Easy::Easy()
LLCurl::Easy* LLCurl::Easy::getEasy()
{
Easy* easy = new Easy();
- easy->mCurlEasyHandle = curl_easy_init();
+ easy->mCurlEasyHandle = allocEasyHandle();
+
if (!easy->mCurlEasyHandle)
{
// this can happen if we have too many open files (fails in c-ares/ares_init.c)
- llwarns << "curl_multi_init() returned NULL! Easy handles: " << gCurlEasyCount << " Multi handles: " << gCurlMultiCount << llendl;
+ llwarns << "allocEasyHandle() returned NULL! Easy handles: " << gCurlEasyCount << " Multi handles: " << gCurlMultiCount << llendl;
delete easy;
return NULL;
}
- // set no DMS caching as default for all easy handles. This prevents them adopting a
+ // set no DNS caching as default for all easy handles. This prevents them adopting a
// multi handles cache if they are added to one.
- curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_DNS_CACHE_TIMEOUT, 0);
+ CURLcode result = curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_DNS_CACHE_TIMEOUT, 0);
+ check_curl_code(result);
+
++gCurlEasyCount;
return easy;
}
LLCurl::Easy::~Easy()
{
- curl_easy_cleanup(mCurlEasyHandle);
+ releaseEasyHandle(mCurlEasyHandle);
--gCurlEasyCount;
curl_slist_free_all(mHeaders);
for_each(mStrings.begin(), mStrings.end(), DeletePointerArray());
@@ -338,9 +421,9 @@ void LLCurl::Easy::setHeaders()
void LLCurl::Easy::getTransferInfo(LLCurl::TransferInfo* info)
{
- curl_easy_getinfo(mCurlEasyHandle, CURLINFO_SIZE_DOWNLOAD, &info->mSizeDownload);
- curl_easy_getinfo(mCurlEasyHandle, CURLINFO_TOTAL_TIME, &info->mTotalTime);
- curl_easy_getinfo(mCurlEasyHandle, CURLINFO_SPEED_DOWNLOAD, &info->mSpeedDownload);
+ check_curl_code(curl_easy_getinfo(mCurlEasyHandle, CURLINFO_SIZE_DOWNLOAD, &info->mSizeDownload));
+ check_curl_code(curl_easy_getinfo(mCurlEasyHandle, CURLINFO_TOTAL_TIME, &info->mTotalTime));
+ check_curl_code(curl_easy_getinfo(mCurlEasyHandle, CURLINFO_SPEED_DOWNLOAD, &info->mSpeedDownload));
}
U32 LLCurl::Easy::report(CURLcode code)
@@ -350,13 +433,14 @@ U32 LLCurl::Easy::report(CURLcode code)
if (code == CURLE_OK)
{
- curl_easy_getinfo(mCurlEasyHandle, CURLINFO_RESPONSE_CODE, &responseCode);
+ check_curl_code(curl_easy_getinfo(mCurlEasyHandle, CURLINFO_RESPONSE_CODE, &responseCode));
//*TODO: get reason from first line of mHeaderOutput
}
else
{
responseCode = 499;
responseReason = strerror(code) + " : " + mErrorBuffer;
+ setopt(CURLOPT_FRESH_CONNECT, TRUE);
}
if (mResponder)
@@ -372,17 +456,20 @@ U32 LLCurl::Easy::report(CURLcode code)
// Note: these all assume the caller tracks the value (i.e. keeps it persistant)
void LLCurl::Easy::setopt(CURLoption option, S32 value)
{
- curl_easy_setopt(mCurlEasyHandle, option, value);
+ CURLcode result = curl_easy_setopt(mCurlEasyHandle, option, value);
+ check_curl_code(result);
}
void LLCurl::Easy::setopt(CURLoption option, void* value)
{
- curl_easy_setopt(mCurlEasyHandle, option, value);
+ CURLcode result = curl_easy_setopt(mCurlEasyHandle, option, value);
+ check_curl_code(result);
}
void LLCurl::Easy::setopt(CURLoption option, char* value)
{
- curl_easy_setopt(mCurlEasyHandle, option, value);
+ CURLcode result = curl_easy_setopt(mCurlEasyHandle, option, value);
+ check_curl_code(result);
}
// Note: this copies the string so that the caller does not have to keep it around
@@ -391,7 +478,8 @@ void LLCurl::Easy::setoptString(CURLoption option, const std::string& value)
char* tstring = new char[value.length()+1];
strcpy(tstring, value.c_str());
mStrings.push_back(tstring);
- curl_easy_setopt(mCurlEasyHandle, option, tstring);
+ CURLcode result = curl_easy_setopt(mCurlEasyHandle, option, tstring);
+ check_curl_code(result);
}
void LLCurl::Easy::slist_append(const char* str)
@@ -443,7 +531,7 @@ void LLCurl::Easy::prepRequest(const std::string& url,
if (post) setoptString(CURLOPT_ENCODING, "");
-// setopt(CURLOPT_VERBOSE, 1); // usefull for debugging
+ //setopt(CURLOPT_VERBOSE, 1); // usefull for debugging
setopt(CURLOPT_NOSIGNAL, 1);
mOutput.reset(new LLBufferArray);
@@ -467,6 +555,9 @@ void LLCurl::Easy::prepRequest(const std::string& url,
setCA();
setopt(CURLOPT_SSL_VERIFYPEER, true);
+
+ //don't verify host name so urls with scrubbed host names will work (improves DNS performance)
+ setopt(CURLOPT_SSL_VERIFYHOST, 0);
setopt(CURLOPT_TIMEOUT, CURL_REQUEST_TIMEOUT);
setoptString(CURLOPT_URL, url);
@@ -532,6 +623,7 @@ LLCurl::Multi::Multi()
llwarns << "curl_multi_init() returned NULL! Easy handles: " << gCurlEasyCount << " Multi handles: " << gCurlMultiCount << llendl;
mCurlMultiHandle = curl_multi_init();
}
+
llassert_always(mCurlMultiHandle);
++gCurlMultiCount;
}
@@ -543,7 +635,7 @@ LLCurl::Multi::~Multi()
iter != mEasyActiveList.end(); ++iter)
{
Easy* easy = *iter;
- curl_multi_remove_handle(mCurlMultiHandle, easy->getCurlHandle());
+ check_curl_multi_code(curl_multi_remove_handle(mCurlMultiHandle, easy->getCurlHandle()));
delete easy;
}
mEasyActiveList.clear();
@@ -553,7 +645,7 @@ LLCurl::Multi::~Multi()
for_each(mEasyFreeList.begin(), mEasyFreeList.end(), DeletePointer());
mEasyFreeList.clear();
- curl_multi_cleanup(mCurlMultiHandle);
+ check_curl_multi_code(curl_multi_cleanup(mCurlMultiHandle));
--gCurlMultiCount;
}
@@ -574,8 +666,10 @@ S32 LLCurl::Multi::perform()
CURLMcode code = curl_multi_perform(mCurlMultiHandle, &q);
if (CURLM_CALL_MULTI_PERFORM != code || q == 0)
{
+ check_curl_multi_code(code);
break;
}
+
}
mQueued = q;
return q;
@@ -642,11 +736,12 @@ LLCurl::Easy* LLCurl::Multi::allocEasy()
bool LLCurl::Multi::addEasy(Easy* easy)
{
CURLMcode mcode = curl_multi_add_handle(mCurlMultiHandle, easy->getCurlHandle());
- if (mcode != CURLM_OK)
- {
- llwarns << "Curl Error: " << curl_multi_strerror(mcode) << llendl;
- return false;
- }
+ check_curl_multi_code(mcode);
+ //if (mcode != CURLM_OK)
+ //{
+ // llwarns << "Curl Error: " << curl_multi_strerror(mcode) << llendl;
+ // return false;
+ //}
return true;
}
@@ -667,22 +762,14 @@ void LLCurl::Multi::easyFree(Easy* easy)
void LLCurl::Multi::removeEasy(Easy* easy)
{
- curl_multi_remove_handle(mCurlMultiHandle, easy->getCurlHandle());
+ check_curl_multi_code(curl_multi_remove_handle(mCurlMultiHandle, easy->getCurlHandle()));
easyFree(easy);
}
//static
std::string LLCurl::strerror(CURLcode errorcode)
{
-#if LL_DARWIN
- // curl_easy_strerror was added in libcurl 7.12.0. Unfortunately, the version in the Mac OS X 10.3.9 SDK is 7.10.2...
- // There's a problem with the custom curl headers in our build that keeps me from #ifdefing this on the libcurl version number
- // (the correct check would be #if LIBCURL_VERSION_NUM >= 0x070c00). We'll fix the header problem soon, but for now
- // just punt and print the numeric error code on the Mac.
- return llformat("%d", errorcode);
-#else // LL_DARWIN
return std::string(curl_easy_strerror(errorcode));
-#endif // LL_DARWIN
}
////////////////////////////////////////////////////////////////////////////
@@ -694,6 +781,7 @@ LLCurlRequest::LLCurlRequest() :
mActiveRequestCount(0)
{
mThreadID = LLThread::currentID();
+ mProcessing = FALSE;
}
LLCurlRequest::~LLCurlRequest()
@@ -728,6 +816,11 @@ LLCurl::Easy* LLCurlRequest::allocEasy()
bool LLCurlRequest::addEasy(LLCurl::Easy* easy)
{
llassert_always(mActiveMulti);
+
+ if (mProcessing)
+ {
+ llerrs << "Posting to a LLCurlRequest instance from within a responder is not allowed (causes DNS timeouts)." << llendl;
+ }
bool res = mActiveMulti->addEasy(easy);
return res;
}
@@ -785,12 +878,41 @@ bool LLCurlRequest::post(const std::string& url,
bool res = addEasy(easy);
return res;
}
+
+bool LLCurlRequest::post(const std::string& url,
+ const headers_t& headers,
+ const std::string& data,
+ LLCurl::ResponderPtr responder)
+{
+ LLCurl::Easy* easy = allocEasy();
+ if (!easy)
+ {
+ return false;
+ }
+ easy->prepRequest(url, headers, responder);
+
+ easy->getInput().write(data.data(), data.size());
+ S32 bytes = easy->getInput().str().length();
+ easy->setopt(CURLOPT_POST, 1);
+ easy->setopt(CURLOPT_POSTFIELDS, (void*)NULL);
+ easy->setopt(CURLOPT_POSTFIELDSIZE, bytes);
+
+ easy->slist_append("Content-Type: application/octet-stream");
+ easy->setHeaders();
+
+ lldebugs << "POSTING: " << bytes << " bytes." << llendl;
+ bool res = addEasy(easy);
+ return res;
+}
+
// Note: call once per frame
S32 LLCurlRequest::process()
{
llassert_always(mThreadID == LLThread::currentID());
S32 res = 0;
+
+ mProcessing = TRUE;
for (curlmulti_set_t::iterator iter = mMultiSet.begin();
iter != mMultiSet.end(); )
{
@@ -804,6 +926,7 @@ S32 LLCurlRequest::process()
delete multi;
}
}
+ mProcessing = FALSE;
return res;
}
@@ -1033,8 +1156,12 @@ void LLCurl::initClass()
// Do not change this "unless you are familiar with and mean to control
// internal operations of libcurl"
// - http://curl.haxx.se/libcurl/c/curl_global_init.html
- curl_global_init(CURL_GLOBAL_ALL);
+ CURLcode code = curl_global_init(CURL_GLOBAL_ALL);
+
+ check_curl_code(code);
+ Easy::sHandleMutex = new LLMutex(NULL);
+
#if SAFE_SSL
S32 mutex_count = CRYPTO_num_locks();
for (S32 i=0; i<mutex_count; i++)
@@ -1052,7 +1179,19 @@ void LLCurl::cleanupClass()
CRYPTO_set_locking_callback(NULL);
for_each(sSSLMutex.begin(), sSSLMutex.end(), DeletePointer());
#endif
- curl_global_cleanup();
+
+ delete Easy::sHandleMutex;
+ Easy::sHandleMutex = NULL;
+
+ for (std::set<CURL*>::iterator iter = Easy::sFreeHandles.begin(); iter != Easy::sFreeHandles.end(); ++iter)
+ {
+ CURL* curl = *iter;
+ curl_easy_cleanup(curl);
+ }
+
+ Easy::sFreeHandles.clear();
+
+ llassert(Easy::sActiveHandles.empty());
}
const unsigned int LLCurl::MAX_REDIRECTS = 5;
diff --git a/indra/llmessage/llcurl.h b/indra/llmessage/llcurl.h
index 64dadd6640..4ce3fa1078 100644
--- a/indra/llmessage/llcurl.h
+++ b/indra/llmessage/llcurl.h
@@ -202,6 +202,8 @@ public:
void get(const std::string& url, LLCurl::ResponderPtr responder);
bool getByteRange(const std::string& url, const headers_t& headers, S32 offset, S32 length, LLCurl::ResponderPtr responder);
bool post(const std::string& url, const headers_t& headers, const LLSD& data, LLCurl::ResponderPtr responder);
+ bool post(const std::string& url, const headers_t& headers, const std::string& data, LLCurl::ResponderPtr responder);
+
S32 process();
S32 getQueued();
@@ -215,6 +217,7 @@ private:
curlmulti_set_t mMultiSet;
LLCurl::Multi* mActiveMulti;
S32 mActiveRequestCount;
+ BOOL mProcessing;
U32 mThreadID; // debug
};
diff --git a/indra/llmessage/llhttpassetstorage.cpp b/indra/llmessage/llhttpassetstorage.cpp
index 9ea2ff4153..5a38b7fd9f 100644
--- a/indra/llmessage/llhttpassetstorage.cpp
+++ b/indra/llmessage/llhttpassetstorage.cpp
@@ -174,8 +174,8 @@ LLSD LLHTTPAssetRequest::getFullDetails() const
double curl_total_time = -1.0f;
double curl_size_upload = -1.0f;
double curl_size_download = -1.0f;
- long curl_content_length_upload = -1;
- long curl_content_length_download = -1;
+ double curl_content_length_upload = -1.0f;
+ double curl_content_length_download = -1.0f;
long curl_request_size = -1;
const char* curl_content_type = NULL;
@@ -194,8 +194,8 @@ LLSD LLHTTPAssetRequest::getFullDetails() const
sd["curl_total_time"] = curl_total_time;
sd["curl_size_upload"] = curl_size_upload;
sd["curl_size_download"] = curl_size_download;
- sd["curl_content_length_upload"] = (int) curl_content_length_upload;
- sd["curl_content_length_download"] = (int) curl_content_length_download;
+ sd["curl_content_length_upload"] = curl_content_length_upload;
+ sd["curl_content_length_download"] = curl_content_length_download;
sd["curl_request_size"] = (int) curl_request_size;
if (curl_content_type)
{
diff --git a/indra/llmessage/llregionflags.h b/indra/llmessage/llregionflags.h
index b9b974ec4f..7b796a0fa8 100644
--- a/indra/llmessage/llregionflags.h
+++ b/indra/llmessage/llregionflags.h
@@ -42,9 +42,6 @@ const U32 REGION_FLAGS_RESET_HOME_ON_TELEPORT = (1 << 3);
// Does the sun move?
const U32 REGION_FLAGS_SUN_FIXED = (1 << 4);
-// Tax free zone (no taxes on objects, land, etc.)
-const U32 REGION_FLAGS_TAX_FREE = (1 << 5);
-
// Can't change the terrain heightfield, even on owned parcels,
// but can plant trees and grass.
const U32 REGION_FLAGS_BLOCK_TERRAFORM = (1 << 6);
@@ -54,17 +51,12 @@ const U32 REGION_FLAGS_BLOCK_LAND_RESELL = (1 << 7);
// All content wiped once per night
const U32 REGION_FLAGS_SANDBOX = (1 << 8);
-const U32 REGION_FLAGS_NULL_LAYER = (1 << 9);
-// const U32 REGION_FLAGS_SKIP_AGENT_ACTION = (1 << 10);
-const U32 REGION_FLAGS_HARD_ALLOW_LAND_TRANSFER = (1 << 10); // Region allows land reselling
-// const U32 REGION_FLAGS_SKIP_UPDATE_INTEREST_LIST= (1 << 11);
-const U32 REGION_FLAGS_HARD_ALLOW_POST_CLASSIFIED = (1 << 11); // Region allows posting of classified ads
const U32 REGION_FLAGS_SKIP_COLLISIONS = (1 << 12); // Pin all non agent rigid bodies
const U32 REGION_FLAGS_SKIP_SCRIPTS = (1 << 13);
const U32 REGION_FLAGS_SKIP_PHYSICS = (1 << 14); // Skip all physics
const U32 REGION_FLAGS_EXTERNALLY_VISIBLE = (1 << 15);
-//const U32 REGION_FLAGS_MAINLAND_VISIBLE = (1 << 16);
-const U32 REGION_FLAGS_PUBLIC_ALLOWED = (1 << 17);
+const U32 REGION_FLAGS_ALLOW_RETURN_ENCROACHING_OBJECT = (1 << 16);
+const U32 REGION_FLAGS_ALLOW_RETURN_ENCROACHING_ESTATE_OBJECT = (1 << 17);
const U32 REGION_FLAGS_BLOCK_DWELL = (1 << 18);
// Is flight allowed?
@@ -81,18 +73,13 @@ const U32 REGION_FLAGS_ESTATE_SKIP_SCRIPTS = (1 << 21);
const U32 REGION_FLAGS_RESTRICT_PUSHOBJECT = (1 << 22);
const U32 REGION_FLAGS_DENY_ANONYMOUS = (1 << 23);
-// const U32 REGION_FLAGS_DENY_IDENTIFIED = (1 << 24);
-// const U32 REGION_FLAGS_DENY_TRANSACTED = (1 << 25);
const U32 REGION_FLAGS_ALLOW_PARCEL_CHANGES = (1 << 26);
-// const U32 REGION_FLAGS_ABUSE_EMAIL_TO_ESTATE_OWNER = (1 << 27); // We no longer support ELAR
-
const U32 REGION_FLAGS_ALLOW_VOICE = (1 << 28);
const U32 REGION_FLAGS_BLOCK_PARCEL_SEARCH = (1 << 29);
const U32 REGION_FLAGS_DENY_AGEUNVERIFIED = (1 << 30);
-const U32 REGION_FLAGS_SKIP_MONO_SCRIPTS = (1 << 31);
const U32 REGION_FLAGS_DEFAULT = REGION_FLAGS_ALLOW_LANDMARK |
REGION_FLAGS_ALLOW_SET_HOME |
@@ -105,7 +92,6 @@ const U32 REGION_FLAGS_PRELUDE_UNSET = REGION_FLAGS_ALLOW_LANDMARK
| REGION_FLAGS_ALLOW_SET_HOME;
const U32 REGION_FLAGS_ESTATE_MASK = REGION_FLAGS_EXTERNALLY_VISIBLE
- | REGION_FLAGS_PUBLIC_ALLOWED
| REGION_FLAGS_SUN_FIXED
| REGION_FLAGS_DENY_ANONYMOUS
| REGION_FLAGS_DENY_AGEUNVERIFIED;
diff --git a/indra/llmessage/llsdmessagebuilder.cpp b/indra/llmessage/llsdmessagebuilder.cpp
index 42c179782f..2698a271ee 100644
--- a/indra/llmessage/llsdmessagebuilder.cpp
+++ b/indra/llmessage/llsdmessagebuilder.cpp
@@ -29,6 +29,7 @@
#include "llsdmessagebuilder.h"
#include "llmessagetemplate.h"
+#include "llmath.h"
#include "llquaternion.h"
#include "llsdutil.h"
#include "llsdutil_math.h"
diff --git a/indra/llmessage/lltemplatemessagebuilder.cpp b/indra/llmessage/lltemplatemessagebuilder.cpp
index 6611d704e6..9e8eb48460 100644
--- a/indra/llmessage/lltemplatemessagebuilder.cpp
+++ b/indra/llmessage/lltemplatemessagebuilder.cpp
@@ -29,6 +29,7 @@
#include "lltemplatemessagebuilder.h"
#include "llmessagetemplate.h"
+#include "llmath.h"
#include "llquaternion.h"
#include "u64.h"
#include "v3dmath.h"
diff --git a/indra/llmessage/lltemplatemessagereader.cpp b/indra/llmessage/lltemplatemessagereader.cpp
index 3bfcd58c69..f470e1b2a5 100644
--- a/indra/llmessage/lltemplatemessagereader.cpp
+++ b/indra/llmessage/lltemplatemessagereader.cpp
@@ -30,6 +30,7 @@
#include "llfasttimer.h"
#include "llmessagebuilder.h"
#include "llmessagetemplate.h"
+#include "llmath.h"
#include "llquaternion.h"
#include "message.h"
#include "u64.h"
diff --git a/indra/llmessage/lltransfermanager.cpp b/indra/llmessage/lltransfermanager.cpp
index 754eb99cbd..034680caf8 100644
--- a/indra/llmessage/lltransfermanager.cpp
+++ b/indra/llmessage/lltransfermanager.cpp
@@ -338,7 +338,7 @@ void LLTransferManager::processTransferInfo(LLMessageSystem *msgp, void **)
}
}
- llinfos << "Receiving " << transfer_id << ", size " << size << " bytes" << llendl;
+ //llinfos << "Receiving " << transfer_id << ", size " << size << " bytes" << llendl;
ttp->setSize(size);
ttp->setGotInfo(TRUE);
diff --git a/indra/llmessage/lltransfersourceasset.cpp b/indra/llmessage/lltransfersourceasset.cpp
index 7e57841580..8537773a3f 100644
--- a/indra/llmessage/lltransfersourceasset.cpp
+++ b/indra/llmessage/lltransfersourceasset.cpp
@@ -251,3 +251,4 @@ BOOL LLTransferSourceParamsAsset::unpackParams(LLDataPacker &dp)
return TRUE;
}
+
diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp
index cb9d1c3731..28bd09fc4c 100644
--- a/indra/llmessage/llurlrequest.cpp
+++ b/indra/llmessage/llurlrequest.cpp
@@ -440,6 +440,9 @@ bool LLURLRequest::configure()
case HTTP_GET:
mDetail->mCurlRequest->setopt(CURLOPT_HTTPGET, 1);
mDetail->mCurlRequest->setopt(CURLOPT_FOLLOWLOCATION, 1);
+
+ // Set Accept-Encoding to allow response compression
+ mDetail->mCurlRequest->setoptString(CURLOPT_ENCODING, "");
rv = true;
break;
@@ -464,6 +467,9 @@ bool LLURLRequest::configure()
// Set the handle for an http post
mDetail->mCurlRequest->setPost(NULL, bytes);
+
+ // Set Accept-Encoding to allow response compression
+ mDetail->mCurlRequest->setoptString(CURLOPT_ENCODING, "");
rv = true;
break;
diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp
index 2f0d815be5..d0b0e178b8 100644
--- a/indra/llmessage/message.cpp
+++ b/indra/llmessage/message.cpp
@@ -2441,12 +2441,12 @@ void dump_prehash_files()
" * Generated from message template version number %.3f\n"
" */\n",
gMessageSystem->mMessageFileVersionNumber);
- fprintf(fp, "\n\nextern F32 gPrehashVersionNumber;\n\n");
+ fprintf(fp, "\n\nextern F32 const gPrehashVersionNumber;\n\n");
for (i = 0; i < MESSAGE_NUMBER_OF_HASH_BUCKETS; i++)
{
if (!LLMessageStringTable::getInstance()->mEmpty[i] && LLMessageStringTable::getInstance()->mString[i][0] != '.')
{
- fprintf(fp, "extern char * _PREHASH_%s;\n", LLMessageStringTable::getInstance()->mString[i]);
+ fprintf(fp, "extern char const* const _PREHASH_%s;\n", LLMessageStringTable::getInstance()->mString[i]);
}
}
fprintf(fp, "\n\n#endif\n");
@@ -2471,12 +2471,12 @@ void dump_prehash_files()
gMessageSystem->mMessageFileVersionNumber);
fprintf(fp, "#include \"linden_common.h\"\n");
fprintf(fp, "#include \"message.h\"\n\n");
- fprintf(fp, "\n\nF32 gPrehashVersionNumber = %.3ff;\n\n", gMessageSystem->mMessageFileVersionNumber);
+ fprintf(fp, "\n\nF32 const gPrehashVersionNumber = %.3ff;\n\n", gMessageSystem->mMessageFileVersionNumber);
for (i = 0; i < MESSAGE_NUMBER_OF_HASH_BUCKETS; i++)
{
if (!LLMessageStringTable::getInstance()->mEmpty[i] && LLMessageStringTable::getInstance()->mString[i][0] != '.')
{
- fprintf(fp, "char * _PREHASH_%s = LLMessageStringTable::getInstance()->getString(\"%s\");\n", LLMessageStringTable::getInstance()->mString[i], LLMessageStringTable::getInstance()->mString[i]);
+ fprintf(fp, "char const* const _PREHASH_%s = LLMessageStringTable::getInstance()->getString(\"%s\");\n", LLMessageStringTable::getInstance()->mString[i], LLMessageStringTable::getInstance()->mString[i]);
}
}
fclose(fp);
diff --git a/indra/llmessage/message_prehash.cpp b/indra/llmessage/message_prehash.cpp
index eb1e366149..5d03615e53 100644
--- a/indra/llmessage/message_prehash.cpp
+++ b/indra/llmessage/message_prehash.cpp
@@ -32,1346 +32,1346 @@
-F32 gPrehashVersionNumber = 2.000f;
+F32 const gPrehashVersionNumber = 2.000f;
-char* _PREHASH_X = LLMessageStringTable::getInstance()->getString("X");
-char* _PREHASH_Y = LLMessageStringTable::getInstance()->getString("Y");
-char* _PREHASH_Z = LLMessageStringTable::getInstance()->getString("Z");
-char* _PREHASH_AddFlags = LLMessageStringTable::getInstance()->getString("AddFlags");
-char* _PREHASH_FailureInfo = LLMessageStringTable::getInstance()->getString("FailureInfo");
-char* _PREHASH_MapData = LLMessageStringTable::getInstance()->getString("MapData");
-char* _PREHASH_AddItem = LLMessageStringTable::getInstance()->getString("AddItem");
-char* _PREHASH_MeanCollision = LLMessageStringTable::getInstance()->getString("MeanCollision");
-char* _PREHASH_RezScript = LLMessageStringTable::getInstance()->getString("RezScript");
-char* _PREHASH_AvatarSitResponse = LLMessageStringTable::getInstance()->getString("AvatarSitResponse");
-char* _PREHASH_InventoryAssetResponse = LLMessageStringTable::getInstance()->getString("InventoryAssetResponse");
-char* _PREHASH_KillObject = LLMessageStringTable::getInstance()->getString("KillObject");
-char* _PREHASH_ProposalID = LLMessageStringTable::getInstance()->getString("ProposalID");
-char* _PREHASH_SerialNum = LLMessageStringTable::getInstance()->getString("SerialNum");
-char* _PREHASH_Duration = LLMessageStringTable::getInstance()->getString("Duration");
-char* _PREHASH_ScriptQuestion = LLMessageStringTable::getInstance()->getString("ScriptQuestion");
-char* _PREHASH_AddCircuitCode = LLMessageStringTable::getInstance()->getString("AddCircuitCode");
-char* _PREHASH_UseCircuitCode = LLMessageStringTable::getInstance()->getString("UseCircuitCode");
-char* _PREHASH_ViewerCircuitCode = LLMessageStringTable::getInstance()->getString("ViewerCircuitCode");
-char* _PREHASH_ScriptAnswerYes = LLMessageStringTable::getInstance()->getString("ScriptAnswerYes");
-char* _PREHASH_PartnerID = LLMessageStringTable::getInstance()->getString("PartnerID");
-char* _PREHASH_DirLandQuery = LLMessageStringTable::getInstance()->getString("DirLandQuery");
-char* _PREHASH_TeleportStart = LLMessageStringTable::getInstance()->getString("TeleportStart");
-char* _PREHASH_AboutText = LLMessageStringTable::getInstance()->getString("AboutText");
-char* _PREHASH_VisualParam = LLMessageStringTable::getInstance()->getString("VisualParam");
-char* _PREHASH_GroupPrims = LLMessageStringTable::getInstance()->getString("GroupPrims");
-char* _PREHASH_SelectedPrims = LLMessageStringTable::getInstance()->getString("SelectedPrims");
-char* _PREHASH_ID = LLMessageStringTable::getInstance()->getString("ID");
-char* _PREHASH_UUIDNameRequest = LLMessageStringTable::getInstance()->getString("UUIDNameRequest");
-char* _PREHASH_UUIDGroupNameRequest = LLMessageStringTable::getInstance()->getString("UUIDGroupNameRequest");
-char* _PREHASH_GroupAccountTransactionsRequest = LLMessageStringTable::getInstance()->getString("GroupAccountTransactionsRequest");
-char* _PREHASH_MapNameRequest = LLMessageStringTable::getInstance()->getString("MapNameRequest");
-char* _PREHASH_UpdateSimulator = LLMessageStringTable::getInstance()->getString("UpdateSimulator");
-char* _PREHASH_BillableFactor = LLMessageStringTable::getInstance()->getString("BillableFactor");
-char* _PREHASH_ObjectBonusFactor = LLMessageStringTable::getInstance()->getString("ObjectBonusFactor");
-char* _PREHASH_EnableSimulator = LLMessageStringTable::getInstance()->getString("EnableSimulator");
-char* _PREHASH_DisableSimulator = LLMessageStringTable::getInstance()->getString("DisableSimulator");
-char* _PREHASH_ConfirmEnableSimulator = LLMessageStringTable::getInstance()->getString("ConfirmEnableSimulator");
-char* _PREHASH_LayerType = LLMessageStringTable::getInstance()->getString("LayerType");
-char* _PREHASH_OwnerRole = LLMessageStringTable::getInstance()->getString("OwnerRole");
-char* _PREHASH_ParcelOverlay = LLMessageStringTable::getInstance()->getString("ParcelOverlay");
-char* _PREHASH_GroupOwned = LLMessageStringTable::getInstance()->getString("GroupOwned");
-char* _PREHASH_IP = LLMessageStringTable::getInstance()->getString("IP");
-char* _PREHASH_ChatFromViewer = LLMessageStringTable::getInstance()->getString("ChatFromViewer");
-char* _PREHASH_AvgAgentsInView = LLMessageStringTable::getInstance()->getString("AvgAgentsInView");
-char* _PREHASH_AgentsInView = LLMessageStringTable::getInstance()->getString("AgentsInView");
-char* _PREHASH_GroupTitle = LLMessageStringTable::getInstance()->getString("GroupTitle");
-char* _PREHASH_MapLayerReply = LLMessageStringTable::getInstance()->getString("MapLayerReply");
-char* _PREHASH_CompoundMsgID = LLMessageStringTable::getInstance()->getString("CompoundMsgID");
-char* _PREHASH_CameraConstraint = LLMessageStringTable::getInstance()->getString("CameraConstraint");
-char* _PREHASH_DownloadTotals = LLMessageStringTable::getInstance()->getString("DownloadTotals");
-char* _PREHASH_GenCounter = LLMessageStringTable::getInstance()->getString("GenCounter");
-char* _PREHASH_FrozenData = LLMessageStringTable::getInstance()->getString("FrozenData");
-char* _PREHASH_ChildAgentDying = LLMessageStringTable::getInstance()->getString("ChildAgentDying");
-char* _PREHASH_To = LLMessageStringTable::getInstance()->getString("To");
-char* _PREHASH_CopyInventoryFromNotecard = LLMessageStringTable::getInstance()->getString("CopyInventoryFromNotecard");
-char* _PREHASH_RezObjectFromNotecard = LLMessageStringTable::getInstance()->getString("RezObjectFromNotecard");
-char* _PREHASH_ParcelDirFeeCurrent = LLMessageStringTable::getInstance()->getString("ParcelDirFeeCurrent");
-char* _PREHASH_SeedCapability = LLMessageStringTable::getInstance()->getString("SeedCapability");
-char* _PREHASH_ObjectDuplicate = LLMessageStringTable::getInstance()->getString("ObjectDuplicate");
-char* _PREHASH_InventoryData = LLMessageStringTable::getInstance()->getString("InventoryData");
-char* _PREHASH_ReplyData = LLMessageStringTable::getInstance()->getString("ReplyData");
-char* _PREHASH_ResetList = LLMessageStringTable::getInstance()->getString("ResetList");
-char* _PREHASH_MediaID = LLMessageStringTable::getInstance()->getString("MediaID");
-char* _PREHASH_RelatedRights = LLMessageStringTable::getInstance()->getString("RelatedRights");
-char* _PREHASH_RedirectGridX = LLMessageStringTable::getInstance()->getString("RedirectGridX");
-char* _PREHASH_RedirectGridY = LLMessageStringTable::getInstance()->getString("RedirectGridY");
-char* _PREHASH_TransferID = LLMessageStringTable::getInstance()->getString("TransferID");
-char* _PREHASH_TexturesChanged = LLMessageStringTable::getInstance()->getString("TexturesChanged");
-char* _PREHASH_UserLookAt = LLMessageStringTable::getInstance()->getString("UserLookAt");
-char* _PREHASH_TestBlock1 = LLMessageStringTable::getInstance()->getString("TestBlock1");
-char* _PREHASH_SensedData = LLMessageStringTable::getInstance()->getString("SensedData");
-char* _PREHASH_UpdateBlock = LLMessageStringTable::getInstance()->getString("UpdateBlock");
-char* _PREHASH_ClassifiedGodDelete = LLMessageStringTable::getInstance()->getString("ClassifiedGodDelete");
-char* _PREHASH_ObjectGrabUpdate = LLMessageStringTable::getInstance()->getString("ObjectGrabUpdate");
-char* _PREHASH_LocationPos = LLMessageStringTable::getInstance()->getString("LocationPos");
-char* _PREHASH_TaxDate = LLMessageStringTable::getInstance()->getString("TaxDate");
-char* _PREHASH_StartDateTime = LLMessageStringTable::getInstance()->getString("StartDateTime");
-char* _PREHASH_ObjectUpdateCached = LLMessageStringTable::getInstance()->getString("ObjectUpdateCached");
-char* _PREHASH_Packets = LLMessageStringTable::getInstance()->getString("Packets");
-char* _PREHASH_FailureType = LLMessageStringTable::getInstance()->getString("FailureType");
-char* _PREHASH_UpdateGroupInfo = LLMessageStringTable::getInstance()->getString("UpdateGroupInfo");
-char* _PREHASH_ObjectPermissions = LLMessageStringTable::getInstance()->getString("ObjectPermissions");
-char* _PREHASH_RevokePermissions = LLMessageStringTable::getInstance()->getString("RevokePermissions");
-char* _PREHASH_UpdateFlags = LLMessageStringTable::getInstance()->getString("UpdateFlags");
-char* _PREHASH_ObjectExportSelected = LLMessageStringTable::getInstance()->getString("ObjectExportSelected");
-char* _PREHASH_RezSelected = LLMessageStringTable::getInstance()->getString("RezSelected");
-char* _PREHASH_AutoPilot = LLMessageStringTable::getInstance()->getString("AutoPilot");
-char* _PREHASH_UpdateMuteListEntry = LLMessageStringTable::getInstance()->getString("UpdateMuteListEntry");
-char* _PREHASH_RemoveMuteListEntry = LLMessageStringTable::getInstance()->getString("RemoveMuteListEntry");
-char* _PREHASH_SetSimStatusInDatabase = LLMessageStringTable::getInstance()->getString("SetSimStatusInDatabase");
-char* _PREHASH_SetSimPresenceInDatabase = LLMessageStringTable::getInstance()->getString("SetSimPresenceInDatabase");
-char* _PREHASH_CameraProperty = LLMessageStringTable::getInstance()->getString("CameraProperty");
-char* _PREHASH_BrushSize = LLMessageStringTable::getInstance()->getString("BrushSize");
-char* _PREHASH_SimulatorSetMap = LLMessageStringTable::getInstance()->getString("SimulatorSetMap");
-char* _PREHASH_RegionPresenceRequestByRegionID = LLMessageStringTable::getInstance()->getString("RegionPresenceRequestByRegionID");
-char* _PREHASH_ParcelObjectOwnersReply = LLMessageStringTable::getInstance()->getString("ParcelObjectOwnersReply");
-char* _PREHASH_GroupMembersReply = LLMessageStringTable::getInstance()->getString("GroupMembersReply");
-char* _PREHASH_GroupRoleMembersReply = LLMessageStringTable::getInstance()->getString("GroupRoleMembersReply");
-char* _PREHASH_RequestRegionInfo = LLMessageStringTable::getInstance()->getString("RequestRegionInfo");
-char* _PREHASH_AABBMax = LLMessageStringTable::getInstance()->getString("AABBMax");
-char* _PREHASH_RequestPayPrice = LLMessageStringTable::getInstance()->getString("RequestPayPrice");
-char* _PREHASH_SimulatorPresentAtLocation = LLMessageStringTable::getInstance()->getString("SimulatorPresentAtLocation");
-char* _PREHASH_AgentRequestSit = LLMessageStringTable::getInstance()->getString("AgentRequestSit");
-char* _PREHASH_AABBMin = LLMessageStringTable::getInstance()->getString("AABBMin");
-char* _PREHASH_ClassifiedFlags = LLMessageStringTable::getInstance()->getString("ClassifiedFlags");
-char* _PREHASH_ControlFlags = LLMessageStringTable::getInstance()->getString("ControlFlags");
-char* _PREHASH_TeleportRequest = LLMessageStringTable::getInstance()->getString("TeleportRequest");
-char* _PREHASH_ScriptTeleportRequest = LLMessageStringTable::getInstance()->getString("ScriptTeleportRequest");
-char* _PREHASH_EstateCovenantRequest = LLMessageStringTable::getInstance()->getString("EstateCovenantRequest");
-char* _PREHASH_DateUTC = LLMessageStringTable::getInstance()->getString("DateUTC");
-char* _PREHASH_TaskIDs = LLMessageStringTable::getInstance()->getString("TaskIDs");
-char* _PREHASH_RequestResult = LLMessageStringTable::getInstance()->getString("RequestResult");
-char* _PREHASH_CanAcceptAgents = LLMessageStringTable::getInstance()->getString("CanAcceptAgents");
-char* _PREHASH_ObjectSaleInfo = LLMessageStringTable::getInstance()->getString("ObjectSaleInfo");
-char* _PREHASH_KillChildAgents = LLMessageStringTable::getInstance()->getString("KillChildAgents");
-char* _PREHASH_Balance = LLMessageStringTable::getInstance()->getString("Balance");
-char* _PREHASH_DerezContainer = LLMessageStringTable::getInstance()->getString("DerezContainer");
-char* _PREHASH_ObjectData = LLMessageStringTable::getInstance()->getString("ObjectData");
-char* _PREHASH_CameraAtAxis = LLMessageStringTable::getInstance()->getString("CameraAtAxis");
-char* _PREHASH_InfoBlock = LLMessageStringTable::getInstance()->getString("InfoBlock");
-char* _PREHASH_OwnershipCost = LLMessageStringTable::getInstance()->getString("OwnershipCost");
-char* _PREHASH_AvatarNotesUpdate = LLMessageStringTable::getInstance()->getString("AvatarNotesUpdate");
-char* _PREHASH_PID = LLMessageStringTable::getInstance()->getString("PID");
-char* _PREHASH_DirPopularReply = LLMessageStringTable::getInstance()->getString("DirPopularReply");
-char* _PREHASH_TerrainHeightRange00 = LLMessageStringTable::getInstance()->getString("TerrainHeightRange00");
-char* _PREHASH_SimData = LLMessageStringTable::getInstance()->getString("SimData");
-char* _PREHASH_TerrainHeightRange01 = LLMessageStringTable::getInstance()->getString("TerrainHeightRange01");
-char* _PREHASH_TerrainHeightRange10 = LLMessageStringTable::getInstance()->getString("TerrainHeightRange10");
-char* _PREHASH_TerrainHeightRange11 = LLMessageStringTable::getInstance()->getString("TerrainHeightRange11");
-char* _PREHASH_UpdateInventoryItem = LLMessageStringTable::getInstance()->getString("UpdateInventoryItem");
-char* _PREHASH_UpdateCreateInventoryItem = LLMessageStringTable::getInstance()->getString("UpdateCreateInventoryItem");
-char* _PREHASH_MoveInventoryItem = LLMessageStringTable::getInstance()->getString("MoveInventoryItem");
-char* _PREHASH_CopyInventoryItem = LLMessageStringTable::getInstance()->getString("CopyInventoryItem");
-char* _PREHASH_LinkInventoryItem = LLMessageStringTable::getInstance()->getString("LinkInventoryItem");
-char* _PREHASH_RemoveInventoryItem = LLMessageStringTable::getInstance()->getString("RemoveInventoryItem");
-char* _PREHASH_CreateInventoryItem = LLMessageStringTable::getInstance()->getString("CreateInventoryItem");
-char* _PREHASH_PathTwistBegin = LLMessageStringTable::getInstance()->getString("PathTwistBegin");
-char* _PREHASH_CRC = LLMessageStringTable::getInstance()->getString("CRC");
-char* _PREHASH_AttachmentPoint = LLMessageStringTable::getInstance()->getString("AttachmentPoint");
-char* _PREHASH_TelehubBlock = LLMessageStringTable::getInstance()->getString("TelehubBlock");
-char* _PREHASH_FOVBlock = LLMessageStringTable::getInstance()->getString("FOVBlock");
-char* _PREHASH_StartLocationData = LLMessageStringTable::getInstance()->getString("StartLocationData");
-char* _PREHASH_PositionData = LLMessageStringTable::getInstance()->getString("PositionData");
-char* _PREHASH_TimeSinceLast = LLMessageStringTable::getInstance()->getString("TimeSinceLast");
-char* _PREHASH_MapImage = LLMessageStringTable::getInstance()->getString("MapImage");
-char* _PREHASH_Objects = LLMessageStringTable::getInstance()->getString("Objects");
-char* _PREHASH_URL = LLMessageStringTable::getInstance()->getString("URL");
-char* _PREHASH_CreationDate = LLMessageStringTable::getInstance()->getString("CreationDate");
-char* _PREHASH_JointPivot = LLMessageStringTable::getInstance()->getString("JointPivot");
-char* _PREHASH_FPS = LLMessageStringTable::getInstance()->getString("FPS");
-char* _PREHASH_HasTelehub = LLMessageStringTable::getInstance()->getString("HasTelehub");
-char* _PREHASH_PathEnd = LLMessageStringTable::getInstance()->getString("PathEnd");
-char* _PREHASH_ScriptDataReply = LLMessageStringTable::getInstance()->getString("ScriptDataReply");
-char* _PREHASH_MapBlockReply = LLMessageStringTable::getInstance()->getString("MapBlockReply");
-char* _PREHASH_PropertiesData = LLMessageStringTable::getInstance()->getString("PropertiesData");
-char* _PREHASH_ViewerEffect = LLMessageStringTable::getInstance()->getString("ViewerEffect");
-char* _PREHASH_FreezeUser = LLMessageStringTable::getInstance()->getString("FreezeUser");
-char* _PREHASH_OwnerPrims = LLMessageStringTable::getInstance()->getString("OwnerPrims");
-char* _PREHASH_ObjectGrab = LLMessageStringTable::getInstance()->getString("ObjectGrab");
-char* _PREHASH_ToAgentID = LLMessageStringTable::getInstance()->getString("ToAgentID");
-char* _PREHASH_SimulatorMapUpdate = LLMessageStringTable::getInstance()->getString("SimulatorMapUpdate");
-char* _PREHASH_TransferPacket = LLMessageStringTable::getInstance()->getString("TransferPacket");
-char* _PREHASH_ObjectName = LLMessageStringTable::getInstance()->getString("ObjectName");
-char* _PREHASH_GroupPowers = LLMessageStringTable::getInstance()->getString("GroupPowers");
-char* _PREHASH_OriginalName = LLMessageStringTable::getInstance()->getString("OriginalName");
-char* _PREHASH_CompletePingCheck = LLMessageStringTable::getInstance()->getString("CompletePingCheck");
-char* _PREHASH_OnlineStatus = LLMessageStringTable::getInstance()->getString("OnlineStatus");
-char* _PREHASH_ObjectDrop = LLMessageStringTable::getInstance()->getString("ObjectDrop");
-char* _PREHASH_UseBigPackets = LLMessageStringTable::getInstance()->getString("UseBigPackets");
-char* _PREHASH_GroupNoticesListReply = LLMessageStringTable::getInstance()->getString("GroupNoticesListReply");
-char* _PREHASH_ParcelAccessListReply = LLMessageStringTable::getInstance()->getString("ParcelAccessListReply");
-char* _PREHASH_RpcChannelReply = LLMessageStringTable::getInstance()->getString("RpcChannelReply");
-char* _PREHASH_RegionPresenceResponse = LLMessageStringTable::getInstance()->getString("RegionPresenceResponse");
-char* _PREHASH_CharterMember = LLMessageStringTable::getInstance()->getString("CharterMember");
-char* _PREHASH_EdgeData = LLMessageStringTable::getInstance()->getString("EdgeData");
-char* _PREHASH_NameData = LLMessageStringTable::getInstance()->getString("NameData");
-char* _PREHASH_RegionPushOverride = LLMessageStringTable::getInstance()->getString("RegionPushOverride");
-char* _PREHASH_SimName = LLMessageStringTable::getInstance()->getString("SimName");
-char* _PREHASH_UserReport = LLMessageStringTable::getInstance()->getString("UserReport");
-char* _PREHASH_DownloadPriority = LLMessageStringTable::getInstance()->getString("DownloadPriority");
-char* _PREHASH_ToAgentId = LLMessageStringTable::getInstance()->getString("ToAgentId");
-char* _PREHASH_DirPopularQuery = LLMessageStringTable::getInstance()->getString("DirPopularQuery");
-char* _PREHASH_Mag = LLMessageStringTable::getInstance()->getString("Mag");
-char* _PREHASH_ParcelPropertiesRequestByID = LLMessageStringTable::getInstance()->getString("ParcelPropertiesRequestByID");
-char* _PREHASH_ObjectLink = LLMessageStringTable::getInstance()->getString("ObjectLink");
-char* _PREHASH_RpcScriptReplyInbound = LLMessageStringTable::getInstance()->getString("RpcScriptReplyInbound");
-char* _PREHASH_RezData = LLMessageStringTable::getInstance()->getString("RezData");
-char* _PREHASH_RemoveInventoryObjects = LLMessageStringTable::getInstance()->getString("RemoveInventoryObjects");
-char* _PREHASH_GroupProposalBallot = LLMessageStringTable::getInstance()->getString("GroupProposalBallot");
-char* _PREHASH_RPCServerIP = LLMessageStringTable::getInstance()->getString("RPCServerIP");
-char* _PREHASH_Far = LLMessageStringTable::getInstance()->getString("Far");
-char* _PREHASH_GodSessionID = LLMessageStringTable::getInstance()->getString("GodSessionID");
-char* _PREHASH_FLAboutText = LLMessageStringTable::getInstance()->getString("FLAboutText");
-char* _PREHASH_RegionHandshakeReply = LLMessageStringTable::getInstance()->getString("RegionHandshakeReply");
-char* _PREHASH_GroupActiveProposalItemReply = LLMessageStringTable::getInstance()->getString("GroupActiveProposalItemReply");
-char* _PREHASH_MapItemReply = LLMessageStringTable::getInstance()->getString("MapItemReply");
-char* _PREHASH_Seconds = LLMessageStringTable::getInstance()->getString("Seconds");
-char* _PREHASH_UpdateUserInfo = LLMessageStringTable::getInstance()->getString("UpdateUserInfo");
-char* _PREHASH_AggregatePermTexturesOwner = LLMessageStringTable::getInstance()->getString("AggregatePermTexturesOwner");
-char* _PREHASH_Set = LLMessageStringTable::getInstance()->getString("Set");
-char* _PREHASH_NewName = LLMessageStringTable::getInstance()->getString("NewName");
-char* _PREHASH_Key = LLMessageStringTable::getInstance()->getString("Key");
-char* _PREHASH_AgentID = LLMessageStringTable::getInstance()->getString("AgentID");
-char* _PREHASH_EventNotificationRemoveRequest = LLMessageStringTable::getInstance()->getString("EventNotificationRemoveRequest");
-char* _PREHASH_NewFolderID = LLMessageStringTable::getInstance()->getString("NewFolderID");
-char* _PREHASH_Arc = LLMessageStringTable::getInstance()->getString("Arc");
-char* _PREHASH_RegionX = LLMessageStringTable::getInstance()->getString("RegionX");
-char* _PREHASH_RegionY = LLMessageStringTable::getInstance()->getString("RegionY");
-char* _PREHASH_RequestData = LLMessageStringTable::getInstance()->getString("RequestData");
-char* _PREHASH_Msg = LLMessageStringTable::getInstance()->getString("Msg");
-char* _PREHASH_Top = LLMessageStringTable::getInstance()->getString("Top");
-char* _PREHASH_MiscStats = LLMessageStringTable::getInstance()->getString("MiscStats");
-char* _PREHASH_ImageID = LLMessageStringTable::getInstance()->getString("ImageID");
-char* _PREHASH_DataPacket = LLMessageStringTable::getInstance()->getString("DataPacket");
-char* _PREHASH_You = LLMessageStringTable::getInstance()->getString("You");
-char* _PREHASH_ScriptControlChange = LLMessageStringTable::getInstance()->getString("ScriptControlChange");
-char* _PREHASH_LoadURL = LLMessageStringTable::getInstance()->getString("LoadURL");
-char* _PREHASH_SetCPURatio = LLMessageStringTable::getInstance()->getString("SetCPURatio");
-char* _PREHASH_NameValueData = LLMessageStringTable::getInstance()->getString("NameValueData");
-char* _PREHASH_AtomicPassObject = LLMessageStringTable::getInstance()->getString("AtomicPassObject");
-char* _PREHASH_ErrorMessage = LLMessageStringTable::getInstance()->getString("ErrorMessage");
-char* _PREHASH_ViewerFrozenMessage = LLMessageStringTable::getInstance()->getString("ViewerFrozenMessage");
-char* _PREHASH_HealthMessage = LLMessageStringTable::getInstance()->getString("HealthMessage");
-char* _PREHASH_LogTextMessage = LLMessageStringTable::getInstance()->getString("LogTextMessage");
-char* _PREHASH_TimeDilation = LLMessageStringTable::getInstance()->getString("TimeDilation");
-char* _PREHASH_RemoveContribution = LLMessageStringTable::getInstance()->getString("RemoveContribution");
-char* _PREHASH_Contribution = LLMessageStringTable::getInstance()->getString("Contribution");
-char* _PREHASH_SetGroupContribution = LLMessageStringTable::getInstance()->getString("SetGroupContribution");
-char* _PREHASH_Offline = LLMessageStringTable::getInstance()->getString("Offline");
-char* _PREHASH_AgentIsNowWearing = LLMessageStringTable::getInstance()->getString("AgentIsNowWearing");
-char* _PREHASH_Members = LLMessageStringTable::getInstance()->getString("Members");
-char* _PREHASH_FailedResends = LLMessageStringTable::getInstance()->getString("FailedResends");
-char* _PREHASH_SecPerDay = LLMessageStringTable::getInstance()->getString("SecPerDay");
-char* _PREHASH_CameraCenter = LLMessageStringTable::getInstance()->getString("CameraCenter");
-char* _PREHASH_CameraLeftAxis = LLMessageStringTable::getInstance()->getString("CameraLeftAxis");
-char* _PREHASH_ExBlock = LLMessageStringTable::getInstance()->getString("ExBlock");
-char* _PREHASH_Channel = LLMessageStringTable::getInstance()->getString("Channel");
-char* _PREHASH_NetTest = LLMessageStringTable::getInstance()->getString("NetTest");
-char* _PREHASH_DiscardLevel = LLMessageStringTable::getInstance()->getString("DiscardLevel");
-char* _PREHASH_LayerID = LLMessageStringTable::getInstance()->getString("LayerID");
-char* _PREHASH_GrabOffset = LLMessageStringTable::getInstance()->getString("GrabOffset");
-char* _PREHASH_SimPort = LLMessageStringTable::getInstance()->getString("SimPort");
-char* _PREHASH_PricePerMeter = LLMessageStringTable::getInstance()->getString("PricePerMeter");
-char* _PREHASH_RegionFlags = LLMessageStringTable::getInstance()->getString("RegionFlags");
-char* _PREHASH_VoteResult = LLMessageStringTable::getInstance()->getString("VoteResult");
-char* _PREHASH_ParcelDirFeeEstimate = LLMessageStringTable::getInstance()->getString("ParcelDirFeeEstimate");
-char* _PREHASH_ModifyBlock = LLMessageStringTable::getInstance()->getString("ModifyBlock");
-char* _PREHASH_InventoryBlock = LLMessageStringTable::getInstance()->getString("InventoryBlock");
-char* _PREHASH_ReplyBlock = LLMessageStringTable::getInstance()->getString("ReplyBlock");
-char* _PREHASH_ValidUntil = LLMessageStringTable::getInstance()->getString("ValidUntil");
-char* _PREHASH_VelocityInterpolateOn = LLMessageStringTable::getInstance()->getString("VelocityInterpolateOn");
-char* _PREHASH_ClassifiedDelete = LLMessageStringTable::getInstance()->getString("ClassifiedDelete");
-char* _PREHASH_RegionDenyAnonymous = LLMessageStringTable::getInstance()->getString("RegionDenyAnonymous");
-char* _PREHASH_FLImageID = LLMessageStringTable::getInstance()->getString("FLImageID");
-char* _PREHASH_AllowPublish = LLMessageStringTable::getInstance()->getString("AllowPublish");
-char* _PREHASH_SitName = LLMessageStringTable::getInstance()->getString("SitName");
-char* _PREHASH_RegionsVisited = LLMessageStringTable::getInstance()->getString("RegionsVisited");
-char* _PREHASH_DirClassifiedReply = LLMessageStringTable::getInstance()->getString("DirClassifiedReply");
-char* _PREHASH_AvatarClassifiedReply = LLMessageStringTable::getInstance()->getString("AvatarClassifiedReply");
-char* _PREHASH_MediaURL = LLMessageStringTable::getInstance()->getString("MediaURL");
-char* _PREHASH_CompleteAgentMovement = LLMessageStringTable::getInstance()->getString("CompleteAgentMovement");
-char* _PREHASH_ClassifiedID = LLMessageStringTable::getInstance()->getString("ClassifiedID");
-char* _PREHASH_LocalID = LLMessageStringTable::getInstance()->getString("LocalID");
-char* _PREHASH_SpaceIP = LLMessageStringTable::getInstance()->getString("SpaceIP");
-char* _PREHASH_RemoveItem = LLMessageStringTable::getInstance()->getString("RemoveItem");
-char* _PREHASH_LogFailedMoneyTransaction = LLMessageStringTable::getInstance()->getString("LogFailedMoneyTransaction");
-char* _PREHASH_ViewerStartAuction = LLMessageStringTable::getInstance()->getString("ViewerStartAuction");
-char* _PREHASH_StartAuction = LLMessageStringTable::getInstance()->getString("StartAuction");
-char* _PREHASH_DuplicateFlags = LLMessageStringTable::getInstance()->getString("DuplicateFlags");
-char* _PREHASH_RegionInfo2 = LLMessageStringTable::getInstance()->getString("RegionInfo2");
-char* _PREHASH_TextColor = LLMessageStringTable::getInstance()->getString("TextColor");
-char* _PREHASH_SlaveID = LLMessageStringTable::getInstance()->getString("SlaveID");
-char* _PREHASH_Charter = LLMessageStringTable::getInstance()->getString("Charter");
-char* _PREHASH_AlertData = LLMessageStringTable::getInstance()->getString("AlertData");
-char* _PREHASH_AlertInfo = LLMessageStringTable::getInstance()->getString("AlertInfo");
-char* _PREHASH_TargetBlock = LLMessageStringTable::getInstance()->getString("TargetBlock");
-char* _PREHASH_CheckParcelAuctions = LLMessageStringTable::getInstance()->getString("CheckParcelAuctions");
-char* _PREHASH_ParcelAuctions = LLMessageStringTable::getInstance()->getString("ParcelAuctions");
-char* _PREHASH_OwnerIsGroup = LLMessageStringTable::getInstance()->getString("OwnerIsGroup");
-char* _PREHASH_NameValuePair = LLMessageStringTable::getInstance()->getString("NameValuePair");
-char* _PREHASH_RemoveNameValuePair = LLMessageStringTable::getInstance()->getString("RemoveNameValuePair");
-char* _PREHASH_BulkUpdateInventory = LLMessageStringTable::getInstance()->getString("BulkUpdateInventory");
-char* _PREHASH_UpdateTaskInventory = LLMessageStringTable::getInstance()->getString("UpdateTaskInventory");
-char* _PREHASH_RemoveTaskInventory = LLMessageStringTable::getInstance()->getString("RemoveTaskInventory");
-char* _PREHASH_MoveTaskInventory = LLMessageStringTable::getInstance()->getString("MoveTaskInventory");
-char* _PREHASH_RequestTaskInventory = LLMessageStringTable::getInstance()->getString("RequestTaskInventory");
-char* _PREHASH_ReplyTaskInventory = LLMessageStringTable::getInstance()->getString("ReplyTaskInventory");
-char* _PREHASH_AggregatePermInventory = LLMessageStringTable::getInstance()->getString("AggregatePermInventory");
-char* _PREHASH_GroupAccountTransactionsReply = LLMessageStringTable::getInstance()->getString("GroupAccountTransactionsReply");
-char* _PREHASH_SimulatorInfo = LLMessageStringTable::getInstance()->getString("SimulatorInfo");
-char* _PREHASH_WearableData = LLMessageStringTable::getInstance()->getString("WearableData");
-char* _PREHASH_Enabled = LLMessageStringTable::getInstance()->getString("Enabled");
-char* _PREHASH_Savings = LLMessageStringTable::getInstance()->getString("Savings");
-char* _PREHASH_SimulatorLoad = LLMessageStringTable::getInstance()->getString("SimulatorLoad");
-char* _PREHASH_InternalRegionIP = LLMessageStringTable::getInstance()->getString("InternalRegionIP");
-char* _PREHASH_ExternalRegionIP = LLMessageStringTable::getInstance()->getString("ExternalRegionIP");
-char* _PREHASH_TotalPairs = LLMessageStringTable::getInstance()->getString("TotalPairs");
-char* _PREHASH_CreateGroupRequest = LLMessageStringTable::getInstance()->getString("CreateGroupRequest");
-char* _PREHASH_JoinGroupRequest = LLMessageStringTable::getInstance()->getString("JoinGroupRequest");
-char* _PREHASH_LeaveGroupRequest = LLMessageStringTable::getInstance()->getString("LeaveGroupRequest");
-char* _PREHASH_InviteGroupRequest = LLMessageStringTable::getInstance()->getString("InviteGroupRequest");
-char* _PREHASH_LiveHelpGroupRequest = LLMessageStringTable::getInstance()->getString("LiveHelpGroupRequest");
-char* _PREHASH_PriceParcelClaimFactor = LLMessageStringTable::getInstance()->getString("PriceParcelClaimFactor");
-char* _PREHASH_BillableArea = LLMessageStringTable::getInstance()->getString("BillableArea");
-char* _PREHASH_ObjectID = LLMessageStringTable::getInstance()->getString("ObjectID");
-char* _PREHASH_ObjectFlagUpdate = LLMessageStringTable::getInstance()->getString("ObjectFlagUpdate");
-char* _PREHASH_GroupRoleUpdate = LLMessageStringTable::getInstance()->getString("GroupRoleUpdate");
-char* _PREHASH_RequestInventoryAsset = LLMessageStringTable::getInstance()->getString("RequestInventoryAsset");
-char* _PREHASH_ChangedGrid = LLMessageStringTable::getInstance()->getString("ChangedGrid");
-char* _PREHASH_AgentDropGroup = LLMessageStringTable::getInstance()->getString("AgentDropGroup");
-char* _PREHASH_Details = LLMessageStringTable::getInstance()->getString("Details");
-char* _PREHASH_LocationX = LLMessageStringTable::getInstance()->getString("LocationX");
-char* _PREHASH_SaleType = LLMessageStringTable::getInstance()->getString("SaleType");
-char* _PREHASH_LocationY = LLMessageStringTable::getInstance()->getString("LocationY");
-char* _PREHASH_LocationZ = LLMessageStringTable::getInstance()->getString("LocationZ");
-char* _PREHASH_EconomyData = LLMessageStringTable::getInstance()->getString("EconomyData");
-char* _PREHASH_HeadRotation = LLMessageStringTable::getInstance()->getString("HeadRotation");
-char* _PREHASH_DeleteOnCompletion = LLMessageStringTable::getInstance()->getString("DeleteOnCompletion");
-char* _PREHASH_PublicPort = LLMessageStringTable::getInstance()->getString("PublicPort");
-char* _PREHASH_DirClassifiedQuery = LLMessageStringTable::getInstance()->getString("DirClassifiedQuery");
-char* _PREHASH_CallbackID = LLMessageStringTable::getInstance()->getString("CallbackID");
-char* _PREHASH_RequestParcelTransfer = LLMessageStringTable::getInstance()->getString("RequestParcelTransfer");
-char* _PREHASH_RoleCount = LLMessageStringTable::getInstance()->getString("RoleCount");
-char* _PREHASH_ObjectCapacity = LLMessageStringTable::getInstance()->getString("ObjectCapacity");
-char* _PREHASH_RequestID = LLMessageStringTable::getInstance()->getString("RequestID");
-char* _PREHASH_RequestXfer = LLMessageStringTable::getInstance()->getString("RequestXfer");
-char* _PREHASH_ObjectTaxCurrent = LLMessageStringTable::getInstance()->getString("ObjectTaxCurrent");
-char* _PREHASH_LightTaxCurrent = LLMessageStringTable::getInstance()->getString("LightTaxCurrent");
-char* _PREHASH_LandTaxCurrent = LLMessageStringTable::getInstance()->getString("LandTaxCurrent");
-char* _PREHASH_GroupTaxCurrent = LLMessageStringTable::getInstance()->getString("GroupTaxCurrent");
-char* _PREHASH_FetchInventoryDescendents = LLMessageStringTable::getInstance()->getString("FetchInventoryDescendents");
-char* _PREHASH_InventoryDescendents = LLMessageStringTable::getInstance()->getString("InventoryDescendents");
-char* _PREHASH_Descendents = LLMessageStringTable::getInstance()->getString("Descendents");
-char* _PREHASH_PurgeInventoryDescendents = LLMessageStringTable::getInstance()->getString("PurgeInventoryDescendents");
-char* _PREHASH_ShowDir = LLMessageStringTable::getInstance()->getString("ShowDir");
-char* _PREHASH_IsOwner = LLMessageStringTable::getInstance()->getString("IsOwner");
-char* _PREHASH_Timestamp = LLMessageStringTable::getInstance()->getString("Timestamp");
-char* _PREHASH_GlobalPos = LLMessageStringTable::getInstance()->getString("GlobalPos");
-char* _PREHASH_GrabOffsetInitial = LLMessageStringTable::getInstance()->getString("GrabOffsetInitial");
-char* _PREHASH_IsTrial = LLMessageStringTable::getInstance()->getString("IsTrial");
-char* _PREHASH_ObjectDuplicateOnRay = LLMessageStringTable::getInstance()->getString("ObjectDuplicateOnRay");
-char* _PREHASH_GroupMembershipCount = LLMessageStringTable::getInstance()->getString("GroupMembershipCount");
-char* _PREHASH_MethodData = LLMessageStringTable::getInstance()->getString("MethodData");
-char* _PREHASH_ActivateGestures = LLMessageStringTable::getInstance()->getString("ActivateGestures");
-char* _PREHASH_DeactivateGestures = LLMessageStringTable::getInstance()->getString("DeactivateGestures");
-char* _PREHASH_ProposalData = LLMessageStringTable::getInstance()->getString("ProposalData");
-char* _PREHASH_PosGlobal = LLMessageStringTable::getInstance()->getString("PosGlobal");
-char* _PREHASH_SearchID = LLMessageStringTable::getInstance()->getString("SearchID");
-char* _PREHASH_RezMultipleAttachmentsFromInv = LLMessageStringTable::getInstance()->getString("RezMultipleAttachmentsFromInv");
-char* _PREHASH_SearchName = LLMessageStringTable::getInstance()->getString("SearchName");
-char* _PREHASH_VersionString = LLMessageStringTable::getInstance()->getString("VersionString");
-char* _PREHASH_CreateGroupReply = LLMessageStringTable::getInstance()->getString("CreateGroupReply");
-char* _PREHASH_LeaveGroupReply = LLMessageStringTable::getInstance()->getString("LeaveGroupReply");
-char* _PREHASH_ActualArea = LLMessageStringTable::getInstance()->getString("ActualArea");
-char* _PREHASH_Message = LLMessageStringTable::getInstance()->getString("Message");
-char* _PREHASH_ClickAction = LLMessageStringTable::getInstance()->getString("ClickAction");
-char* _PREHASH_AssetUploadComplete = LLMessageStringTable::getInstance()->getString("AssetUploadComplete");
-char* _PREHASH_RequestType = LLMessageStringTable::getInstance()->getString("RequestType");
-char* _PREHASH_UUID = LLMessageStringTable::getInstance()->getString("UUID");
-char* _PREHASH_BaseMask = LLMessageStringTable::getInstance()->getString("BaseMask");
-char* _PREHASH_NetBlock = LLMessageStringTable::getInstance()->getString("NetBlock");
-char* _PREHASH_GlobalX = LLMessageStringTable::getInstance()->getString("GlobalX");
-char* _PREHASH_GlobalY = LLMessageStringTable::getInstance()->getString("GlobalY");
-char* _PREHASH_CopyRotates = LLMessageStringTable::getInstance()->getString("CopyRotates");
-char* _PREHASH_KickUserAck = LLMessageStringTable::getInstance()->getString("KickUserAck");
-char* _PREHASH_TopPick = LLMessageStringTable::getInstance()->getString("TopPick"); //legacy var need to be deleted -angela
-char* _PREHASH_SessionID = LLMessageStringTable::getInstance()->getString("SessionID");
-char* _PREHASH_GlobalZ = LLMessageStringTable::getInstance()->getString("GlobalZ");
-char* _PREHASH_DeclineFriendship = LLMessageStringTable::getInstance()->getString("DeclineFriendship");
-char* _PREHASH_FormFriendship = LLMessageStringTable::getInstance()->getString("FormFriendship");
-char* _PREHASH_TerminateFriendship = LLMessageStringTable::getInstance()->getString("TerminateFriendship");
-char* _PREHASH_TaskData = LLMessageStringTable::getInstance()->getString("TaskData");
-char* _PREHASH_SimWideMaxPrims = LLMessageStringTable::getInstance()->getString("SimWideMaxPrims");
-char* _PREHASH_TotalPrims = LLMessageStringTable::getInstance()->getString("TotalPrims");
-char* _PREHASH_ProfileBegin = LLMessageStringTable::getInstance()->getString("ProfileBegin");
-char* _PREHASH_Request = LLMessageStringTable::getInstance()->getString("Request");
-char* _PREHASH_GroupAccountDetailsRequest = LLMessageStringTable::getInstance()->getString("GroupAccountDetailsRequest");
-char* _PREHASH_GroupActiveProposalsRequest = LLMessageStringTable::getInstance()->getString("GroupActiveProposalsRequest");
-char* _PREHASH_StringValue = LLMessageStringTable::getInstance()->getString("StringValue");
-char* _PREHASH_Version = LLMessageStringTable::getInstance()->getString("Version");
-char* _PREHASH_OtherCount = LLMessageStringTable::getInstance()->getString("OtherCount");
-char* _PREHASH_MemberCount = LLMessageStringTable::getInstance()->getString("MemberCount");
-char* _PREHASH_ChatData = LLMessageStringTable::getInstance()->getString("ChatData");
-char* _PREHASH_IsGroupOwned = LLMessageStringTable::getInstance()->getString("IsGroupOwned");
-char* _PREHASH_EnergyEfficiency = LLMessageStringTable::getInstance()->getString("EnergyEfficiency");
-char* _PREHASH_PickInfoUpdate = LLMessageStringTable::getInstance()->getString("PickInfoUpdate");
-char* _PREHASH_PickDelete = LLMessageStringTable::getInstance()->getString("PickDelete");
-char* _PREHASH_ScriptReset = LLMessageStringTable::getInstance()->getString("ScriptReset");
-char* _PREHASH_Requester = LLMessageStringTable::getInstance()->getString("Requester");
-char* _PREHASH_ForSale = LLMessageStringTable::getInstance()->getString("ForSale");
-char* _PREHASH_NearestLandingRegionReply = LLMessageStringTable::getInstance()->getString("NearestLandingRegionReply");
-char* _PREHASH_ParcelID = LLMessageStringTable::getInstance()->getString("ParcelID");
-char* _PREHASH_Godlike = LLMessageStringTable::getInstance()->getString("Godlike");
-char* _PREHASH_TotalDebits = LLMessageStringTable::getInstance()->getString("TotalDebits");
-char* _PREHASH_Direction = LLMessageStringTable::getInstance()->getString("Direction");
-char* _PREHASH_HealthData = LLMessageStringTable::getInstance()->getString("HealthData");
-char* _PREHASH_LeftAxis = LLMessageStringTable::getInstance()->getString("LeftAxis");
-char* _PREHASH_LocationBlock = LLMessageStringTable::getInstance()->getString("LocationBlock");
-char* _PREHASH_ObjectImage = LLMessageStringTable::getInstance()->getString("ObjectImage");
-char* _PREHASH_TerrainStartHeight00 = LLMessageStringTable::getInstance()->getString("TerrainStartHeight00");
-char* _PREHASH_TerrainStartHeight01 = LLMessageStringTable::getInstance()->getString("TerrainStartHeight01");
-char* _PREHASH_TerrainStartHeight10 = LLMessageStringTable::getInstance()->getString("TerrainStartHeight10");
-char* _PREHASH_TerrainStartHeight11 = LLMessageStringTable::getInstance()->getString("TerrainStartHeight11");
-char* _PREHASH_WaterHeight = LLMessageStringTable::getInstance()->getString("WaterHeight");
-char* _PREHASH_FetchInventoryReply = LLMessageStringTable::getInstance()->getString("FetchInventoryReply");
-char* _PREHASH_GroupAccountSummaryReply = LLMessageStringTable::getInstance()->getString("GroupAccountSummaryReply");
-char* _PREHASH_AttachedSound = LLMessageStringTable::getInstance()->getString("AttachedSound");
-char* _PREHASH_ParamInUse = LLMessageStringTable::getInstance()->getString("ParamInUse");
-char* _PREHASH_GodKickUser = LLMessageStringTable::getInstance()->getString("GodKickUser");
-char* _PREHASH_PickName = LLMessageStringTable::getInstance()->getString("PickName");
-char* _PREHASH_TaskName = LLMessageStringTable::getInstance()->getString("TaskName");
-char* _PREHASH_ObjectCount = LLMessageStringTable::getInstance()->getString("ObjectCount");
-char* _PREHASH_RegionPresenceRequestByHandle = LLMessageStringTable::getInstance()->getString("RegionPresenceRequestByHandle");
-char* _PREHASH_RezSingleAttachmentFromInv = LLMessageStringTable::getInstance()->getString("RezSingleAttachmentFromInv");
-char* _PREHASH_ChildAgentUpdate = LLMessageStringTable::getInstance()->getString("ChildAgentUpdate");
-char* _PREHASH_IsOwnerGroup = LLMessageStringTable::getInstance()->getString("IsOwnerGroup");
-char* _PREHASH_AgentHeightWidth = LLMessageStringTable::getInstance()->getString("AgentHeightWidth");
-char* _PREHASH_VerticalAngle = LLMessageStringTable::getInstance()->getString("VerticalAngle");
-char* _PREHASH_WearableType = LLMessageStringTable::getInstance()->getString("WearableType");
-char* _PREHASH_AggregatePermNextOwner = LLMessageStringTable::getInstance()->getString("AggregatePermNextOwner");
-char* _PREHASH_ShowInList = LLMessageStringTable::getInstance()->getString("ShowInList");
-char* _PREHASH_UpdateParcel = LLMessageStringTable::getInstance()->getString("UpdateParcel");
-char* _PREHASH_SetAlwaysRun = LLMessageStringTable::getInstance()->getString("SetAlwaysRun");
-char* _PREHASH_NVPair = LLMessageStringTable::getInstance()->getString("NVPair");
-char* _PREHASH_SearchType = LLMessageStringTable::getInstance()->getString("SearchType");
-char* _PREHASH_ObjectSpinStart = LLMessageStringTable::getInstance()->getString("ObjectSpinStart");
-char* _PREHASH_UseEstateSun = LLMessageStringTable::getInstance()->getString("UseEstateSun");
-char* _PREHASH_RegionID = LLMessageStringTable::getInstance()->getString("RegionID");
-char* _PREHASH_AbuseRegionID = LLMessageStringTable::getInstance()->getString("AbuseRegionID");
-char* _PREHASH_Creator = LLMessageStringTable::getInstance()->getString("Creator");
-char* _PREHASH_ProposalText = LLMessageStringTable::getInstance()->getString("ProposalText");
-char* _PREHASH_DirEventsReply = LLMessageStringTable::getInstance()->getString("DirEventsReply");
-char* _PREHASH_EventInfoReply = LLMessageStringTable::getInstance()->getString("EventInfoReply");
-char* _PREHASH_UserInfoReply = LLMessageStringTable::getInstance()->getString("UserInfoReply");
-char* _PREHASH_PathRadiusOffset = LLMessageStringTable::getInstance()->getString("PathRadiusOffset");
-char* _PREHASH_TextureData = LLMessageStringTable::getInstance()->getString("TextureData");
-char* _PREHASH_ChatPass = LLMessageStringTable::getInstance()->getString("ChatPass");
-char* _PREHASH_TargetID = LLMessageStringTable::getInstance()->getString("TargetID");
-char* _PREHASH_DefaultPayPrice = LLMessageStringTable::getInstance()->getString("DefaultPayPrice");
-char* _PREHASH_UserLocation = LLMessageStringTable::getInstance()->getString("UserLocation");
-char* _PREHASH_MaxPrims = LLMessageStringTable::getInstance()->getString("MaxPrims");
-char* _PREHASH_LandmarkID = LLMessageStringTable::getInstance()->getString("LandmarkID");
-char* _PREHASH_InitiateDownload = LLMessageStringTable::getInstance()->getString("InitiateDownload");
-char* _PREHASH_Name = LLMessageStringTable::getInstance()->getString("Name");
-char* _PREHASH_OtherCleanTime = LLMessageStringTable::getInstance()->getString("OtherCleanTime");
-char* _PREHASH_ParcelSetOtherCleanTime = LLMessageStringTable::getInstance()->getString("ParcelSetOtherCleanTime");
-char* _PREHASH_TeleportPriceExponent = LLMessageStringTable::getInstance()->getString("TeleportPriceExponent");
-char* _PREHASH_Gain = LLMessageStringTable::getInstance()->getString("Gain");
-char* _PREHASH_PacketAck = LLMessageStringTable::getInstance()->getString("PacketAck");
-char* _PREHASH_PathSkew = LLMessageStringTable::getInstance()->getString("PathSkew");
-char* _PREHASH_SimulatorShutdownRequest = LLMessageStringTable::getInstance()->getString("SimulatorShutdownRequest");
-char* _PREHASH_NearestLandingRegionRequest = LLMessageStringTable::getInstance()->getString("NearestLandingRegionRequest");
-char* _PREHASH_OtherID = LLMessageStringTable::getInstance()->getString("OtherID");
-char* _PREHASH_MemberID = LLMessageStringTable::getInstance()->getString("MemberID");
-char* _PREHASH_MapLayerRequest = LLMessageStringTable::getInstance()->getString("MapLayerRequest");
-char* _PREHASH_ObjectScale = LLMessageStringTable::getInstance()->getString("ObjectScale");
-char* _PREHASH_TargetIP = LLMessageStringTable::getInstance()->getString("TargetIP");
-char* _PREHASH_Redo = LLMessageStringTable::getInstance()->getString("Redo");
-char* _PREHASH_MoneyBalance = LLMessageStringTable::getInstance()->getString("MoneyBalance");
-char* _PREHASH_TrackAgent = LLMessageStringTable::getInstance()->getString("TrackAgent");
-char* _PREHASH_MaxX = LLMessageStringTable::getInstance()->getString("MaxX");
-char* _PREHASH_Data = LLMessageStringTable::getInstance()->getString("Data");
-char* _PREHASH_MaxY = LLMessageStringTable::getInstance()->getString("MaxY");
-char* _PREHASH_TextureAnim = LLMessageStringTable::getInstance()->getString("TextureAnim");
-char* _PREHASH_ReturnIDs = LLMessageStringTable::getInstance()->getString("ReturnIDs");
-char* _PREHASH_Date = LLMessageStringTable::getInstance()->getString("Date");
-char* _PREHASH_AgentWearablesUpdate = LLMessageStringTable::getInstance()->getString("AgentWearablesUpdate");
-char* _PREHASH_AgentDataUpdate = LLMessageStringTable::getInstance()->getString("AgentDataUpdate");
-char* _PREHASH_GroupDataUpdate = LLMessageStringTable::getInstance()->getString("GroupDataUpdate");
-char* _PREHASH_Hash = LLMessageStringTable::getInstance()->getString("Hash");
-char* _PREHASH_AgentGroupDataUpdate = LLMessageStringTable::getInstance()->getString("AgentGroupDataUpdate");
-char* _PREHASH_Left = LLMessageStringTable::getInstance()->getString("Left");
-char* _PREHASH_Mask = LLMessageStringTable::getInstance()->getString("Mask");
-char* _PREHASH_ForceMouselook = LLMessageStringTable::getInstance()->getString("ForceMouselook");
-char* _PREHASH_Success = LLMessageStringTable::getInstance()->getString("Success");
-char* _PREHASH_ObjectGroup = LLMessageStringTable::getInstance()->getString("ObjectGroup");
-char* _PREHASH_SunHour = LLMessageStringTable::getInstance()->getString("SunHour");
-char* _PREHASH_MinX = LLMessageStringTable::getInstance()->getString("MinX");
-char* _PREHASH_ScriptSensorReply = LLMessageStringTable::getInstance()->getString("ScriptSensorReply");
-char* _PREHASH_MinY = LLMessageStringTable::getInstance()->getString("MinY");
-char* _PREHASH_Command = LLMessageStringTable::getInstance()->getString("Command");
-char* _PREHASH_Desc = LLMessageStringTable::getInstance()->getString("Desc");
-char* _PREHASH_AttachmentNeedsSave = LLMessageStringTable::getInstance()->getString("AttachmentNeedsSave");
-char* _PREHASH_HistoryItemData = LLMessageStringTable::getInstance()->getString("HistoryItemData");
-char* _PREHASH_AgentCachedTexture = LLMessageStringTable::getInstance()->getString("AgentCachedTexture");
-char* _PREHASH_Subject = LLMessageStringTable::getInstance()->getString("Subject");
-char* _PREHASH_East = LLMessageStringTable::getInstance()->getString("East");
-char* _PREHASH_QueryReplies = LLMessageStringTable::getInstance()->getString("QueryReplies");
-char* _PREHASH_ObjectCategory = LLMessageStringTable::getInstance()->getString("ObjectCategory");
-char* _PREHASH_Time = LLMessageStringTable::getInstance()->getString("Time");
-char* _PREHASH_CreateLandmarkForEvent = LLMessageStringTable::getInstance()->getString("CreateLandmarkForEvent");
-char* _PREHASH_ParentID = LLMessageStringTable::getInstance()->getString("ParentID");
-char* _PREHASH_Ping = LLMessageStringTable::getInstance()->getString("Ping");
-char* _PREHASH_Perp = LLMessageStringTable::getInstance()->getString("Perp");
-char* _PREHASH_Code = LLMessageStringTable::getInstance()->getString("Code");
-char* _PREHASH_InvType = LLMessageStringTable::getInstance()->getString("InvType");
-char* _PREHASH_AgentFOV = LLMessageStringTable::getInstance()->getString("AgentFOV");
-char* _PREHASH_Audible = LLMessageStringTable::getInstance()->getString("Audible");
-char* _PREHASH_AuctionData = LLMessageStringTable::getInstance()->getString("AuctionData");
-char* _PREHASH_IDBlock = LLMessageStringTable::getInstance()->getString("IDBlock");
-char* _PREHASH_West = LLMessageStringTable::getInstance()->getString("West");
-char* _PREHASH_Undo = LLMessageStringTable::getInstance()->getString("Undo");
-char* _PREHASH_TotalNumItems = LLMessageStringTable::getInstance()->getString("TotalNumItems");
-char* _PREHASH_Info = LLMessageStringTable::getInstance()->getString("Info");
-char* _PREHASH_Area = LLMessageStringTable::getInstance()->getString("Area");
-char* _PREHASH_SimCrashed = LLMessageStringTable::getInstance()->getString("SimCrashed");
-char* _PREHASH_Text = LLMessageStringTable::getInstance()->getString("Text");
-char* _PREHASH_PriceGroupCreate = LLMessageStringTable::getInstance()->getString("PriceGroupCreate");
-char* _PREHASH_ObjectShape = LLMessageStringTable::getInstance()->getString("ObjectShape");
-char* _PREHASH_GroupRoleDataReply = LLMessageStringTable::getInstance()->getString("GroupRoleDataReply");
-char* _PREHASH_MuteCRC = LLMessageStringTable::getInstance()->getString("MuteCRC");
-char* _PREHASH_Size = LLMessageStringTable::getInstance()->getString("Size");
-char* _PREHASH_FromAddress = LLMessageStringTable::getInstance()->getString("FromAddress");
-char* _PREHASH_Body = LLMessageStringTable::getInstance()->getString("Body");
-char* _PREHASH_FileData = LLMessageStringTable::getInstance()->getString("FileData");
-char* _PREHASH_List = LLMessageStringTable::getInstance()->getString("List");
-char* _PREHASH_KickUser = LLMessageStringTable::getInstance()->getString("KickUser");
-char* _PREHASH_OtherPrims = LLMessageStringTable::getInstance()->getString("OtherPrims");
-char* _PREHASH_RunTime = LLMessageStringTable::getInstance()->getString("RunTime");
-char* _PREHASH_GrantUserRights = LLMessageStringTable::getInstance()->getString("GrantUserRights");
-char* _PREHASH_RpcScriptRequestInboundForward = LLMessageStringTable::getInstance()->getString("RpcScriptRequestInboundForward");
-char* _PREHASH_More = LLMessageStringTable::getInstance()->getString("More");
-char* _PREHASH_Majority = LLMessageStringTable::getInstance()->getString("Majority");
-char* _PREHASH_MetersTraveled = LLMessageStringTable::getInstance()->getString("MetersTraveled");
-char* _PREHASH_Stat = LLMessageStringTable::getInstance()->getString("Stat");
-char* _PREHASH_SoundID = LLMessageStringTable::getInstance()->getString("SoundID");
-char* _PREHASH_Item = LLMessageStringTable::getInstance()->getString("Item");
-char* _PREHASH_User = LLMessageStringTable::getInstance()->getString("User");
-char* _PREHASH_Prey = LLMessageStringTable::getInstance()->getString("Prey");
-char* _PREHASH_RayStart = LLMessageStringTable::getInstance()->getString("RayStart");
-char* _PREHASH_UsecSinceStart = LLMessageStringTable::getInstance()->getString("UsecSinceStart");
-char* _PREHASH_ParcelData = LLMessageStringTable::getInstance()->getString("ParcelData");
-char* _PREHASH_CameraUpAxis = LLMessageStringTable::getInstance()->getString("CameraUpAxis");
-char* _PREHASH_ScriptDialog = LLMessageStringTable::getInstance()->getString("ScriptDialog");
-char* _PREHASH_MasterParcelData = LLMessageStringTable::getInstance()->getString("MasterParcelData");
-char* _PREHASH_Invalid = LLMessageStringTable::getInstance()->getString("Invalid");
-char* _PREHASH_ProfileCurve = LLMessageStringTable::getInstance()->getString("ProfileCurve");
-char* _PREHASH_ParcelAccessListUpdate = LLMessageStringTable::getInstance()->getString("ParcelAccessListUpdate");
-char* _PREHASH_MuteListUpdate = LLMessageStringTable::getInstance()->getString("MuteListUpdate");
-char* _PREHASH_SendPacket = LLMessageStringTable::getInstance()->getString("SendPacket");
-char* _PREHASH_SendXferPacket = LLMessageStringTable::getInstance()->getString("SendXferPacket");
-char* _PREHASH_RegionDenyIdentified = LLMessageStringTable::getInstance()->getString("RegionDenyIdentified");
-char* _PREHASH_NotecardItemID = LLMessageStringTable::getInstance()->getString("NotecardItemID");
-char* _PREHASH_LastName = LLMessageStringTable::getInstance()->getString("LastName");
-char* _PREHASH_From = LLMessageStringTable::getInstance()->getString("From");
-char* _PREHASH_RoleChange = LLMessageStringTable::getInstance()->getString("RoleChange");
-char* _PREHASH_Port = LLMessageStringTable::getInstance()->getString("Port");
-char* _PREHASH_MemberTitle = LLMessageStringTable::getInstance()->getString("MemberTitle");
-char* _PREHASH_LogParcelChanges = LLMessageStringTable::getInstance()->getString("LogParcelChanges");
-char* _PREHASH_AgentCachedTextureResponse = LLMessageStringTable::getInstance()->getString("AgentCachedTextureResponse");
-char* _PREHASH_DeRezObject = LLMessageStringTable::getInstance()->getString("DeRezObject");
-char* _PREHASH_IsTemporary = LLMessageStringTable::getInstance()->getString("IsTemporary");
-char* _PREHASH_InsigniaID = LLMessageStringTable::getInstance()->getString("InsigniaID");
-char* _PREHASH_CheckFlags = LLMessageStringTable::getInstance()->getString("CheckFlags");
-char* _PREHASH_EventID = LLMessageStringTable::getInstance()->getString("EventID");
-char* _PREHASH_Selected = LLMessageStringTable::getInstance()->getString("Selected");
-char* _PREHASH_FromAgentId = LLMessageStringTable::getInstance()->getString("FromAgentId");
-char* _PREHASH_Type = LLMessageStringTable::getInstance()->getString("Type");
-char* _PREHASH_ChatType = LLMessageStringTable::getInstance()->getString("ChatType");
-char* _PREHASH_ReportData = LLMessageStringTable::getInstance()->getString("ReportData");
-char* _PREHASH_RequestBlock = LLMessageStringTable::getInstance()->getString("RequestBlock");
-char* _PREHASH_GrantData = LLMessageStringTable::getInstance()->getString("GrantData");
-char* _PREHASH_DetachAttachmentIntoInv = LLMessageStringTable::getInstance()->getString("DetachAttachmentIntoInv");
-char* _PREHASH_ParcelDisableObjects = LLMessageStringTable::getInstance()->getString("ParcelDisableObjects");
-char* _PREHASH_Sections = LLMessageStringTable::getInstance()->getString("Sections");
-char* _PREHASH_GodLevel = LLMessageStringTable::getInstance()->getString("GodLevel");
-char* _PREHASH_PayPriceReply = LLMessageStringTable::getInstance()->getString("PayPriceReply");
-char* _PREHASH_QueryID = LLMessageStringTable::getInstance()->getString("QueryID");
-char* _PREHASH_CameraEyeOffset = LLMessageStringTable::getInstance()->getString("CameraEyeOffset");
-char* _PREHASH_AgentPosition = LLMessageStringTable::getInstance()->getString("AgentPosition");
-char* _PREHASH_GrabPosition = LLMessageStringTable::getInstance()->getString("GrabPosition");
-char* _PREHASH_OnlineNotification = LLMessageStringTable::getInstance()->getString("OnlineNotification");
-char* _PREHASH_OfflineNotification = LLMessageStringTable::getInstance()->getString("OfflineNotification");
-char* _PREHASH_SendPostcard = LLMessageStringTable::getInstance()->getString("SendPostcard");
-char* _PREHASH_RequestFlags = LLMessageStringTable::getInstance()->getString("RequestFlags");
-char* _PREHASH_GroupAccountSummaryRequest = LLMessageStringTable::getInstance()->getString("GroupAccountSummaryRequest");
-char* _PREHASH_GroupVoteHistoryRequest = LLMessageStringTable::getInstance()->getString("GroupVoteHistoryRequest");
-char* _PREHASH_ParamValue = LLMessageStringTable::getInstance()->getString("ParamValue");
-char* _PREHASH_MaxAgents = LLMessageStringTable::getInstance()->getString("MaxAgents");
-char* _PREHASH_CreateNewOutfitAttachments = LLMessageStringTable::getInstance()->getString("CreateNewOutfitAttachments");
-char* _PREHASH_RegionHandle = LLMessageStringTable::getInstance()->getString("RegionHandle");
-char* _PREHASH_TeleportProgress = LLMessageStringTable::getInstance()->getString("TeleportProgress");
-char* _PREHASH_AgentQuitCopy = LLMessageStringTable::getInstance()->getString("AgentQuitCopy");
-char* _PREHASH_AvatarInterestsUpdate = LLMessageStringTable::getInstance()->getString("AvatarInterestsUpdate");
-char* _PREHASH_GroupNoticeID = LLMessageStringTable::getInstance()->getString("GroupNoticeID");
-char* _PREHASH_ParcelName = LLMessageStringTable::getInstance()->getString("ParcelName");
-char* _PREHASH_PriceObjectRent = LLMessageStringTable::getInstance()->getString("PriceObjectRent");
-char* _PREHASH_OfferCallingCard = LLMessageStringTable::getInstance()->getString("OfferCallingCard");
-char* _PREHASH_AcceptCallingCard = LLMessageStringTable::getInstance()->getString("AcceptCallingCard");
-char* _PREHASH_DeclineCallingCard = LLMessageStringTable::getInstance()->getString("DeclineCallingCard");
-char* _PREHASH_AgentAccess = LLMessageStringTable::getInstance()->getString("AgentAccess");
-char* _PREHASH_AgentLegacyAccess = LLMessageStringTable::getInstance()->getString("AgentLegacyAccess");
-char* _PREHASH_AgentMaxAccess = LLMessageStringTable::getInstance()->getString("AgentMaxAccess");
-char* _PREHASH_DataHomeLocationReply = LLMessageStringTable::getInstance()->getString("DataHomeLocationReply");
-char* _PREHASH_EventLocationReply = LLMessageStringTable::getInstance()->getString("EventLocationReply");
-char* _PREHASH_TerseDateID = LLMessageStringTable::getInstance()->getString("TerseDateID");
-char* _PREHASH_ObjectOwner = LLMessageStringTable::getInstance()->getString("ObjectOwner");
-char* _PREHASH_AssetID = LLMessageStringTable::getInstance()->getString("AssetID");
-char* _PREHASH_AlertMessage = LLMessageStringTable::getInstance()->getString("AlertMessage");
-char* _PREHASH_AgentAlertMessage = LLMessageStringTable::getInstance()->getString("AgentAlertMessage");
-char* _PREHASH_EstateOwnerMessage = LLMessageStringTable::getInstance()->getString("EstateOwnerMessage");
-char* _PREHASH_ParcelMediaCommandMessage = LLMessageStringTable::getInstance()->getString("ParcelMediaCommandMessage");
-char* _PREHASH_Auction = LLMessageStringTable::getInstance()->getString("Auction");
-char* _PREHASH_Category = LLMessageStringTable::getInstance()->getString("Category");
-char* _PREHASH_FilePath = LLMessageStringTable::getInstance()->getString("FilePath");
-char* _PREHASH_ItemFlags = LLMessageStringTable::getInstance()->getString("ItemFlags");
-char* _PREHASH_Invoice = LLMessageStringTable::getInstance()->getString("Invoice");
-char* _PREHASH_IntervalDays = LLMessageStringTable::getInstance()->getString("IntervalDays");
-char* _PREHASH_PathScaleX = LLMessageStringTable::getInstance()->getString("PathScaleX");
-char* _PREHASH_FromTaskID = LLMessageStringTable::getInstance()->getString("FromTaskID");
-char* _PREHASH_PathScaleY = LLMessageStringTable::getInstance()->getString("PathScaleY");
-char* _PREHASH_TimeInfo = LLMessageStringTable::getInstance()->getString("TimeInfo");
-char* _PREHASH_PublicCount = LLMessageStringTable::getInstance()->getString("PublicCount");
-char* _PREHASH_ParcelJoin = LLMessageStringTable::getInstance()->getString("ParcelJoin");
-char* _PREHASH_GroupRolesCount = LLMessageStringTable::getInstance()->getString("GroupRolesCount");
-char* _PREHASH_SimulatorBlock = LLMessageStringTable::getInstance()->getString("SimulatorBlock");
-char* _PREHASH_GroupID = LLMessageStringTable::getInstance()->getString("GroupID");
-char* _PREHASH_AgentVel = LLMessageStringTable::getInstance()->getString("AgentVel");
-char* _PREHASH_RequestImage = LLMessageStringTable::getInstance()->getString("RequestImage");
-char* _PREHASH_NetStats = LLMessageStringTable::getInstance()->getString("NetStats");
-char* _PREHASH_AgentPos = LLMessageStringTable::getInstance()->getString("AgentPos");
-char* _PREHASH_AgentSit = LLMessageStringTable::getInstance()->getString("AgentSit");
-char* _PREHASH_Material = LLMessageStringTable::getInstance()->getString("Material");
-char* _PREHASH_ObjectDeGrab = LLMessageStringTable::getInstance()->getString("ObjectDeGrab");
-char* _PREHASH_VelocityInterpolateOff = LLMessageStringTable::getInstance()->getString("VelocityInterpolateOff");
-char* _PREHASH_AuthorizedBuyerID = LLMessageStringTable::getInstance()->getString("AuthorizedBuyerID");
-char* _PREHASH_AvatarPropertiesReply = LLMessageStringTable::getInstance()->getString("AvatarPropertiesReply");
-char* _PREHASH_GroupProfileReply = LLMessageStringTable::getInstance()->getString("GroupProfileReply");
-char* _PREHASH_SimOwner = LLMessageStringTable::getInstance()->getString("SimOwner");
-char* _PREHASH_SalePrice = LLMessageStringTable::getInstance()->getString("SalePrice");
-char* _PREHASH_Animation = LLMessageStringTable::getInstance()->getString("Animation");
-char* _PREHASH_OwnerID = LLMessageStringTable::getInstance()->getString("OwnerID");
-char* _PREHASH_NearestLandingRegionUpdated = LLMessageStringTable::getInstance()->getString("NearestLandingRegionUpdated");
-char* _PREHASH_PassToAgent = LLMessageStringTable::getInstance()->getString("PassToAgent");
-char* _PREHASH_PreyAgent = LLMessageStringTable::getInstance()->getString("PreyAgent");
-char* _PREHASH_SimStats = LLMessageStringTable::getInstance()->getString("SimStats");
-char* _PREHASH_LogoutReply = LLMessageStringTable::getInstance()->getString("LogoutReply");
-char* _PREHASH_FeatureDisabled = LLMessageStringTable::getInstance()->getString("FeatureDisabled");
-char* _PREHASH_PhysicalAvatarEventList = LLMessageStringTable::getInstance()->getString("PhysicalAvatarEventList");
-char* _PREHASH_ObjectLocalID = LLMessageStringTable::getInstance()->getString("ObjectLocalID");
-char* _PREHASH_Dropped = LLMessageStringTable::getInstance()->getString("Dropped");
-char* _PREHASH_WebProfilesDisabled = LLMessageStringTable::getInstance()->getString("WebProfilesDisabled");
-char* _PREHASH_Destination = LLMessageStringTable::getInstance()->getString("Destination");
-char* _PREHASH_MasterID = LLMessageStringTable::getInstance()->getString("MasterID");
-char* _PREHASH_TransferData = LLMessageStringTable::getInstance()->getString("TransferData");
-char* _PREHASH_WantToMask = LLMessageStringTable::getInstance()->getString("WantToMask");
-char* _PREHASH_ParcelSelectObjects = LLMessageStringTable::getInstance()->getString("ParcelSelectObjects");
-char* _PREHASH_ExtraParams = LLMessageStringTable::getInstance()->getString("ExtraParams");
-char* _PREHASH_CreatorID = LLMessageStringTable::getInstance()->getString("CreatorID");
-char* _PREHASH_Summary = LLMessageStringTable::getInstance()->getString("Summary");
-char* _PREHASH_BuyObjectInventory = LLMessageStringTable::getInstance()->getString("BuyObjectInventory");
-char* _PREHASH_FetchInventory = LLMessageStringTable::getInstance()->getString("FetchInventory");
-char* _PREHASH_InventoryID = LLMessageStringTable::getInstance()->getString("InventoryID");
-char* _PREHASH_PacketNumber = LLMessageStringTable::getInstance()->getString("PacketNumber");
-char* _PREHASH_SetFollowCamProperties = LLMessageStringTable::getInstance()->getString("SetFollowCamProperties");
-char* _PREHASH_ClearFollowCamProperties = LLMessageStringTable::getInstance()->getString("ClearFollowCamProperties");
-char* _PREHASH_SequenceID = LLMessageStringTable::getInstance()->getString("SequenceID");
-char* _PREHASH_DataServerLogout = LLMessageStringTable::getInstance()->getString("DataServerLogout");
-char* _PREHASH_NameValue = LLMessageStringTable::getInstance()->getString("NameValue");
-char* _PREHASH_PathShearX = LLMessageStringTable::getInstance()->getString("PathShearX");
-char* _PREHASH_PathShearY = LLMessageStringTable::getInstance()->getString("PathShearY");
-char* _PREHASH_Velocity = LLMessageStringTable::getInstance()->getString("Velocity");
-char* _PREHASH_SecPerYear = LLMessageStringTable::getInstance()->getString("SecPerYear");
-char* _PREHASH_FirstName = LLMessageStringTable::getInstance()->getString("FirstName");
-char* _PREHASH_AttachedSoundGainChange = LLMessageStringTable::getInstance()->getString("AttachedSoundGainChange");
-char* _PREHASH_LocationID = LLMessageStringTable::getInstance()->getString("LocationID");
-char* _PREHASH_Running = LLMessageStringTable::getInstance()->getString("Running");
-char* _PREHASH_AgentThrottle = LLMessageStringTable::getInstance()->getString("AgentThrottle");
-char* _PREHASH_NeighborList = LLMessageStringTable::getInstance()->getString("NeighborList");
-char* _PREHASH_PathTaperX = LLMessageStringTable::getInstance()->getString("PathTaperX");
-char* _PREHASH_PathTaperY = LLMessageStringTable::getInstance()->getString("PathTaperY");
-char* _PREHASH_AgentRelated = LLMessageStringTable::getInstance()->getString("AgentRelated");
-char* _PREHASH_GranterBlock = LLMessageStringTable::getInstance()->getString("GranterBlock");
-char* _PREHASH_UseCachedMuteList = LLMessageStringTable::getInstance()->getString("UseCachedMuteList");
-char* _PREHASH_FailStats = LLMessageStringTable::getInstance()->getString("FailStats");
-char* _PREHASH_Tempfile = LLMessageStringTable::getInstance()->getString("Tempfile");
-char* _PREHASH_BuyerID = LLMessageStringTable::getInstance()->getString("BuyerID");
-char* _PREHASH_DirPeopleReply = LLMessageStringTable::getInstance()->getString("DirPeopleReply");
-char* _PREHASH_TransferInfo = LLMessageStringTable::getInstance()->getString("TransferInfo");
-char* _PREHASH_AvatarPickerRequestBackend = LLMessageStringTable::getInstance()->getString("AvatarPickerRequestBackend");
-char* _PREHASH_AvatarPropertiesRequestBackend = LLMessageStringTable::getInstance()->getString("AvatarPropertiesRequestBackend");
-char* _PREHASH_UpdateData = LLMessageStringTable::getInstance()->getString("UpdateData");
-char* _PREHASH_SimFPS = LLMessageStringTable::getInstance()->getString("SimFPS");
-char* _PREHASH_ReporterID = LLMessageStringTable::getInstance()->getString("ReporterID");
-char* _PREHASH_ButtonLabel = LLMessageStringTable::getInstance()->getString("ButtonLabel");
-char* _PREHASH_GranterID = LLMessageStringTable::getInstance()->getString("GranterID");
-char* _PREHASH_WantToText = LLMessageStringTable::getInstance()->getString("WantToText");
-char* _PREHASH_ReportType = LLMessageStringTable::getInstance()->getString("ReportType");
-char* _PREHASH_SimulatorReady = LLMessageStringTable::getInstance()->getString("SimulatorReady");
-char* _PREHASH_DataBlock = LLMessageStringTable::getInstance()->getString("DataBlock");
-char* _PREHASH_AnimationSourceList = LLMessageStringTable::getInstance()->getString("AnimationSourceList");
-char* _PREHASH_SubscribeLoad = LLMessageStringTable::getInstance()->getString("SubscribeLoad");
-char* _PREHASH_UnsubscribeLoad = LLMessageStringTable::getInstance()->getString("UnsubscribeLoad");
-char* _PREHASH_Packet = LLMessageStringTable::getInstance()->getString("Packet");
-char* _PREHASH_UndoLand = LLMessageStringTable::getInstance()->getString("UndoLand");
-char* _PREHASH_SimAccess = LLMessageStringTable::getInstance()->getString("SimAccess");
-char* _PREHASH_AbuserID = LLMessageStringTable::getInstance()->getString("AbuserID");
-char* _PREHASH_MembershipFee = LLMessageStringTable::getInstance()->getString("MembershipFee");
-char* _PREHASH_InviteGroupResponse = LLMessageStringTable::getInstance()->getString("InviteGroupResponse");
-char* _PREHASH_CreateInventoryFolder = LLMessageStringTable::getInstance()->getString("CreateInventoryFolder");
-char* _PREHASH_UpdateInventoryFolder = LLMessageStringTable::getInstance()->getString("UpdateInventoryFolder");
-char* _PREHASH_MoveInventoryFolder = LLMessageStringTable::getInstance()->getString("MoveInventoryFolder");
-char* _PREHASH_RemoveInventoryFolder = LLMessageStringTable::getInstance()->getString("RemoveInventoryFolder");
-char* _PREHASH_MoneyData = LLMessageStringTable::getInstance()->getString("MoneyData");
-char* _PREHASH_ObjectDeselect = LLMessageStringTable::getInstance()->getString("ObjectDeselect");
-char* _PREHASH_NewAssetID = LLMessageStringTable::getInstance()->getString("NewAssetID");
-char* _PREHASH_ObjectAdd = LLMessageStringTable::getInstance()->getString("ObjectAdd");
-char* _PREHASH_RayEndIsIntersection = LLMessageStringTable::getInstance()->getString("RayEndIsIntersection");
-char* _PREHASH_CompleteAuction = LLMessageStringTable::getInstance()->getString("CompleteAuction");
-char* _PREHASH_CircuitCode = LLMessageStringTable::getInstance()->getString("CircuitCode");
-char* _PREHASH_AgentMovementComplete = LLMessageStringTable::getInstance()->getString("AgentMovementComplete");
-char* _PREHASH_ViewerIP = LLMessageStringTable::getInstance()->getString("ViewerIP");
-char* _PREHASH_Header = LLMessageStringTable::getInstance()->getString("Header");
-char* _PREHASH_GestureFlags = LLMessageStringTable::getInstance()->getString("GestureFlags");
-char* _PREHASH_XferID = LLMessageStringTable::getInstance()->getString("XferID");
-char* _PREHASH_StatValue = LLMessageStringTable::getInstance()->getString("StatValue");
-char* _PREHASH_TaskID = LLMessageStringTable::getInstance()->getString("TaskID");
-char* _PREHASH_PickID = LLMessageStringTable::getInstance()->getString("PickID");
-char* _PREHASH_RayEnd = LLMessageStringTable::getInstance()->getString("RayEnd");
-char* _PREHASH_Throttles = LLMessageStringTable::getInstance()->getString("Throttles");
-char* _PREHASH_RebakeAvatarTextures = LLMessageStringTable::getInstance()->getString("RebakeAvatarTextures");
-char* _PREHASH_UpAxis = LLMessageStringTable::getInstance()->getString("UpAxis");
-char* _PREHASH_AgentTextures = LLMessageStringTable::getInstance()->getString("AgentTextures");
-char* _PREHASH_NotecardData = LLMessageStringTable::getInstance()->getString("NotecardData");
-char* _PREHASH_Radius = LLMessageStringTable::getInstance()->getString("Radius");
-char* _PREHASH_OffCircuit = LLMessageStringTable::getInstance()->getString("OffCircuit");
-char* _PREHASH_Access = LLMessageStringTable::getInstance()->getString("Access");
-char* _PREHASH_TitleRoleID = LLMessageStringTable::getInstance()->getString("TitleRoleID");
-char* _PREHASH_SquareMetersCredit = LLMessageStringTable::getInstance()->getString("SquareMetersCredit");
-char* _PREHASH_Filename = LLMessageStringTable::getInstance()->getString("Filename");
-char* _PREHASH_ClassifiedInfoRequest = LLMessageStringTable::getInstance()->getString("ClassifiedInfoRequest");
-char* _PREHASH_ParcelInfoRequest = LLMessageStringTable::getInstance()->getString("ParcelInfoRequest");
-char* _PREHASH_ParcelObjectOwnersRequest = LLMessageStringTable::getInstance()->getString("ParcelObjectOwnersRequest");
-char* _PREHASH_TeleportLandmarkRequest = LLMessageStringTable::getInstance()->getString("TeleportLandmarkRequest");
-char* _PREHASH_EventInfoRequest = LLMessageStringTable::getInstance()->getString("EventInfoRequest");
-char* _PREHASH_MoneyBalanceRequest = LLMessageStringTable::getInstance()->getString("MoneyBalanceRequest");
-char* _PREHASH_GroupMembersRequest = LLMessageStringTable::getInstance()->getString("GroupMembersRequest");
-char* _PREHASH_GroupRoleMembersRequest = LLMessageStringTable::getInstance()->getString("GroupRoleMembersRequest");
-char* _PREHASH_ChatFromSimulator = LLMessageStringTable::getInstance()->getString("ChatFromSimulator");
-char* _PREHASH_OldFolderID = LLMessageStringTable::getInstance()->getString("OldFolderID");
-char* _PREHASH_UserInfoRequest = LLMessageStringTable::getInstance()->getString("UserInfoRequest");
-char* _PREHASH_TextureID = LLMessageStringTable::getInstance()->getString("TextureID");
-char* _PREHASH_ProfileURL = LLMessageStringTable::getInstance()->getString("ProfileURL");
-char* _PREHASH_Handle = LLMessageStringTable::getInstance()->getString("Handle");
-char* _PREHASH_ButtonIndex = LLMessageStringTable::getInstance()->getString("ButtonIndex");
-char* _PREHASH_GetScriptRunning = LLMessageStringTable::getInstance()->getString("GetScriptRunning");
-char* _PREHASH_SetScriptRunning = LLMessageStringTable::getInstance()->getString("SetScriptRunning");
-char* _PREHASH_Health = LLMessageStringTable::getInstance()->getString("Health");
-char* _PREHASH_CircuitInfo = LLMessageStringTable::getInstance()->getString("CircuitInfo");
-char* _PREHASH_ObjectBuy = LLMessageStringTable::getInstance()->getString("ObjectBuy");
-char* _PREHASH_ProfileEnd = LLMessageStringTable::getInstance()->getString("ProfileEnd");
-char* _PREHASH_Effect = LLMessageStringTable::getInstance()->getString("Effect");
-char* _PREHASH_TestMessage = LLMessageStringTable::getInstance()->getString("TestMessage");
-char* _PREHASH_ScriptMailRegistration = LLMessageStringTable::getInstance()->getString("ScriptMailRegistration");
-char* _PREHASH_AgentSetAppearance = LLMessageStringTable::getInstance()->getString("AgentSetAppearance");
-char* _PREHASH_AvatarAppearance = LLMessageStringTable::getInstance()->getString("AvatarAppearance");
-char* _PREHASH_RegionData = LLMessageStringTable::getInstance()->getString("RegionData");
-char* _PREHASH_RequestingRegionData = LLMessageStringTable::getInstance()->getString("RequestingRegionData");
-char* _PREHASH_LandingRegionData = LLMessageStringTable::getInstance()->getString("LandingRegionData");
-char* _PREHASH_SitTransform = LLMessageStringTable::getInstance()->getString("SitTransform");
-char* _PREHASH_TerrainBase0 = LLMessageStringTable::getInstance()->getString("TerrainBase0");
-char* _PREHASH_SkillsMask = LLMessageStringTable::getInstance()->getString("SkillsMask");
-char* _PREHASH_AtAxis = LLMessageStringTable::getInstance()->getString("AtAxis");
-char* _PREHASH_TerrainBase1 = LLMessageStringTable::getInstance()->getString("TerrainBase1");
-char* _PREHASH_Reason = LLMessageStringTable::getInstance()->getString("Reason");
-char* _PREHASH_TerrainBase2 = LLMessageStringTable::getInstance()->getString("TerrainBase2");
-char* _PREHASH_TerrainBase3 = LLMessageStringTable::getInstance()->getString("TerrainBase3");
-char* _PREHASH_Params = LLMessageStringTable::getInstance()->getString("Params");
-char* _PREHASH_PingID = LLMessageStringTable::getInstance()->getString("PingID");
-char* _PREHASH_Change = LLMessageStringTable::getInstance()->getString("Change");
-char* _PREHASH_Height = LLMessageStringTable::getInstance()->getString("Height");
-char* _PREHASH_Region = LLMessageStringTable::getInstance()->getString("Region");
-char* _PREHASH_TelehubInfo = LLMessageStringTable::getInstance()->getString("TelehubInfo");
-char* _PREHASH_StateSave = LLMessageStringTable::getInstance()->getString("StateSave");
-char* _PREHASH_RoleData = LLMessageStringTable::getInstance()->getString("RoleData");
-char* _PREHASH_AgentAnimation = LLMessageStringTable::getInstance()->getString("AgentAnimation");
-char* _PREHASH_AvatarAnimation = LLMessageStringTable::getInstance()->getString("AvatarAnimation");
-char* _PREHASH_LogDwellTime = LLMessageStringTable::getInstance()->getString("LogDwellTime");
-char* _PREHASH_ParcelGodMarkAsContent = LLMessageStringTable::getInstance()->getString("ParcelGodMarkAsContent");
-char* _PREHASH_UsePhysics = LLMessageStringTable::getInstance()->getString("UsePhysics");
-char* _PREHASH_RegionDenyTransacted = LLMessageStringTable::getInstance()->getString("RegionDenyTransacted");
-char* _PREHASH_JointType = LLMessageStringTable::getInstance()->getString("JointType");
-char* _PREHASH_ObjectTaxEstimate = LLMessageStringTable::getInstance()->getString("ObjectTaxEstimate");
-char* _PREHASH_LightTaxEstimate = LLMessageStringTable::getInstance()->getString("LightTaxEstimate");
-char* _PREHASH_LandTaxEstimate = LLMessageStringTable::getInstance()->getString("LandTaxEstimate");
-char* _PREHASH_TeleportLandingStatusChanged = LLMessageStringTable::getInstance()->getString("TeleportLandingStatusChanged");
-char* _PREHASH_GroupTaxEstimate = LLMessageStringTable::getInstance()->getString("GroupTaxEstimate");
-char* _PREHASH_AvgViewerFPS = LLMessageStringTable::getInstance()->getString("AvgViewerFPS");
-char* _PREHASH_Buttons = LLMessageStringTable::getInstance()->getString("Buttons");
-char* _PREHASH_Sender = LLMessageStringTable::getInstance()->getString("Sender");
-char* _PREHASH_Dialog = LLMessageStringTable::getInstance()->getString("Dialog");
-char* _PREHASH_TargetData = LLMessageStringTable::getInstance()->getString("TargetData");
-char* _PREHASH_DestID = LLMessageStringTable::getInstance()->getString("DestID");
-char* _PREHASH_PricePublicObjectDelete = LLMessageStringTable::getInstance()->getString("PricePublicObjectDelete");
-char* _PREHASH_ObjectDelete = LLMessageStringTable::getInstance()->getString("ObjectDelete");
-char* _PREHASH_Delete = LLMessageStringTable::getInstance()->getString("Delete");
-char* _PREHASH_EventGodDelete = LLMessageStringTable::getInstance()->getString("EventGodDelete");
-char* _PREHASH_LastTaxDate = LLMessageStringTable::getInstance()->getString("LastTaxDate");
-char* _PREHASH_MapImageID = LLMessageStringTable::getInstance()->getString("MapImageID");
-char* _PREHASH_EndDateTime = LLMessageStringTable::getInstance()->getString("EndDateTime");
-char* _PREHASH_TerrainDetail0 = LLMessageStringTable::getInstance()->getString("TerrainDetail0");
-char* _PREHASH_TerrainDetail1 = LLMessageStringTable::getInstance()->getString("TerrainDetail1");
-char* _PREHASH_TerrainDetail2 = LLMessageStringTable::getInstance()->getString("TerrainDetail2");
-char* _PREHASH_TerrainDetail3 = LLMessageStringTable::getInstance()->getString("TerrainDetail3");
-char* _PREHASH_Offset = LLMessageStringTable::getInstance()->getString("Offset");
-char* _PREHASH_ObjectDelink = LLMessageStringTable::getInstance()->getString("ObjectDelink");
-char* _PREHASH_TargetObject = LLMessageStringTable::getInstance()->getString("TargetObject");
-char* _PREHASH_IsEstateManager = LLMessageStringTable::getInstance()->getString("IsEstateManager");
-char* _PREHASH_CancelAuction = LLMessageStringTable::getInstance()->getString("CancelAuction");
-char* _PREHASH_ObjectDetach = LLMessageStringTable::getInstance()->getString("ObjectDetach");
-char* _PREHASH_Compressed = LLMessageStringTable::getInstance()->getString("Compressed");
-char* _PREHASH_PathBegin = LLMessageStringTable::getInstance()->getString("PathBegin");
-char* _PREHASH_BypassRaycast = LLMessageStringTable::getInstance()->getString("BypassRaycast");
-char* _PREHASH_WinnerID = LLMessageStringTable::getInstance()->getString("WinnerID");
-char* _PREHASH_ChannelType = LLMessageStringTable::getInstance()->getString("ChannelType");
-char* _PREHASH_NonExemptMembers = LLMessageStringTable::getInstance()->getString("NonExemptMembers");
-char* _PREHASH_Agents = LLMessageStringTable::getInstance()->getString("Agents");
-char* _PREHASH_MemberData = LLMessageStringTable::getInstance()->getString("MemberData");
-char* _PREHASH_ToGroupID = LLMessageStringTable::getInstance()->getString("ToGroupID");
-char* _PREHASH_ImageNotInDatabase = LLMessageStringTable::getInstance()->getString("ImageNotInDatabase");
-char* _PREHASH_StartDate = LLMessageStringTable::getInstance()->getString("StartDate");
-char* _PREHASH_AnimID = LLMessageStringTable::getInstance()->getString("AnimID");
-char* _PREHASH_Serial = LLMessageStringTable::getInstance()->getString("Serial");
-char* _PREHASH_AbuseRegionName = LLMessageStringTable::getInstance()->getString("AbuseRegionName");
-char* _PREHASH_ModifyLand = LLMessageStringTable::getInstance()->getString("ModifyLand");
-char* _PREHASH_Digest = LLMessageStringTable::getInstance()->getString("Digest");
-char* _PREHASH_Victim = LLMessageStringTable::getInstance()->getString("Victim");
-char* _PREHASH_Script = LLMessageStringTable::getInstance()->getString("Script");
-char* _PREHASH_PickInfoReply = LLMessageStringTable::getInstance()->getString("PickInfoReply");
-char* _PREHASH_MoneyBalanceReply = LLMessageStringTable::getInstance()->getString("MoneyBalanceReply");
-char* _PREHASH_RoutedMoneyBalanceReply = LLMessageStringTable::getInstance()->getString("RoutedMoneyBalanceReply");
-char* _PREHASH_RoleID = LLMessageStringTable::getInstance()->getString("RoleID");
-char* _PREHASH_RegionInfo = LLMessageStringTable::getInstance()->getString("RegionInfo");
-char* _PREHASH_GodUpdateRegionInfo = LLMessageStringTable::getInstance()->getString("GodUpdateRegionInfo");
-char* _PREHASH_StartAnim = LLMessageStringTable::getInstance()->getString("StartAnim");
-char* _PREHASH_Action = LLMessageStringTable::getInstance()->getString("Action");
-char* _PREHASH_Location = LLMessageStringTable::getInstance()->getString("Location");
-char* _PREHASH_Rights = LLMessageStringTable::getInstance()->getString("Rights");
-char* _PREHASH_SearchDir = LLMessageStringTable::getInstance()->getString("SearchDir");
-char* _PREHASH_TransferRequest = LLMessageStringTable::getInstance()->getString("TransferRequest");
-char* _PREHASH_ScriptSensorRequest = LLMessageStringTable::getInstance()->getString("ScriptSensorRequest");
-char* _PREHASH_MoneyTransferRequest = LLMessageStringTable::getInstance()->getString("MoneyTransferRequest");
-char* _PREHASH_EjectGroupMemberRequest = LLMessageStringTable::getInstance()->getString("EjectGroupMemberRequest");
-char* _PREHASH_SkillsText = LLMessageStringTable::getInstance()->getString("SkillsText");
-char* _PREHASH_Resent = LLMessageStringTable::getInstance()->getString("Resent");
-char* _PREHASH_Center = LLMessageStringTable::getInstance()->getString("Center");
-char* _PREHASH_SharedData = LLMessageStringTable::getInstance()->getString("SharedData");
-char* _PREHASH_PSBlock = LLMessageStringTable::getInstance()->getString("PSBlock");
-char* _PREHASH_UUIDNameBlock = LLMessageStringTable::getInstance()->getString("UUIDNameBlock");
-char* _PREHASH_GroupTitleUpdate = LLMessageStringTable::getInstance()->getString("GroupTitleUpdate");
-char* _PREHASH_Method = LLMessageStringTable::getInstance()->getString("Method");
-char* _PREHASH_TouchName = LLMessageStringTable::getInstance()->getString("TouchName");
-char* _PREHASH_UpdateType = LLMessageStringTable::getInstance()->getString("UpdateType");
-char* _PREHASH_KickedFromEstateID = LLMessageStringTable::getInstance()->getString("KickedFromEstateID");
-char* _PREHASH_CandidateID = LLMessageStringTable::getInstance()->getString("CandidateID");
-char* _PREHASH_ParamData = LLMessageStringTable::getInstance()->getString("ParamData");
-char* _PREHASH_GodlikeMessage = LLMessageStringTable::getInstance()->getString("GodlikeMessage");
-char* _PREHASH_SystemMessage = LLMessageStringTable::getInstance()->getString("SystemMessage");
-char* _PREHASH_BodyRotation = LLMessageStringTable::getInstance()->getString("BodyRotation");
-char* _PREHASH_SearchRegions = LLMessageStringTable::getInstance()->getString("SearchRegions");
-char* _PREHASH_AnimationData = LLMessageStringTable::getInstance()->getString("AnimationData");
-char* _PREHASH_StatID = LLMessageStringTable::getInstance()->getString("StatID");
-char* _PREHASH_ItemID = LLMessageStringTable::getInstance()->getString("ItemID");
-char* _PREHASH_ScriptDialogReply = LLMessageStringTable::getInstance()->getString("ScriptDialogReply");
-char* _PREHASH_RegionIDAndHandleReply = LLMessageStringTable::getInstance()->getString("RegionIDAndHandleReply");
-char* _PREHASH_CameraAtOffset = LLMessageStringTable::getInstance()->getString("CameraAtOffset");
-char* _PREHASH_VoteID = LLMessageStringTable::getInstance()->getString("VoteID");
-char* _PREHASH_ParcelGodForceOwner = LLMessageStringTable::getInstance()->getString("ParcelGodForceOwner");
-char* _PREHASH_Filter = LLMessageStringTable::getInstance()->getString("Filter");
-char* _PREHASH_InviteData = LLMessageStringTable::getInstance()->getString("InviteData");
-char* _PREHASH_PCode = LLMessageStringTable::getInstance()->getString("PCode");
-char* _PREHASH_SearchPos = LLMessageStringTable::getInstance()->getString("SearchPos");
-char* _PREHASH_PreyID = LLMessageStringTable::getInstance()->getString("PreyID");
-char* _PREHASH_TerrainLowerLimit = LLMessageStringTable::getInstance()->getString("TerrainLowerLimit");
-char* _PREHASH_EventFlags = LLMessageStringTable::getInstance()->getString("EventFlags");
-char* _PREHASH_TallyVotes = LLMessageStringTable::getInstance()->getString("TallyVotes");
-char* _PREHASH_Result = LLMessageStringTable::getInstance()->getString("Result");
-char* _PREHASH_LookAt = LLMessageStringTable::getInstance()->getString("LookAt");
-char* _PREHASH_SearchOrder = LLMessageStringTable::getInstance()->getString("SearchOrder");
-char* _PREHASH_PayButton = LLMessageStringTable::getInstance()->getString("PayButton");
-char* _PREHASH_SelfCount = LLMessageStringTable::getInstance()->getString("SelfCount");
-char* _PREHASH_PacketCount = LLMessageStringTable::getInstance()->getString("PacketCount");
-char* _PREHASH_ParcelBuyPass = LLMessageStringTable::getInstance()->getString("ParcelBuyPass");
-char* _PREHASH_OldItemID = LLMessageStringTable::getInstance()->getString("OldItemID");
-char* _PREHASH_RegionPort = LLMessageStringTable::getInstance()->getString("RegionPort");
-char* _PREHASH_PriceEnergyUnit = LLMessageStringTable::getInstance()->getString("PriceEnergyUnit");
-char* _PREHASH_Bitmap = LLMessageStringTable::getInstance()->getString("Bitmap");
-char* _PREHASH_CacheMissType = LLMessageStringTable::getInstance()->getString("CacheMissType");
-char* _PREHASH_VFileID = LLMessageStringTable::getInstance()->getString("VFileID");
-char* _PREHASH_GroupInsigniaID = LLMessageStringTable::getInstance()->getString("GroupInsigniaID");
-char* _PREHASH_Online = LLMessageStringTable::getInstance()->getString("Online");
-char* _PREHASH_KickFlags = LLMessageStringTable::getInstance()->getString("KickFlags");
-char* _PREHASH_CovenantID = LLMessageStringTable::getInstance()->getString("CovenantID");
-char* _PREHASH_SysCPU = LLMessageStringTable::getInstance()->getString("SysCPU");
-char* _PREHASH_EMail = LLMessageStringTable::getInstance()->getString("EMail");
-char* _PREHASH_AggregatePermTextures = LLMessageStringTable::getInstance()->getString("AggregatePermTextures");
-char* _PREHASH_ChatChannel = LLMessageStringTable::getInstance()->getString("ChatChannel");
-char* _PREHASH_ReturnID = LLMessageStringTable::getInstance()->getString("ReturnID");
-char* _PREHASH_ObjectAttach = LLMessageStringTable::getInstance()->getString("ObjectAttach");
-char* _PREHASH_TargetPort = LLMessageStringTable::getInstance()->getString("TargetPort");
-char* _PREHASH_ObjectSpinStop = LLMessageStringTable::getInstance()->getString("ObjectSpinStop");
-char* _PREHASH_FullID = LLMessageStringTable::getInstance()->getString("FullID");
-char* _PREHASH_ActivateGroup = LLMessageStringTable::getInstance()->getString("ActivateGroup");
-char* _PREHASH_SysGPU = LLMessageStringTable::getInstance()->getString("SysGPU");
-char* _PREHASH_AvatarInterestsReply = LLMessageStringTable::getInstance()->getString("AvatarInterestsReply");
-char* _PREHASH_StartLure = LLMessageStringTable::getInstance()->getString("StartLure");
-char* _PREHASH_SysRAM = LLMessageStringTable::getInstance()->getString("SysRAM");
-char* _PREHASH_ObjectPosition = LLMessageStringTable::getInstance()->getString("ObjectPosition");
-char* _PREHASH_SitPosition = LLMessageStringTable::getInstance()->getString("SitPosition");
-char* _PREHASH_StartTime = LLMessageStringTable::getInstance()->getString("StartTime");
-char* _PREHASH_BornOn = LLMessageStringTable::getInstance()->getString("BornOn");
-char* _PREHASH_CameraCollidePlane = LLMessageStringTable::getInstance()->getString("CameraCollidePlane");
-char* _PREHASH_EconomyDataRequest = LLMessageStringTable::getInstance()->getString("EconomyDataRequest");
-char* _PREHASH_TeleportLureRequest = LLMessageStringTable::getInstance()->getString("TeleportLureRequest");
-char* _PREHASH_FolderID = LLMessageStringTable::getInstance()->getString("FolderID");
-char* _PREHASH_RegionHandleRequest = LLMessageStringTable::getInstance()->getString("RegionHandleRequest");
-char* _PREHASH_ScriptDataRequest = LLMessageStringTable::getInstance()->getString("ScriptDataRequest");
-char* _PREHASH_GroupRoleDataRequest = LLMessageStringTable::getInstance()->getString("GroupRoleDataRequest");
-char* _PREHASH_GroupTitlesRequest = LLMessageStringTable::getInstance()->getString("GroupTitlesRequest");
-char* _PREHASH_AgentWearablesRequest = LLMessageStringTable::getInstance()->getString("AgentWearablesRequest");
-char* _PREHASH_MapBlockRequest = LLMessageStringTable::getInstance()->getString("MapBlockRequest");
-char* _PREHASH_LureID = LLMessageStringTable::getInstance()->getString("LureID");
-char* _PREHASH_CopyCenters = LLMessageStringTable::getInstance()->getString("CopyCenters");
-char* _PREHASH_ParamList = LLMessageStringTable::getInstance()->getString("ParamList");
-char* _PREHASH_InventorySerial = LLMessageStringTable::getInstance()->getString("InventorySerial");
-char* _PREHASH_EdgeDataPacket = LLMessageStringTable::getInstance()->getString("EdgeDataPacket");
-char* _PREHASH_AvatarPickerReply = LLMessageStringTable::getInstance()->getString("AvatarPickerReply");
-char* _PREHASH_ParcelDwellReply = LLMessageStringTable::getInstance()->getString("ParcelDwellReply");
-char* _PREHASH_IsForSale = LLMessageStringTable::getInstance()->getString("IsForSale");
-char* _PREHASH_MuteID = LLMessageStringTable::getInstance()->getString("MuteID");
-char* _PREHASH_MeanCollisionAlert = LLMessageStringTable::getInstance()->getString("MeanCollisionAlert");
-char* _PREHASH_CanAcceptTasks = LLMessageStringTable::getInstance()->getString("CanAcceptTasks");
-char* _PREHASH_ItemData = LLMessageStringTable::getInstance()->getString("ItemData");
-char* _PREHASH_AnimationList = LLMessageStringTable::getInstance()->getString("AnimationList");
-char* _PREHASH_Reputation = LLMessageStringTable::getInstance()->getString("Reputation");
-char* _PREHASH_IntValue = LLMessageStringTable::getInstance()->getString("IntValue");
-char* _PREHASH_TargetType = LLMessageStringTable::getInstance()->getString("TargetType");
-char* _PREHASH_Amount = LLMessageStringTable::getInstance()->getString("Amount");
-char* _PREHASH_HasAttachment = LLMessageStringTable::getInstance()->getString("HasAttachment");
-char* _PREHASH_UpdateAttachment = LLMessageStringTable::getInstance()->getString("UpdateAttachment");
-char* _PREHASH_RemoveAttachment = LLMessageStringTable::getInstance()->getString("RemoveAttachment");
-char* _PREHASH_HeightWidthBlock = LLMessageStringTable::getInstance()->getString("HeightWidthBlock");
-char* _PREHASH_RequestObjectPropertiesFamily = LLMessageStringTable::getInstance()->getString("RequestObjectPropertiesFamily");
-char* _PREHASH_ObjectPropertiesFamily = LLMessageStringTable::getInstance()->getString("ObjectPropertiesFamily");
-char* _PREHASH_UserData = LLMessageStringTable::getInstance()->getString("UserData");
-char* _PREHASH_IsReadable = LLMessageStringTable::getInstance()->getString("IsReadable");
-char* _PREHASH_PathCurve = LLMessageStringTable::getInstance()->getString("PathCurve");
-char* _PREHASH_Status = LLMessageStringTable::getInstance()->getString("Status");
-char* _PREHASH_FromGroup = LLMessageStringTable::getInstance()->getString("FromGroup");
-char* _PREHASH_AlreadyVoted = LLMessageStringTable::getInstance()->getString("AlreadyVoted");
-char* _PREHASH_PlacesReply = LLMessageStringTable::getInstance()->getString("PlacesReply");
-char* _PREHASH_DirPlacesReply = LLMessageStringTable::getInstance()->getString("DirPlacesReply");
-char* _PREHASH_ParcelBuy = LLMessageStringTable::getInstance()->getString("ParcelBuy");
-char* _PREHASH_DirFindQueryBackend = LLMessageStringTable::getInstance()->getString("DirFindQueryBackend");
-char* _PREHASH_DirPlacesQueryBackend = LLMessageStringTable::getInstance()->getString("DirPlacesQueryBackend");
-char* _PREHASH_DirClassifiedQueryBackend = LLMessageStringTable::getInstance()->getString("DirClassifiedQueryBackend");
-char* _PREHASH_DirLandQueryBackend = LLMessageStringTable::getInstance()->getString("DirLandQueryBackend");
-char* _PREHASH_DirPopularQueryBackend = LLMessageStringTable::getInstance()->getString("DirPopularQueryBackend");
-char* _PREHASH_HistoryData = LLMessageStringTable::getInstance()->getString("HistoryData");
-char* _PREHASH_SnapshotID = LLMessageStringTable::getInstance()->getString("SnapshotID");
-char* _PREHASH_Aspect = LLMessageStringTable::getInstance()->getString("Aspect");
-char* _PREHASH_ParamSize = LLMessageStringTable::getInstance()->getString("ParamSize");
-char* _PREHASH_VoteCast = LLMessageStringTable::getInstance()->getString("VoteCast");
-char* _PREHASH_CastsShadows = LLMessageStringTable::getInstance()->getString("CastsShadows");
-char* _PREHASH_EveryoneMask = LLMessageStringTable::getInstance()->getString("EveryoneMask");
-char* _PREHASH_ObjectSpinUpdate = LLMessageStringTable::getInstance()->getString("ObjectSpinUpdate");
-char* _PREHASH_MaturePublish = LLMessageStringTable::getInstance()->getString("MaturePublish");
-char* _PREHASH_UseExistingAsset = LLMessageStringTable::getInstance()->getString("UseExistingAsset");
-char* _PREHASH_Powers = LLMessageStringTable::getInstance()->getString("Powers");
-char* _PREHASH_ParcelLocalID = LLMessageStringTable::getInstance()->getString("ParcelLocalID");
-char* _PREHASH_TeleportCancel = LLMessageStringTable::getInstance()->getString("TeleportCancel");
-char* _PREHASH_UnixTime = LLMessageStringTable::getInstance()->getString("UnixTime");
-char* _PREHASH_QueryFlags = LLMessageStringTable::getInstance()->getString("QueryFlags");
-char* _PREHASH_AlwaysRun = LLMessageStringTable::getInstance()->getString("AlwaysRun");
-char* _PREHASH_Bottom = LLMessageStringTable::getInstance()->getString("Bottom");
-char* _PREHASH_ButtonData = LLMessageStringTable::getInstance()->getString("ButtonData");
-char* _PREHASH_SoundData = LLMessageStringTable::getInstance()->getString("SoundData");
-char* _PREHASH_ViewerStats = LLMessageStringTable::getInstance()->getString("ViewerStats");
-char* _PREHASH_RegionHandshake = LLMessageStringTable::getInstance()->getString("RegionHandshake");
-char* _PREHASH_ObjectDescription = LLMessageStringTable::getInstance()->getString("ObjectDescription");
-char* _PREHASH_Description = LLMessageStringTable::getInstance()->getString("Description");
-char* _PREHASH_ParamType = LLMessageStringTable::getInstance()->getString("ParamType");
-char* _PREHASH_UUIDNameReply = LLMessageStringTable::getInstance()->getString("UUIDNameReply");
-char* _PREHASH_UUIDGroupNameReply = LLMessageStringTable::getInstance()->getString("UUIDGroupNameReply");
-char* _PREHASH_SaveAssetIntoInventory = LLMessageStringTable::getInstance()->getString("SaveAssetIntoInventory");
-char* _PREHASH_UserInfo = LLMessageStringTable::getInstance()->getString("UserInfo");
-char* _PREHASH_AnimSequenceID = LLMessageStringTable::getInstance()->getString("AnimSequenceID");
-char* _PREHASH_NVPairs = LLMessageStringTable::getInstance()->getString("NVPairs");
-char* _PREHASH_GroupNoticesListRequest = LLMessageStringTable::getInstance()->getString("GroupNoticesListRequest");
-char* _PREHASH_ParcelAccessListRequest = LLMessageStringTable::getInstance()->getString("ParcelAccessListRequest");
-char* _PREHASH_MuteListRequest = LLMessageStringTable::getInstance()->getString("MuteListRequest");
-char* _PREHASH_RpcChannelRequest = LLMessageStringTable::getInstance()->getString("RpcChannelRequest");
-char* _PREHASH_LandStatRequest = LLMessageStringTable::getInstance()->getString("LandStatRequest");
-char* _PREHASH_PlacesQuery = LLMessageStringTable::getInstance()->getString("PlacesQuery");
-char* _PREHASH_DirPlacesQuery = LLMessageStringTable::getInstance()->getString("DirPlacesQuery");
-char* _PREHASH_SortOrder = LLMessageStringTable::getInstance()->getString("SortOrder");
-char* _PREHASH_Hunter = LLMessageStringTable::getInstance()->getString("Hunter");
-char* _PREHASH_SunAngVelocity = LLMessageStringTable::getInstance()->getString("SunAngVelocity");
-char* _PREHASH_BinaryBucket = LLMessageStringTable::getInstance()->getString("BinaryBucket");
-char* _PREHASH_ImagePacket = LLMessageStringTable::getInstance()->getString("ImagePacket");
-char* _PREHASH_StartGroupProposal = LLMessageStringTable::getInstance()->getString("StartGroupProposal");
-char* _PREHASH_EnergyLevel = LLMessageStringTable::getInstance()->getString("EnergyLevel");
-char* _PREHASH_PriceForListing = LLMessageStringTable::getInstance()->getString("PriceForListing");
-char* _PREHASH_Scale = LLMessageStringTable::getInstance()->getString("Scale");
-char* _PREHASH_EstateCovenantReply = LLMessageStringTable::getInstance()->getString("EstateCovenantReply");
-char* _PREHASH_ParentEstateID = LLMessageStringTable::getInstance()->getString("ParentEstateID");
-char* _PREHASH_Extra2 = LLMessageStringTable::getInstance()->getString("Extra2");
-char* _PREHASH_Throttle = LLMessageStringTable::getInstance()->getString("Throttle");
-char* _PREHASH_SimIP = LLMessageStringTable::getInstance()->getString("SimIP");
-char* _PREHASH_GodID = LLMessageStringTable::getInstance()->getString("GodID");
-char* _PREHASH_TeleportMinPrice = LLMessageStringTable::getInstance()->getString("TeleportMinPrice");
-char* _PREHASH_VoteItem = LLMessageStringTable::getInstance()->getString("VoteItem");
-char* _PREHASH_ObjectRotation = LLMessageStringTable::getInstance()->getString("ObjectRotation");
-char* _PREHASH_SitRotation = LLMessageStringTable::getInstance()->getString("SitRotation");
-char* _PREHASH_SnapSelection = LLMessageStringTable::getInstance()->getString("SnapSelection");
-char* _PREHASH_SoundTrigger = LLMessageStringTable::getInstance()->getString("SoundTrigger");
-char* _PREHASH_TerrainRaiseLimit = LLMessageStringTable::getInstance()->getString("TerrainRaiseLimit");
-char* _PREHASH_Quorum = LLMessageStringTable::getInstance()->getString("Quorum");
-char* _PREHASH_AgentBlock = LLMessageStringTable::getInstance()->getString("AgentBlock");
-char* _PREHASH_CommandBlock = LLMessageStringTable::getInstance()->getString("CommandBlock");
-char* _PREHASH_PricePublicObjectDecay = LLMessageStringTable::getInstance()->getString("PricePublicObjectDecay");
-char* _PREHASH_SpawnPointPos = LLMessageStringTable::getInstance()->getString("SpawnPointPos");
-char* _PREHASH_VolumeDetail = LLMessageStringTable::getInstance()->getString("VolumeDetail");
-char* _PREHASH_FromAgentName = LLMessageStringTable::getInstance()->getString("FromAgentName");
-char* _PREHASH_Range = LLMessageStringTable::getInstance()->getString("Range");
-char* _PREHASH_DirectoryVisibility = LLMessageStringTable::getInstance()->getString("DirectoryVisibility");
-char* _PREHASH_PublicIP = LLMessageStringTable::getInstance()->getString("PublicIP");
-char* _PREHASH_TeleportFailed = LLMessageStringTable::getInstance()->getString("TeleportFailed");
-char* _PREHASH_PreloadSound = LLMessageStringTable::getInstance()->getString("PreloadSound");
-char* _PREHASH_ScreenshotID = LLMessageStringTable::getInstance()->getString("ScreenshotID");
-char* _PREHASH_CovenantTimestamp = LLMessageStringTable::getInstance()->getString("CovenantTimestamp");
-char* _PREHASH_OldestUnacked = LLMessageStringTable::getInstance()->getString("OldestUnacked");
-char* _PREHASH_SimulatorIP = LLMessageStringTable::getInstance()->getString("SimulatorIP");
-char* _PREHASH_Value = LLMessageStringTable::getInstance()->getString("Value");
-char* _PREHASH_JointAxisOrAnchor = LLMessageStringTable::getInstance()->getString("JointAxisOrAnchor");
-char* _PREHASH_Test0 = LLMessageStringTable::getInstance()->getString("Test0");
-char* _PREHASH_Test1 = LLMessageStringTable::getInstance()->getString("Test1");
-char* _PREHASH_Test2 = LLMessageStringTable::getInstance()->getString("Test2");
-char* _PREHASH_SunPhase = LLMessageStringTable::getInstance()->getString("SunPhase");
-char* _PREHASH_ParcelDivide = LLMessageStringTable::getInstance()->getString("ParcelDivide");
-char* _PREHASH_PriceObjectClaim = LLMessageStringTable::getInstance()->getString("PriceObjectClaim");
-char* _PREHASH_Field = LLMessageStringTable::getInstance()->getString("Field");
-char* _PREHASH_Ratio = LLMessageStringTable::getInstance()->getString("Ratio");
-char* _PREHASH_JoinGroupReply = LLMessageStringTable::getInstance()->getString("JoinGroupReply");
-char* _PREHASH_LiveHelpGroupReply = LLMessageStringTable::getInstance()->getString("LiveHelpGroupReply");
-char* _PREHASH_Score = LLMessageStringTable::getInstance()->getString("Score");
-char* _PREHASH_Image = LLMessageStringTable::getInstance()->getString("Image");
-char* _PREHASH_ObjectClickAction = LLMessageStringTable::getInstance()->getString("ObjectClickAction");
-char* _PREHASH_Parameter = LLMessageStringTable::getInstance()->getString("Parameter");
-char* _PREHASH_Flags = LLMessageStringTable::getInstance()->getString("Flags");
-char* _PREHASH_Plane = LLMessageStringTable::getInstance()->getString("Plane");
-char* _PREHASH_Width = LLMessageStringTable::getInstance()->getString("Width");
-char* _PREHASH_Right = LLMessageStringTable::getInstance()->getString("Right");
-char* _PREHASH_DirFindQuery = LLMessageStringTable::getInstance()->getString("DirFindQuery");
-char* _PREHASH_Textures = LLMessageStringTable::getInstance()->getString("Textures");
-char* _PREHASH_EventData = LLMessageStringTable::getInstance()->getString("EventData");
-char* _PREHASH_Final = LLMessageStringTable::getInstance()->getString("Final");
-char* _PREHASH_System = LLMessageStringTable::getInstance()->getString("System");
-char* _PREHASH_TelehubPos = LLMessageStringTable::getInstance()->getString("TelehubPos");
-char* _PREHASH_ReportAutosaveCrash = LLMessageStringTable::getInstance()->getString("ReportAutosaveCrash");
-char* _PREHASH_CreateTrustedCircuit = LLMessageStringTable::getInstance()->getString("CreateTrustedCircuit");
-char* _PREHASH_DenyTrustedCircuit = LLMessageStringTable::getInstance()->getString("DenyTrustedCircuit");
-char* _PREHASH_RequestTrustedCircuit = LLMessageStringTable::getInstance()->getString("RequestTrustedCircuit");
-char* _PREHASH_Codec = LLMessageStringTable::getInstance()->getString("Codec");
-char* _PREHASH_Modal = LLMessageStringTable::getInstance()->getString("Modal");
-char* _PREHASH_ChildAgentUnknown = LLMessageStringTable::getInstance()->getString("ChildAgentUnknown");
-char* _PREHASH_LandingType = LLMessageStringTable::getInstance()->getString("LandingType");
-char* _PREHASH_ScriptRunningReply = LLMessageStringTable::getInstance()->getString("ScriptRunningReply");
-char* _PREHASH_Reply = LLMessageStringTable::getInstance()->getString("Reply");
-char* _PREHASH_GroupAccountDetailsReply = LLMessageStringTable::getInstance()->getString("GroupAccountDetailsReply");
-char* _PREHASH_TelehubRot = LLMessageStringTable::getInstance()->getString("TelehubRot");
-char* _PREHASH_AcceptFriendship = LLMessageStringTable::getInstance()->getString("AcceptFriendship");
-char* _PREHASH_ItemType = LLMessageStringTable::getInstance()->getString("ItemType");
-char* _PREHASH_DwellInfo = LLMessageStringTable::getInstance()->getString("DwellInfo");
-char* _PREHASH_AgentResume = LLMessageStringTable::getInstance()->getString("AgentResume");
-char* _PREHASH_MailFilter = LLMessageStringTable::getInstance()->getString("MailFilter");
-char* _PREHASH_Disconnect = LLMessageStringTable::getInstance()->getString("Disconnect");
-char* _PREHASH_SimPosition = LLMessageStringTable::getInstance()->getString("SimPosition");
-char* _PREHASH_SimWideTotalPrims = LLMessageStringTable::getInstance()->getString("SimWideTotalPrims");
-char* _PREHASH_Index = LLMessageStringTable::getInstance()->getString("Index");
-char* _PREHASH_SimFilename = LLMessageStringTable::getInstance()->getString("SimFilename");
-char* _PREHASH_LastOwnerID = LLMessageStringTable::getInstance()->getString("LastOwnerID");
-char* _PREHASH_GroupNoticeRequest = LLMessageStringTable::getInstance()->getString("GroupNoticeRequest");
-char* _PREHASH_EmailMessageRequest = LLMessageStringTable::getInstance()->getString("EmailMessageRequest");
-char* _PREHASH_MapItemRequest = LLMessageStringTable::getInstance()->getString("MapItemRequest");
-char* _PREHASH_AgentCount = LLMessageStringTable::getInstance()->getString("AgentCount");
-char* _PREHASH_MessageBlock = LLMessageStringTable::getInstance()->getString("MessageBlock");
-char* _PREHASH_FuseBlock = LLMessageStringTable::getInstance()->getString("FuseBlock");
-char* _PREHASH_AgentGroupData = LLMessageStringTable::getInstance()->getString("AgentGroupData");
-char* _PREHASH_ClassifiedInfoUpdate = LLMessageStringTable::getInstance()->getString("ClassifiedInfoUpdate");
-char* _PREHASH_RegionPos = LLMessageStringTable::getInstance()->getString("RegionPos");
-char* _PREHASH_ParcelMediaUpdate = LLMessageStringTable::getInstance()->getString("ParcelMediaUpdate");
-char* _PREHASH_NoticeID = LLMessageStringTable::getInstance()->getString("NoticeID");
-char* _PREHASH_GridX = LLMessageStringTable::getInstance()->getString("GridX");
-char* _PREHASH_GridY = LLMessageStringTable::getInstance()->getString("GridY");
-char* _PREHASH_Title = LLMessageStringTable::getInstance()->getString("Title");
-char* _PREHASH_AuctionID = LLMessageStringTable::getInstance()->getString("AuctionID");
-char* _PREHASH_VoteType = LLMessageStringTable::getInstance()->getString("VoteType");
-char* _PREHASH_CategoryID = LLMessageStringTable::getInstance()->getString("CategoryID");
-char* _PREHASH_Token = LLMessageStringTable::getInstance()->getString("Token");
-char* _PREHASH_AggregatePerms = LLMessageStringTable::getInstance()->getString("AggregatePerms");
-char* _PREHASH_ObjectSelect = LLMessageStringTable::getInstance()->getString("ObjectSelect");
-char* _PREHASH_ForceObjectSelect = LLMessageStringTable::getInstance()->getString("ForceObjectSelect");
-char* _PREHASH_Price = LLMessageStringTable::getInstance()->getString("Price");
-char* _PREHASH_SunDirection = LLMessageStringTable::getInstance()->getString("SunDirection");
-char* _PREHASH_FromName = LLMessageStringTable::getInstance()->getString("FromName");
-char* _PREHASH_ChangeInventoryItemFlags = LLMessageStringTable::getInstance()->getString("ChangLLInventoryItemFlags");
-char* _PREHASH_Force = LLMessageStringTable::getInstance()->getString("Force");
-char* _PREHASH_TransactionBlock = LLMessageStringTable::getInstance()->getString("TransactionBlock");
-char* _PREHASH_PowersMask = LLMessageStringTable::getInstance()->getString("PowersMask");
-char* _PREHASH_Stamp = LLMessageStringTable::getInstance()->getString("Stamp");
-char* _PREHASH_TotalCredits = LLMessageStringTable::getInstance()->getString("TotalCredits");
-char* _PREHASH_State = LLMessageStringTable::getInstance()->getString("State");
-char* _PREHASH_TextureIndex = LLMessageStringTable::getInstance()->getString("TextureIndex");
-char* _PREHASH_InviteeID = LLMessageStringTable::getInstance()->getString("InviteeID");
-char* _PREHASH_ParcelReclaim = LLMessageStringTable::getInstance()->getString("ParcelReclaim");
-char* _PREHASH_Money = LLMessageStringTable::getInstance()->getString("Money");
-char* _PREHASH_PathTwist = LLMessageStringTable::getInstance()->getString("PathTwist");
-char* _PREHASH_AuthBuyerID = LLMessageStringTable::getInstance()->getString("AuthBuyerID");
-char* _PREHASH_Color = LLMessageStringTable::getInstance()->getString("Color");
-char* _PREHASH_SourceType = LLMessageStringTable::getInstance()->getString("SourceType");
-char* _PREHASH_World = LLMessageStringTable::getInstance()->getString("World");
-char* _PREHASH_QueryData = LLMessageStringTable::getInstance()->getString("QueryData");
-char* _PREHASH_Users = LLMessageStringTable::getInstance()->getString("Users");
-char* _PREHASH_SysOS = LLMessageStringTable::getInstance()->getString("SysOS");
-char* _PREHASH_Notes = LLMessageStringTable::getInstance()->getString("Notes");
-char* _PREHASH_AvatarID = LLMessageStringTable::getInstance()->getString("AvatarID");
-char* _PREHASH_FounderID = LLMessageStringTable::getInstance()->getString("FounderID");
-char* _PREHASH_EndPointID = LLMessageStringTable::getInstance()->getString("EndPointID");
-char* _PREHASH_LocationLookAt = LLMessageStringTable::getInstance()->getString("LocationLookAt");
-char* _PREHASH_Sound = LLMessageStringTable::getInstance()->getString("Sound");
-char* _PREHASH_Cover = LLMessageStringTable::getInstance()->getString("Cover");
-char* _PREHASH_TotalObjectCount = LLMessageStringTable::getInstance()->getString("TotalObjectCount");
-char* _PREHASH_TextureEntry = LLMessageStringTable::getInstance()->getString("TextureEntry");
-char* _PREHASH_SquareMetersCommitted = LLMessageStringTable::getInstance()->getString("SquareMetersCommitted");
-char* _PREHASH_ChannelID = LLMessageStringTable::getInstance()->getString("ChannelID");
-char* _PREHASH_Dwell = LLMessageStringTable::getInstance()->getString("Dwell");
-char* _PREHASH_North = LLMessageStringTable::getInstance()->getString("North");
-char* _PREHASH_AgentUpdate = LLMessageStringTable::getInstance()->getString("AgentUpdate");
-char* _PREHASH_PickGodDelete = LLMessageStringTable::getInstance()->getString("PickGodDelete");
-char* _PREHASH_HostName = LLMessageStringTable::getInstance()->getString("HostName");
-char* _PREHASH_PriceParcelClaim = LLMessageStringTable::getInstance()->getString("PriceParcelClaim");
-char* _PREHASH_ParcelClaim = LLMessageStringTable::getInstance()->getString("ParcelClaim");
-char* _PREHASH_AgentPowers = LLMessageStringTable::getInstance()->getString("AgentPowers");
-char* _PREHASH_ProfileHollow = LLMessageStringTable::getInstance()->getString("ProfileHollow");
-char* _PREHASH_GroupRoleChanges = LLMessageStringTable::getInstance()->getString("GroupRoleChanges");
-char* _PREHASH_Count = LLMessageStringTable::getInstance()->getString("Count");
-char* _PREHASH_South = LLMessageStringTable::getInstance()->getString("South");
-char* _PREHASH_ObjectUpdateCompressed = LLMessageStringTable::getInstance()->getString("ObjectUpdateCompressed");
-char* _PREHASH_MuteFlags = LLMessageStringTable::getInstance()->getString("MuteFlags");
-char* _PREHASH_Group = LLMessageStringTable::getInstance()->getString("Group");
-char* _PREHASH_AgentPause = LLMessageStringTable::getInstance()->getString("AgentPause");
-char* _PREHASH_LanguagesText = LLMessageStringTable::getInstance()->getString("LanguagesText");
-char* _PREHASH_Error = LLMessageStringTable::getInstance()->getString("Error");
-char* _PREHASH_InternalScriptMail = LLMessageStringTable::getInstance()->getString("InternalScriptMail");
-char* _PREHASH_FindAgent = LLMessageStringTable::getInstance()->getString("FindAgent");
-char* _PREHASH_AgentData = LLMessageStringTable::getInstance()->getString("AgentData");
-char* _PREHASH_FolderData = LLMessageStringTable::getInstance()->getString("FolderData");
-char* _PREHASH_AssetBlock = LLMessageStringTable::getInstance()->getString("AssetBlock");
-char* _PREHASH_AcceptNotices = LLMessageStringTable::getInstance()->getString("AcceptNotices");
-char* _PREHASH_SetGroupAcceptNotices = LLMessageStringTable::getInstance()->getString("SetGroupAcceptNotices");
-char* _PREHASH_CloseCircuit = LLMessageStringTable::getInstance()->getString("CloseCircuit");
-char* _PREHASH_TeleportFinish = LLMessageStringTable::getInstance()->getString("TeleportFinish");
-char* _PREHASH_PathRevolutions = LLMessageStringTable::getInstance()->getString("PathRevolutions");
-char* _PREHASH_ClassifiedInfoReply = LLMessageStringTable::getInstance()->getString("ClassifiedInfoReply");
-char* _PREHASH_ParcelInfoReply = LLMessageStringTable::getInstance()->getString("ParcelInfoReply");
-char* _PREHASH_AutosaveData = LLMessageStringTable::getInstance()->getString("AutosaveData");
-char* _PREHASH_SetStartLocation = LLMessageStringTable::getInstance()->getString("SetStartLocation");
-char* _PREHASH_PassHours = LLMessageStringTable::getInstance()->getString("PassHours");
-char* _PREHASH_AttachmentPt = LLMessageStringTable::getInstance()->getString("AttachmentPt");
-char* _PREHASH_ParcelFlags = LLMessageStringTable::getInstance()->getString("ParcelFlags");
-char* _PREHASH_NumVotes = LLMessageStringTable::getInstance()->getString("NumVotes");
-char* _PREHASH_AvatarPickerRequest = LLMessageStringTable::getInstance()->getString("AvatarPickerRequest");
-char* _PREHASH_TeleportLocationRequest = LLMessageStringTable::getInstance()->getString("TeleportLocationRequest");
-char* _PREHASH_DataHomeLocationRequest = LLMessageStringTable::getInstance()->getString("DataHomeLocationRequest");
-char* _PREHASH_EventNotificationAddRequest = LLMessageStringTable::getInstance()->getString("EventNotificationAddRequest");
-char* _PREHASH_ParcelDwellRequest = LLMessageStringTable::getInstance()->getString("ParcelDwellRequest");
-char* _PREHASH_EventLocationRequest = LLMessageStringTable::getInstance()->getString("EventLocationRequest");
-char* _PREHASH_SetStartLocationRequest = LLMessageStringTable::getInstance()->getString("SetStartLocationRequest");
-char* _PREHASH_QueryStart = LLMessageStringTable::getInstance()->getString("QueryStart");
-char* _PREHASH_EjectData = LLMessageStringTable::getInstance()->getString("EjectData");
-char* _PREHASH_AvatarTextureUpdate = LLMessageStringTable::getInstance()->getString("AvatarTextureUpdate");
-char* _PREHASH_RPCServerPort = LLMessageStringTable::getInstance()->getString("RPCServerPort");
-char* _PREHASH_Bytes = LLMessageStringTable::getInstance()->getString("Bytes");
-char* _PREHASH_Extra = LLMessageStringTable::getInstance()->getString("Extra");
-char* _PREHASH_ForceScriptControlRelease = LLMessageStringTable::getInstance()->getString("ForceScriptControlRelease");
-char* _PREHASH_ParcelRelease = LLMessageStringTable::getInstance()->getString("ParcelRelease");
-char* _PREHASH_VFileType = LLMessageStringTable::getInstance()->getString("VFileType");
-char* _PREHASH_EjectGroupMemberReply = LLMessageStringTable::getInstance()->getString("EjectGroupMemberReply");
-char* _PREHASH_ImageData = LLMessageStringTable::getInstance()->getString("ImageData");
-char* _PREHASH_SimulatorViewerTimeMessage = LLMessageStringTable::getInstance()->getString("SimulatorViewerTimeMessage");
-char* _PREHASH_Rotation = LLMessageStringTable::getInstance()->getString("Rotation");
-char* _PREHASH_Selection = LLMessageStringTable::getInstance()->getString("Selection");
-char* _PREHASH_TransactionData = LLMessageStringTable::getInstance()->getString("TransactionData");
-char* _PREHASH_OperationData = LLMessageStringTable::getInstance()->getString("OperationData");
-char* _PREHASH_ExpirationDate = LLMessageStringTable::getInstance()->getString("ExpirationDate");
-char* _PREHASH_ParcelDeedToGroup = LLMessageStringTable::getInstance()->getString("ParcelDeedToGroup");
-char* _PREHASH_AvatarPicksReply = LLMessageStringTable::getInstance()->getString("AvatarPicksReply");
-char* _PREHASH_GroupTitlesReply = LLMessageStringTable::getInstance()->getString("GroupTitlesReply");
-char* _PREHASH_AgentInfo = LLMessageStringTable::getInstance()->getString("AgentInfo");
-char* _PREHASH_MoneyTransferBackend = LLMessageStringTable::getInstance()->getString("MoneyTransferBackend");
-char* _PREHASH_NextOwnerMask = LLMessageStringTable::getInstance()->getString("NextOwnerMask");
-char* _PREHASH_MuteData = LLMessageStringTable::getInstance()->getString("MuteData");
-char* _PREHASH_PassPrice = LLMessageStringTable::getInstance()->getString("PassPrice");
-char* _PREHASH_SourceID = LLMessageStringTable::getInstance()->getString("SourceID");
-char* _PREHASH_ChangeUserRights = LLMessageStringTable::getInstance()->getString("ChangeUserRights");
-char* _PREHASH_TeleportFlags = LLMessageStringTable::getInstance()->getString("TeleportFlags");
-char* _PREHASH_SlaveParcelData = LLMessageStringTable::getInstance()->getString("SlaveParcelData");
-char* _PREHASH_AssetData = LLMessageStringTable::getInstance()->getString("AssetData");
-char* _PREHASH_MultipleObjectUpdate = LLMessageStringTable::getInstance()->getString("MultipleObjectUpdate");
-char* _PREHASH_ObjectUpdate = LLMessageStringTable::getInstance()->getString("ObjectUpdate");
-char* _PREHASH_ImprovedTerseObjectUpdate = LLMessageStringTable::getInstance()->getString("ImprovedTerseObjectUpdate");
-char* _PREHASH_ConfirmXferPacket = LLMessageStringTable::getInstance()->getString("ConfirmXferPacket");
-char* _PREHASH_StartPingCheck = LLMessageStringTable::getInstance()->getString("StartPingCheck");
-char* _PREHASH_SimWideDeletes = LLMessageStringTable::getInstance()->getString("SimWideDeletes");
-char* _PREHASH_LandStatReply = LLMessageStringTable::getInstance()->getString("LandStatReply");
-char* _PREHASH_IsPhantom = LLMessageStringTable::getInstance()->getString("IsPhantom");
-char* _PREHASH_AgentList = LLMessageStringTable::getInstance()->getString("AgentList");
-char* _PREHASH_SimApproved = LLMessageStringTable::getInstance()->getString("SimApproved");
-char* _PREHASH_RezObject = LLMessageStringTable::getInstance()->getString("RezObject");
-char* _PREHASH_TaskLocalID = LLMessageStringTable::getInstance()->getString("TaskLocalID");
-char* _PREHASH_ClaimDate = LLMessageStringTable::getInstance()->getString("ClaimDate");
-char* _PREHASH_MergeParcel = LLMessageStringTable::getInstance()->getString("MergeParcel");
-char* _PREHASH_Priority = LLMessageStringTable::getInstance()->getString("Priority");
-char* _PREHASH_QueryText = LLMessageStringTable::getInstance()->getString("QueryText");
-char* _PREHASH_GroupNoticeAdd = LLMessageStringTable::getInstance()->getString("GroupNoticeAdd");
-char* _PREHASH_ReturnType = LLMessageStringTable::getInstance()->getString("ReturnType");
-char* _PREHASH_FetchFolders = LLMessageStringTable::getInstance()->getString("FetchFolders");
-char* _PREHASH_SimulatorPublicHostBlock = LLMessageStringTable::getInstance()->getString("SimulatorPublicHostBlock");
-char* _PREHASH_HeaderData = LLMessageStringTable::getInstance()->getString("HeaderData");
-char* _PREHASH_RequestMultipleObjects = LLMessageStringTable::getInstance()->getString("RequestMultipleObjects");
-char* _PREHASH_RetrieveInstantMessages = LLMessageStringTable::getInstance()->getString("RetrieveInstantMessages");
-char* _PREHASH_OpenCircuit = LLMessageStringTable::getInstance()->getString("OpenCircuit");
-char* _PREHASH_CrossedRegion = LLMessageStringTable::getInstance()->getString("CrossedRegion");
-char* _PREHASH_DirGroupsReply = LLMessageStringTable::getInstance()->getString("DirGroupsReply");
-char* _PREHASH_AvatarGroupsReply = LLMessageStringTable::getInstance()->getString("AvatarGroupsReply");
-char* _PREHASH_EmailMessageReply = LLMessageStringTable::getInstance()->getString("EmailMessageReply");
-char* _PREHASH_GroupVoteHistoryItemReply = LLMessageStringTable::getInstance()->getString("GroupVoteHistoryItemReply");
-char* _PREHASH_ViewerPosition = LLMessageStringTable::getInstance()->getString("ViewerPosition");
-char* _PREHASH_Position = LLMessageStringTable::getInstance()->getString("Position");
-char* _PREHASH_ParentEstate = LLMessageStringTable::getInstance()->getString("ParentEstate");
-char* _PREHASH_EstateName = LLMessageStringTable::getInstance()->getString("EstateName");
-char* _PREHASH_MuteName = LLMessageStringTable::getInstance()->getString("MuteName");
-char* _PREHASH_ParcelRename = LLMessageStringTable::getInstance()->getString("ParcelRename");
-char* _PREHASH_ViewerFilename = LLMessageStringTable::getInstance()->getString("ViewerFilename");
-char* _PREHASH_UserReportInternal = LLMessageStringTable::getInstance()->getString("UserReportInternal");
-char* _PREHASH_AvatarPropertiesRequest = LLMessageStringTable::getInstance()->getString("AvatarPropertiesRequest");
-char* _PREHASH_ParcelPropertiesRequest = LLMessageStringTable::getInstance()->getString("ParcelPropertiesRequest");
-char* _PREHASH_GroupProfileRequest = LLMessageStringTable::getInstance()->getString("GroupProfileRequest");
-char* _PREHASH_AgentDataUpdateRequest = LLMessageStringTable::getInstance()->getString("AgentDataUpdateRequest");
-char* _PREHASH_PriceObjectScaleFactor = LLMessageStringTable::getInstance()->getString("PriceObjectScaleFactor");
-char* _PREHASH_OpenEnrollment = LLMessageStringTable::getInstance()->getString("OpenEnrollment");
-char* _PREHASH_GroupData = LLMessageStringTable::getInstance()->getString("GroupData");
-char* _PREHASH_RequestGodlikePowers = LLMessageStringTable::getInstance()->getString("RequestGodlikePowers");
-char* _PREHASH_GrantGodlikePowers = LLMessageStringTable::getInstance()->getString("GrantGodlikePowers");
-char* _PREHASH_TransactionID = LLMessageStringTable::getInstance()->getString("TransactionID");
-char* _PREHASH_DestinationID = LLMessageStringTable::getInstance()->getString("DestinationID");
-char* _PREHASH_Controls = LLMessageStringTable::getInstance()->getString("Controls");
-char* _PREHASH_FirstDetachAll = LLMessageStringTable::getInstance()->getString("FirstDetachAll");
-char* _PREHASH_EstateID = LLMessageStringTable::getInstance()->getString("EstateID");
-char* _PREHASH_ImprovedInstantMessage = LLMessageStringTable::getInstance()->getString("ImprovedInstantMessage");
-char* _PREHASH_CheckParcelSales = LLMessageStringTable::getInstance()->getString("CheckParcelSales");
-char* _PREHASH_ParcelSales = LLMessageStringTable::getInstance()->getString("ParcelSales");
-char* _PREHASH_CurrentInterval = LLMessageStringTable::getInstance()->getString("CurrentInterval");
-char* _PREHASH_PriceRentLight = LLMessageStringTable::getInstance()->getString("PriceRentLight");
-char* _PREHASH_MediaAutoScale = LLMessageStringTable::getInstance()->getString("MediaAutoScale");
-char* _PREHASH_NeighborBlock = LLMessageStringTable::getInstance()->getString("NeighborBlock");
-char* _PREHASH_LayerData = LLMessageStringTable::getInstance()->getString("LayerData");
-char* _PREHASH_NVPairData = LLMessageStringTable::getInstance()->getString("NVPairData");
-char* _PREHASH_TeleportLocal = LLMessageStringTable::getInstance()->getString("TeleportLocal");
-char* _PREHASH_EjecteeID = LLMessageStringTable::getInstance()->getString("EjecteeID");
-char* _PREHASH_VoteInitiator = LLMessageStringTable::getInstance()->getString("VoteInitiator");
-char* _PREHASH_TypeData = LLMessageStringTable::getInstance()->getString("TypeData");
-char* _PREHASH_OwnerIDs = LLMessageStringTable::getInstance()->getString("OwnerIDs");
-char* _PREHASH_SystemKickUser = LLMessageStringTable::getInstance()->getString("SystemKickUser");
-char* _PREHASH_TransactionTime = LLMessageStringTable::getInstance()->getString("TransactionTime");
-char* _PREHASH_TimeToLive = LLMessageStringTable::getInstance()->getString("TimeToLive");
-char* _PREHASH_OldAgentID = LLMessageStringTable::getInstance()->getString("OldAgentID");
-char* _PREHASH_MusicURL = LLMessageStringTable::getInstance()->getString("MusicURL");
-char* _PREHASH_ParcelPrimBonus = LLMessageStringTable::getInstance()->getString("ParcelPrimBonus");
-char* _PREHASH_EjectUser = LLMessageStringTable::getInstance()->getString("EjectUser");
-char* _PREHASH_CoarseLocationUpdate = LLMessageStringTable::getInstance()->getString("CoarseLocationUpdate");
-char* _PREHASH_ChildAgentPositionUpdate = LLMessageStringTable::getInstance()->getString("ChildAgentPositionUpdate");
-char* _PREHASH_StoreLocal = LLMessageStringTable::getInstance()->getString("StoreLocal");
-char* _PREHASH_GroupName = LLMessageStringTable::getInstance()->getString("GroupName");
-char* _PREHASH_PriceParcelRent = LLMessageStringTable::getInstance()->getString("PriceParcelRent");
-char* _PREHASH_SimStatus = LLMessageStringTable::getInstance()->getString("SimStatus");
-char* _PREHASH_TransactionSuccess = LLMessageStringTable::getInstance()->getString("TransactionSuccess");
-char* _PREHASH_LureType = LLMessageStringTable::getInstance()->getString("LureType");
-char* _PREHASH_GroupMask = LLMessageStringTable::getInstance()->getString("GroupMask");
-char* _PREHASH_SitObject = LLMessageStringTable::getInstance()->getString("SitObject");
-char* _PREHASH_Override = LLMessageStringTable::getInstance()->getString("Override");
-char* _PREHASH_LocomotionState = LLMessageStringTable::getInstance()->getString("LocomotionState");
-char* _PREHASH_PriceUpload = LLMessageStringTable::getInstance()->getString("PriceUpload");
-char* _PREHASH_RemoveParcel = LLMessageStringTable::getInstance()->getString("RemoveParcel");
-char* _PREHASH_ConfirmAuctionStart = LLMessageStringTable::getInstance()->getString("ConfirmAuctionStart");
-char* _PREHASH_RpcScriptRequestInbound = LLMessageStringTable::getInstance()->getString("RpcScriptRequestInbound");
-char* _PREHASH_ActiveGroupID = LLMessageStringTable::getInstance()->getString("ActiveGroupID");
-char* _PREHASH_ParcelReturnObjects = LLMessageStringTable::getInstance()->getString("ParcelReturnObjects");
-char* _PREHASH_TotalObjects = LLMessageStringTable::getInstance()->getString("TotalObjects");
-char* _PREHASH_ObjectExtraParams = LLMessageStringTable::getInstance()->getString("ObjectExtraParams");
-char* _PREHASH_Questions = LLMessageStringTable::getInstance()->getString("Questions");
-char* _PREHASH_TransferAbort = LLMessageStringTable::getInstance()->getString("TransferAbort");
-char* _PREHASH_TransferInventory = LLMessageStringTable::getInstance()->getString("TransferInventory");
-char* _PREHASH_RayTargetID = LLMessageStringTable::getInstance()->getString("RayTargetID");
-char* _PREHASH_ClaimPrice = LLMessageStringTable::getInstance()->getString("ClaimPrice");
-char* _PREHASH_ObjectProperties = LLMessageStringTable::getInstance()->getString("ObjectProperties");
-char* _PREHASH_ParcelProperties = LLMessageStringTable::getInstance()->getString("ParcelProperties");
-char* _PREHASH_EstateOwnerID = LLMessageStringTable::getInstance()->getString("EstateOwnerID");
-char* _PREHASH_LogoutRequest = LLMessageStringTable::getInstance()->getString("LogoutRequest");
-char* _PREHASH_AssetUploadRequest = LLMessageStringTable::getInstance()->getString("AssetUploadRequest");
-char* _PREHASH_TransactionType = LLMessageStringTable::getInstance()->getString("TransactionType");
-char* _PREHASH_AvatarPropertiesUpdate = LLMessageStringTable::getInstance()->getString("AvatarPropertiesUpdate");
-char* _PREHASH_ParcelPropertiesUpdate = LLMessageStringTable::getInstance()->getString("ParcelPropertiesUpdate");
-char* _PREHASH_FetchItems = LLMessageStringTable::getInstance()->getString("FetchItems");
-char* _PREHASH_AbortXfer = LLMessageStringTable::getInstance()->getString("AbortXfer");
-char* _PREHASH_DeRezAck = LLMessageStringTable::getInstance()->getString("DeRezAck");
-char* _PREHASH_TakeControls = LLMessageStringTable::getInstance()->getString("TakeControls");
-char* _PREHASH_DirLandReply = LLMessageStringTable::getInstance()->getString("DirLandReply");
-char* _PREHASH_MuteType = LLMessageStringTable::getInstance()->getString("MuteType");
-char* _PREHASH_IMViaEMail = LLMessageStringTable::getInstance()->getString("IMViaEMail");
-char* _PREHASH_RentPrice = LLMessageStringTable::getInstance()->getString("RentPrice");
-char* _PREHASH_GenericMessage = LLMessageStringTable::getInstance()->getString("GenericMessage");
-char* _PREHASH_ChildAgentAlive = LLMessageStringTable::getInstance()->getString("ChildAgentAlive");
-char* _PREHASH_AssetType = LLMessageStringTable::getInstance()->getString("AssetType");
-char* _PREHASH_SpawnPointBlock = LLMessageStringTable::getInstance()->getString("SpawnPointBlock");
-char* _PREHASH_AttachmentBlock = LLMessageStringTable::getInstance()->getString("AttachmentBlock");
-char* _PREHASH_ObjectMaterial = LLMessageStringTable::getInstance()->getString("ObjectMaterial");
-char* _PREHASH_OwnerName = LLMessageStringTable::getInstance()->getString("OwnerName");
-char* _PREHASH_AvatarNotesReply = LLMessageStringTable::getInstance()->getString("AvatarNotesReply");
-char* _PREHASH_CacheID = LLMessageStringTable::getInstance()->getString("CacheID");
-char* _PREHASH_OwnerMask = LLMessageStringTable::getInstance()->getString("OwnerMask");
-char* _PREHASH_TransferInventoryAck = LLMessageStringTable::getInstance()->getString("TransferInventoryAck");
-char* _PREHASH_RegionDenyAgeUnverified = LLMessageStringTable::getInstance()->getString("RegionDenyAgeUnverified");
-char* _PREHASH_AgeVerificationBlock = LLMessageStringTable::getInstance()->getString("AgeVerificationBlock");
-char* _PREHASH_UCoord = LLMessageStringTable::getInstance()->getString("UCoord");
-char* _PREHASH_VCoord = LLMessageStringTable::getInstance()->getString("VCoord");
-char* _PREHASH_FaceIndex = LLMessageStringTable::getInstance()->getString("FaceIndex");
-char* _PREHASH_StatusData = LLMessageStringTable::getInstance()->getString("StatusData");
-char* _PREHASH_ProductSKU = LLMessageStringTable::getInstance()->getString("ProductSKU");
+char const* const _PREHASH_X = LLMessageStringTable::getInstance()->getString("X");
+char const* const _PREHASH_Y = LLMessageStringTable::getInstance()->getString("Y");
+char const* const _PREHASH_Z = LLMessageStringTable::getInstance()->getString("Z");
+char const* const _PREHASH_AddFlags = LLMessageStringTable::getInstance()->getString("AddFlags");
+char const* const _PREHASH_FailureInfo = LLMessageStringTable::getInstance()->getString("FailureInfo");
+char const* const _PREHASH_MapData = LLMessageStringTable::getInstance()->getString("MapData");
+char const* const _PREHASH_AddItem = LLMessageStringTable::getInstance()->getString("AddItem");
+char const* const _PREHASH_MeanCollision = LLMessageStringTable::getInstance()->getString("MeanCollision");
+char const* const _PREHASH_RezScript = LLMessageStringTable::getInstance()->getString("RezScript");
+char const* const _PREHASH_AvatarSitResponse = LLMessageStringTable::getInstance()->getString("AvatarSitResponse");
+char const* const _PREHASH_InventoryAssetResponse = LLMessageStringTable::getInstance()->getString("InventoryAssetResponse");
+char const* const _PREHASH_KillObject = LLMessageStringTable::getInstance()->getString("KillObject");
+char const* const _PREHASH_ProposalID = LLMessageStringTable::getInstance()->getString("ProposalID");
+char const* const _PREHASH_SerialNum = LLMessageStringTable::getInstance()->getString("SerialNum");
+char const* const _PREHASH_Duration = LLMessageStringTable::getInstance()->getString("Duration");
+char const* const _PREHASH_ScriptQuestion = LLMessageStringTable::getInstance()->getString("ScriptQuestion");
+char const* const _PREHASH_AddCircuitCode = LLMessageStringTable::getInstance()->getString("AddCircuitCode");
+char const* const _PREHASH_UseCircuitCode = LLMessageStringTable::getInstance()->getString("UseCircuitCode");
+char const* const _PREHASH_ViewerCircuitCode = LLMessageStringTable::getInstance()->getString("ViewerCircuitCode");
+char const* const _PREHASH_ScriptAnswerYes = LLMessageStringTable::getInstance()->getString("ScriptAnswerYes");
+char const* const _PREHASH_PartnerID = LLMessageStringTable::getInstance()->getString("PartnerID");
+char const* const _PREHASH_DirLandQuery = LLMessageStringTable::getInstance()->getString("DirLandQuery");
+char const* const _PREHASH_TeleportStart = LLMessageStringTable::getInstance()->getString("TeleportStart");
+char const* const _PREHASH_AboutText = LLMessageStringTable::getInstance()->getString("AboutText");
+char const* const _PREHASH_VisualParam = LLMessageStringTable::getInstance()->getString("VisualParam");
+char const* const _PREHASH_GroupPrims = LLMessageStringTable::getInstance()->getString("GroupPrims");
+char const* const _PREHASH_SelectedPrims = LLMessageStringTable::getInstance()->getString("SelectedPrims");
+char const* const _PREHASH_ID = LLMessageStringTable::getInstance()->getString("ID");
+char const* const _PREHASH_UUIDNameRequest = LLMessageStringTable::getInstance()->getString("UUIDNameRequest");
+char const* const _PREHASH_UUIDGroupNameRequest = LLMessageStringTable::getInstance()->getString("UUIDGroupNameRequest");
+char const* const _PREHASH_GroupAccountTransactionsRequest = LLMessageStringTable::getInstance()->getString("GroupAccountTransactionsRequest");
+char const* const _PREHASH_MapNameRequest = LLMessageStringTable::getInstance()->getString("MapNameRequest");
+char const* const _PREHASH_UpdateSimulator = LLMessageStringTable::getInstance()->getString("UpdateSimulator");
+char const* const _PREHASH_BillableFactor = LLMessageStringTable::getInstance()->getString("BillableFactor");
+char const* const _PREHASH_ObjectBonusFactor = LLMessageStringTable::getInstance()->getString("ObjectBonusFactor");
+char const* const _PREHASH_EnableSimulator = LLMessageStringTable::getInstance()->getString("EnableSimulator");
+char const* const _PREHASH_DisableSimulator = LLMessageStringTable::getInstance()->getString("DisableSimulator");
+char const* const _PREHASH_ConfirmEnableSimulator = LLMessageStringTable::getInstance()->getString("ConfirmEnableSimulator");
+char const* const _PREHASH_LayerType = LLMessageStringTable::getInstance()->getString("LayerType");
+char const* const _PREHASH_OwnerRole = LLMessageStringTable::getInstance()->getString("OwnerRole");
+char const* const _PREHASH_ParcelOverlay = LLMessageStringTable::getInstance()->getString("ParcelOverlay");
+char const* const _PREHASH_GroupOwned = LLMessageStringTable::getInstance()->getString("GroupOwned");
+char const* const _PREHASH_IP = LLMessageStringTable::getInstance()->getString("IP");
+char const* const _PREHASH_ChatFromViewer = LLMessageStringTable::getInstance()->getString("ChatFromViewer");
+char const* const _PREHASH_AvgAgentsInView = LLMessageStringTable::getInstance()->getString("AvgAgentsInView");
+char const* const _PREHASH_AgentsInView = LLMessageStringTable::getInstance()->getString("AgentsInView");
+char const* const _PREHASH_GroupTitle = LLMessageStringTable::getInstance()->getString("GroupTitle");
+char const* const _PREHASH_MapLayerReply = LLMessageStringTable::getInstance()->getString("MapLayerReply");
+char const* const _PREHASH_CompoundMsgID = LLMessageStringTable::getInstance()->getString("CompoundMsgID");
+char const* const _PREHASH_CameraConstraint = LLMessageStringTable::getInstance()->getString("CameraConstraint");
+char const* const _PREHASH_DownloadTotals = LLMessageStringTable::getInstance()->getString("DownloadTotals");
+char const* const _PREHASH_GenCounter = LLMessageStringTable::getInstance()->getString("GenCounter");
+char const* const _PREHASH_FrozenData = LLMessageStringTable::getInstance()->getString("FrozenData");
+char const* const _PREHASH_ChildAgentDying = LLMessageStringTable::getInstance()->getString("ChildAgentDying");
+char const* const _PREHASH_To = LLMessageStringTable::getInstance()->getString("To");
+char const* const _PREHASH_CopyInventoryFromNotecard = LLMessageStringTable::getInstance()->getString("CopyInventoryFromNotecard");
+char const* const _PREHASH_RezObjectFromNotecard = LLMessageStringTable::getInstance()->getString("RezObjectFromNotecard");
+char const* const _PREHASH_ParcelDirFeeCurrent = LLMessageStringTable::getInstance()->getString("ParcelDirFeeCurrent");
+char const* const _PREHASH_SeedCapability = LLMessageStringTable::getInstance()->getString("SeedCapability");
+char const* const _PREHASH_ObjectDuplicate = LLMessageStringTable::getInstance()->getString("ObjectDuplicate");
+char const* const _PREHASH_InventoryData = LLMessageStringTable::getInstance()->getString("InventoryData");
+char const* const _PREHASH_ReplyData = LLMessageStringTable::getInstance()->getString("ReplyData");
+char const* const _PREHASH_ResetList = LLMessageStringTable::getInstance()->getString("ResetList");
+char const* const _PREHASH_MediaID = LLMessageStringTable::getInstance()->getString("MediaID");
+char const* const _PREHASH_RelatedRights = LLMessageStringTable::getInstance()->getString("RelatedRights");
+char const* const _PREHASH_RedirectGridX = LLMessageStringTable::getInstance()->getString("RedirectGridX");
+char const* const _PREHASH_RedirectGridY = LLMessageStringTable::getInstance()->getString("RedirectGridY");
+char const* const _PREHASH_TransferID = LLMessageStringTable::getInstance()->getString("TransferID");
+char const* const _PREHASH_TexturesChanged = LLMessageStringTable::getInstance()->getString("TexturesChanged");
+char const* const _PREHASH_UserLookAt = LLMessageStringTable::getInstance()->getString("UserLookAt");
+char const* const _PREHASH_TestBlock1 = LLMessageStringTable::getInstance()->getString("TestBlock1");
+char const* const _PREHASH_SensedData = LLMessageStringTable::getInstance()->getString("SensedData");
+char const* const _PREHASH_UpdateBlock = LLMessageStringTable::getInstance()->getString("UpdateBlock");
+char const* const _PREHASH_ClassifiedGodDelete = LLMessageStringTable::getInstance()->getString("ClassifiedGodDelete");
+char const* const _PREHASH_ObjectGrabUpdate = LLMessageStringTable::getInstance()->getString("ObjectGrabUpdate");
+char const* const _PREHASH_LocationPos = LLMessageStringTable::getInstance()->getString("LocationPos");
+char const* const _PREHASH_TaxDate = LLMessageStringTable::getInstance()->getString("TaxDate");
+char const* const _PREHASH_StartDateTime = LLMessageStringTable::getInstance()->getString("StartDateTime");
+char const* const _PREHASH_ObjectUpdateCached = LLMessageStringTable::getInstance()->getString("ObjectUpdateCached");
+char const* const _PREHASH_Packets = LLMessageStringTable::getInstance()->getString("Packets");
+char const* const _PREHASH_FailureType = LLMessageStringTable::getInstance()->getString("FailureType");
+char const* const _PREHASH_UpdateGroupInfo = LLMessageStringTable::getInstance()->getString("UpdateGroupInfo");
+char const* const _PREHASH_ObjectPermissions = LLMessageStringTable::getInstance()->getString("ObjectPermissions");
+char const* const _PREHASH_RevokePermissions = LLMessageStringTable::getInstance()->getString("RevokePermissions");
+char const* const _PREHASH_UpdateFlags = LLMessageStringTable::getInstance()->getString("UpdateFlags");
+char const* const _PREHASH_ObjectExportSelected = LLMessageStringTable::getInstance()->getString("ObjectExportSelected");
+char const* const _PREHASH_RezSelected = LLMessageStringTable::getInstance()->getString("RezSelected");
+char const* const _PREHASH_AutoPilot = LLMessageStringTable::getInstance()->getString("AutoPilot");
+char const* const _PREHASH_UpdateMuteListEntry = LLMessageStringTable::getInstance()->getString("UpdateMuteListEntry");
+char const* const _PREHASH_RemoveMuteListEntry = LLMessageStringTable::getInstance()->getString("RemoveMuteListEntry");
+char const* const _PREHASH_SetSimStatusInDatabase = LLMessageStringTable::getInstance()->getString("SetSimStatusInDatabase");
+char const* const _PREHASH_SetSimPresenceInDatabase = LLMessageStringTable::getInstance()->getString("SetSimPresenceInDatabase");
+char const* const _PREHASH_CameraProperty = LLMessageStringTable::getInstance()->getString("CameraProperty");
+char const* const _PREHASH_BrushSize = LLMessageStringTable::getInstance()->getString("BrushSize");
+char const* const _PREHASH_SimulatorSetMap = LLMessageStringTable::getInstance()->getString("SimulatorSetMap");
+char const* const _PREHASH_RegionPresenceRequestByRegionID = LLMessageStringTable::getInstance()->getString("RegionPresenceRequestByRegionID");
+char const* const _PREHASH_ParcelObjectOwnersReply = LLMessageStringTable::getInstance()->getString("ParcelObjectOwnersReply");
+char const* const _PREHASH_GroupMembersReply = LLMessageStringTable::getInstance()->getString("GroupMembersReply");
+char const* const _PREHASH_GroupRoleMembersReply = LLMessageStringTable::getInstance()->getString("GroupRoleMembersReply");
+char const* const _PREHASH_RequestRegionInfo = LLMessageStringTable::getInstance()->getString("RequestRegionInfo");
+char const* const _PREHASH_AABBMax = LLMessageStringTable::getInstance()->getString("AABBMax");
+char const* const _PREHASH_RequestPayPrice = LLMessageStringTable::getInstance()->getString("RequestPayPrice");
+char const* const _PREHASH_SimulatorPresentAtLocation = LLMessageStringTable::getInstance()->getString("SimulatorPresentAtLocation");
+char const* const _PREHASH_AgentRequestSit = LLMessageStringTable::getInstance()->getString("AgentRequestSit");
+char const* const _PREHASH_AABBMin = LLMessageStringTable::getInstance()->getString("AABBMin");
+char const* const _PREHASH_ClassifiedFlags = LLMessageStringTable::getInstance()->getString("ClassifiedFlags");
+char const* const _PREHASH_ControlFlags = LLMessageStringTable::getInstance()->getString("ControlFlags");
+char const* const _PREHASH_TeleportRequest = LLMessageStringTable::getInstance()->getString("TeleportRequest");
+char const* const _PREHASH_ScriptTeleportRequest = LLMessageStringTable::getInstance()->getString("ScriptTeleportRequest");
+char const* const _PREHASH_EstateCovenantRequest = LLMessageStringTable::getInstance()->getString("EstateCovenantRequest");
+char const* const _PREHASH_DateUTC = LLMessageStringTable::getInstance()->getString("DateUTC");
+char const* const _PREHASH_TaskIDs = LLMessageStringTable::getInstance()->getString("TaskIDs");
+char const* const _PREHASH_RequestResult = LLMessageStringTable::getInstance()->getString("RequestResult");
+char const* const _PREHASH_CanAcceptAgents = LLMessageStringTable::getInstance()->getString("CanAcceptAgents");
+char const* const _PREHASH_ObjectSaleInfo = LLMessageStringTable::getInstance()->getString("ObjectSaleInfo");
+char const* const _PREHASH_KillChildAgents = LLMessageStringTable::getInstance()->getString("KillChildAgents");
+char const* const _PREHASH_Balance = LLMessageStringTable::getInstance()->getString("Balance");
+char const* const _PREHASH_DerezContainer = LLMessageStringTable::getInstance()->getString("DerezContainer");
+char const* const _PREHASH_ObjectData = LLMessageStringTable::getInstance()->getString("ObjectData");
+char const* const _PREHASH_CameraAtAxis = LLMessageStringTable::getInstance()->getString("CameraAtAxis");
+char const* const _PREHASH_InfoBlock = LLMessageStringTable::getInstance()->getString("InfoBlock");
+char const* const _PREHASH_OwnershipCost = LLMessageStringTable::getInstance()->getString("OwnershipCost");
+char const* const _PREHASH_AvatarNotesUpdate = LLMessageStringTable::getInstance()->getString("AvatarNotesUpdate");
+char const* const _PREHASH_PID = LLMessageStringTable::getInstance()->getString("PID");
+char const* const _PREHASH_DirPopularReply = LLMessageStringTable::getInstance()->getString("DirPopularReply");
+char const* const _PREHASH_TerrainHeightRange00 = LLMessageStringTable::getInstance()->getString("TerrainHeightRange00");
+char const* const _PREHASH_SimData = LLMessageStringTable::getInstance()->getString("SimData");
+char const* const _PREHASH_TerrainHeightRange01 = LLMessageStringTable::getInstance()->getString("TerrainHeightRange01");
+char const* const _PREHASH_TerrainHeightRange10 = LLMessageStringTable::getInstance()->getString("TerrainHeightRange10");
+char const* const _PREHASH_TerrainHeightRange11 = LLMessageStringTable::getInstance()->getString("TerrainHeightRange11");
+char const* const _PREHASH_UpdateInventoryItem = LLMessageStringTable::getInstance()->getString("UpdateInventoryItem");
+char const* const _PREHASH_UpdateCreateInventoryItem = LLMessageStringTable::getInstance()->getString("UpdateCreateInventoryItem");
+char const* const _PREHASH_MoveInventoryItem = LLMessageStringTable::getInstance()->getString("MoveInventoryItem");
+char const* const _PREHASH_CopyInventoryItem = LLMessageStringTable::getInstance()->getString("CopyInventoryItem");
+char const* const _PREHASH_LinkInventoryItem = LLMessageStringTable::getInstance()->getString("LinkInventoryItem");
+char const* const _PREHASH_RemoveInventoryItem = LLMessageStringTable::getInstance()->getString("RemoveInventoryItem");
+char const* const _PREHASH_CreateInventoryItem = LLMessageStringTable::getInstance()->getString("CreateInventoryItem");
+char const* const _PREHASH_PathTwistBegin = LLMessageStringTable::getInstance()->getString("PathTwistBegin");
+char const* const _PREHASH_CRC = LLMessageStringTable::getInstance()->getString("CRC");
+char const* const _PREHASH_AttachmentPoint = LLMessageStringTable::getInstance()->getString("AttachmentPoint");
+char const* const _PREHASH_TelehubBlock = LLMessageStringTable::getInstance()->getString("TelehubBlock");
+char const* const _PREHASH_FOVBlock = LLMessageStringTable::getInstance()->getString("FOVBlock");
+char const* const _PREHASH_StartLocationData = LLMessageStringTable::getInstance()->getString("StartLocationData");
+char const* const _PREHASH_PositionData = LLMessageStringTable::getInstance()->getString("PositionData");
+char const* const _PREHASH_TimeSinceLast = LLMessageStringTable::getInstance()->getString("TimeSinceLast");
+char const* const _PREHASH_MapImage = LLMessageStringTable::getInstance()->getString("MapImage");
+char const* const _PREHASH_Objects = LLMessageStringTable::getInstance()->getString("Objects");
+char const* const _PREHASH_URL = LLMessageStringTable::getInstance()->getString("URL");
+char const* const _PREHASH_CreationDate = LLMessageStringTable::getInstance()->getString("CreationDate");
+char const* const _PREHASH_JointPivot = LLMessageStringTable::getInstance()->getString("JointPivot");
+char const* const _PREHASH_FPS = LLMessageStringTable::getInstance()->getString("FPS");
+char const* const _PREHASH_HasTelehub = LLMessageStringTable::getInstance()->getString("HasTelehub");
+char const* const _PREHASH_PathEnd = LLMessageStringTable::getInstance()->getString("PathEnd");
+char const* const _PREHASH_ScriptDataReply = LLMessageStringTable::getInstance()->getString("ScriptDataReply");
+char const* const _PREHASH_MapBlockReply = LLMessageStringTable::getInstance()->getString("MapBlockReply");
+char const* const _PREHASH_PropertiesData = LLMessageStringTable::getInstance()->getString("PropertiesData");
+char const* const _PREHASH_ViewerEffect = LLMessageStringTable::getInstance()->getString("ViewerEffect");
+char const* const _PREHASH_FreezeUser = LLMessageStringTable::getInstance()->getString("FreezeUser");
+char const* const _PREHASH_OwnerPrims = LLMessageStringTable::getInstance()->getString("OwnerPrims");
+char const* const _PREHASH_ObjectGrab = LLMessageStringTable::getInstance()->getString("ObjectGrab");
+char const* const _PREHASH_ToAgentID = LLMessageStringTable::getInstance()->getString("ToAgentID");
+char const* const _PREHASH_SimulatorMapUpdate = LLMessageStringTable::getInstance()->getString("SimulatorMapUpdate");
+char const* const _PREHASH_TransferPacket = LLMessageStringTable::getInstance()->getString("TransferPacket");
+char const* const _PREHASH_ObjectName = LLMessageStringTable::getInstance()->getString("ObjectName");
+char const* const _PREHASH_GroupPowers = LLMessageStringTable::getInstance()->getString("GroupPowers");
+char const* const _PREHASH_OriginalName = LLMessageStringTable::getInstance()->getString("OriginalName");
+char const* const _PREHASH_CompletePingCheck = LLMessageStringTable::getInstance()->getString("CompletePingCheck");
+char const* const _PREHASH_OnlineStatus = LLMessageStringTable::getInstance()->getString("OnlineStatus");
+char const* const _PREHASH_ObjectDrop = LLMessageStringTable::getInstance()->getString("ObjectDrop");
+char const* const _PREHASH_UseBigPackets = LLMessageStringTable::getInstance()->getString("UseBigPackets");
+char const* const _PREHASH_GroupNoticesListReply = LLMessageStringTable::getInstance()->getString("GroupNoticesListReply");
+char const* const _PREHASH_ParcelAccessListReply = LLMessageStringTable::getInstance()->getString("ParcelAccessListReply");
+char const* const _PREHASH_RpcChannelReply = LLMessageStringTable::getInstance()->getString("RpcChannelReply");
+char const* const _PREHASH_RegionPresenceResponse = LLMessageStringTable::getInstance()->getString("RegionPresenceResponse");
+char const* const _PREHASH_CharterMember = LLMessageStringTable::getInstance()->getString("CharterMember");
+char const* const _PREHASH_EdgeData = LLMessageStringTable::getInstance()->getString("EdgeData");
+char const* const _PREHASH_NameData = LLMessageStringTable::getInstance()->getString("NameData");
+char const* const _PREHASH_RegionPushOverride = LLMessageStringTable::getInstance()->getString("RegionPushOverride");
+char const* const _PREHASH_SimName = LLMessageStringTable::getInstance()->getString("SimName");
+char const* const _PREHASH_UserReport = LLMessageStringTable::getInstance()->getString("UserReport");
+char const* const _PREHASH_DownloadPriority = LLMessageStringTable::getInstance()->getString("DownloadPriority");
+char const* const _PREHASH_ToAgentId = LLMessageStringTable::getInstance()->getString("ToAgentId");
+char const* const _PREHASH_DirPopularQuery = LLMessageStringTable::getInstance()->getString("DirPopularQuery");
+char const* const _PREHASH_Mag = LLMessageStringTable::getInstance()->getString("Mag");
+char const* const _PREHASH_ParcelPropertiesRequestByID = LLMessageStringTable::getInstance()->getString("ParcelPropertiesRequestByID");
+char const* const _PREHASH_ObjectLink = LLMessageStringTable::getInstance()->getString("ObjectLink");
+char const* const _PREHASH_RpcScriptReplyInbound = LLMessageStringTable::getInstance()->getString("RpcScriptReplyInbound");
+char const* const _PREHASH_RezData = LLMessageStringTable::getInstance()->getString("RezData");
+char const* const _PREHASH_RemoveInventoryObjects = LLMessageStringTable::getInstance()->getString("RemoveInventoryObjects");
+char const* const _PREHASH_GroupProposalBallot = LLMessageStringTable::getInstance()->getString("GroupProposalBallot");
+char const* const _PREHASH_RPCServerIP = LLMessageStringTable::getInstance()->getString("RPCServerIP");
+char const* const _PREHASH_Far = LLMessageStringTable::getInstance()->getString("Far");
+char const* const _PREHASH_GodSessionID = LLMessageStringTable::getInstance()->getString("GodSessionID");
+char const* const _PREHASH_FLAboutText = LLMessageStringTable::getInstance()->getString("FLAboutText");
+char const* const _PREHASH_RegionHandshakeReply = LLMessageStringTable::getInstance()->getString("RegionHandshakeReply");
+char const* const _PREHASH_GroupActiveProposalItemReply = LLMessageStringTable::getInstance()->getString("GroupActiveProposalItemReply");
+char const* const _PREHASH_MapItemReply = LLMessageStringTable::getInstance()->getString("MapItemReply");
+char const* const _PREHASH_Seconds = LLMessageStringTable::getInstance()->getString("Seconds");
+char const* const _PREHASH_UpdateUserInfo = LLMessageStringTable::getInstance()->getString("UpdateUserInfo");
+char const* const _PREHASH_AggregatePermTexturesOwner = LLMessageStringTable::getInstance()->getString("AggregatePermTexturesOwner");
+char const* const _PREHASH_Set = LLMessageStringTable::getInstance()->getString("Set");
+char const* const _PREHASH_NewName = LLMessageStringTable::getInstance()->getString("NewName");
+char const* const _PREHASH_Key = LLMessageStringTable::getInstance()->getString("Key");
+char const* const _PREHASH_AgentID = LLMessageStringTable::getInstance()->getString("AgentID");
+char const* const _PREHASH_EventNotificationRemoveRequest = LLMessageStringTable::getInstance()->getString("EventNotificationRemoveRequest");
+char const* const _PREHASH_NewFolderID = LLMessageStringTable::getInstance()->getString("NewFolderID");
+char const* const _PREHASH_Arc = LLMessageStringTable::getInstance()->getString("Arc");
+char const* const _PREHASH_RegionX = LLMessageStringTable::getInstance()->getString("RegionX");
+char const* const _PREHASH_RegionY = LLMessageStringTable::getInstance()->getString("RegionY");
+char const* const _PREHASH_RequestData = LLMessageStringTable::getInstance()->getString("RequestData");
+char const* const _PREHASH_Msg = LLMessageStringTable::getInstance()->getString("Msg");
+char const* const _PREHASH_Top = LLMessageStringTable::getInstance()->getString("Top");
+char const* const _PREHASH_MiscStats = LLMessageStringTable::getInstance()->getString("MiscStats");
+char const* const _PREHASH_ImageID = LLMessageStringTable::getInstance()->getString("ImageID");
+char const* const _PREHASH_DataPacket = LLMessageStringTable::getInstance()->getString("DataPacket");
+char const* const _PREHASH_You = LLMessageStringTable::getInstance()->getString("You");
+char const* const _PREHASH_ScriptControlChange = LLMessageStringTable::getInstance()->getString("ScriptControlChange");
+char const* const _PREHASH_LoadURL = LLMessageStringTable::getInstance()->getString("LoadURL");
+char const* const _PREHASH_SetCPURatio = LLMessageStringTable::getInstance()->getString("SetCPURatio");
+char const* const _PREHASH_NameValueData = LLMessageStringTable::getInstance()->getString("NameValueData");
+char const* const _PREHASH_AtomicPassObject = LLMessageStringTable::getInstance()->getString("AtomicPassObject");
+char const* const _PREHASH_ErrorMessage = LLMessageStringTable::getInstance()->getString("ErrorMessage");
+char const* const _PREHASH_ViewerFrozenMessage = LLMessageStringTable::getInstance()->getString("ViewerFrozenMessage");
+char const* const _PREHASH_HealthMessage = LLMessageStringTable::getInstance()->getString("HealthMessage");
+char const* const _PREHASH_LogTextMessage = LLMessageStringTable::getInstance()->getString("LogTextMessage");
+char const* const _PREHASH_TimeDilation = LLMessageStringTable::getInstance()->getString("TimeDilation");
+char const* const _PREHASH_RemoveContribution = LLMessageStringTable::getInstance()->getString("RemoveContribution");
+char const* const _PREHASH_Contribution = LLMessageStringTable::getInstance()->getString("Contribution");
+char const* const _PREHASH_SetGroupContribution = LLMessageStringTable::getInstance()->getString("SetGroupContribution");
+char const* const _PREHASH_Offline = LLMessageStringTable::getInstance()->getString("Offline");
+char const* const _PREHASH_AgentIsNowWearing = LLMessageStringTable::getInstance()->getString("AgentIsNowWearing");
+char const* const _PREHASH_Members = LLMessageStringTable::getInstance()->getString("Members");
+char const* const _PREHASH_FailedResends = LLMessageStringTable::getInstance()->getString("FailedResends");
+char const* const _PREHASH_SecPerDay = LLMessageStringTable::getInstance()->getString("SecPerDay");
+char const* const _PREHASH_CameraCenter = LLMessageStringTable::getInstance()->getString("CameraCenter");
+char const* const _PREHASH_CameraLeftAxis = LLMessageStringTable::getInstance()->getString("CameraLeftAxis");
+char const* const _PREHASH_ExBlock = LLMessageStringTable::getInstance()->getString("ExBlock");
+char const* const _PREHASH_Channel = LLMessageStringTable::getInstance()->getString("Channel");
+char const* const _PREHASH_NetTest = LLMessageStringTable::getInstance()->getString("NetTest");
+char const* const _PREHASH_DiscardLevel = LLMessageStringTable::getInstance()->getString("DiscardLevel");
+char const* const _PREHASH_LayerID = LLMessageStringTable::getInstance()->getString("LayerID");
+char const* const _PREHASH_GrabOffset = LLMessageStringTable::getInstance()->getString("GrabOffset");
+char const* const _PREHASH_SimPort = LLMessageStringTable::getInstance()->getString("SimPort");
+char const* const _PREHASH_PricePerMeter = LLMessageStringTable::getInstance()->getString("PricePerMeter");
+char const* const _PREHASH_RegionFlags = LLMessageStringTable::getInstance()->getString("RegionFlags");
+char const* const _PREHASH_VoteResult = LLMessageStringTable::getInstance()->getString("VoteResult");
+char const* const _PREHASH_ParcelDirFeeEstimate = LLMessageStringTable::getInstance()->getString("ParcelDirFeeEstimate");
+char const* const _PREHASH_ModifyBlock = LLMessageStringTable::getInstance()->getString("ModifyBlock");
+char const* const _PREHASH_InventoryBlock = LLMessageStringTable::getInstance()->getString("InventoryBlock");
+char const* const _PREHASH_ReplyBlock = LLMessageStringTable::getInstance()->getString("ReplyBlock");
+char const* const _PREHASH_ValidUntil = LLMessageStringTable::getInstance()->getString("ValidUntil");
+char const* const _PREHASH_VelocityInterpolateOn = LLMessageStringTable::getInstance()->getString("VelocityInterpolateOn");
+char const* const _PREHASH_ClassifiedDelete = LLMessageStringTable::getInstance()->getString("ClassifiedDelete");
+char const* const _PREHASH_RegionDenyAnonymous = LLMessageStringTable::getInstance()->getString("RegionDenyAnonymous");
+char const* const _PREHASH_FLImageID = LLMessageStringTable::getInstance()->getString("FLImageID");
+char const* const _PREHASH_AllowPublish = LLMessageStringTable::getInstance()->getString("AllowPublish");
+char const* const _PREHASH_SitName = LLMessageStringTable::getInstance()->getString("SitName");
+char const* const _PREHASH_RegionsVisited = LLMessageStringTable::getInstance()->getString("RegionsVisited");
+char const* const _PREHASH_DirClassifiedReply = LLMessageStringTable::getInstance()->getString("DirClassifiedReply");
+char const* const _PREHASH_AvatarClassifiedReply = LLMessageStringTable::getInstance()->getString("AvatarClassifiedReply");
+char const* const _PREHASH_MediaURL = LLMessageStringTable::getInstance()->getString("MediaURL");
+char const* const _PREHASH_CompleteAgentMovement = LLMessageStringTable::getInstance()->getString("CompleteAgentMovement");
+char const* const _PREHASH_ClassifiedID = LLMessageStringTable::getInstance()->getString("ClassifiedID");
+char const* const _PREHASH_LocalID = LLMessageStringTable::getInstance()->getString("LocalID");
+char const* const _PREHASH_SpaceIP = LLMessageStringTable::getInstance()->getString("SpaceIP");
+char const* const _PREHASH_RemoveItem = LLMessageStringTable::getInstance()->getString("RemoveItem");
+char const* const _PREHASH_LogFailedMoneyTransaction = LLMessageStringTable::getInstance()->getString("LogFailedMoneyTransaction");
+char const* const _PREHASH_ViewerStartAuction = LLMessageStringTable::getInstance()->getString("ViewerStartAuction");
+char const* const _PREHASH_StartAuction = LLMessageStringTable::getInstance()->getString("StartAuction");
+char const* const _PREHASH_DuplicateFlags = LLMessageStringTable::getInstance()->getString("DuplicateFlags");
+char const* const _PREHASH_RegionInfo2 = LLMessageStringTable::getInstance()->getString("RegionInfo2");
+char const* const _PREHASH_TextColor = LLMessageStringTable::getInstance()->getString("TextColor");
+char const* const _PREHASH_SlaveID = LLMessageStringTable::getInstance()->getString("SlaveID");
+char const* const _PREHASH_Charter = LLMessageStringTable::getInstance()->getString("Charter");
+char const* const _PREHASH_AlertData = LLMessageStringTable::getInstance()->getString("AlertData");
+char const* const _PREHASH_AlertInfo = LLMessageStringTable::getInstance()->getString("AlertInfo");
+char const* const _PREHASH_TargetBlock = LLMessageStringTable::getInstance()->getString("TargetBlock");
+char const* const _PREHASH_CheckParcelAuctions = LLMessageStringTable::getInstance()->getString("CheckParcelAuctions");
+char const* const _PREHASH_ParcelAuctions = LLMessageStringTable::getInstance()->getString("ParcelAuctions");
+char const* const _PREHASH_OwnerIsGroup = LLMessageStringTable::getInstance()->getString("OwnerIsGroup");
+char const* const _PREHASH_NameValuePair = LLMessageStringTable::getInstance()->getString("NameValuePair");
+char const* const _PREHASH_RemoveNameValuePair = LLMessageStringTable::getInstance()->getString("RemoveNameValuePair");
+char const* const _PREHASH_BulkUpdateInventory = LLMessageStringTable::getInstance()->getString("BulkUpdateInventory");
+char const* const _PREHASH_UpdateTaskInventory = LLMessageStringTable::getInstance()->getString("UpdateTaskInventory");
+char const* const _PREHASH_RemoveTaskInventory = LLMessageStringTable::getInstance()->getString("RemoveTaskInventory");
+char const* const _PREHASH_MoveTaskInventory = LLMessageStringTable::getInstance()->getString("MoveTaskInventory");
+char const* const _PREHASH_RequestTaskInventory = LLMessageStringTable::getInstance()->getString("RequestTaskInventory");
+char const* const _PREHASH_ReplyTaskInventory = LLMessageStringTable::getInstance()->getString("ReplyTaskInventory");
+char const* const _PREHASH_AggregatePermInventory = LLMessageStringTable::getInstance()->getString("AggregatePermInventory");
+char const* const _PREHASH_GroupAccountTransactionsReply = LLMessageStringTable::getInstance()->getString("GroupAccountTransactionsReply");
+char const* const _PREHASH_SimulatorInfo = LLMessageStringTable::getInstance()->getString("SimulatorInfo");
+char const* const _PREHASH_WearableData = LLMessageStringTable::getInstance()->getString("WearableData");
+char const* const _PREHASH_Enabled = LLMessageStringTable::getInstance()->getString("Enabled");
+char const* const _PREHASH_Savings = LLMessageStringTable::getInstance()->getString("Savings");
+char const* const _PREHASH_SimulatorLoad = LLMessageStringTable::getInstance()->getString("SimulatorLoad");
+char const* const _PREHASH_InternalRegionIP = LLMessageStringTable::getInstance()->getString("InternalRegionIP");
+char const* const _PREHASH_ExternalRegionIP = LLMessageStringTable::getInstance()->getString("ExternalRegionIP");
+char const* const _PREHASH_TotalPairs = LLMessageStringTable::getInstance()->getString("TotalPairs");
+char const* const _PREHASH_CreateGroupRequest = LLMessageStringTable::getInstance()->getString("CreateGroupRequest");
+char const* const _PREHASH_JoinGroupRequest = LLMessageStringTable::getInstance()->getString("JoinGroupRequest");
+char const* const _PREHASH_LeaveGroupRequest = LLMessageStringTable::getInstance()->getString("LeaveGroupRequest");
+char const* const _PREHASH_InviteGroupRequest = LLMessageStringTable::getInstance()->getString("InviteGroupRequest");
+char const* const _PREHASH_LiveHelpGroupRequest = LLMessageStringTable::getInstance()->getString("LiveHelpGroupRequest");
+char const* const _PREHASH_PriceParcelClaimFactor = LLMessageStringTable::getInstance()->getString("PriceParcelClaimFactor");
+char const* const _PREHASH_BillableArea = LLMessageStringTable::getInstance()->getString("BillableArea");
+char const* const _PREHASH_ObjectID = LLMessageStringTable::getInstance()->getString("ObjectID");
+char const* const _PREHASH_ObjectFlagUpdate = LLMessageStringTable::getInstance()->getString("ObjectFlagUpdate");
+char const* const _PREHASH_GroupRoleUpdate = LLMessageStringTable::getInstance()->getString("GroupRoleUpdate");
+char const* const _PREHASH_RequestInventoryAsset = LLMessageStringTable::getInstance()->getString("RequestInventoryAsset");
+char const* const _PREHASH_ChangedGrid = LLMessageStringTable::getInstance()->getString("ChangedGrid");
+char const* const _PREHASH_AgentDropGroup = LLMessageStringTable::getInstance()->getString("AgentDropGroup");
+char const* const _PREHASH_Details = LLMessageStringTable::getInstance()->getString("Details");
+char const* const _PREHASH_LocationX = LLMessageStringTable::getInstance()->getString("LocationX");
+char const* const _PREHASH_SaleType = LLMessageStringTable::getInstance()->getString("SaleType");
+char const* const _PREHASH_LocationY = LLMessageStringTable::getInstance()->getString("LocationY");
+char const* const _PREHASH_LocationZ = LLMessageStringTable::getInstance()->getString("LocationZ");
+char const* const _PREHASH_EconomyData = LLMessageStringTable::getInstance()->getString("EconomyData");
+char const* const _PREHASH_HeadRotation = LLMessageStringTable::getInstance()->getString("HeadRotation");
+char const* const _PREHASH_DeleteOnCompletion = LLMessageStringTable::getInstance()->getString("DeleteOnCompletion");
+char const* const _PREHASH_PublicPort = LLMessageStringTable::getInstance()->getString("PublicPort");
+char const* const _PREHASH_DirClassifiedQuery = LLMessageStringTable::getInstance()->getString("DirClassifiedQuery");
+char const* const _PREHASH_CallbackID = LLMessageStringTable::getInstance()->getString("CallbackID");
+char const* const _PREHASH_RequestParcelTransfer = LLMessageStringTable::getInstance()->getString("RequestParcelTransfer");
+char const* const _PREHASH_RoleCount = LLMessageStringTable::getInstance()->getString("RoleCount");
+char const* const _PREHASH_ObjectCapacity = LLMessageStringTable::getInstance()->getString("ObjectCapacity");
+char const* const _PREHASH_RequestID = LLMessageStringTable::getInstance()->getString("RequestID");
+char const* const _PREHASH_RequestXfer = LLMessageStringTable::getInstance()->getString("RequestXfer");
+char const* const _PREHASH_ObjectTaxCurrent = LLMessageStringTable::getInstance()->getString("ObjectTaxCurrent");
+char const* const _PREHASH_LightTaxCurrent = LLMessageStringTable::getInstance()->getString("LightTaxCurrent");
+char const* const _PREHASH_LandTaxCurrent = LLMessageStringTable::getInstance()->getString("LandTaxCurrent");
+char const* const _PREHASH_GroupTaxCurrent = LLMessageStringTable::getInstance()->getString("GroupTaxCurrent");
+char const* const _PREHASH_FetchInventoryDescendents = LLMessageStringTable::getInstance()->getString("FetchInventoryDescendents");
+char const* const _PREHASH_InventoryDescendents = LLMessageStringTable::getInstance()->getString("InventoryDescendents");
+char const* const _PREHASH_Descendents = LLMessageStringTable::getInstance()->getString("Descendents");
+char const* const _PREHASH_PurgeInventoryDescendents = LLMessageStringTable::getInstance()->getString("PurgeInventoryDescendents");
+char const* const _PREHASH_ShowDir = LLMessageStringTable::getInstance()->getString("ShowDir");
+char const* const _PREHASH_IsOwner = LLMessageStringTable::getInstance()->getString("IsOwner");
+char const* const _PREHASH_Timestamp = LLMessageStringTable::getInstance()->getString("Timestamp");
+char const* const _PREHASH_GlobalPos = LLMessageStringTable::getInstance()->getString("GlobalPos");
+char const* const _PREHASH_GrabOffsetInitial = LLMessageStringTable::getInstance()->getString("GrabOffsetInitial");
+char const* const _PREHASH_IsTrial = LLMessageStringTable::getInstance()->getString("IsTrial");
+char const* const _PREHASH_ObjectDuplicateOnRay = LLMessageStringTable::getInstance()->getString("ObjectDuplicateOnRay");
+char const* const _PREHASH_GroupMembershipCount = LLMessageStringTable::getInstance()->getString("GroupMembershipCount");
+char const* const _PREHASH_MethodData = LLMessageStringTable::getInstance()->getString("MethodData");
+char const* const _PREHASH_ActivateGestures = LLMessageStringTable::getInstance()->getString("ActivateGestures");
+char const* const _PREHASH_DeactivateGestures = LLMessageStringTable::getInstance()->getString("DeactivateGestures");
+char const* const _PREHASH_ProposalData = LLMessageStringTable::getInstance()->getString("ProposalData");
+char const* const _PREHASH_PosGlobal = LLMessageStringTable::getInstance()->getString("PosGlobal");
+char const* const _PREHASH_SearchID = LLMessageStringTable::getInstance()->getString("SearchID");
+char const* const _PREHASH_RezMultipleAttachmentsFromInv = LLMessageStringTable::getInstance()->getString("RezMultipleAttachmentsFromInv");
+char const* const _PREHASH_SearchName = LLMessageStringTable::getInstance()->getString("SearchName");
+char const* const _PREHASH_VersionString = LLMessageStringTable::getInstance()->getString("VersionString");
+char const* const _PREHASH_CreateGroupReply = LLMessageStringTable::getInstance()->getString("CreateGroupReply");
+char const* const _PREHASH_LeaveGroupReply = LLMessageStringTable::getInstance()->getString("LeaveGroupReply");
+char const* const _PREHASH_ActualArea = LLMessageStringTable::getInstance()->getString("ActualArea");
+char const* const _PREHASH_Message = LLMessageStringTable::getInstance()->getString("Message");
+char const* const _PREHASH_ClickAction = LLMessageStringTable::getInstance()->getString("ClickAction");
+char const* const _PREHASH_AssetUploadComplete = LLMessageStringTable::getInstance()->getString("AssetUploadComplete");
+char const* const _PREHASH_RequestType = LLMessageStringTable::getInstance()->getString("RequestType");
+char const* const _PREHASH_UUID = LLMessageStringTable::getInstance()->getString("UUID");
+char const* const _PREHASH_BaseMask = LLMessageStringTable::getInstance()->getString("BaseMask");
+char const* const _PREHASH_NetBlock = LLMessageStringTable::getInstance()->getString("NetBlock");
+char const* const _PREHASH_GlobalX = LLMessageStringTable::getInstance()->getString("GlobalX");
+char const* const _PREHASH_GlobalY = LLMessageStringTable::getInstance()->getString("GlobalY");
+char const* const _PREHASH_CopyRotates = LLMessageStringTable::getInstance()->getString("CopyRotates");
+char const* const _PREHASH_KickUserAck = LLMessageStringTable::getInstance()->getString("KickUserAck");
+char const* const _PREHASH_TopPick = LLMessageStringTable::getInstance()->getString("TopPick"); //legacy var need to be deleted -angela
+char const* const _PREHASH_SessionID = LLMessageStringTable::getInstance()->getString("SessionID");
+char const* const _PREHASH_GlobalZ = LLMessageStringTable::getInstance()->getString("GlobalZ");
+char const* const _PREHASH_DeclineFriendship = LLMessageStringTable::getInstance()->getString("DeclineFriendship");
+char const* const _PREHASH_FormFriendship = LLMessageStringTable::getInstance()->getString("FormFriendship");
+char const* const _PREHASH_TerminateFriendship = LLMessageStringTable::getInstance()->getString("TerminateFriendship");
+char const* const _PREHASH_TaskData = LLMessageStringTable::getInstance()->getString("TaskData");
+char const* const _PREHASH_SimWideMaxPrims = LLMessageStringTable::getInstance()->getString("SimWideMaxPrims");
+char const* const _PREHASH_TotalPrims = LLMessageStringTable::getInstance()->getString("TotalPrims");
+char const* const _PREHASH_ProfileBegin = LLMessageStringTable::getInstance()->getString("ProfileBegin");
+char const* const _PREHASH_Request = LLMessageStringTable::getInstance()->getString("Request");
+char const* const _PREHASH_GroupAccountDetailsRequest = LLMessageStringTable::getInstance()->getString("GroupAccountDetailsRequest");
+char const* const _PREHASH_GroupActiveProposalsRequest = LLMessageStringTable::getInstance()->getString("GroupActiveProposalsRequest");
+char const* const _PREHASH_StringValue = LLMessageStringTable::getInstance()->getString("StringValue");
+char const* const _PREHASH_Version = LLMessageStringTable::getInstance()->getString("Version");
+char const* const _PREHASH_OtherCount = LLMessageStringTable::getInstance()->getString("OtherCount");
+char const* const _PREHASH_MemberCount = LLMessageStringTable::getInstance()->getString("MemberCount");
+char const* const _PREHASH_ChatData = LLMessageStringTable::getInstance()->getString("ChatData");
+char const* const _PREHASH_IsGroupOwned = LLMessageStringTable::getInstance()->getString("IsGroupOwned");
+char const* const _PREHASH_EnergyEfficiency = LLMessageStringTable::getInstance()->getString("EnergyEfficiency");
+char const* const _PREHASH_PickInfoUpdate = LLMessageStringTable::getInstance()->getString("PickInfoUpdate");
+char const* const _PREHASH_PickDelete = LLMessageStringTable::getInstance()->getString("PickDelete");
+char const* const _PREHASH_ScriptReset = LLMessageStringTable::getInstance()->getString("ScriptReset");
+char const* const _PREHASH_Requester = LLMessageStringTable::getInstance()->getString("Requester");
+char const* const _PREHASH_ForSale = LLMessageStringTable::getInstance()->getString("ForSale");
+char const* const _PREHASH_NearestLandingRegionReply = LLMessageStringTable::getInstance()->getString("NearestLandingRegionReply");
+char const* const _PREHASH_ParcelID = LLMessageStringTable::getInstance()->getString("ParcelID");
+char const* const _PREHASH_Godlike = LLMessageStringTable::getInstance()->getString("Godlike");
+char const* const _PREHASH_TotalDebits = LLMessageStringTable::getInstance()->getString("TotalDebits");
+char const* const _PREHASH_Direction = LLMessageStringTable::getInstance()->getString("Direction");
+char const* const _PREHASH_HealthData = LLMessageStringTable::getInstance()->getString("HealthData");
+char const* const _PREHASH_LeftAxis = LLMessageStringTable::getInstance()->getString("LeftAxis");
+char const* const _PREHASH_LocationBlock = LLMessageStringTable::getInstance()->getString("LocationBlock");
+char const* const _PREHASH_ObjectImage = LLMessageStringTable::getInstance()->getString("ObjectImage");
+char const* const _PREHASH_TerrainStartHeight00 = LLMessageStringTable::getInstance()->getString("TerrainStartHeight00");
+char const* const _PREHASH_TerrainStartHeight01 = LLMessageStringTable::getInstance()->getString("TerrainStartHeight01");
+char const* const _PREHASH_TerrainStartHeight10 = LLMessageStringTable::getInstance()->getString("TerrainStartHeight10");
+char const* const _PREHASH_TerrainStartHeight11 = LLMessageStringTable::getInstance()->getString("TerrainStartHeight11");
+char const* const _PREHASH_WaterHeight = LLMessageStringTable::getInstance()->getString("WaterHeight");
+char const* const _PREHASH_FetchInventoryReply = LLMessageStringTable::getInstance()->getString("FetchInventoryReply");
+char const* const _PREHASH_GroupAccountSummaryReply = LLMessageStringTable::getInstance()->getString("GroupAccountSummaryReply");
+char const* const _PREHASH_AttachedSound = LLMessageStringTable::getInstance()->getString("AttachedSound");
+char const* const _PREHASH_ParamInUse = LLMessageStringTable::getInstance()->getString("ParamInUse");
+char const* const _PREHASH_GodKickUser = LLMessageStringTable::getInstance()->getString("GodKickUser");
+char const* const _PREHASH_PickName = LLMessageStringTable::getInstance()->getString("PickName");
+char const* const _PREHASH_TaskName = LLMessageStringTable::getInstance()->getString("TaskName");
+char const* const _PREHASH_ObjectCount = LLMessageStringTable::getInstance()->getString("ObjectCount");
+char const* const _PREHASH_RegionPresenceRequestByHandle = LLMessageStringTable::getInstance()->getString("RegionPresenceRequestByHandle");
+char const* const _PREHASH_RezSingleAttachmentFromInv = LLMessageStringTable::getInstance()->getString("RezSingleAttachmentFromInv");
+char const* const _PREHASH_ChildAgentUpdate = LLMessageStringTable::getInstance()->getString("ChildAgentUpdate");
+char const* const _PREHASH_IsOwnerGroup = LLMessageStringTable::getInstance()->getString("IsOwnerGroup");
+char const* const _PREHASH_AgentHeightWidth = LLMessageStringTable::getInstance()->getString("AgentHeightWidth");
+char const* const _PREHASH_VerticalAngle = LLMessageStringTable::getInstance()->getString("VerticalAngle");
+char const* const _PREHASH_WearableType = LLMessageStringTable::getInstance()->getString("WearableType");
+char const* const _PREHASH_AggregatePermNextOwner = LLMessageStringTable::getInstance()->getString("AggregatePermNextOwner");
+char const* const _PREHASH_ShowInList = LLMessageStringTable::getInstance()->getString("ShowInList");
+char const* const _PREHASH_UpdateParcel = LLMessageStringTable::getInstance()->getString("UpdateParcel");
+char const* const _PREHASH_SetAlwaysRun = LLMessageStringTable::getInstance()->getString("SetAlwaysRun");
+char const* const _PREHASH_NVPair = LLMessageStringTable::getInstance()->getString("NVPair");
+char const* const _PREHASH_SearchType = LLMessageStringTable::getInstance()->getString("SearchType");
+char const* const _PREHASH_ObjectSpinStart = LLMessageStringTable::getInstance()->getString("ObjectSpinStart");
+char const* const _PREHASH_UseEstateSun = LLMessageStringTable::getInstance()->getString("UseEstateSun");
+char const* const _PREHASH_RegionID = LLMessageStringTable::getInstance()->getString("RegionID");
+char const* const _PREHASH_AbuseRegionID = LLMessageStringTable::getInstance()->getString("AbuseRegionID");
+char const* const _PREHASH_Creator = LLMessageStringTable::getInstance()->getString("Creator");
+char const* const _PREHASH_ProposalText = LLMessageStringTable::getInstance()->getString("ProposalText");
+char const* const _PREHASH_DirEventsReply = LLMessageStringTable::getInstance()->getString("DirEventsReply");
+char const* const _PREHASH_EventInfoReply = LLMessageStringTable::getInstance()->getString("EventInfoReply");
+char const* const _PREHASH_UserInfoReply = LLMessageStringTable::getInstance()->getString("UserInfoReply");
+char const* const _PREHASH_PathRadiusOffset = LLMessageStringTable::getInstance()->getString("PathRadiusOffset");
+char const* const _PREHASH_TextureData = LLMessageStringTable::getInstance()->getString("TextureData");
+char const* const _PREHASH_ChatPass = LLMessageStringTable::getInstance()->getString("ChatPass");
+char const* const _PREHASH_TargetID = LLMessageStringTable::getInstance()->getString("TargetID");
+char const* const _PREHASH_DefaultPayPrice = LLMessageStringTable::getInstance()->getString("DefaultPayPrice");
+char const* const _PREHASH_UserLocation = LLMessageStringTable::getInstance()->getString("UserLocation");
+char const* const _PREHASH_MaxPrims = LLMessageStringTable::getInstance()->getString("MaxPrims");
+char const* const _PREHASH_LandmarkID = LLMessageStringTable::getInstance()->getString("LandmarkID");
+char const* const _PREHASH_InitiateDownload = LLMessageStringTable::getInstance()->getString("InitiateDownload");
+char const* const _PREHASH_Name = LLMessageStringTable::getInstance()->getString("Name");
+char const* const _PREHASH_OtherCleanTime = LLMessageStringTable::getInstance()->getString("OtherCleanTime");
+char const* const _PREHASH_ParcelSetOtherCleanTime = LLMessageStringTable::getInstance()->getString("ParcelSetOtherCleanTime");
+char const* const _PREHASH_TeleportPriceExponent = LLMessageStringTable::getInstance()->getString("TeleportPriceExponent");
+char const* const _PREHASH_Gain = LLMessageStringTable::getInstance()->getString("Gain");
+char const* const _PREHASH_PacketAck = LLMessageStringTable::getInstance()->getString("PacketAck");
+char const* const _PREHASH_PathSkew = LLMessageStringTable::getInstance()->getString("PathSkew");
+char const* const _PREHASH_SimulatorShutdownRequest = LLMessageStringTable::getInstance()->getString("SimulatorShutdownRequest");
+char const* const _PREHASH_NearestLandingRegionRequest = LLMessageStringTable::getInstance()->getString("NearestLandingRegionRequest");
+char const* const _PREHASH_OtherID = LLMessageStringTable::getInstance()->getString("OtherID");
+char const* const _PREHASH_MemberID = LLMessageStringTable::getInstance()->getString("MemberID");
+char const* const _PREHASH_MapLayerRequest = LLMessageStringTable::getInstance()->getString("MapLayerRequest");
+char const* const _PREHASH_ObjectScale = LLMessageStringTable::getInstance()->getString("ObjectScale");
+char const* const _PREHASH_TargetIP = LLMessageStringTable::getInstance()->getString("TargetIP");
+char const* const _PREHASH_Redo = LLMessageStringTable::getInstance()->getString("Redo");
+char const* const _PREHASH_MoneyBalance = LLMessageStringTable::getInstance()->getString("MoneyBalance");
+char const* const _PREHASH_TrackAgent = LLMessageStringTable::getInstance()->getString("TrackAgent");
+char const* const _PREHASH_MaxX = LLMessageStringTable::getInstance()->getString("MaxX");
+char const* const _PREHASH_Data = LLMessageStringTable::getInstance()->getString("Data");
+char const* const _PREHASH_MaxY = LLMessageStringTable::getInstance()->getString("MaxY");
+char const* const _PREHASH_TextureAnim = LLMessageStringTable::getInstance()->getString("TextureAnim");
+char const* const _PREHASH_ReturnIDs = LLMessageStringTable::getInstance()->getString("ReturnIDs");
+char const* const _PREHASH_Date = LLMessageStringTable::getInstance()->getString("Date");
+char const* const _PREHASH_AgentWearablesUpdate = LLMessageStringTable::getInstance()->getString("AgentWearablesUpdate");
+char const* const _PREHASH_AgentDataUpdate = LLMessageStringTable::getInstance()->getString("AgentDataUpdate");
+char const* const _PREHASH_GroupDataUpdate = LLMessageStringTable::getInstance()->getString("GroupDataUpdate");
+char const* const _PREHASH_Hash = LLMessageStringTable::getInstance()->getString("Hash");
+char const* const _PREHASH_AgentGroupDataUpdate = LLMessageStringTable::getInstance()->getString("AgentGroupDataUpdate");
+char const* const _PREHASH_Left = LLMessageStringTable::getInstance()->getString("Left");
+char const* const _PREHASH_Mask = LLMessageStringTable::getInstance()->getString("Mask");
+char const* const _PREHASH_ForceMouselook = LLMessageStringTable::getInstance()->getString("ForceMouselook");
+char const* const _PREHASH_Success = LLMessageStringTable::getInstance()->getString("Success");
+char const* const _PREHASH_ObjectGroup = LLMessageStringTable::getInstance()->getString("ObjectGroup");
+char const* const _PREHASH_SunHour = LLMessageStringTable::getInstance()->getString("SunHour");
+char const* const _PREHASH_MinX = LLMessageStringTable::getInstance()->getString("MinX");
+char const* const _PREHASH_ScriptSensorReply = LLMessageStringTable::getInstance()->getString("ScriptSensorReply");
+char const* const _PREHASH_MinY = LLMessageStringTable::getInstance()->getString("MinY");
+char const* const _PREHASH_Command = LLMessageStringTable::getInstance()->getString("Command");
+char const* const _PREHASH_Desc = LLMessageStringTable::getInstance()->getString("Desc");
+char const* const _PREHASH_AttachmentNeedsSave = LLMessageStringTable::getInstance()->getString("AttachmentNeedsSave");
+char const* const _PREHASH_HistoryItemData = LLMessageStringTable::getInstance()->getString("HistoryItemData");
+char const* const _PREHASH_AgentCachedTexture = LLMessageStringTable::getInstance()->getString("AgentCachedTexture");
+char const* const _PREHASH_Subject = LLMessageStringTable::getInstance()->getString("Subject");
+char const* const _PREHASH_East = LLMessageStringTable::getInstance()->getString("East");
+char const* const _PREHASH_QueryReplies = LLMessageStringTable::getInstance()->getString("QueryReplies");
+char const* const _PREHASH_ObjectCategory = LLMessageStringTable::getInstance()->getString("ObjectCategory");
+char const* const _PREHASH_Time = LLMessageStringTable::getInstance()->getString("Time");
+char const* const _PREHASH_CreateLandmarkForEvent = LLMessageStringTable::getInstance()->getString("CreateLandmarkForEvent");
+char const* const _PREHASH_ParentID = LLMessageStringTable::getInstance()->getString("ParentID");
+char const* const _PREHASH_Ping = LLMessageStringTable::getInstance()->getString("Ping");
+char const* const _PREHASH_Perp = LLMessageStringTable::getInstance()->getString("Perp");
+char const* const _PREHASH_Code = LLMessageStringTable::getInstance()->getString("Code");
+char const* const _PREHASH_InvType = LLMessageStringTable::getInstance()->getString("InvType");
+char const* const _PREHASH_AgentFOV = LLMessageStringTable::getInstance()->getString("AgentFOV");
+char const* const _PREHASH_Audible = LLMessageStringTable::getInstance()->getString("Audible");
+char const* const _PREHASH_AuctionData = LLMessageStringTable::getInstance()->getString("AuctionData");
+char const* const _PREHASH_IDBlock = LLMessageStringTable::getInstance()->getString("IDBlock");
+char const* const _PREHASH_West = LLMessageStringTable::getInstance()->getString("West");
+char const* const _PREHASH_Undo = LLMessageStringTable::getInstance()->getString("Undo");
+char const* const _PREHASH_TotalNumItems = LLMessageStringTable::getInstance()->getString("TotalNumItems");
+char const* const _PREHASH_Info = LLMessageStringTable::getInstance()->getString("Info");
+char const* const _PREHASH_Area = LLMessageStringTable::getInstance()->getString("Area");
+char const* const _PREHASH_SimCrashed = LLMessageStringTable::getInstance()->getString("SimCrashed");
+char const* const _PREHASH_Text = LLMessageStringTable::getInstance()->getString("Text");
+char const* const _PREHASH_PriceGroupCreate = LLMessageStringTable::getInstance()->getString("PriceGroupCreate");
+char const* const _PREHASH_ObjectShape = LLMessageStringTable::getInstance()->getString("ObjectShape");
+char const* const _PREHASH_GroupRoleDataReply = LLMessageStringTable::getInstance()->getString("GroupRoleDataReply");
+char const* const _PREHASH_MuteCRC = LLMessageStringTable::getInstance()->getString("MuteCRC");
+char const* const _PREHASH_Size = LLMessageStringTable::getInstance()->getString("Size");
+char const* const _PREHASH_FromAddress = LLMessageStringTable::getInstance()->getString("FromAddress");
+char const* const _PREHASH_Body = LLMessageStringTable::getInstance()->getString("Body");
+char const* const _PREHASH_FileData = LLMessageStringTable::getInstance()->getString("FileData");
+char const* const _PREHASH_List = LLMessageStringTable::getInstance()->getString("List");
+char const* const _PREHASH_KickUser = LLMessageStringTable::getInstance()->getString("KickUser");
+char const* const _PREHASH_OtherPrims = LLMessageStringTable::getInstance()->getString("OtherPrims");
+char const* const _PREHASH_RunTime = LLMessageStringTable::getInstance()->getString("RunTime");
+char const* const _PREHASH_GrantUserRights = LLMessageStringTable::getInstance()->getString("GrantUserRights");
+char const* const _PREHASH_RpcScriptRequestInboundForward = LLMessageStringTable::getInstance()->getString("RpcScriptRequestInboundForward");
+char const* const _PREHASH_More = LLMessageStringTable::getInstance()->getString("More");
+char const* const _PREHASH_Majority = LLMessageStringTable::getInstance()->getString("Majority");
+char const* const _PREHASH_MetersTraveled = LLMessageStringTable::getInstance()->getString("MetersTraveled");
+char const* const _PREHASH_Stat = LLMessageStringTable::getInstance()->getString("Stat");
+char const* const _PREHASH_SoundID = LLMessageStringTable::getInstance()->getString("SoundID");
+char const* const _PREHASH_Item = LLMessageStringTable::getInstance()->getString("Item");
+char const* const _PREHASH_User = LLMessageStringTable::getInstance()->getString("User");
+char const* const _PREHASH_Prey = LLMessageStringTable::getInstance()->getString("Prey");
+char const* const _PREHASH_RayStart = LLMessageStringTable::getInstance()->getString("RayStart");
+char const* const _PREHASH_UsecSinceStart = LLMessageStringTable::getInstance()->getString("UsecSinceStart");
+char const* const _PREHASH_ParcelData = LLMessageStringTable::getInstance()->getString("ParcelData");
+char const* const _PREHASH_CameraUpAxis = LLMessageStringTable::getInstance()->getString("CameraUpAxis");
+char const* const _PREHASH_ScriptDialog = LLMessageStringTable::getInstance()->getString("ScriptDialog");
+char const* const _PREHASH_MasterParcelData = LLMessageStringTable::getInstance()->getString("MasterParcelData");
+char const* const _PREHASH_Invalid = LLMessageStringTable::getInstance()->getString("Invalid");
+char const* const _PREHASH_ProfileCurve = LLMessageStringTable::getInstance()->getString("ProfileCurve");
+char const* const _PREHASH_ParcelAccessListUpdate = LLMessageStringTable::getInstance()->getString("ParcelAccessListUpdate");
+char const* const _PREHASH_MuteListUpdate = LLMessageStringTable::getInstance()->getString("MuteListUpdate");
+char const* const _PREHASH_SendPacket = LLMessageStringTable::getInstance()->getString("SendPacket");
+char const* const _PREHASH_SendXferPacket = LLMessageStringTable::getInstance()->getString("SendXferPacket");
+char const* const _PREHASH_RegionDenyIdentified = LLMessageStringTable::getInstance()->getString("RegionDenyIdentified");
+char const* const _PREHASH_NotecardItemID = LLMessageStringTable::getInstance()->getString("NotecardItemID");
+char const* const _PREHASH_LastName = LLMessageStringTable::getInstance()->getString("LastName");
+char const* const _PREHASH_From = LLMessageStringTable::getInstance()->getString("From");
+char const* const _PREHASH_RoleChange = LLMessageStringTable::getInstance()->getString("RoleChange");
+char const* const _PREHASH_Port = LLMessageStringTable::getInstance()->getString("Port");
+char const* const _PREHASH_MemberTitle = LLMessageStringTable::getInstance()->getString("MemberTitle");
+char const* const _PREHASH_LogParcelChanges = LLMessageStringTable::getInstance()->getString("LogParcelChanges");
+char const* const _PREHASH_AgentCachedTextureResponse = LLMessageStringTable::getInstance()->getString("AgentCachedTextureResponse");
+char const* const _PREHASH_DeRezObject = LLMessageStringTable::getInstance()->getString("DeRezObject");
+char const* const _PREHASH_IsTemporary = LLMessageStringTable::getInstance()->getString("IsTemporary");
+char const* const _PREHASH_InsigniaID = LLMessageStringTable::getInstance()->getString("InsigniaID");
+char const* const _PREHASH_CheckFlags = LLMessageStringTable::getInstance()->getString("CheckFlags");
+char const* const _PREHASH_EventID = LLMessageStringTable::getInstance()->getString("EventID");
+char const* const _PREHASH_Selected = LLMessageStringTable::getInstance()->getString("Selected");
+char const* const _PREHASH_FromAgentId = LLMessageStringTable::getInstance()->getString("FromAgentId");
+char const* const _PREHASH_Type = LLMessageStringTable::getInstance()->getString("Type");
+char const* const _PREHASH_ChatType = LLMessageStringTable::getInstance()->getString("ChatType");
+char const* const _PREHASH_ReportData = LLMessageStringTable::getInstance()->getString("ReportData");
+char const* const _PREHASH_RequestBlock = LLMessageStringTable::getInstance()->getString("RequestBlock");
+char const* const _PREHASH_GrantData = LLMessageStringTable::getInstance()->getString("GrantData");
+char const* const _PREHASH_DetachAttachmentIntoInv = LLMessageStringTable::getInstance()->getString("DetachAttachmentIntoInv");
+char const* const _PREHASH_ParcelDisableObjects = LLMessageStringTable::getInstance()->getString("ParcelDisableObjects");
+char const* const _PREHASH_Sections = LLMessageStringTable::getInstance()->getString("Sections");
+char const* const _PREHASH_GodLevel = LLMessageStringTable::getInstance()->getString("GodLevel");
+char const* const _PREHASH_PayPriceReply = LLMessageStringTable::getInstance()->getString("PayPriceReply");
+char const* const _PREHASH_QueryID = LLMessageStringTable::getInstance()->getString("QueryID");
+char const* const _PREHASH_CameraEyeOffset = LLMessageStringTable::getInstance()->getString("CameraEyeOffset");
+char const* const _PREHASH_AgentPosition = LLMessageStringTable::getInstance()->getString("AgentPosition");
+char const* const _PREHASH_GrabPosition = LLMessageStringTable::getInstance()->getString("GrabPosition");
+char const* const _PREHASH_OnlineNotification = LLMessageStringTable::getInstance()->getString("OnlineNotification");
+char const* const _PREHASH_OfflineNotification = LLMessageStringTable::getInstance()->getString("OfflineNotification");
+char const* const _PREHASH_SendPostcard = LLMessageStringTable::getInstance()->getString("SendPostcard");
+char const* const _PREHASH_RequestFlags = LLMessageStringTable::getInstance()->getString("RequestFlags");
+char const* const _PREHASH_GroupAccountSummaryRequest = LLMessageStringTable::getInstance()->getString("GroupAccountSummaryRequest");
+char const* const _PREHASH_GroupVoteHistoryRequest = LLMessageStringTable::getInstance()->getString("GroupVoteHistoryRequest");
+char const* const _PREHASH_ParamValue = LLMessageStringTable::getInstance()->getString("ParamValue");
+char const* const _PREHASH_MaxAgents = LLMessageStringTable::getInstance()->getString("MaxAgents");
+char const* const _PREHASH_CreateNewOutfitAttachments = LLMessageStringTable::getInstance()->getString("CreateNewOutfitAttachments");
+char const* const _PREHASH_RegionHandle = LLMessageStringTable::getInstance()->getString("RegionHandle");
+char const* const _PREHASH_TeleportProgress = LLMessageStringTable::getInstance()->getString("TeleportProgress");
+char const* const _PREHASH_AgentQuitCopy = LLMessageStringTable::getInstance()->getString("AgentQuitCopy");
+char const* const _PREHASH_AvatarInterestsUpdate = LLMessageStringTable::getInstance()->getString("AvatarInterestsUpdate");
+char const* const _PREHASH_GroupNoticeID = LLMessageStringTable::getInstance()->getString("GroupNoticeID");
+char const* const _PREHASH_ParcelName = LLMessageStringTable::getInstance()->getString("ParcelName");
+char const* const _PREHASH_PriceObjectRent = LLMessageStringTable::getInstance()->getString("PriceObjectRent");
+char const* const _PREHASH_OfferCallingCard = LLMessageStringTable::getInstance()->getString("OfferCallingCard");
+char const* const _PREHASH_AcceptCallingCard = LLMessageStringTable::getInstance()->getString("AcceptCallingCard");
+char const* const _PREHASH_DeclineCallingCard = LLMessageStringTable::getInstance()->getString("DeclineCallingCard");
+char const* const _PREHASH_AgentAccess = LLMessageStringTable::getInstance()->getString("AgentAccess");
+char const* const _PREHASH_AgentLegacyAccess = LLMessageStringTable::getInstance()->getString("AgentLegacyAccess");
+char const* const _PREHASH_AgentMaxAccess = LLMessageStringTable::getInstance()->getString("AgentMaxAccess");
+char const* const _PREHASH_DataHomeLocationReply = LLMessageStringTable::getInstance()->getString("DataHomeLocationReply");
+char const* const _PREHASH_EventLocationReply = LLMessageStringTable::getInstance()->getString("EventLocationReply");
+char const* const _PREHASH_TerseDateID = LLMessageStringTable::getInstance()->getString("TerseDateID");
+char const* const _PREHASH_ObjectOwner = LLMessageStringTable::getInstance()->getString("ObjectOwner");
+char const* const _PREHASH_AssetID = LLMessageStringTable::getInstance()->getString("AssetID");
+char const* const _PREHASH_AlertMessage = LLMessageStringTable::getInstance()->getString("AlertMessage");
+char const* const _PREHASH_AgentAlertMessage = LLMessageStringTable::getInstance()->getString("AgentAlertMessage");
+char const* const _PREHASH_EstateOwnerMessage = LLMessageStringTable::getInstance()->getString("EstateOwnerMessage");
+char const* const _PREHASH_ParcelMediaCommandMessage = LLMessageStringTable::getInstance()->getString("ParcelMediaCommandMessage");
+char const* const _PREHASH_Auction = LLMessageStringTable::getInstance()->getString("Auction");
+char const* const _PREHASH_Category = LLMessageStringTable::getInstance()->getString("Category");
+char const* const _PREHASH_FilePath = LLMessageStringTable::getInstance()->getString("FilePath");
+char const* const _PREHASH_ItemFlags = LLMessageStringTable::getInstance()->getString("ItemFlags");
+char const* const _PREHASH_Invoice = LLMessageStringTable::getInstance()->getString("Invoice");
+char const* const _PREHASH_IntervalDays = LLMessageStringTable::getInstance()->getString("IntervalDays");
+char const* const _PREHASH_PathScaleX = LLMessageStringTable::getInstance()->getString("PathScaleX");
+char const* const _PREHASH_FromTaskID = LLMessageStringTable::getInstance()->getString("FromTaskID");
+char const* const _PREHASH_PathScaleY = LLMessageStringTable::getInstance()->getString("PathScaleY");
+char const* const _PREHASH_TimeInfo = LLMessageStringTable::getInstance()->getString("TimeInfo");
+char const* const _PREHASH_PublicCount = LLMessageStringTable::getInstance()->getString("PublicCount");
+char const* const _PREHASH_ParcelJoin = LLMessageStringTable::getInstance()->getString("ParcelJoin");
+char const* const _PREHASH_GroupRolesCount = LLMessageStringTable::getInstance()->getString("GroupRolesCount");
+char const* const _PREHASH_SimulatorBlock = LLMessageStringTable::getInstance()->getString("SimulatorBlock");
+char const* const _PREHASH_GroupID = LLMessageStringTable::getInstance()->getString("GroupID");
+char const* const _PREHASH_AgentVel = LLMessageStringTable::getInstance()->getString("AgentVel");
+char const* const _PREHASH_RequestImage = LLMessageStringTable::getInstance()->getString("RequestImage");
+char const* const _PREHASH_NetStats = LLMessageStringTable::getInstance()->getString("NetStats");
+char const* const _PREHASH_AgentPos = LLMessageStringTable::getInstance()->getString("AgentPos");
+char const* const _PREHASH_AgentSit = LLMessageStringTable::getInstance()->getString("AgentSit");
+char const* const _PREHASH_Material = LLMessageStringTable::getInstance()->getString("Material");
+char const* const _PREHASH_ObjectDeGrab = LLMessageStringTable::getInstance()->getString("ObjectDeGrab");
+char const* const _PREHASH_VelocityInterpolateOff = LLMessageStringTable::getInstance()->getString("VelocityInterpolateOff");
+char const* const _PREHASH_AuthorizedBuyerID = LLMessageStringTable::getInstance()->getString("AuthorizedBuyerID");
+char const* const _PREHASH_AvatarPropertiesReply = LLMessageStringTable::getInstance()->getString("AvatarPropertiesReply");
+char const* const _PREHASH_GroupProfileReply = LLMessageStringTable::getInstance()->getString("GroupProfileReply");
+char const* const _PREHASH_SimOwner = LLMessageStringTable::getInstance()->getString("SimOwner");
+char const* const _PREHASH_SalePrice = LLMessageStringTable::getInstance()->getString("SalePrice");
+char const* const _PREHASH_Animation = LLMessageStringTable::getInstance()->getString("Animation");
+char const* const _PREHASH_OwnerID = LLMessageStringTable::getInstance()->getString("OwnerID");
+char const* const _PREHASH_NearestLandingRegionUpdated = LLMessageStringTable::getInstance()->getString("NearestLandingRegionUpdated");
+char const* const _PREHASH_PassToAgent = LLMessageStringTable::getInstance()->getString("PassToAgent");
+char const* const _PREHASH_PreyAgent = LLMessageStringTable::getInstance()->getString("PreyAgent");
+char const* const _PREHASH_SimStats = LLMessageStringTable::getInstance()->getString("SimStats");
+char const* const _PREHASH_LogoutReply = LLMessageStringTable::getInstance()->getString("LogoutReply");
+char const* const _PREHASH_FeatureDisabled = LLMessageStringTable::getInstance()->getString("FeatureDisabled");
+char const* const _PREHASH_PhysicalAvatarEventList = LLMessageStringTable::getInstance()->getString("PhysicalAvatarEventList");
+char const* const _PREHASH_ObjectLocalID = LLMessageStringTable::getInstance()->getString("ObjectLocalID");
+char const* const _PREHASH_Dropped = LLMessageStringTable::getInstance()->getString("Dropped");
+char const* const _PREHASH_WebProfilesDisabled = LLMessageStringTable::getInstance()->getString("WebProfilesDisabled");
+char const* const _PREHASH_Destination = LLMessageStringTable::getInstance()->getString("Destination");
+char const* const _PREHASH_MasterID = LLMessageStringTable::getInstance()->getString("MasterID");
+char const* const _PREHASH_TransferData = LLMessageStringTable::getInstance()->getString("TransferData");
+char const* const _PREHASH_WantToMask = LLMessageStringTable::getInstance()->getString("WantToMask");
+char const* const _PREHASH_ParcelSelectObjects = LLMessageStringTable::getInstance()->getString("ParcelSelectObjects");
+char const* const _PREHASH_ExtraParams = LLMessageStringTable::getInstance()->getString("ExtraParams");
+char const* const _PREHASH_CreatorID = LLMessageStringTable::getInstance()->getString("CreatorID");
+char const* const _PREHASH_Summary = LLMessageStringTable::getInstance()->getString("Summary");
+char const* const _PREHASH_BuyObjectInventory = LLMessageStringTable::getInstance()->getString("BuyObjectInventory");
+char const* const _PREHASH_FetchInventory = LLMessageStringTable::getInstance()->getString("FetchInventory");
+char const* const _PREHASH_InventoryID = LLMessageStringTable::getInstance()->getString("InventoryID");
+char const* const _PREHASH_PacketNumber = LLMessageStringTable::getInstance()->getString("PacketNumber");
+char const* const _PREHASH_SetFollowCamProperties = LLMessageStringTable::getInstance()->getString("SetFollowCamProperties");
+char const* const _PREHASH_ClearFollowCamProperties = LLMessageStringTable::getInstance()->getString("ClearFollowCamProperties");
+char const* const _PREHASH_SequenceID = LLMessageStringTable::getInstance()->getString("SequenceID");
+char const* const _PREHASH_DataServerLogout = LLMessageStringTable::getInstance()->getString("DataServerLogout");
+char const* const _PREHASH_NameValue = LLMessageStringTable::getInstance()->getString("NameValue");
+char const* const _PREHASH_PathShearX = LLMessageStringTable::getInstance()->getString("PathShearX");
+char const* const _PREHASH_PathShearY = LLMessageStringTable::getInstance()->getString("PathShearY");
+char const* const _PREHASH_Velocity = LLMessageStringTable::getInstance()->getString("Velocity");
+char const* const _PREHASH_SecPerYear = LLMessageStringTable::getInstance()->getString("SecPerYear");
+char const* const _PREHASH_FirstName = LLMessageStringTable::getInstance()->getString("FirstName");
+char const* const _PREHASH_AttachedSoundGainChange = LLMessageStringTable::getInstance()->getString("AttachedSoundGainChange");
+char const* const _PREHASH_LocationID = LLMessageStringTable::getInstance()->getString("LocationID");
+char const* const _PREHASH_Running = LLMessageStringTable::getInstance()->getString("Running");
+char const* const _PREHASH_AgentThrottle = LLMessageStringTable::getInstance()->getString("AgentThrottle");
+char const* const _PREHASH_NeighborList = LLMessageStringTable::getInstance()->getString("NeighborList");
+char const* const _PREHASH_PathTaperX = LLMessageStringTable::getInstance()->getString("PathTaperX");
+char const* const _PREHASH_PathTaperY = LLMessageStringTable::getInstance()->getString("PathTaperY");
+char const* const _PREHASH_AgentRelated = LLMessageStringTable::getInstance()->getString("AgentRelated");
+char const* const _PREHASH_GranterBlock = LLMessageStringTable::getInstance()->getString("GranterBlock");
+char const* const _PREHASH_UseCachedMuteList = LLMessageStringTable::getInstance()->getString("UseCachedMuteList");
+char const* const _PREHASH_FailStats = LLMessageStringTable::getInstance()->getString("FailStats");
+char const* const _PREHASH_Tempfile = LLMessageStringTable::getInstance()->getString("Tempfile");
+char const* const _PREHASH_BuyerID = LLMessageStringTable::getInstance()->getString("BuyerID");
+char const* const _PREHASH_DirPeopleReply = LLMessageStringTable::getInstance()->getString("DirPeopleReply");
+char const* const _PREHASH_TransferInfo = LLMessageStringTable::getInstance()->getString("TransferInfo");
+char const* const _PREHASH_AvatarPickerRequestBackend = LLMessageStringTable::getInstance()->getString("AvatarPickerRequestBackend");
+char const* const _PREHASH_AvatarPropertiesRequestBackend = LLMessageStringTable::getInstance()->getString("AvatarPropertiesRequestBackend");
+char const* const _PREHASH_UpdateData = LLMessageStringTable::getInstance()->getString("UpdateData");
+char const* const _PREHASH_SimFPS = LLMessageStringTable::getInstance()->getString("SimFPS");
+char const* const _PREHASH_ReporterID = LLMessageStringTable::getInstance()->getString("ReporterID");
+char const* const _PREHASH_ButtonLabel = LLMessageStringTable::getInstance()->getString("ButtonLabel");
+char const* const _PREHASH_GranterID = LLMessageStringTable::getInstance()->getString("GranterID");
+char const* const _PREHASH_WantToText = LLMessageStringTable::getInstance()->getString("WantToText");
+char const* const _PREHASH_ReportType = LLMessageStringTable::getInstance()->getString("ReportType");
+char const* const _PREHASH_SimulatorReady = LLMessageStringTable::getInstance()->getString("SimulatorReady");
+char const* const _PREHASH_DataBlock = LLMessageStringTable::getInstance()->getString("DataBlock");
+char const* const _PREHASH_AnimationSourceList = LLMessageStringTable::getInstance()->getString("AnimationSourceList");
+char const* const _PREHASH_SubscribeLoad = LLMessageStringTable::getInstance()->getString("SubscribeLoad");
+char const* const _PREHASH_UnsubscribeLoad = LLMessageStringTable::getInstance()->getString("UnsubscribeLoad");
+char const* const _PREHASH_Packet = LLMessageStringTable::getInstance()->getString("Packet");
+char const* const _PREHASH_UndoLand = LLMessageStringTable::getInstance()->getString("UndoLand");
+char const* const _PREHASH_SimAccess = LLMessageStringTable::getInstance()->getString("SimAccess");
+char const* const _PREHASH_AbuserID = LLMessageStringTable::getInstance()->getString("AbuserID");
+char const* const _PREHASH_MembershipFee = LLMessageStringTable::getInstance()->getString("MembershipFee");
+char const* const _PREHASH_InviteGroupResponse = LLMessageStringTable::getInstance()->getString("InviteGroupResponse");
+char const* const _PREHASH_CreateInventoryFolder = LLMessageStringTable::getInstance()->getString("CreateInventoryFolder");
+char const* const _PREHASH_UpdateInventoryFolder = LLMessageStringTable::getInstance()->getString("UpdateInventoryFolder");
+char const* const _PREHASH_MoveInventoryFolder = LLMessageStringTable::getInstance()->getString("MoveInventoryFolder");
+char const* const _PREHASH_RemoveInventoryFolder = LLMessageStringTable::getInstance()->getString("RemoveInventoryFolder");
+char const* const _PREHASH_MoneyData = LLMessageStringTable::getInstance()->getString("MoneyData");
+char const* const _PREHASH_ObjectDeselect = LLMessageStringTable::getInstance()->getString("ObjectDeselect");
+char const* const _PREHASH_NewAssetID = LLMessageStringTable::getInstance()->getString("NewAssetID");
+char const* const _PREHASH_ObjectAdd = LLMessageStringTable::getInstance()->getString("ObjectAdd");
+char const* const _PREHASH_RayEndIsIntersection = LLMessageStringTable::getInstance()->getString("RayEndIsIntersection");
+char const* const _PREHASH_CompleteAuction = LLMessageStringTable::getInstance()->getString("CompleteAuction");
+char const* const _PREHASH_CircuitCode = LLMessageStringTable::getInstance()->getString("CircuitCode");
+char const* const _PREHASH_AgentMovementComplete = LLMessageStringTable::getInstance()->getString("AgentMovementComplete");
+char const* const _PREHASH_ViewerIP = LLMessageStringTable::getInstance()->getString("ViewerIP");
+char const* const _PREHASH_Header = LLMessageStringTable::getInstance()->getString("Header");
+char const* const _PREHASH_GestureFlags = LLMessageStringTable::getInstance()->getString("GestureFlags");
+char const* const _PREHASH_XferID = LLMessageStringTable::getInstance()->getString("XferID");
+char const* const _PREHASH_StatValue = LLMessageStringTable::getInstance()->getString("StatValue");
+char const* const _PREHASH_TaskID = LLMessageStringTable::getInstance()->getString("TaskID");
+char const* const _PREHASH_PickID = LLMessageStringTable::getInstance()->getString("PickID");
+char const* const _PREHASH_RayEnd = LLMessageStringTable::getInstance()->getString("RayEnd");
+char const* const _PREHASH_Throttles = LLMessageStringTable::getInstance()->getString("Throttles");
+char const* const _PREHASH_RebakeAvatarTextures = LLMessageStringTable::getInstance()->getString("RebakeAvatarTextures");
+char const* const _PREHASH_UpAxis = LLMessageStringTable::getInstance()->getString("UpAxis");
+char const* const _PREHASH_AgentTextures = LLMessageStringTable::getInstance()->getString("AgentTextures");
+char const* const _PREHASH_NotecardData = LLMessageStringTable::getInstance()->getString("NotecardData");
+char const* const _PREHASH_Radius = LLMessageStringTable::getInstance()->getString("Radius");
+char const* const _PREHASH_OffCircuit = LLMessageStringTable::getInstance()->getString("OffCircuit");
+char const* const _PREHASH_Access = LLMessageStringTable::getInstance()->getString("Access");
+char const* const _PREHASH_TitleRoleID = LLMessageStringTable::getInstance()->getString("TitleRoleID");
+char const* const _PREHASH_SquareMetersCredit = LLMessageStringTable::getInstance()->getString("SquareMetersCredit");
+char const* const _PREHASH_Filename = LLMessageStringTable::getInstance()->getString("Filename");
+char const* const _PREHASH_ClassifiedInfoRequest = LLMessageStringTable::getInstance()->getString("ClassifiedInfoRequest");
+char const* const _PREHASH_ParcelInfoRequest = LLMessageStringTable::getInstance()->getString("ParcelInfoRequest");
+char const* const _PREHASH_ParcelObjectOwnersRequest = LLMessageStringTable::getInstance()->getString("ParcelObjectOwnersRequest");
+char const* const _PREHASH_TeleportLandmarkRequest = LLMessageStringTable::getInstance()->getString("TeleportLandmarkRequest");
+char const* const _PREHASH_EventInfoRequest = LLMessageStringTable::getInstance()->getString("EventInfoRequest");
+char const* const _PREHASH_MoneyBalanceRequest = LLMessageStringTable::getInstance()->getString("MoneyBalanceRequest");
+char const* const _PREHASH_GroupMembersRequest = LLMessageStringTable::getInstance()->getString("GroupMembersRequest");
+char const* const _PREHASH_GroupRoleMembersRequest = LLMessageStringTable::getInstance()->getString("GroupRoleMembersRequest");
+char const* const _PREHASH_ChatFromSimulator = LLMessageStringTable::getInstance()->getString("ChatFromSimulator");
+char const* const _PREHASH_OldFolderID = LLMessageStringTable::getInstance()->getString("OldFolderID");
+char const* const _PREHASH_UserInfoRequest = LLMessageStringTable::getInstance()->getString("UserInfoRequest");
+char const* const _PREHASH_TextureID = LLMessageStringTable::getInstance()->getString("TextureID");
+char const* const _PREHASH_ProfileURL = LLMessageStringTable::getInstance()->getString("ProfileURL");
+char const* const _PREHASH_Handle = LLMessageStringTable::getInstance()->getString("Handle");
+char const* const _PREHASH_ButtonIndex = LLMessageStringTable::getInstance()->getString("ButtonIndex");
+char const* const _PREHASH_GetScriptRunning = LLMessageStringTable::getInstance()->getString("GetScriptRunning");
+char const* const _PREHASH_SetScriptRunning = LLMessageStringTable::getInstance()->getString("SetScriptRunning");
+char const* const _PREHASH_Health = LLMessageStringTable::getInstance()->getString("Health");
+char const* const _PREHASH_CircuitInfo = LLMessageStringTable::getInstance()->getString("CircuitInfo");
+char const* const _PREHASH_ObjectBuy = LLMessageStringTable::getInstance()->getString("ObjectBuy");
+char const* const _PREHASH_ProfileEnd = LLMessageStringTable::getInstance()->getString("ProfileEnd");
+char const* const _PREHASH_Effect = LLMessageStringTable::getInstance()->getString("Effect");
+char const* const _PREHASH_TestMessage = LLMessageStringTable::getInstance()->getString("TestMessage");
+char const* const _PREHASH_ScriptMailRegistration = LLMessageStringTable::getInstance()->getString("ScriptMailRegistration");
+char const* const _PREHASH_AgentSetAppearance = LLMessageStringTable::getInstance()->getString("AgentSetAppearance");
+char const* const _PREHASH_AvatarAppearance = LLMessageStringTable::getInstance()->getString("AvatarAppearance");
+char const* const _PREHASH_RegionData = LLMessageStringTable::getInstance()->getString("RegionData");
+char const* const _PREHASH_RequestingRegionData = LLMessageStringTable::getInstance()->getString("RequestingRegionData");
+char const* const _PREHASH_LandingRegionData = LLMessageStringTable::getInstance()->getString("LandingRegionData");
+char const* const _PREHASH_SitTransform = LLMessageStringTable::getInstance()->getString("SitTransform");
+char const* const _PREHASH_TerrainBase0 = LLMessageStringTable::getInstance()->getString("TerrainBase0");
+char const* const _PREHASH_SkillsMask = LLMessageStringTable::getInstance()->getString("SkillsMask");
+char const* const _PREHASH_AtAxis = LLMessageStringTable::getInstance()->getString("AtAxis");
+char const* const _PREHASH_TerrainBase1 = LLMessageStringTable::getInstance()->getString("TerrainBase1");
+char const* const _PREHASH_Reason = LLMessageStringTable::getInstance()->getString("Reason");
+char const* const _PREHASH_TerrainBase2 = LLMessageStringTable::getInstance()->getString("TerrainBase2");
+char const* const _PREHASH_TerrainBase3 = LLMessageStringTable::getInstance()->getString("TerrainBase3");
+char const* const _PREHASH_Params = LLMessageStringTable::getInstance()->getString("Params");
+char const* const _PREHASH_PingID = LLMessageStringTable::getInstance()->getString("PingID");
+char const* const _PREHASH_Change = LLMessageStringTable::getInstance()->getString("Change");
+char const* const _PREHASH_Height = LLMessageStringTable::getInstance()->getString("Height");
+char const* const _PREHASH_Region = LLMessageStringTable::getInstance()->getString("Region");
+char const* const _PREHASH_TelehubInfo = LLMessageStringTable::getInstance()->getString("TelehubInfo");
+char const* const _PREHASH_StateSave = LLMessageStringTable::getInstance()->getString("StateSave");
+char const* const _PREHASH_RoleData = LLMessageStringTable::getInstance()->getString("RoleData");
+char const* const _PREHASH_AgentAnimation = LLMessageStringTable::getInstance()->getString("AgentAnimation");
+char const* const _PREHASH_AvatarAnimation = LLMessageStringTable::getInstance()->getString("AvatarAnimation");
+char const* const _PREHASH_LogDwellTime = LLMessageStringTable::getInstance()->getString("LogDwellTime");
+char const* const _PREHASH_ParcelGodMarkAsContent = LLMessageStringTable::getInstance()->getString("ParcelGodMarkAsContent");
+char const* const _PREHASH_UsePhysics = LLMessageStringTable::getInstance()->getString("UsePhysics");
+char const* const _PREHASH_RegionDenyTransacted = LLMessageStringTable::getInstance()->getString("RegionDenyTransacted");
+char const* const _PREHASH_JointType = LLMessageStringTable::getInstance()->getString("JointType");
+char const* const _PREHASH_ObjectTaxEstimate = LLMessageStringTable::getInstance()->getString("ObjectTaxEstimate");
+char const* const _PREHASH_LightTaxEstimate = LLMessageStringTable::getInstance()->getString("LightTaxEstimate");
+char const* const _PREHASH_LandTaxEstimate = LLMessageStringTable::getInstance()->getString("LandTaxEstimate");
+char const* const _PREHASH_TeleportLandingStatusChanged = LLMessageStringTable::getInstance()->getString("TeleportLandingStatusChanged");
+char const* const _PREHASH_GroupTaxEstimate = LLMessageStringTable::getInstance()->getString("GroupTaxEstimate");
+char const* const _PREHASH_AvgViewerFPS = LLMessageStringTable::getInstance()->getString("AvgViewerFPS");
+char const* const _PREHASH_Buttons = LLMessageStringTable::getInstance()->getString("Buttons");
+char const* const _PREHASH_Sender = LLMessageStringTable::getInstance()->getString("Sender");
+char const* const _PREHASH_Dialog = LLMessageStringTable::getInstance()->getString("Dialog");
+char const* const _PREHASH_TargetData = LLMessageStringTable::getInstance()->getString("TargetData");
+char const* const _PREHASH_DestID = LLMessageStringTable::getInstance()->getString("DestID");
+char const* const _PREHASH_PricePublicObjectDelete = LLMessageStringTable::getInstance()->getString("PricePublicObjectDelete");
+char const* const _PREHASH_ObjectDelete = LLMessageStringTable::getInstance()->getString("ObjectDelete");
+char const* const _PREHASH_Delete = LLMessageStringTable::getInstance()->getString("Delete");
+char const* const _PREHASH_EventGodDelete = LLMessageStringTable::getInstance()->getString("EventGodDelete");
+char const* const _PREHASH_LastTaxDate = LLMessageStringTable::getInstance()->getString("LastTaxDate");
+char const* const _PREHASH_MapImageID = LLMessageStringTable::getInstance()->getString("MapImageID");
+char const* const _PREHASH_EndDateTime = LLMessageStringTable::getInstance()->getString("EndDateTime");
+char const* const _PREHASH_TerrainDetail0 = LLMessageStringTable::getInstance()->getString("TerrainDetail0");
+char const* const _PREHASH_TerrainDetail1 = LLMessageStringTable::getInstance()->getString("TerrainDetail1");
+char const* const _PREHASH_TerrainDetail2 = LLMessageStringTable::getInstance()->getString("TerrainDetail2");
+char const* const _PREHASH_TerrainDetail3 = LLMessageStringTable::getInstance()->getString("TerrainDetail3");
+char const* const _PREHASH_Offset = LLMessageStringTable::getInstance()->getString("Offset");
+char const* const _PREHASH_ObjectDelink = LLMessageStringTable::getInstance()->getString("ObjectDelink");
+char const* const _PREHASH_TargetObject = LLMessageStringTable::getInstance()->getString("TargetObject");
+char const* const _PREHASH_IsEstateManager = LLMessageStringTable::getInstance()->getString("IsEstateManager");
+char const* const _PREHASH_CancelAuction = LLMessageStringTable::getInstance()->getString("CancelAuction");
+char const* const _PREHASH_ObjectDetach = LLMessageStringTable::getInstance()->getString("ObjectDetach");
+char const* const _PREHASH_Compressed = LLMessageStringTable::getInstance()->getString("Compressed");
+char const* const _PREHASH_PathBegin = LLMessageStringTable::getInstance()->getString("PathBegin");
+char const* const _PREHASH_BypassRaycast = LLMessageStringTable::getInstance()->getString("BypassRaycast");
+char const* const _PREHASH_WinnerID = LLMessageStringTable::getInstance()->getString("WinnerID");
+char const* const _PREHASH_ChannelType = LLMessageStringTable::getInstance()->getString("ChannelType");
+char const* const _PREHASH_NonExemptMembers = LLMessageStringTable::getInstance()->getString("NonExemptMembers");
+char const* const _PREHASH_Agents = LLMessageStringTable::getInstance()->getString("Agents");
+char const* const _PREHASH_MemberData = LLMessageStringTable::getInstance()->getString("MemberData");
+char const* const _PREHASH_ToGroupID = LLMessageStringTable::getInstance()->getString("ToGroupID");
+char const* const _PREHASH_ImageNotInDatabase = LLMessageStringTable::getInstance()->getString("ImageNotInDatabase");
+char const* const _PREHASH_StartDate = LLMessageStringTable::getInstance()->getString("StartDate");
+char const* const _PREHASH_AnimID = LLMessageStringTable::getInstance()->getString("AnimID");
+char const* const _PREHASH_Serial = LLMessageStringTable::getInstance()->getString("Serial");
+char const* const _PREHASH_AbuseRegionName = LLMessageStringTable::getInstance()->getString("AbuseRegionName");
+char const* const _PREHASH_ModifyLand = LLMessageStringTable::getInstance()->getString("ModifyLand");
+char const* const _PREHASH_Digest = LLMessageStringTable::getInstance()->getString("Digest");
+char const* const _PREHASH_Victim = LLMessageStringTable::getInstance()->getString("Victim");
+char const* const _PREHASH_Script = LLMessageStringTable::getInstance()->getString("Script");
+char const* const _PREHASH_PickInfoReply = LLMessageStringTable::getInstance()->getString("PickInfoReply");
+char const* const _PREHASH_MoneyBalanceReply = LLMessageStringTable::getInstance()->getString("MoneyBalanceReply");
+char const* const _PREHASH_RoutedMoneyBalanceReply = LLMessageStringTable::getInstance()->getString("RoutedMoneyBalanceReply");
+char const* const _PREHASH_RoleID = LLMessageStringTable::getInstance()->getString("RoleID");
+char const* const _PREHASH_RegionInfo = LLMessageStringTable::getInstance()->getString("RegionInfo");
+char const* const _PREHASH_GodUpdateRegionInfo = LLMessageStringTable::getInstance()->getString("GodUpdateRegionInfo");
+char const* const _PREHASH_StartAnim = LLMessageStringTable::getInstance()->getString("StartAnim");
+char const* const _PREHASH_Action = LLMessageStringTable::getInstance()->getString("Action");
+char const* const _PREHASH_Location = LLMessageStringTable::getInstance()->getString("Location");
+char const* const _PREHASH_Rights = LLMessageStringTable::getInstance()->getString("Rights");
+char const* const _PREHASH_SearchDir = LLMessageStringTable::getInstance()->getString("SearchDir");
+char const* const _PREHASH_TransferRequest = LLMessageStringTable::getInstance()->getString("TransferRequest");
+char const* const _PREHASH_ScriptSensorRequest = LLMessageStringTable::getInstance()->getString("ScriptSensorRequest");
+char const* const _PREHASH_MoneyTransferRequest = LLMessageStringTable::getInstance()->getString("MoneyTransferRequest");
+char const* const _PREHASH_EjectGroupMemberRequest = LLMessageStringTable::getInstance()->getString("EjectGroupMemberRequest");
+char const* const _PREHASH_SkillsText = LLMessageStringTable::getInstance()->getString("SkillsText");
+char const* const _PREHASH_Resent = LLMessageStringTable::getInstance()->getString("Resent");
+char const* const _PREHASH_Center = LLMessageStringTable::getInstance()->getString("Center");
+char const* const _PREHASH_SharedData = LLMessageStringTable::getInstance()->getString("SharedData");
+char const* const _PREHASH_PSBlock = LLMessageStringTable::getInstance()->getString("PSBlock");
+char const* const _PREHASH_UUIDNameBlock = LLMessageStringTable::getInstance()->getString("UUIDNameBlock");
+char const* const _PREHASH_GroupTitleUpdate = LLMessageStringTable::getInstance()->getString("GroupTitleUpdate");
+char const* const _PREHASH_Method = LLMessageStringTable::getInstance()->getString("Method");
+char const* const _PREHASH_TouchName = LLMessageStringTable::getInstance()->getString("TouchName");
+char const* const _PREHASH_UpdateType = LLMessageStringTable::getInstance()->getString("UpdateType");
+char const* const _PREHASH_KickedFromEstateID = LLMessageStringTable::getInstance()->getString("KickedFromEstateID");
+char const* const _PREHASH_CandidateID = LLMessageStringTable::getInstance()->getString("CandidateID");
+char const* const _PREHASH_ParamData = LLMessageStringTable::getInstance()->getString("ParamData");
+char const* const _PREHASH_GodlikeMessage = LLMessageStringTable::getInstance()->getString("GodlikeMessage");
+char const* const _PREHASH_SystemMessage = LLMessageStringTable::getInstance()->getString("SystemMessage");
+char const* const _PREHASH_BodyRotation = LLMessageStringTable::getInstance()->getString("BodyRotation");
+char const* const _PREHASH_SearchRegions = LLMessageStringTable::getInstance()->getString("SearchRegions");
+char const* const _PREHASH_AnimationData = LLMessageStringTable::getInstance()->getString("AnimationData");
+char const* const _PREHASH_StatID = LLMessageStringTable::getInstance()->getString("StatID");
+char const* const _PREHASH_ItemID = LLMessageStringTable::getInstance()->getString("ItemID");
+char const* const _PREHASH_ScriptDialogReply = LLMessageStringTable::getInstance()->getString("ScriptDialogReply");
+char const* const _PREHASH_RegionIDAndHandleReply = LLMessageStringTable::getInstance()->getString("RegionIDAndHandleReply");
+char const* const _PREHASH_CameraAtOffset = LLMessageStringTable::getInstance()->getString("CameraAtOffset");
+char const* const _PREHASH_VoteID = LLMessageStringTable::getInstance()->getString("VoteID");
+char const* const _PREHASH_ParcelGodForceOwner = LLMessageStringTable::getInstance()->getString("ParcelGodForceOwner");
+char const* const _PREHASH_Filter = LLMessageStringTable::getInstance()->getString("Filter");
+char const* const _PREHASH_InviteData = LLMessageStringTable::getInstance()->getString("InviteData");
+char const* const _PREHASH_PCode = LLMessageStringTable::getInstance()->getString("PCode");
+char const* const _PREHASH_SearchPos = LLMessageStringTable::getInstance()->getString("SearchPos");
+char const* const _PREHASH_PreyID = LLMessageStringTable::getInstance()->getString("PreyID");
+char const* const _PREHASH_TerrainLowerLimit = LLMessageStringTable::getInstance()->getString("TerrainLowerLimit");
+char const* const _PREHASH_EventFlags = LLMessageStringTable::getInstance()->getString("EventFlags");
+char const* const _PREHASH_TallyVotes = LLMessageStringTable::getInstance()->getString("TallyVotes");
+char const* const _PREHASH_Result = LLMessageStringTable::getInstance()->getString("Result");
+char const* const _PREHASH_LookAt = LLMessageStringTable::getInstance()->getString("LookAt");
+char const* const _PREHASH_SearchOrder = LLMessageStringTable::getInstance()->getString("SearchOrder");
+char const* const _PREHASH_PayButton = LLMessageStringTable::getInstance()->getString("PayButton");
+char const* const _PREHASH_SelfCount = LLMessageStringTable::getInstance()->getString("SelfCount");
+char const* const _PREHASH_PacketCount = LLMessageStringTable::getInstance()->getString("PacketCount");
+char const* const _PREHASH_ParcelBuyPass = LLMessageStringTable::getInstance()->getString("ParcelBuyPass");
+char const* const _PREHASH_OldItemID = LLMessageStringTable::getInstance()->getString("OldItemID");
+char const* const _PREHASH_RegionPort = LLMessageStringTable::getInstance()->getString("RegionPort");
+char const* const _PREHASH_PriceEnergyUnit = LLMessageStringTable::getInstance()->getString("PriceEnergyUnit");
+char const* const _PREHASH_Bitmap = LLMessageStringTable::getInstance()->getString("Bitmap");
+char const* const _PREHASH_CacheMissType = LLMessageStringTable::getInstance()->getString("CacheMissType");
+char const* const _PREHASH_VFileID = LLMessageStringTable::getInstance()->getString("VFileID");
+char const* const _PREHASH_GroupInsigniaID = LLMessageStringTable::getInstance()->getString("GroupInsigniaID");
+char const* const _PREHASH_Online = LLMessageStringTable::getInstance()->getString("Online");
+char const* const _PREHASH_KickFlags = LLMessageStringTable::getInstance()->getString("KickFlags");
+char const* const _PREHASH_CovenantID = LLMessageStringTable::getInstance()->getString("CovenantID");
+char const* const _PREHASH_SysCPU = LLMessageStringTable::getInstance()->getString("SysCPU");
+char const* const _PREHASH_EMail = LLMessageStringTable::getInstance()->getString("EMail");
+char const* const _PREHASH_AggregatePermTextures = LLMessageStringTable::getInstance()->getString("AggregatePermTextures");
+char const* const _PREHASH_ChatChannel = LLMessageStringTable::getInstance()->getString("ChatChannel");
+char const* const _PREHASH_ReturnID = LLMessageStringTable::getInstance()->getString("ReturnID");
+char const* const _PREHASH_ObjectAttach = LLMessageStringTable::getInstance()->getString("ObjectAttach");
+char const* const _PREHASH_TargetPort = LLMessageStringTable::getInstance()->getString("TargetPort");
+char const* const _PREHASH_ObjectSpinStop = LLMessageStringTable::getInstance()->getString("ObjectSpinStop");
+char const* const _PREHASH_FullID = LLMessageStringTable::getInstance()->getString("FullID");
+char const* const _PREHASH_ActivateGroup = LLMessageStringTable::getInstance()->getString("ActivateGroup");
+char const* const _PREHASH_SysGPU = LLMessageStringTable::getInstance()->getString("SysGPU");
+char const* const _PREHASH_AvatarInterestsReply = LLMessageStringTable::getInstance()->getString("AvatarInterestsReply");
+char const* const _PREHASH_StartLure = LLMessageStringTable::getInstance()->getString("StartLure");
+char const* const _PREHASH_SysRAM = LLMessageStringTable::getInstance()->getString("SysRAM");
+char const* const _PREHASH_ObjectPosition = LLMessageStringTable::getInstance()->getString("ObjectPosition");
+char const* const _PREHASH_SitPosition = LLMessageStringTable::getInstance()->getString("SitPosition");
+char const* const _PREHASH_StartTime = LLMessageStringTable::getInstance()->getString("StartTime");
+char const* const _PREHASH_BornOn = LLMessageStringTable::getInstance()->getString("BornOn");
+char const* const _PREHASH_CameraCollidePlane = LLMessageStringTable::getInstance()->getString("CameraCollidePlane");
+char const* const _PREHASH_EconomyDataRequest = LLMessageStringTable::getInstance()->getString("EconomyDataRequest");
+char const* const _PREHASH_TeleportLureRequest = LLMessageStringTable::getInstance()->getString("TeleportLureRequest");
+char const* const _PREHASH_FolderID = LLMessageStringTable::getInstance()->getString("FolderID");
+char const* const _PREHASH_RegionHandleRequest = LLMessageStringTable::getInstance()->getString("RegionHandleRequest");
+char const* const _PREHASH_ScriptDataRequest = LLMessageStringTable::getInstance()->getString("ScriptDataRequest");
+char const* const _PREHASH_GroupRoleDataRequest = LLMessageStringTable::getInstance()->getString("GroupRoleDataRequest");
+char const* const _PREHASH_GroupTitlesRequest = LLMessageStringTable::getInstance()->getString("GroupTitlesRequest");
+char const* const _PREHASH_AgentWearablesRequest = LLMessageStringTable::getInstance()->getString("AgentWearablesRequest");
+char const* const _PREHASH_MapBlockRequest = LLMessageStringTable::getInstance()->getString("MapBlockRequest");
+char const* const _PREHASH_LureID = LLMessageStringTable::getInstance()->getString("LureID");
+char const* const _PREHASH_CopyCenters = LLMessageStringTable::getInstance()->getString("CopyCenters");
+char const* const _PREHASH_ParamList = LLMessageStringTable::getInstance()->getString("ParamList");
+char const* const _PREHASH_InventorySerial = LLMessageStringTable::getInstance()->getString("InventorySerial");
+char const* const _PREHASH_EdgeDataPacket = LLMessageStringTable::getInstance()->getString("EdgeDataPacket");
+char const* const _PREHASH_AvatarPickerReply = LLMessageStringTable::getInstance()->getString("AvatarPickerReply");
+char const* const _PREHASH_ParcelDwellReply = LLMessageStringTable::getInstance()->getString("ParcelDwellReply");
+char const* const _PREHASH_IsForSale = LLMessageStringTable::getInstance()->getString("IsForSale");
+char const* const _PREHASH_MuteID = LLMessageStringTable::getInstance()->getString("MuteID");
+char const* const _PREHASH_MeanCollisionAlert = LLMessageStringTable::getInstance()->getString("MeanCollisionAlert");
+char const* const _PREHASH_CanAcceptTasks = LLMessageStringTable::getInstance()->getString("CanAcceptTasks");
+char const* const _PREHASH_ItemData = LLMessageStringTable::getInstance()->getString("ItemData");
+char const* const _PREHASH_AnimationList = LLMessageStringTable::getInstance()->getString("AnimationList");
+char const* const _PREHASH_Reputation = LLMessageStringTable::getInstance()->getString("Reputation");
+char const* const _PREHASH_IntValue = LLMessageStringTable::getInstance()->getString("IntValue");
+char const* const _PREHASH_TargetType = LLMessageStringTable::getInstance()->getString("TargetType");
+char const* const _PREHASH_Amount = LLMessageStringTable::getInstance()->getString("Amount");
+char const* const _PREHASH_HasAttachment = LLMessageStringTable::getInstance()->getString("HasAttachment");
+char const* const _PREHASH_UpdateAttachment = LLMessageStringTable::getInstance()->getString("UpdateAttachment");
+char const* const _PREHASH_RemoveAttachment = LLMessageStringTable::getInstance()->getString("RemoveAttachment");
+char const* const _PREHASH_HeightWidthBlock = LLMessageStringTable::getInstance()->getString("HeightWidthBlock");
+char const* const _PREHASH_RequestObjectPropertiesFamily = LLMessageStringTable::getInstance()->getString("RequestObjectPropertiesFamily");
+char const* const _PREHASH_ObjectPropertiesFamily = LLMessageStringTable::getInstance()->getString("ObjectPropertiesFamily");
+char const* const _PREHASH_UserData = LLMessageStringTable::getInstance()->getString("UserData");
+char const* const _PREHASH_IsReadable = LLMessageStringTable::getInstance()->getString("IsReadable");
+char const* const _PREHASH_PathCurve = LLMessageStringTable::getInstance()->getString("PathCurve");
+char const* const _PREHASH_Status = LLMessageStringTable::getInstance()->getString("Status");
+char const* const _PREHASH_FromGroup = LLMessageStringTable::getInstance()->getString("FromGroup");
+char const* const _PREHASH_AlreadyVoted = LLMessageStringTable::getInstance()->getString("AlreadyVoted");
+char const* const _PREHASH_PlacesReply = LLMessageStringTable::getInstance()->getString("PlacesReply");
+char const* const _PREHASH_DirPlacesReply = LLMessageStringTable::getInstance()->getString("DirPlacesReply");
+char const* const _PREHASH_ParcelBuy = LLMessageStringTable::getInstance()->getString("ParcelBuy");
+char const* const _PREHASH_DirFindQueryBackend = LLMessageStringTable::getInstance()->getString("DirFindQueryBackend");
+char const* const _PREHASH_DirPlacesQueryBackend = LLMessageStringTable::getInstance()->getString("DirPlacesQueryBackend");
+char const* const _PREHASH_DirClassifiedQueryBackend = LLMessageStringTable::getInstance()->getString("DirClassifiedQueryBackend");
+char const* const _PREHASH_DirLandQueryBackend = LLMessageStringTable::getInstance()->getString("DirLandQueryBackend");
+char const* const _PREHASH_DirPopularQueryBackend = LLMessageStringTable::getInstance()->getString("DirPopularQueryBackend");
+char const* const _PREHASH_HistoryData = LLMessageStringTable::getInstance()->getString("HistoryData");
+char const* const _PREHASH_SnapshotID = LLMessageStringTable::getInstance()->getString("SnapshotID");
+char const* const _PREHASH_Aspect = LLMessageStringTable::getInstance()->getString("Aspect");
+char const* const _PREHASH_ParamSize = LLMessageStringTable::getInstance()->getString("ParamSize");
+char const* const _PREHASH_VoteCast = LLMessageStringTable::getInstance()->getString("VoteCast");
+char const* const _PREHASH_CastsShadows = LLMessageStringTable::getInstance()->getString("CastsShadows");
+char const* const _PREHASH_EveryoneMask = LLMessageStringTable::getInstance()->getString("EveryoneMask");
+char const* const _PREHASH_ObjectSpinUpdate = LLMessageStringTable::getInstance()->getString("ObjectSpinUpdate");
+char const* const _PREHASH_MaturePublish = LLMessageStringTable::getInstance()->getString("MaturePublish");
+char const* const _PREHASH_UseExistingAsset = LLMessageStringTable::getInstance()->getString("UseExistingAsset");
+char const* const _PREHASH_Powers = LLMessageStringTable::getInstance()->getString("Powers");
+char const* const _PREHASH_ParcelLocalID = LLMessageStringTable::getInstance()->getString("ParcelLocalID");
+char const* const _PREHASH_TeleportCancel = LLMessageStringTable::getInstance()->getString("TeleportCancel");
+char const* const _PREHASH_UnixTime = LLMessageStringTable::getInstance()->getString("UnixTime");
+char const* const _PREHASH_QueryFlags = LLMessageStringTable::getInstance()->getString("QueryFlags");
+char const* const _PREHASH_AlwaysRun = LLMessageStringTable::getInstance()->getString("AlwaysRun");
+char const* const _PREHASH_Bottom = LLMessageStringTable::getInstance()->getString("Bottom");
+char const* const _PREHASH_ButtonData = LLMessageStringTable::getInstance()->getString("ButtonData");
+char const* const _PREHASH_SoundData = LLMessageStringTable::getInstance()->getString("SoundData");
+char const* const _PREHASH_ViewerStats = LLMessageStringTable::getInstance()->getString("ViewerStats");
+char const* const _PREHASH_RegionHandshake = LLMessageStringTable::getInstance()->getString("RegionHandshake");
+char const* const _PREHASH_ObjectDescription = LLMessageStringTable::getInstance()->getString("ObjectDescription");
+char const* const _PREHASH_Description = LLMessageStringTable::getInstance()->getString("Description");
+char const* const _PREHASH_ParamType = LLMessageStringTable::getInstance()->getString("ParamType");
+char const* const _PREHASH_UUIDNameReply = LLMessageStringTable::getInstance()->getString("UUIDNameReply");
+char const* const _PREHASH_UUIDGroupNameReply = LLMessageStringTable::getInstance()->getString("UUIDGroupNameReply");
+char const* const _PREHASH_SaveAssetIntoInventory = LLMessageStringTable::getInstance()->getString("SaveAssetIntoInventory");
+char const* const _PREHASH_UserInfo = LLMessageStringTable::getInstance()->getString("UserInfo");
+char const* const _PREHASH_AnimSequenceID = LLMessageStringTable::getInstance()->getString("AnimSequenceID");
+char const* const _PREHASH_NVPairs = LLMessageStringTable::getInstance()->getString("NVPairs");
+char const* const _PREHASH_GroupNoticesListRequest = LLMessageStringTable::getInstance()->getString("GroupNoticesListRequest");
+char const* const _PREHASH_ParcelAccessListRequest = LLMessageStringTable::getInstance()->getString("ParcelAccessListRequest");
+char const* const _PREHASH_MuteListRequest = LLMessageStringTable::getInstance()->getString("MuteListRequest");
+char const* const _PREHASH_RpcChannelRequest = LLMessageStringTable::getInstance()->getString("RpcChannelRequest");
+char const* const _PREHASH_LandStatRequest = LLMessageStringTable::getInstance()->getString("LandStatRequest");
+char const* const _PREHASH_PlacesQuery = LLMessageStringTable::getInstance()->getString("PlacesQuery");
+char const* const _PREHASH_DirPlacesQuery = LLMessageStringTable::getInstance()->getString("DirPlacesQuery");
+char const* const _PREHASH_SortOrder = LLMessageStringTable::getInstance()->getString("SortOrder");
+char const* const _PREHASH_Hunter = LLMessageStringTable::getInstance()->getString("Hunter");
+char const* const _PREHASH_SunAngVelocity = LLMessageStringTable::getInstance()->getString("SunAngVelocity");
+char const* const _PREHASH_BinaryBucket = LLMessageStringTable::getInstance()->getString("BinaryBucket");
+char const* const _PREHASH_ImagePacket = LLMessageStringTable::getInstance()->getString("ImagePacket");
+char const* const _PREHASH_StartGroupProposal = LLMessageStringTable::getInstance()->getString("StartGroupProposal");
+char const* const _PREHASH_EnergyLevel = LLMessageStringTable::getInstance()->getString("EnergyLevel");
+char const* const _PREHASH_PriceForListing = LLMessageStringTable::getInstance()->getString("PriceForListing");
+char const* const _PREHASH_Scale = LLMessageStringTable::getInstance()->getString("Scale");
+char const* const _PREHASH_EstateCovenantReply = LLMessageStringTable::getInstance()->getString("EstateCovenantReply");
+char const* const _PREHASH_ParentEstateID = LLMessageStringTable::getInstance()->getString("ParentEstateID");
+char const* const _PREHASH_Extra2 = LLMessageStringTable::getInstance()->getString("Extra2");
+char const* const _PREHASH_Throttle = LLMessageStringTable::getInstance()->getString("Throttle");
+char const* const _PREHASH_SimIP = LLMessageStringTable::getInstance()->getString("SimIP");
+char const* const _PREHASH_GodID = LLMessageStringTable::getInstance()->getString("GodID");
+char const* const _PREHASH_TeleportMinPrice = LLMessageStringTable::getInstance()->getString("TeleportMinPrice");
+char const* const _PREHASH_VoteItem = LLMessageStringTable::getInstance()->getString("VoteItem");
+char const* const _PREHASH_ObjectRotation = LLMessageStringTable::getInstance()->getString("ObjectRotation");
+char const* const _PREHASH_SitRotation = LLMessageStringTable::getInstance()->getString("SitRotation");
+char const* const _PREHASH_SnapSelection = LLMessageStringTable::getInstance()->getString("SnapSelection");
+char const* const _PREHASH_SoundTrigger = LLMessageStringTable::getInstance()->getString("SoundTrigger");
+char const* const _PREHASH_TerrainRaiseLimit = LLMessageStringTable::getInstance()->getString("TerrainRaiseLimit");
+char const* const _PREHASH_Quorum = LLMessageStringTable::getInstance()->getString("Quorum");
+char const* const _PREHASH_AgentBlock = LLMessageStringTable::getInstance()->getString("AgentBlock");
+char const* const _PREHASH_CommandBlock = LLMessageStringTable::getInstance()->getString("CommandBlock");
+char const* const _PREHASH_PricePublicObjectDecay = LLMessageStringTable::getInstance()->getString("PricePublicObjectDecay");
+char const* const _PREHASH_SpawnPointPos = LLMessageStringTable::getInstance()->getString("SpawnPointPos");
+char const* const _PREHASH_VolumeDetail = LLMessageStringTable::getInstance()->getString("VolumeDetail");
+char const* const _PREHASH_FromAgentName = LLMessageStringTable::getInstance()->getString("FromAgentName");
+char const* const _PREHASH_Range = LLMessageStringTable::getInstance()->getString("Range");
+char const* const _PREHASH_DirectoryVisibility = LLMessageStringTable::getInstance()->getString("DirectoryVisibility");
+char const* const _PREHASH_PublicIP = LLMessageStringTable::getInstance()->getString("PublicIP");
+char const* const _PREHASH_TeleportFailed = LLMessageStringTable::getInstance()->getString("TeleportFailed");
+char const* const _PREHASH_PreloadSound = LLMessageStringTable::getInstance()->getString("PreloadSound");
+char const* const _PREHASH_ScreenshotID = LLMessageStringTable::getInstance()->getString("ScreenshotID");
+char const* const _PREHASH_CovenantTimestamp = LLMessageStringTable::getInstance()->getString("CovenantTimestamp");
+char const* const _PREHASH_OldestUnacked = LLMessageStringTable::getInstance()->getString("OldestUnacked");
+char const* const _PREHASH_SimulatorIP = LLMessageStringTable::getInstance()->getString("SimulatorIP");
+char const* const _PREHASH_Value = LLMessageStringTable::getInstance()->getString("Value");
+char const* const _PREHASH_JointAxisOrAnchor = LLMessageStringTable::getInstance()->getString("JointAxisOrAnchor");
+char const* const _PREHASH_Test0 = LLMessageStringTable::getInstance()->getString("Test0");
+char const* const _PREHASH_Test1 = LLMessageStringTable::getInstance()->getString("Test1");
+char const* const _PREHASH_Test2 = LLMessageStringTable::getInstance()->getString("Test2");
+char const* const _PREHASH_SunPhase = LLMessageStringTable::getInstance()->getString("SunPhase");
+char const* const _PREHASH_ParcelDivide = LLMessageStringTable::getInstance()->getString("ParcelDivide");
+char const* const _PREHASH_PriceObjectClaim = LLMessageStringTable::getInstance()->getString("PriceObjectClaim");
+char const* const _PREHASH_Field = LLMessageStringTable::getInstance()->getString("Field");
+char const* const _PREHASH_Ratio = LLMessageStringTable::getInstance()->getString("Ratio");
+char const* const _PREHASH_JoinGroupReply = LLMessageStringTable::getInstance()->getString("JoinGroupReply");
+char const* const _PREHASH_LiveHelpGroupReply = LLMessageStringTable::getInstance()->getString("LiveHelpGroupReply");
+char const* const _PREHASH_Score = LLMessageStringTable::getInstance()->getString("Score");
+char const* const _PREHASH_Image = LLMessageStringTable::getInstance()->getString("Image");
+char const* const _PREHASH_ObjectClickAction = LLMessageStringTable::getInstance()->getString("ObjectClickAction");
+char const* const _PREHASH_Parameter = LLMessageStringTable::getInstance()->getString("Parameter");
+char const* const _PREHASH_Flags = LLMessageStringTable::getInstance()->getString("Flags");
+char const* const _PREHASH_Plane = LLMessageStringTable::getInstance()->getString("Plane");
+char const* const _PREHASH_Width = LLMessageStringTable::getInstance()->getString("Width");
+char const* const _PREHASH_Right = LLMessageStringTable::getInstance()->getString("Right");
+char const* const _PREHASH_DirFindQuery = LLMessageStringTable::getInstance()->getString("DirFindQuery");
+char const* const _PREHASH_Textures = LLMessageStringTable::getInstance()->getString("Textures");
+char const* const _PREHASH_EventData = LLMessageStringTable::getInstance()->getString("EventData");
+char const* const _PREHASH_Final = LLMessageStringTable::getInstance()->getString("Final");
+char const* const _PREHASH_System = LLMessageStringTable::getInstance()->getString("System");
+char const* const _PREHASH_TelehubPos = LLMessageStringTable::getInstance()->getString("TelehubPos");
+char const* const _PREHASH_ReportAutosaveCrash = LLMessageStringTable::getInstance()->getString("ReportAutosaveCrash");
+char const* const _PREHASH_CreateTrustedCircuit = LLMessageStringTable::getInstance()->getString("CreateTrustedCircuit");
+char const* const _PREHASH_DenyTrustedCircuit = LLMessageStringTable::getInstance()->getString("DenyTrustedCircuit");
+char const* const _PREHASH_RequestTrustedCircuit = LLMessageStringTable::getInstance()->getString("RequestTrustedCircuit");
+char const* const _PREHASH_Codec = LLMessageStringTable::getInstance()->getString("Codec");
+char const* const _PREHASH_Modal = LLMessageStringTable::getInstance()->getString("Modal");
+char const* const _PREHASH_ChildAgentUnknown = LLMessageStringTable::getInstance()->getString("ChildAgentUnknown");
+char const* const _PREHASH_LandingType = LLMessageStringTable::getInstance()->getString("LandingType");
+char const* const _PREHASH_ScriptRunningReply = LLMessageStringTable::getInstance()->getString("ScriptRunningReply");
+char const* const _PREHASH_Reply = LLMessageStringTable::getInstance()->getString("Reply");
+char const* const _PREHASH_GroupAccountDetailsReply = LLMessageStringTable::getInstance()->getString("GroupAccountDetailsReply");
+char const* const _PREHASH_TelehubRot = LLMessageStringTable::getInstance()->getString("TelehubRot");
+char const* const _PREHASH_AcceptFriendship = LLMessageStringTable::getInstance()->getString("AcceptFriendship");
+char const* const _PREHASH_ItemType = LLMessageStringTable::getInstance()->getString("ItemType");
+char const* const _PREHASH_DwellInfo = LLMessageStringTable::getInstance()->getString("DwellInfo");
+char const* const _PREHASH_AgentResume = LLMessageStringTable::getInstance()->getString("AgentResume");
+char const* const _PREHASH_MailFilter = LLMessageStringTable::getInstance()->getString("MailFilter");
+char const* const _PREHASH_Disconnect = LLMessageStringTable::getInstance()->getString("Disconnect");
+char const* const _PREHASH_SimPosition = LLMessageStringTable::getInstance()->getString("SimPosition");
+char const* const _PREHASH_SimWideTotalPrims = LLMessageStringTable::getInstance()->getString("SimWideTotalPrims");
+char const* const _PREHASH_Index = LLMessageStringTable::getInstance()->getString("Index");
+char const* const _PREHASH_SimFilename = LLMessageStringTable::getInstance()->getString("SimFilename");
+char const* const _PREHASH_LastOwnerID = LLMessageStringTable::getInstance()->getString("LastOwnerID");
+char const* const _PREHASH_GroupNoticeRequest = LLMessageStringTable::getInstance()->getString("GroupNoticeRequest");
+char const* const _PREHASH_EmailMessageRequest = LLMessageStringTable::getInstance()->getString("EmailMessageRequest");
+char const* const _PREHASH_MapItemRequest = LLMessageStringTable::getInstance()->getString("MapItemRequest");
+char const* const _PREHASH_AgentCount = LLMessageStringTable::getInstance()->getString("AgentCount");
+char const* const _PREHASH_MessageBlock = LLMessageStringTable::getInstance()->getString("MessageBlock");
+char const* const _PREHASH_FuseBlock = LLMessageStringTable::getInstance()->getString("FuseBlock");
+char const* const _PREHASH_AgentGroupData = LLMessageStringTable::getInstance()->getString("AgentGroupData");
+char const* const _PREHASH_ClassifiedInfoUpdate = LLMessageStringTable::getInstance()->getString("ClassifiedInfoUpdate");
+char const* const _PREHASH_RegionPos = LLMessageStringTable::getInstance()->getString("RegionPos");
+char const* const _PREHASH_ParcelMediaUpdate = LLMessageStringTable::getInstance()->getString("ParcelMediaUpdate");
+char const* const _PREHASH_NoticeID = LLMessageStringTable::getInstance()->getString("NoticeID");
+char const* const _PREHASH_GridX = LLMessageStringTable::getInstance()->getString("GridX");
+char const* const _PREHASH_GridY = LLMessageStringTable::getInstance()->getString("GridY");
+char const* const _PREHASH_Title = LLMessageStringTable::getInstance()->getString("Title");
+char const* const _PREHASH_AuctionID = LLMessageStringTable::getInstance()->getString("AuctionID");
+char const* const _PREHASH_VoteType = LLMessageStringTable::getInstance()->getString("VoteType");
+char const* const _PREHASH_CategoryID = LLMessageStringTable::getInstance()->getString("CategoryID");
+char const* const _PREHASH_Token = LLMessageStringTable::getInstance()->getString("Token");
+char const* const _PREHASH_AggregatePerms = LLMessageStringTable::getInstance()->getString("AggregatePerms");
+char const* const _PREHASH_ObjectSelect = LLMessageStringTable::getInstance()->getString("ObjectSelect");
+char const* const _PREHASH_ForceObjectSelect = LLMessageStringTable::getInstance()->getString("ForceObjectSelect");
+char const* const _PREHASH_Price = LLMessageStringTable::getInstance()->getString("Price");
+char const* const _PREHASH_SunDirection = LLMessageStringTable::getInstance()->getString("SunDirection");
+char const* const _PREHASH_FromName = LLMessageStringTable::getInstance()->getString("FromName");
+char const* const _PREHASH_ChangeInventoryItemFlags = LLMessageStringTable::getInstance()->getString("ChangLLInventoryItemFlags");
+char const* const _PREHASH_Force = LLMessageStringTable::getInstance()->getString("Force");
+char const* const _PREHASH_TransactionBlock = LLMessageStringTable::getInstance()->getString("TransactionBlock");
+char const* const _PREHASH_PowersMask = LLMessageStringTable::getInstance()->getString("PowersMask");
+char const* const _PREHASH_Stamp = LLMessageStringTable::getInstance()->getString("Stamp");
+char const* const _PREHASH_TotalCredits = LLMessageStringTable::getInstance()->getString("TotalCredits");
+char const* const _PREHASH_State = LLMessageStringTable::getInstance()->getString("State");
+char const* const _PREHASH_TextureIndex = LLMessageStringTable::getInstance()->getString("TextureIndex");
+char const* const _PREHASH_InviteeID = LLMessageStringTable::getInstance()->getString("InviteeID");
+char const* const _PREHASH_ParcelReclaim = LLMessageStringTable::getInstance()->getString("ParcelReclaim");
+char const* const _PREHASH_Money = LLMessageStringTable::getInstance()->getString("Money");
+char const* const _PREHASH_PathTwist = LLMessageStringTable::getInstance()->getString("PathTwist");
+char const* const _PREHASH_AuthBuyerID = LLMessageStringTable::getInstance()->getString("AuthBuyerID");
+char const* const _PREHASH_Color = LLMessageStringTable::getInstance()->getString("Color");
+char const* const _PREHASH_SourceType = LLMessageStringTable::getInstance()->getString("SourceType");
+char const* const _PREHASH_World = LLMessageStringTable::getInstance()->getString("World");
+char const* const _PREHASH_QueryData = LLMessageStringTable::getInstance()->getString("QueryData");
+char const* const _PREHASH_Users = LLMessageStringTable::getInstance()->getString("Users");
+char const* const _PREHASH_SysOS = LLMessageStringTable::getInstance()->getString("SysOS");
+char const* const _PREHASH_Notes = LLMessageStringTable::getInstance()->getString("Notes");
+char const* const _PREHASH_AvatarID = LLMessageStringTable::getInstance()->getString("AvatarID");
+char const* const _PREHASH_FounderID = LLMessageStringTable::getInstance()->getString("FounderID");
+char const* const _PREHASH_EndPointID = LLMessageStringTable::getInstance()->getString("EndPointID");
+char const* const _PREHASH_LocationLookAt = LLMessageStringTable::getInstance()->getString("LocationLookAt");
+char const* const _PREHASH_Sound = LLMessageStringTable::getInstance()->getString("Sound");
+char const* const _PREHASH_Cover = LLMessageStringTable::getInstance()->getString("Cover");
+char const* const _PREHASH_TotalObjectCount = LLMessageStringTable::getInstance()->getString("TotalObjectCount");
+char const* const _PREHASH_TextureEntry = LLMessageStringTable::getInstance()->getString("TextureEntry");
+char const* const _PREHASH_SquareMetersCommitted = LLMessageStringTable::getInstance()->getString("SquareMetersCommitted");
+char const* const _PREHASH_ChannelID = LLMessageStringTable::getInstance()->getString("ChannelID");
+char const* const _PREHASH_Dwell = LLMessageStringTable::getInstance()->getString("Dwell");
+char const* const _PREHASH_North = LLMessageStringTable::getInstance()->getString("North");
+char const* const _PREHASH_AgentUpdate = LLMessageStringTable::getInstance()->getString("AgentUpdate");
+char const* const _PREHASH_PickGodDelete = LLMessageStringTable::getInstance()->getString("PickGodDelete");
+char const* const _PREHASH_HostName = LLMessageStringTable::getInstance()->getString("HostName");
+char const* const _PREHASH_PriceParcelClaim = LLMessageStringTable::getInstance()->getString("PriceParcelClaim");
+char const* const _PREHASH_ParcelClaim = LLMessageStringTable::getInstance()->getString("ParcelClaim");
+char const* const _PREHASH_AgentPowers = LLMessageStringTable::getInstance()->getString("AgentPowers");
+char const* const _PREHASH_ProfileHollow = LLMessageStringTable::getInstance()->getString("ProfileHollow");
+char const* const _PREHASH_GroupRoleChanges = LLMessageStringTable::getInstance()->getString("GroupRoleChanges");
+char const* const _PREHASH_Count = LLMessageStringTable::getInstance()->getString("Count");
+char const* const _PREHASH_South = LLMessageStringTable::getInstance()->getString("South");
+char const* const _PREHASH_ObjectUpdateCompressed = LLMessageStringTable::getInstance()->getString("ObjectUpdateCompressed");
+char const* const _PREHASH_MuteFlags = LLMessageStringTable::getInstance()->getString("MuteFlags");
+char const* const _PREHASH_Group = LLMessageStringTable::getInstance()->getString("Group");
+char const* const _PREHASH_AgentPause = LLMessageStringTable::getInstance()->getString("AgentPause");
+char const* const _PREHASH_LanguagesText = LLMessageStringTable::getInstance()->getString("LanguagesText");
+char const* const _PREHASH_Error = LLMessageStringTable::getInstance()->getString("Error");
+char const* const _PREHASH_InternalScriptMail = LLMessageStringTable::getInstance()->getString("InternalScriptMail");
+char const* const _PREHASH_FindAgent = LLMessageStringTable::getInstance()->getString("FindAgent");
+char const* const _PREHASH_AgentData = LLMessageStringTable::getInstance()->getString("AgentData");
+char const* const _PREHASH_FolderData = LLMessageStringTable::getInstance()->getString("FolderData");
+char const* const _PREHASH_AssetBlock = LLMessageStringTable::getInstance()->getString("AssetBlock");
+char const* const _PREHASH_AcceptNotices = LLMessageStringTable::getInstance()->getString("AcceptNotices");
+char const* const _PREHASH_SetGroupAcceptNotices = LLMessageStringTable::getInstance()->getString("SetGroupAcceptNotices");
+char const* const _PREHASH_CloseCircuit = LLMessageStringTable::getInstance()->getString("CloseCircuit");
+char const* const _PREHASH_TeleportFinish = LLMessageStringTable::getInstance()->getString("TeleportFinish");
+char const* const _PREHASH_PathRevolutions = LLMessageStringTable::getInstance()->getString("PathRevolutions");
+char const* const _PREHASH_ClassifiedInfoReply = LLMessageStringTable::getInstance()->getString("ClassifiedInfoReply");
+char const* const _PREHASH_ParcelInfoReply = LLMessageStringTable::getInstance()->getString("ParcelInfoReply");
+char const* const _PREHASH_AutosaveData = LLMessageStringTable::getInstance()->getString("AutosaveData");
+char const* const _PREHASH_SetStartLocation = LLMessageStringTable::getInstance()->getString("SetStartLocation");
+char const* const _PREHASH_PassHours = LLMessageStringTable::getInstance()->getString("PassHours");
+char const* const _PREHASH_AttachmentPt = LLMessageStringTable::getInstance()->getString("AttachmentPt");
+char const* const _PREHASH_ParcelFlags = LLMessageStringTable::getInstance()->getString("ParcelFlags");
+char const* const _PREHASH_NumVotes = LLMessageStringTable::getInstance()->getString("NumVotes");
+char const* const _PREHASH_AvatarPickerRequest = LLMessageStringTable::getInstance()->getString("AvatarPickerRequest");
+char const* const _PREHASH_TeleportLocationRequest = LLMessageStringTable::getInstance()->getString("TeleportLocationRequest");
+char const* const _PREHASH_DataHomeLocationRequest = LLMessageStringTable::getInstance()->getString("DataHomeLocationRequest");
+char const* const _PREHASH_EventNotificationAddRequest = LLMessageStringTable::getInstance()->getString("EventNotificationAddRequest");
+char const* const _PREHASH_ParcelDwellRequest = LLMessageStringTable::getInstance()->getString("ParcelDwellRequest");
+char const* const _PREHASH_EventLocationRequest = LLMessageStringTable::getInstance()->getString("EventLocationRequest");
+char const* const _PREHASH_SetStartLocationRequest = LLMessageStringTable::getInstance()->getString("SetStartLocationRequest");
+char const* const _PREHASH_QueryStart = LLMessageStringTable::getInstance()->getString("QueryStart");
+char const* const _PREHASH_EjectData = LLMessageStringTable::getInstance()->getString("EjectData");
+char const* const _PREHASH_AvatarTextureUpdate = LLMessageStringTable::getInstance()->getString("AvatarTextureUpdate");
+char const* const _PREHASH_RPCServerPort = LLMessageStringTable::getInstance()->getString("RPCServerPort");
+char const* const _PREHASH_Bytes = LLMessageStringTable::getInstance()->getString("Bytes");
+char const* const _PREHASH_Extra = LLMessageStringTable::getInstance()->getString("Extra");
+char const* const _PREHASH_ForceScriptControlRelease = LLMessageStringTable::getInstance()->getString("ForceScriptControlRelease");
+char const* const _PREHASH_ParcelRelease = LLMessageStringTable::getInstance()->getString("ParcelRelease");
+char const* const _PREHASH_VFileType = LLMessageStringTable::getInstance()->getString("VFileType");
+char const* const _PREHASH_EjectGroupMemberReply = LLMessageStringTable::getInstance()->getString("EjectGroupMemberReply");
+char const* const _PREHASH_ImageData = LLMessageStringTable::getInstance()->getString("ImageData");
+char const* const _PREHASH_SimulatorViewerTimeMessage = LLMessageStringTable::getInstance()->getString("SimulatorViewerTimeMessage");
+char const* const _PREHASH_Rotation = LLMessageStringTable::getInstance()->getString("Rotation");
+char const* const _PREHASH_Selection = LLMessageStringTable::getInstance()->getString("Selection");
+char const* const _PREHASH_TransactionData = LLMessageStringTable::getInstance()->getString("TransactionData");
+char const* const _PREHASH_OperationData = LLMessageStringTable::getInstance()->getString("OperationData");
+char const* const _PREHASH_ExpirationDate = LLMessageStringTable::getInstance()->getString("ExpirationDate");
+char const* const _PREHASH_ParcelDeedToGroup = LLMessageStringTable::getInstance()->getString("ParcelDeedToGroup");
+char const* const _PREHASH_AvatarPicksReply = LLMessageStringTable::getInstance()->getString("AvatarPicksReply");
+char const* const _PREHASH_GroupTitlesReply = LLMessageStringTable::getInstance()->getString("GroupTitlesReply");
+char const* const _PREHASH_AgentInfo = LLMessageStringTable::getInstance()->getString("AgentInfo");
+char const* const _PREHASH_MoneyTransferBackend = LLMessageStringTable::getInstance()->getString("MoneyTransferBackend");
+char const* const _PREHASH_NextOwnerMask = LLMessageStringTable::getInstance()->getString("NextOwnerMask");
+char const* const _PREHASH_MuteData = LLMessageStringTable::getInstance()->getString("MuteData");
+char const* const _PREHASH_PassPrice = LLMessageStringTable::getInstance()->getString("PassPrice");
+char const* const _PREHASH_SourceID = LLMessageStringTable::getInstance()->getString("SourceID");
+char const* const _PREHASH_ChangeUserRights = LLMessageStringTable::getInstance()->getString("ChangeUserRights");
+char const* const _PREHASH_TeleportFlags = LLMessageStringTable::getInstance()->getString("TeleportFlags");
+char const* const _PREHASH_SlaveParcelData = LLMessageStringTable::getInstance()->getString("SlaveParcelData");
+char const* const _PREHASH_AssetData = LLMessageStringTable::getInstance()->getString("AssetData");
+char const* const _PREHASH_MultipleObjectUpdate = LLMessageStringTable::getInstance()->getString("MultipleObjectUpdate");
+char const* const _PREHASH_ObjectUpdate = LLMessageStringTable::getInstance()->getString("ObjectUpdate");
+char const* const _PREHASH_ImprovedTerseObjectUpdate = LLMessageStringTable::getInstance()->getString("ImprovedTerseObjectUpdate");
+char const* const _PREHASH_ConfirmXferPacket = LLMessageStringTable::getInstance()->getString("ConfirmXferPacket");
+char const* const _PREHASH_StartPingCheck = LLMessageStringTable::getInstance()->getString("StartPingCheck");
+char const* const _PREHASH_SimWideDeletes = LLMessageStringTable::getInstance()->getString("SimWideDeletes");
+char const* const _PREHASH_LandStatReply = LLMessageStringTable::getInstance()->getString("LandStatReply");
+char const* const _PREHASH_IsPhantom = LLMessageStringTable::getInstance()->getString("IsPhantom");
+char const* const _PREHASH_AgentList = LLMessageStringTable::getInstance()->getString("AgentList");
+char const* const _PREHASH_SimApproved = LLMessageStringTable::getInstance()->getString("SimApproved");
+char const* const _PREHASH_RezObject = LLMessageStringTable::getInstance()->getString("RezObject");
+char const* const _PREHASH_TaskLocalID = LLMessageStringTable::getInstance()->getString("TaskLocalID");
+char const* const _PREHASH_ClaimDate = LLMessageStringTable::getInstance()->getString("ClaimDate");
+char const* const _PREHASH_MergeParcel = LLMessageStringTable::getInstance()->getString("MergeParcel");
+char const* const _PREHASH_Priority = LLMessageStringTable::getInstance()->getString("Priority");
+char const* const _PREHASH_QueryText = LLMessageStringTable::getInstance()->getString("QueryText");
+char const* const _PREHASH_GroupNoticeAdd = LLMessageStringTable::getInstance()->getString("GroupNoticeAdd");
+char const* const _PREHASH_ReturnType = LLMessageStringTable::getInstance()->getString("ReturnType");
+char const* const _PREHASH_FetchFolders = LLMessageStringTable::getInstance()->getString("FetchFolders");
+char const* const _PREHASH_SimulatorPublicHostBlock = LLMessageStringTable::getInstance()->getString("SimulatorPublicHostBlock");
+char const* const _PREHASH_HeaderData = LLMessageStringTable::getInstance()->getString("HeaderData");
+char const* const _PREHASH_RequestMultipleObjects = LLMessageStringTable::getInstance()->getString("RequestMultipleObjects");
+char const* const _PREHASH_RetrieveInstantMessages = LLMessageStringTable::getInstance()->getString("RetrieveInstantMessages");
+char const* const _PREHASH_OpenCircuit = LLMessageStringTable::getInstance()->getString("OpenCircuit");
+char const* const _PREHASH_CrossedRegion = LLMessageStringTable::getInstance()->getString("CrossedRegion");
+char const* const _PREHASH_DirGroupsReply = LLMessageStringTable::getInstance()->getString("DirGroupsReply");
+char const* const _PREHASH_AvatarGroupsReply = LLMessageStringTable::getInstance()->getString("AvatarGroupsReply");
+char const* const _PREHASH_EmailMessageReply = LLMessageStringTable::getInstance()->getString("EmailMessageReply");
+char const* const _PREHASH_GroupVoteHistoryItemReply = LLMessageStringTable::getInstance()->getString("GroupVoteHistoryItemReply");
+char const* const _PREHASH_ViewerPosition = LLMessageStringTable::getInstance()->getString("ViewerPosition");
+char const* const _PREHASH_Position = LLMessageStringTable::getInstance()->getString("Position");
+char const* const _PREHASH_ParentEstate = LLMessageStringTable::getInstance()->getString("ParentEstate");
+char const* const _PREHASH_EstateName = LLMessageStringTable::getInstance()->getString("EstateName");
+char const* const _PREHASH_MuteName = LLMessageStringTable::getInstance()->getString("MuteName");
+char const* const _PREHASH_ParcelRename = LLMessageStringTable::getInstance()->getString("ParcelRename");
+char const* const _PREHASH_ViewerFilename = LLMessageStringTable::getInstance()->getString("ViewerFilename");
+char const* const _PREHASH_UserReportInternal = LLMessageStringTable::getInstance()->getString("UserReportInternal");
+char const* const _PREHASH_AvatarPropertiesRequest = LLMessageStringTable::getInstance()->getString("AvatarPropertiesRequest");
+char const* const _PREHASH_ParcelPropertiesRequest = LLMessageStringTable::getInstance()->getString("ParcelPropertiesRequest");
+char const* const _PREHASH_GroupProfileRequest = LLMessageStringTable::getInstance()->getString("GroupProfileRequest");
+char const* const _PREHASH_AgentDataUpdateRequest = LLMessageStringTable::getInstance()->getString("AgentDataUpdateRequest");
+char const* const _PREHASH_PriceObjectScaleFactor = LLMessageStringTable::getInstance()->getString("PriceObjectScaleFactor");
+char const* const _PREHASH_OpenEnrollment = LLMessageStringTable::getInstance()->getString("OpenEnrollment");
+char const* const _PREHASH_GroupData = LLMessageStringTable::getInstance()->getString("GroupData");
+char const* const _PREHASH_RequestGodlikePowers = LLMessageStringTable::getInstance()->getString("RequestGodlikePowers");
+char const* const _PREHASH_GrantGodlikePowers = LLMessageStringTable::getInstance()->getString("GrantGodlikePowers");
+char const* const _PREHASH_TransactionID = LLMessageStringTable::getInstance()->getString("TransactionID");
+char const* const _PREHASH_DestinationID = LLMessageStringTable::getInstance()->getString("DestinationID");
+char const* const _PREHASH_Controls = LLMessageStringTable::getInstance()->getString("Controls");
+char const* const _PREHASH_FirstDetachAll = LLMessageStringTable::getInstance()->getString("FirstDetachAll");
+char const* const _PREHASH_EstateID = LLMessageStringTable::getInstance()->getString("EstateID");
+char const* const _PREHASH_ImprovedInstantMessage = LLMessageStringTable::getInstance()->getString("ImprovedInstantMessage");
+char const* const _PREHASH_CheckParcelSales = LLMessageStringTable::getInstance()->getString("CheckParcelSales");
+char const* const _PREHASH_ParcelSales = LLMessageStringTable::getInstance()->getString("ParcelSales");
+char const* const _PREHASH_CurrentInterval = LLMessageStringTable::getInstance()->getString("CurrentInterval");
+char const* const _PREHASH_PriceRentLight = LLMessageStringTable::getInstance()->getString("PriceRentLight");
+char const* const _PREHASH_MediaAutoScale = LLMessageStringTable::getInstance()->getString("MediaAutoScale");
+char const* const _PREHASH_NeighborBlock = LLMessageStringTable::getInstance()->getString("NeighborBlock");
+char const* const _PREHASH_LayerData = LLMessageStringTable::getInstance()->getString("LayerData");
+char const* const _PREHASH_NVPairData = LLMessageStringTable::getInstance()->getString("NVPairData");
+char const* const _PREHASH_TeleportLocal = LLMessageStringTable::getInstance()->getString("TeleportLocal");
+char const* const _PREHASH_EjecteeID = LLMessageStringTable::getInstance()->getString("EjecteeID");
+char const* const _PREHASH_VoteInitiator = LLMessageStringTable::getInstance()->getString("VoteInitiator");
+char const* const _PREHASH_TypeData = LLMessageStringTable::getInstance()->getString("TypeData");
+char const* const _PREHASH_OwnerIDs = LLMessageStringTable::getInstance()->getString("OwnerIDs");
+char const* const _PREHASH_SystemKickUser = LLMessageStringTable::getInstance()->getString("SystemKickUser");
+char const* const _PREHASH_TransactionTime = LLMessageStringTable::getInstance()->getString("TransactionTime");
+char const* const _PREHASH_TimeToLive = LLMessageStringTable::getInstance()->getString("TimeToLive");
+char const* const _PREHASH_OldAgentID = LLMessageStringTable::getInstance()->getString("OldAgentID");
+char const* const _PREHASH_MusicURL = LLMessageStringTable::getInstance()->getString("MusicURL");
+char const* const _PREHASH_ParcelPrimBonus = LLMessageStringTable::getInstance()->getString("ParcelPrimBonus");
+char const* const _PREHASH_EjectUser = LLMessageStringTable::getInstance()->getString("EjectUser");
+char const* const _PREHASH_CoarseLocationUpdate = LLMessageStringTable::getInstance()->getString("CoarseLocationUpdate");
+char const* const _PREHASH_ChildAgentPositionUpdate = LLMessageStringTable::getInstance()->getString("ChildAgentPositionUpdate");
+char const* const _PREHASH_StoreLocal = LLMessageStringTable::getInstance()->getString("StoreLocal");
+char const* const _PREHASH_GroupName = LLMessageStringTable::getInstance()->getString("GroupName");
+char const* const _PREHASH_PriceParcelRent = LLMessageStringTable::getInstance()->getString("PriceParcelRent");
+char const* const _PREHASH_SimStatus = LLMessageStringTable::getInstance()->getString("SimStatus");
+char const* const _PREHASH_TransactionSuccess = LLMessageStringTable::getInstance()->getString("TransactionSuccess");
+char const* const _PREHASH_LureType = LLMessageStringTable::getInstance()->getString("LureType");
+char const* const _PREHASH_GroupMask = LLMessageStringTable::getInstance()->getString("GroupMask");
+char const* const _PREHASH_SitObject = LLMessageStringTable::getInstance()->getString("SitObject");
+char const* const _PREHASH_Override = LLMessageStringTable::getInstance()->getString("Override");
+char const* const _PREHASH_LocomotionState = LLMessageStringTable::getInstance()->getString("LocomotionState");
+char const* const _PREHASH_PriceUpload = LLMessageStringTable::getInstance()->getString("PriceUpload");
+char const* const _PREHASH_RemoveParcel = LLMessageStringTable::getInstance()->getString("RemoveParcel");
+char const* const _PREHASH_ConfirmAuctionStart = LLMessageStringTable::getInstance()->getString("ConfirmAuctionStart");
+char const* const _PREHASH_RpcScriptRequestInbound = LLMessageStringTable::getInstance()->getString("RpcScriptRequestInbound");
+char const* const _PREHASH_ActiveGroupID = LLMessageStringTable::getInstance()->getString("ActiveGroupID");
+char const* const _PREHASH_ParcelReturnObjects = LLMessageStringTable::getInstance()->getString("ParcelReturnObjects");
+char const* const _PREHASH_TotalObjects = LLMessageStringTable::getInstance()->getString("TotalObjects");
+char const* const _PREHASH_ObjectExtraParams = LLMessageStringTable::getInstance()->getString("ObjectExtraParams");
+char const* const _PREHASH_Questions = LLMessageStringTable::getInstance()->getString("Questions");
+char const* const _PREHASH_TransferAbort = LLMessageStringTable::getInstance()->getString("TransferAbort");
+char const* const _PREHASH_TransferInventory = LLMessageStringTable::getInstance()->getString("TransferInventory");
+char const* const _PREHASH_RayTargetID = LLMessageStringTable::getInstance()->getString("RayTargetID");
+char const* const _PREHASH_ClaimPrice = LLMessageStringTable::getInstance()->getString("ClaimPrice");
+char const* const _PREHASH_ObjectProperties = LLMessageStringTable::getInstance()->getString("ObjectProperties");
+char const* const _PREHASH_ParcelProperties = LLMessageStringTable::getInstance()->getString("ParcelProperties");
+char const* const _PREHASH_EstateOwnerID = LLMessageStringTable::getInstance()->getString("EstateOwnerID");
+char const* const _PREHASH_LogoutRequest = LLMessageStringTable::getInstance()->getString("LogoutRequest");
+char const* const _PREHASH_AssetUploadRequest = LLMessageStringTable::getInstance()->getString("AssetUploadRequest");
+char const* const _PREHASH_TransactionType = LLMessageStringTable::getInstance()->getString("TransactionType");
+char const* const _PREHASH_AvatarPropertiesUpdate = LLMessageStringTable::getInstance()->getString("AvatarPropertiesUpdate");
+char const* const _PREHASH_ParcelPropertiesUpdate = LLMessageStringTable::getInstance()->getString("ParcelPropertiesUpdate");
+char const* const _PREHASH_FetchItems = LLMessageStringTable::getInstance()->getString("FetchItems");
+char const* const _PREHASH_AbortXfer = LLMessageStringTable::getInstance()->getString("AbortXfer");
+char const* const _PREHASH_DeRezAck = LLMessageStringTable::getInstance()->getString("DeRezAck");
+char const* const _PREHASH_TakeControls = LLMessageStringTable::getInstance()->getString("TakeControls");
+char const* const _PREHASH_DirLandReply = LLMessageStringTable::getInstance()->getString("DirLandReply");
+char const* const _PREHASH_MuteType = LLMessageStringTable::getInstance()->getString("MuteType");
+char const* const _PREHASH_IMViaEMail = LLMessageStringTable::getInstance()->getString("IMViaEMail");
+char const* const _PREHASH_RentPrice = LLMessageStringTable::getInstance()->getString("RentPrice");
+char const* const _PREHASH_GenericMessage = LLMessageStringTable::getInstance()->getString("GenericMessage");
+char const* const _PREHASH_ChildAgentAlive = LLMessageStringTable::getInstance()->getString("ChildAgentAlive");
+char const* const _PREHASH_AssetType = LLMessageStringTable::getInstance()->getString("AssetType");
+char const* const _PREHASH_SpawnPointBlock = LLMessageStringTable::getInstance()->getString("SpawnPointBlock");
+char const* const _PREHASH_AttachmentBlock = LLMessageStringTable::getInstance()->getString("AttachmentBlock");
+char const* const _PREHASH_ObjectMaterial = LLMessageStringTable::getInstance()->getString("ObjectMaterial");
+char const* const _PREHASH_OwnerName = LLMessageStringTable::getInstance()->getString("OwnerName");
+char const* const _PREHASH_AvatarNotesReply = LLMessageStringTable::getInstance()->getString("AvatarNotesReply");
+char const* const _PREHASH_CacheID = LLMessageStringTable::getInstance()->getString("CacheID");
+char const* const _PREHASH_OwnerMask = LLMessageStringTable::getInstance()->getString("OwnerMask");
+char const* const _PREHASH_TransferInventoryAck = LLMessageStringTable::getInstance()->getString("TransferInventoryAck");
+char const* const _PREHASH_RegionDenyAgeUnverified = LLMessageStringTable::getInstance()->getString("RegionDenyAgeUnverified");
+char const* const _PREHASH_AgeVerificationBlock = LLMessageStringTable::getInstance()->getString("AgeVerificationBlock");
+char const* const _PREHASH_UCoord = LLMessageStringTable::getInstance()->getString("UCoord");
+char const* const _PREHASH_VCoord = LLMessageStringTable::getInstance()->getString("VCoord");
+char const* const _PREHASH_FaceIndex = LLMessageStringTable::getInstance()->getString("FaceIndex");
+char const* const _PREHASH_StatusData = LLMessageStringTable::getInstance()->getString("StatusData");
+char const* const _PREHASH_ProductSKU = LLMessageStringTable::getInstance()->getString("ProductSKU");
diff --git a/indra/llmessage/message_prehash.h b/indra/llmessage/message_prehash.h
index 08c74d22da..8dc86601e6 100644
--- a/indra/llmessage/message_prehash.h
+++ b/indra/llmessage/message_prehash.h
@@ -32,1347 +32,1347 @@
*/
-extern F32 gPrehashVersionNumber;
+extern F32 const gPrehashVersionNumber;
-extern char * _PREHASH_X;
-extern char * _PREHASH_Y;
-extern char * _PREHASH_Z;
-extern char * _PREHASH_AddFlags;
-extern char * _PREHASH_FailureInfo;
-extern char * _PREHASH_MapData;
-extern char * _PREHASH_AddItem;
-extern char * _PREHASH_MeanCollision;
-extern char * _PREHASH_RezScript;
-extern char * _PREHASH_AvatarSitResponse;
-extern char * _PREHASH_InventoryAssetResponse;
-extern char * _PREHASH_KillObject;
-extern char * _PREHASH_ProposalID;
-extern char * _PREHASH_SerialNum;
-extern char * _PREHASH_Duration;
-extern char * _PREHASH_ScriptQuestion;
-extern char * _PREHASH_AddCircuitCode;
-extern char * _PREHASH_UseCircuitCode;
-extern char * _PREHASH_ViewerCircuitCode;
-extern char * _PREHASH_ScriptAnswerYes;
-extern char * _PREHASH_PartnerID;
-extern char * _PREHASH_DirLandQuery;
-extern char * _PREHASH_TeleportStart;
-extern char * _PREHASH_AboutText;
-extern char * _PREHASH_VisualParam;
-extern char * _PREHASH_GroupPrims;
-extern char * _PREHASH_SelectedPrims;
-extern char * _PREHASH_ID;
-extern char * _PREHASH_UUIDNameRequest;
-extern char * _PREHASH_UUIDGroupNameRequest;
-extern char * _PREHASH_GroupAccountTransactionsRequest;
-extern char * _PREHASH_MapNameRequest;
-extern char * _PREHASH_UpdateSimulator;
-extern char * _PREHASH_BillableFactor;
-extern char * _PREHASH_ObjectBonusFactor;
-extern char * _PREHASH_EnableSimulator;
-extern char * _PREHASH_DisableSimulator;
-extern char * _PREHASH_ConfirmEnableSimulator;
-extern char * _PREHASH_LayerType;
-extern char * _PREHASH_OwnerRole;
-extern char * _PREHASH_ParcelOverlay;
-extern char * _PREHASH_GroupOwned;
-extern char * _PREHASH_IP;
-extern char * _PREHASH_ChatFromViewer;
-extern char * _PREHASH_AvgAgentsInView;
-extern char * _PREHASH_AgentsInView;
-extern char * _PREHASH_GroupTitle;
-extern char * _PREHASH_MapLayerReply;
-extern char * _PREHASH_CompoundMsgID;
-extern char * _PREHASH_CameraConstraint;
-extern char * _PREHASH_DownloadTotals;
-extern char * _PREHASH_GenCounter;
-extern char * _PREHASH_FrozenData;
-extern char * _PREHASH_ChildAgentDying;
-extern char * _PREHASH_To;
-extern char * _PREHASH_CopyInventoryFromNotecard;
-extern char * _PREHASH_RezObjectFromNotecard;
-extern char * _PREHASH_ParcelDirFeeCurrent;
-extern char * _PREHASH_SeedCapability;
-extern char * _PREHASH_ObjectDuplicate;
-extern char * _PREHASH_InventoryData;
-extern char * _PREHASH_ReplyData;
-extern char * _PREHASH_ResetList;
-extern char * _PREHASH_MediaID;
-extern char * _PREHASH_RelatedRights;
-extern char * _PREHASH_RedirectGridX;
-extern char * _PREHASH_RedirectGridY;
-extern char * _PREHASH_TransferID;
-extern char * _PREHASH_TexturesChanged;
-extern char * _PREHASH_UserLookAt;
-extern char * _PREHASH_TestBlock1;
-extern char * _PREHASH_SensedData;
-extern char * _PREHASH_UpdateBlock;
-extern char * _PREHASH_ClassifiedGodDelete;
-extern char * _PREHASH_ObjectGrabUpdate;
-extern char * _PREHASH_LocationPos;
-extern char * _PREHASH_TaxDate;
-extern char * _PREHASH_StartDateTime;
-extern char * _PREHASH_ObjectUpdateCached;
-extern char * _PREHASH_Packets;
-extern char * _PREHASH_FailureType;
-extern char * _PREHASH_UpdateGroupInfo;
-extern char * _PREHASH_ObjectPermissions;
-extern char * _PREHASH_RevokePermissions;
-extern char * _PREHASH_UpdateFlags;
-extern char * _PREHASH_ObjectExportSelected;
-extern char * _PREHASH_RezSelected;
-extern char * _PREHASH_AutoPilot;
-extern char * _PREHASH_UpdateMuteListEntry;
-extern char * _PREHASH_RemoveMuteListEntry;
-extern char * _PREHASH_SetSimStatusInDatabase;
-extern char * _PREHASH_SetSimPresenceInDatabase;
-extern char * _PREHASH_CameraProperty;
-extern char * _PREHASH_BrushSize;
-extern char * _PREHASH_SimulatorSetMap;
-extern char * _PREHASH_RegionPresenceRequestByRegionID;
-extern char * _PREHASH_ParcelObjectOwnersReply;
-extern char * _PREHASH_GroupMembersReply;
-extern char * _PREHASH_GroupRoleMembersReply;
-extern char * _PREHASH_RequestRegionInfo;
-extern char * _PREHASH_AABBMax;
-extern char * _PREHASH_RequestPayPrice;
-extern char * _PREHASH_SimulatorPresentAtLocation;
-extern char * _PREHASH_AgentRequestSit;
-extern char * _PREHASH_AABBMin;
-extern char * _PREHASH_ClassifiedFlags;
-extern char * _PREHASH_ControlFlags;
-extern char * _PREHASH_TeleportRequest;
-extern char * _PREHASH_ScriptTeleportRequest;
-extern char * _PREHASH_EstateCovenantRequest;
-extern char * _PREHASH_DateUTC;
-extern char * _PREHASH_TaskIDs;
-extern char * _PREHASH_RequestResult;
-extern char * _PREHASH_CanAcceptAgents;
-extern char * _PREHASH_ObjectSaleInfo;
-extern char * _PREHASH_KillChildAgents;
-extern char * _PREHASH_Balance;
-extern char * _PREHASH_DerezContainer;
-extern char * _PREHASH_ObjectData;
-extern char * _PREHASH_CameraAtAxis;
-extern char * _PREHASH_InfoBlock;
-extern char * _PREHASH_OwnershipCost;
-extern char * _PREHASH_AvatarNotesUpdate;
-extern char * _PREHASH_PID;
-extern char * _PREHASH_DirPopularReply;
-extern char * _PREHASH_TerrainHeightRange00;
-extern char * _PREHASH_SimData;
-extern char * _PREHASH_TerrainHeightRange01;
-extern char * _PREHASH_TerrainHeightRange10;
-extern char * _PREHASH_TerrainHeightRange11;
-extern char * _PREHASH_UpdateInventoryItem;
-extern char * _PREHASH_UpdateCreateInventoryItem;
-extern char * _PREHASH_MoveInventoryItem;
-extern char * _PREHASH_CopyInventoryItem;
-extern char * _PREHASH_LinkInventoryItem;
-extern char * _PREHASH_RemoveInventoryItem;
-extern char * _PREHASH_CreateInventoryItem;
-extern char * _PREHASH_PathTwistBegin;
-extern char * _PREHASH_CRC;
-extern char * _PREHASH_AttachmentPoint;
-extern char * _PREHASH_TelehubBlock;
-extern char * _PREHASH_FOVBlock;
-extern char * _PREHASH_StartLocationData;
-extern char * _PREHASH_PositionData;
-extern char * _PREHASH_TimeSinceLast;
-extern char * _PREHASH_MapImage;
-extern char * _PREHASH_Objects;
-extern char * _PREHASH_URL;
-extern char * _PREHASH_CreationDate;
-extern char * _PREHASH_JointPivot;
-extern char * _PREHASH_FPS;
-extern char * _PREHASH_HasTelehub;
-extern char * _PREHASH_PathEnd;
-extern char * _PREHASH_ScriptDataReply;
-extern char * _PREHASH_MapBlockReply;
-extern char * _PREHASH_PropertiesData;
-extern char * _PREHASH_ViewerEffect;
-extern char * _PREHASH_FreezeUser;
-extern char * _PREHASH_OwnerPrims;
-extern char * _PREHASH_ObjectGrab;
-extern char * _PREHASH_ToAgentID;
-extern char * _PREHASH_SimulatorMapUpdate;
-extern char * _PREHASH_TransferPacket;
-extern char * _PREHASH_ObjectName;
-extern char * _PREHASH_GroupPowers;
-extern char * _PREHASH_OriginalName;
-extern char * _PREHASH_CompletePingCheck;
-extern char * _PREHASH_OnlineStatus;
-extern char * _PREHASH_ObjectDrop;
-extern char * _PREHASH_UseBigPackets;
-extern char * _PREHASH_GroupNoticesListReply;
-extern char * _PREHASH_ParcelAccessListReply;
-extern char * _PREHASH_RpcChannelReply;
-extern char * _PREHASH_RegionPresenceResponse;
-extern char * _PREHASH_CharterMember;
-extern char * _PREHASH_EdgeData;
-extern char * _PREHASH_NameData;
-extern char * _PREHASH_RegionPushOverride;
-extern char * _PREHASH_SimName;
-extern char * _PREHASH_UserReport;
-extern char * _PREHASH_DownloadPriority;
-extern char * _PREHASH_ToAgentId;
-extern char * _PREHASH_DirPopularQuery;
-extern char * _PREHASH_Mag;
-extern char * _PREHASH_ParcelPropertiesRequestByID;
-extern char * _PREHASH_ObjectLink;
-extern char * _PREHASH_RpcScriptReplyInbound;
-extern char * _PREHASH_RezData;
-extern char * _PREHASH_RemoveInventoryObjects;
-extern char * _PREHASH_GroupProposalBallot;
-extern char * _PREHASH_RPCServerIP;
-extern char * _PREHASH_Far;
-extern char * _PREHASH_GodSessionID;
-extern char * _PREHASH_FLAboutText;
-extern char * _PREHASH_RegionHandshakeReply;
-extern char * _PREHASH_GroupActiveProposalItemReply;
-extern char * _PREHASH_MapItemReply;
-extern char * _PREHASH_Seconds;
-extern char * _PREHASH_UpdateUserInfo;
-extern char * _PREHASH_AggregatePermTexturesOwner;
-extern char * _PREHASH_Set;
-extern char * _PREHASH_NewName;
-extern char * _PREHASH_Key;
-extern char * _PREHASH_AgentID;
-extern char * _PREHASH_EventNotificationRemoveRequest;
-extern char * _PREHASH_NewFolderID;
-extern char * _PREHASH_Arc;
-extern char * _PREHASH_RegionX;
-extern char * _PREHASH_RegionY;
-extern char * _PREHASH_RequestData;
-extern char * _PREHASH_Msg;
-extern char * _PREHASH_Top;
-extern char * _PREHASH_MiscStats;
-extern char * _PREHASH_ImageID;
-extern char * _PREHASH_DataPacket;
-extern char * _PREHASH_You;
-extern char * _PREHASH_ScriptControlChange;
-extern char * _PREHASH_LoadURL;
-extern char * _PREHASH_SetCPURatio;
-extern char * _PREHASH_NameValueData;
-extern char * _PREHASH_AtomicPassObject;
-extern char * _PREHASH_ErrorMessage;
-extern char * _PREHASH_ViewerFrozenMessage;
-extern char * _PREHASH_HealthMessage;
-extern char * _PREHASH_LogTextMessage;
-extern char * _PREHASH_TimeDilation;
-extern char * _PREHASH_RemoveContribution;
-extern char * _PREHASH_Contribution;
-extern char * _PREHASH_SetGroupContribution;
-extern char * _PREHASH_Offline;
-extern char * _PREHASH_AgentIsNowWearing;
-extern char * _PREHASH_Members;
-extern char * _PREHASH_FailedResends;
-extern char * _PREHASH_SecPerDay;
-extern char * _PREHASH_CameraCenter;
-extern char * _PREHASH_CameraLeftAxis;
-extern char * _PREHASH_ExBlock;
-extern char * _PREHASH_Channel;
-extern char * _PREHASH_NetTest;
-extern char * _PREHASH_DiscardLevel;
-extern char * _PREHASH_LayerID;
-extern char * _PREHASH_GrabOffset;
-extern char * _PREHASH_SimPort;
-extern char * _PREHASH_PricePerMeter;
-extern char * _PREHASH_RegionFlags;
-extern char * _PREHASH_VoteResult;
-extern char * _PREHASH_ParcelDirFeeEstimate;
-extern char * _PREHASH_ModifyBlock;
-extern char * _PREHASH_InventoryBlock;
-extern char * _PREHASH_ReplyBlock;
-extern char * _PREHASH_ValidUntil;
-extern char * _PREHASH_VelocityInterpolateOn;
-extern char * _PREHASH_ClassifiedDelete;
-extern char * _PREHASH_RegionDenyAnonymous;
-extern char * _PREHASH_FLImageID;
-extern char * _PREHASH_AllowPublish;
-extern char * _PREHASH_SitName;
-extern char * _PREHASH_RegionsVisited;
-extern char * _PREHASH_DirClassifiedReply;
-extern char * _PREHASH_AvatarClassifiedReply;
-extern char * _PREHASH_MediaURL;
-extern char * _PREHASH_CompleteAgentMovement;
-extern char * _PREHASH_ClassifiedID;
-extern char * _PREHASH_LocalID;
-extern char * _PREHASH_SpaceIP;
-extern char * _PREHASH_RemoveItem;
-extern char * _PREHASH_LogFailedMoneyTransaction;
-extern char * _PREHASH_ViewerStartAuction;
-extern char * _PREHASH_StartAuction;
-extern char * _PREHASH_DuplicateFlags;
-extern char * _PREHASH_RegionInfo2;
-extern char * _PREHASH_TextColor;
-extern char * _PREHASH_SlaveID;
-extern char * _PREHASH_Charter;
-extern char * _PREHASH_AlertData;
-extern char * _PREHASH_AlertInfo;
-extern char * _PREHASH_TargetBlock;
-extern char * _PREHASH_CheckParcelAuctions;
-extern char * _PREHASH_ParcelAuctions;
-extern char * _PREHASH_OwnerIsGroup;
-extern char * _PREHASH_NameValuePair;
-extern char * _PREHASH_RemoveNameValuePair;
-extern char * _PREHASH_BulkUpdateInventory;
-extern char * _PREHASH_UpdateTaskInventory;
-extern char * _PREHASH_RemoveTaskInventory;
-extern char * _PREHASH_MoveTaskInventory;
-extern char * _PREHASH_RequestTaskInventory;
-extern char * _PREHASH_ReplyTaskInventory;
-extern char * _PREHASH_AggregatePermInventory;
-extern char * _PREHASH_GroupAccountTransactionsReply;
-extern char * _PREHASH_SimulatorInfo;
-extern char * _PREHASH_WearableData;
-extern char * _PREHASH_Enabled;
-extern char * _PREHASH_Savings;
-extern char * _PREHASH_SimulatorLoad;
-extern char * _PREHASH_InternalRegionIP;
-extern char * _PREHASH_ExternalRegionIP;
-extern char * _PREHASH_TotalPairs;
-extern char * _PREHASH_CreateGroupRequest;
-extern char * _PREHASH_JoinGroupRequest;
-extern char * _PREHASH_LeaveGroupRequest;
-extern char * _PREHASH_InviteGroupRequest;
-extern char * _PREHASH_LiveHelpGroupRequest;
-extern char * _PREHASH_PriceParcelClaimFactor;
-extern char * _PREHASH_BillableArea;
-extern char * _PREHASH_ObjectID;
-extern char * _PREHASH_ObjectFlagUpdate;
-extern char * _PREHASH_GroupRoleUpdate;
-extern char * _PREHASH_RequestInventoryAsset;
-extern char * _PREHASH_ChangedGrid;
-extern char * _PREHASH_AgentDropGroup;
-extern char * _PREHASH_Details;
-extern char * _PREHASH_LocationX;
-extern char * _PREHASH_SaleType;
-extern char * _PREHASH_LocationY;
-extern char * _PREHASH_LocationZ;
-extern char * _PREHASH_EconomyData;
-extern char * _PREHASH_HeadRotation;
-extern char * _PREHASH_DeleteOnCompletion;
-extern char * _PREHASH_PublicPort;
-extern char * _PREHASH_DirClassifiedQuery;
-extern char * _PREHASH_CallbackID;
-extern char * _PREHASH_RequestParcelTransfer;
-extern char * _PREHASH_RoleCount;
-extern char * _PREHASH_ObjectCapacity;
-extern char * _PREHASH_RequestID;
-extern char * _PREHASH_RequestXfer;
-extern char * _PREHASH_ObjectTaxCurrent;
-extern char * _PREHASH_LightTaxCurrent;
-extern char * _PREHASH_LandTaxCurrent;
-extern char * _PREHASH_GroupTaxCurrent;
-extern char * _PREHASH_FetchInventoryDescendents;
-extern char * _PREHASH_InventoryDescendents;
-extern char * _PREHASH_Descendents;
-extern char * _PREHASH_PurgeInventoryDescendents;
-extern char * _PREHASH_ShowDir;
-extern char * _PREHASH_IsOwner;
-extern char * _PREHASH_Timestamp;
-extern char * _PREHASH_GlobalPos;
-extern char * _PREHASH_GrabOffsetInitial;
-extern char * _PREHASH_IsTrial;
-extern char * _PREHASH_ObjectDuplicateOnRay;
-extern char * _PREHASH_GroupMembershipCount;
-extern char * _PREHASH_MethodData;
-extern char * _PREHASH_ActivateGestures;
-extern char * _PREHASH_DeactivateGestures;
-extern char * _PREHASH_ProposalData;
-extern char * _PREHASH_PosGlobal;
-extern char * _PREHASH_SearchID;
-extern char * _PREHASH_RezMultipleAttachmentsFromInv;
-extern char * _PREHASH_SearchName;
-extern char * _PREHASH_VersionString;
-extern char * _PREHASH_CreateGroupReply;
-extern char * _PREHASH_LeaveGroupReply;
-extern char * _PREHASH_ActualArea;
-extern char * _PREHASH_Message;
-extern char * _PREHASH_ClickAction;
-extern char * _PREHASH_AssetUploadComplete;
-extern char * _PREHASH_RequestType;
-extern char * _PREHASH_UUID;
-extern char * _PREHASH_BaseMask;
-extern char * _PREHASH_NetBlock;
-extern char * _PREHASH_GlobalX;
-extern char * _PREHASH_GlobalY;
-extern char * _PREHASH_CopyRotates;
-extern char * _PREHASH_KickUserAck;
-extern char * _PREHASH_TopPick;
-extern char * _PREHASH_SessionID;
-extern char * _PREHASH_GlobalZ;
-extern char * _PREHASH_DeclineFriendship;
-extern char * _PREHASH_FormFriendship;
-extern char * _PREHASH_TerminateFriendship;
-extern char * _PREHASH_TaskData;
-extern char * _PREHASH_SimWideMaxPrims;
-extern char * _PREHASH_TotalPrims;
-extern char * _PREHASH_ProfileBegin;
-extern char * _PREHASH_Request;
-extern char * _PREHASH_GroupAccountDetailsRequest;
-extern char * _PREHASH_GroupActiveProposalsRequest;
-extern char * _PREHASH_StringValue;
-extern char * _PREHASH_Version;
-extern char * _PREHASH_OtherCount;
-extern char * _PREHASH_MemberCount;
-extern char * _PREHASH_ChatData;
-extern char * _PREHASH_IsGroupOwned;
-extern char * _PREHASH_EnergyEfficiency;
-extern char * _PREHASH_PickInfoUpdate;
-extern char * _PREHASH_PickDelete;
-extern char * _PREHASH_ScriptReset;
-extern char * _PREHASH_Requester;
-extern char * _PREHASH_ForSale;
-extern char * _PREHASH_NearestLandingRegionReply;
-extern char * _PREHASH_ParcelID;
-extern char * _PREHASH_Godlike;
-extern char * _PREHASH_TotalDebits;
-extern char * _PREHASH_Direction;
-extern char * _PREHASH_HealthData;
-extern char * _PREHASH_LeftAxis;
-extern char * _PREHASH_LocationBlock;
-extern char * _PREHASH_ObjectImage;
-extern char * _PREHASH_TerrainStartHeight00;
-extern char * _PREHASH_TerrainStartHeight01;
-extern char * _PREHASH_TerrainStartHeight10;
-extern char * _PREHASH_TerrainStartHeight11;
-extern char * _PREHASH_WaterHeight;
-extern char * _PREHASH_FetchInventoryReply;
-extern char * _PREHASH_GroupAccountSummaryReply;
-extern char * _PREHASH_AttachedSound;
-extern char * _PREHASH_ParamInUse;
-extern char * _PREHASH_GodKickUser;
-extern char * _PREHASH_PickName;
-extern char * _PREHASH_TaskName;
-extern char * _PREHASH_ObjectCount;
-extern char * _PREHASH_RegionPresenceRequestByHandle;
-extern char * _PREHASH_RezSingleAttachmentFromInv;
-extern char * _PREHASH_ChildAgentUpdate;
-extern char * _PREHASH_IsOwnerGroup;
-extern char * _PREHASH_AgentHeightWidth;
-extern char * _PREHASH_VerticalAngle;
-extern char * _PREHASH_WearableType;
-extern char * _PREHASH_AggregatePermNextOwner;
-extern char * _PREHASH_ShowInList;
-extern char * _PREHASH_UpdateParcel;
-extern char * _PREHASH_SetAlwaysRun;
-extern char * _PREHASH_NVPair;
-extern char * _PREHASH_SearchType;
-extern char * _PREHASH_ObjectSpinStart;
-extern char * _PREHASH_UseEstateSun;
-extern char * _PREHASH_RegionID;
-extern char * _PREHASH_AbuseRegionID;
-extern char * _PREHASH_Creator;
-extern char * _PREHASH_ProposalText;
-extern char * _PREHASH_DirEventsReply;
-extern char * _PREHASH_EventInfoReply;
-extern char * _PREHASH_UserInfoReply;
-extern char * _PREHASH_PathRadiusOffset;
-extern char * _PREHASH_TextureData;
-extern char * _PREHASH_ChatPass;
-extern char * _PREHASH_TargetID;
-extern char * _PREHASH_DefaultPayPrice;
-extern char * _PREHASH_UserLocation;
-extern char * _PREHASH_MaxPrims;
-extern char * _PREHASH_LandmarkID;
-extern char * _PREHASH_InitiateDownload;
-extern char * _PREHASH_Name;
-extern char * _PREHASH_OtherCleanTime;
-extern char * _PREHASH_ParcelSetOtherCleanTime;
-extern char * _PREHASH_TeleportPriceExponent;
-extern char * _PREHASH_Gain;
-extern char * _PREHASH_PacketAck;
-extern char * _PREHASH_PathSkew;
-extern char * _PREHASH_SimulatorShutdownRequest;
-extern char * _PREHASH_NearestLandingRegionRequest;
-extern char * _PREHASH_OtherID;
-extern char * _PREHASH_MemberID;
-extern char * _PREHASH_MapLayerRequest;
-extern char * _PREHASH_ObjectScale;
-extern char * _PREHASH_TargetIP;
-extern char * _PREHASH_Redo;
-extern char * _PREHASH_MoneyBalance;
-extern char * _PREHASH_TrackAgent;
-extern char * _PREHASH_MaxX;
-extern char * _PREHASH_Data;
-extern char * _PREHASH_MaxY;
-extern char * _PREHASH_TextureAnim;
-extern char * _PREHASH_ReturnIDs;
-extern char * _PREHASH_Date;
-extern char * _PREHASH_AgentWearablesUpdate;
-extern char * _PREHASH_AgentDataUpdate;
-extern char * _PREHASH_GroupDataUpdate;
-extern char * _PREHASH_Hash;
-extern char * _PREHASH_AgentGroupDataUpdate;
-extern char * _PREHASH_Left;
-extern char * _PREHASH_Mask;
-extern char * _PREHASH_ForceMouselook;
-extern char * _PREHASH_Success;
-extern char * _PREHASH_ObjectGroup;
-extern char * _PREHASH_SunHour;
-extern char * _PREHASH_MinX;
-extern char * _PREHASH_ScriptSensorReply;
-extern char * _PREHASH_MinY;
-extern char * _PREHASH_Command;
-extern char * _PREHASH_Desc;
-extern char * _PREHASH_AttachmentNeedsSave;
-extern char * _PREHASH_HistoryItemData;
-extern char * _PREHASH_AgentCachedTexture;
-extern char * _PREHASH_Subject;
-extern char * _PREHASH_East;
-extern char * _PREHASH_QueryReplies;
-extern char * _PREHASH_ObjectCategory;
-extern char * _PREHASH_Time;
-extern char * _PREHASH_CreateLandmarkForEvent;
-extern char * _PREHASH_ParentID;
-extern char * _PREHASH_Ping;
-extern char * _PREHASH_Perp;
-extern char * _PREHASH_Code;
-extern char * _PREHASH_InvType;
-extern char * _PREHASH_AgentFOV;
-extern char * _PREHASH_Audible;
-extern char * _PREHASH_AuctionData;
-extern char * _PREHASH_IDBlock;
-extern char * _PREHASH_West;
-extern char * _PREHASH_Undo;
-extern char * _PREHASH_TotalNumItems;
-extern char * _PREHASH_Info;
-extern char * _PREHASH_Area;
-extern char * _PREHASH_SimCrashed;
-extern char * _PREHASH_Text;
-extern char * _PREHASH_PriceGroupCreate;
-extern char * _PREHASH_ObjectShape;
-extern char * _PREHASH_GroupRoleDataReply;
-extern char * _PREHASH_MuteCRC;
-extern char * _PREHASH_Size;
-extern char * _PREHASH_FromAddress;
-extern char * _PREHASH_Body;
-extern char * _PREHASH_FileData;
-extern char * _PREHASH_List;
-extern char * _PREHASH_KickUser;
-extern char * _PREHASH_OtherPrims;
-extern char * _PREHASH_RunTime;
-extern char * _PREHASH_GrantUserRights;
-extern char * _PREHASH_RpcScriptRequestInboundForward;
-extern char * _PREHASH_More;
-extern char * _PREHASH_Majority;
-extern char * _PREHASH_MetersTraveled;
-extern char * _PREHASH_Stat;
-extern char * _PREHASH_SoundID;
-extern char * _PREHASH_Item;
-extern char * _PREHASH_User;
-extern char * _PREHASH_Prey;
-extern char * _PREHASH_RayStart;
-extern char * _PREHASH_UsecSinceStart;
-extern char * _PREHASH_ParcelData;
-extern char * _PREHASH_CameraUpAxis;
-extern char * _PREHASH_ScriptDialog;
-extern char * _PREHASH_MasterParcelData;
-extern char * _PREHASH_Invalid;
-extern char * _PREHASH_ProfileCurve;
-extern char * _PREHASH_ParcelAccessListUpdate;
-extern char * _PREHASH_MuteListUpdate;
-extern char * _PREHASH_SendPacket;
-extern char * _PREHASH_SendXferPacket;
-extern char * _PREHASH_RegionDenyIdentified;
-extern char * _PREHASH_NotecardItemID;
-extern char * _PREHASH_LastName;
-extern char * _PREHASH_From;
-extern char * _PREHASH_RoleChange;
-extern char * _PREHASH_Port;
-extern char * _PREHASH_MemberTitle;
-extern char * _PREHASH_LogParcelChanges;
-extern char * _PREHASH_AgentCachedTextureResponse;
-extern char * _PREHASH_DeRezObject;
-extern char * _PREHASH_IsTemporary;
-extern char * _PREHASH_InsigniaID;
-extern char * _PREHASH_CheckFlags;
-extern char * _PREHASH_EventID;
-extern char * _PREHASH_Selected;
-extern char * _PREHASH_FromAgentId;
-extern char * _PREHASH_Type;
-extern char * _PREHASH_ChatType;
-extern char * _PREHASH_ReportData;
-extern char * _PREHASH_RequestBlock;
-extern char * _PREHASH_GrantData;
-extern char * _PREHASH_DetachAttachmentIntoInv;
-extern char * _PREHASH_ParcelDisableObjects;
-extern char * _PREHASH_Sections;
-extern char * _PREHASH_GodLevel;
-extern char * _PREHASH_PayPriceReply;
-extern char * _PREHASH_QueryID;
-extern char * _PREHASH_CameraEyeOffset;
-extern char * _PREHASH_AgentPosition;
-extern char * _PREHASH_GrabPosition;
-extern char * _PREHASH_OnlineNotification;
-extern char * _PREHASH_OfflineNotification;
-extern char * _PREHASH_SendPostcard;
-extern char * _PREHASH_RequestFlags;
-extern char * _PREHASH_GroupAccountSummaryRequest;
-extern char * _PREHASH_GroupVoteHistoryRequest;
-extern char * _PREHASH_ParamValue;
-extern char * _PREHASH_MaxAgents;
-extern char * _PREHASH_CreateNewOutfitAttachments;
-extern char * _PREHASH_RegionHandle;
-extern char * _PREHASH_TeleportProgress;
-extern char * _PREHASH_AgentQuitCopy;
-extern char * _PREHASH_AvatarInterestsUpdate;
-extern char * _PREHASH_GroupNoticeID;
-extern char * _PREHASH_ParcelName;
-extern char * _PREHASH_PriceObjectRent;
-extern char * _PREHASH_OfferCallingCard;
-extern char * _PREHASH_AcceptCallingCard;
-extern char * _PREHASH_DeclineCallingCard;
-extern char * _PREHASH_AgentAccess;
-extern char * _PREHASH_AgentLegacyAccess;
-extern char * _PREHASH_AgentMaxAccess;
-extern char * _PREHASH_DataHomeLocationReply;
-extern char * _PREHASH_EventLocationReply;
-extern char * _PREHASH_TerseDateID;
-extern char * _PREHASH_ObjectOwner;
-extern char * _PREHASH_AssetID;
-extern char * _PREHASH_AlertMessage;
-extern char * _PREHASH_AgentAlertMessage;
-extern char * _PREHASH_EstateOwnerMessage;
-extern char * _PREHASH_ParcelMediaCommandMessage;
-extern char * _PREHASH_Auction;
-extern char * _PREHASH_Category;
-extern char * _PREHASH_FilePath;
-extern char * _PREHASH_ItemFlags;
-extern char * _PREHASH_Invoice;
-extern char * _PREHASH_IntervalDays;
-extern char * _PREHASH_PathScaleX;
-extern char * _PREHASH_FromTaskID;
-extern char * _PREHASH_PathScaleY;
-extern char * _PREHASH_TimeInfo;
-extern char * _PREHASH_PublicCount;
-extern char * _PREHASH_ParcelJoin;
-extern char * _PREHASH_GroupRolesCount;
-extern char * _PREHASH_SimulatorBlock;
-extern char * _PREHASH_GroupID;
-extern char * _PREHASH_AgentVel;
-extern char * _PREHASH_RequestImage;
-extern char * _PREHASH_NetStats;
-extern char * _PREHASH_AgentPos;
-extern char * _PREHASH_AgentSit;
-extern char * _PREHASH_Material;
-extern char * _PREHASH_ObjectDeGrab;
-extern char * _PREHASH_VelocityInterpolateOff;
-extern char * _PREHASH_AuthorizedBuyerID;
-extern char * _PREHASH_AvatarPropertiesReply;
-extern char * _PREHASH_GroupProfileReply;
-extern char * _PREHASH_SimOwner;
-extern char * _PREHASH_SalePrice;
-extern char * _PREHASH_Animation;
-extern char * _PREHASH_OwnerID;
-extern char * _PREHASH_NearestLandingRegionUpdated;
-extern char * _PREHASH_PassToAgent;
-extern char * _PREHASH_PreyAgent;
-extern char * _PREHASH_SimStats;
-extern char * _PREHASH_LogoutReply;
-extern char * _PREHASH_FeatureDisabled;
-extern char * _PREHASH_PhysicalAvatarEventList;
-extern char * _PREHASH_ObjectLocalID;
-extern char * _PREHASH_Dropped;
-extern char * _PREHASH_WebProfilesDisabled;
-extern char * _PREHASH_Destination;
-extern char * _PREHASH_MasterID;
-extern char * _PREHASH_TransferData;
-extern char * _PREHASH_WantToMask;
-extern char * _PREHASH_ParcelSelectObjects;
-extern char * _PREHASH_ExtraParams;
-extern char * _PREHASH_CreatorID;
-extern char * _PREHASH_Summary;
-extern char * _PREHASH_BuyObjectInventory;
-extern char * _PREHASH_FetchInventory;
-extern char * _PREHASH_InventoryID;
-extern char * _PREHASH_PacketNumber;
-extern char * _PREHASH_SetFollowCamProperties;
-extern char * _PREHASH_ClearFollowCamProperties;
-extern char * _PREHASH_SequenceID;
-extern char * _PREHASH_DataServerLogout;
-extern char * _PREHASH_NameValue;
-extern char * _PREHASH_PathShearX;
-extern char * _PREHASH_PathShearY;
-extern char * _PREHASH_Velocity;
-extern char * _PREHASH_SecPerYear;
-extern char * _PREHASH_FirstName;
-extern char * _PREHASH_AttachedSoundGainChange;
-extern char * _PREHASH_LocationID;
-extern char * _PREHASH_Running;
-extern char * _PREHASH_AgentThrottle;
-extern char * _PREHASH_NeighborList;
-extern char * _PREHASH_PathTaperX;
-extern char * _PREHASH_PathTaperY;
-extern char * _PREHASH_AgentRelated;
-extern char * _PREHASH_GranterBlock;
-extern char * _PREHASH_UseCachedMuteList;
-extern char * _PREHASH_FailStats;
-extern char * _PREHASH_Tempfile;
-extern char * _PREHASH_BuyerID;
-extern char * _PREHASH_DirPeopleReply;
-extern char * _PREHASH_TransferInfo;
-extern char * _PREHASH_AvatarPickerRequestBackend;
-extern char * _PREHASH_AvatarPropertiesRequestBackend;
-extern char * _PREHASH_UpdateData;
-extern char * _PREHASH_SimFPS;
-extern char * _PREHASH_ReporterID;
-extern char * _PREHASH_ButtonLabel;
-extern char * _PREHASH_GranterID;
-extern char * _PREHASH_WantToText;
-extern char * _PREHASH_ReportType;
-extern char * _PREHASH_SimulatorReady;
-extern char * _PREHASH_DataBlock;
-extern char * _PREHASH_AnimationSourceList;
-extern char * _PREHASH_SubscribeLoad;
-extern char * _PREHASH_UnsubscribeLoad;
-extern char * _PREHASH_Packet;
-extern char * _PREHASH_UndoLand;
-extern char * _PREHASH_SimAccess;
-extern char * _PREHASH_AbuserID;
-extern char * _PREHASH_MembershipFee;
-extern char * _PREHASH_InviteGroupResponse;
-extern char * _PREHASH_CreateInventoryFolder;
-extern char * _PREHASH_UpdateInventoryFolder;
-extern char * _PREHASH_MoveInventoryFolder;
-extern char * _PREHASH_RemoveInventoryFolder;
-extern char * _PREHASH_MoneyData;
-extern char * _PREHASH_ObjectDeselect;
-extern char * _PREHASH_NewAssetID;
-extern char * _PREHASH_ObjectAdd;
-extern char * _PREHASH_RayEndIsIntersection;
-extern char * _PREHASH_CompleteAuction;
-extern char * _PREHASH_CircuitCode;
-extern char * _PREHASH_AgentMovementComplete;
-extern char * _PREHASH_ViewerIP;
-extern char * _PREHASH_Header;
-extern char * _PREHASH_GestureFlags;
-extern char * _PREHASH_XferID;
-extern char * _PREHASH_StatValue;
-extern char * _PREHASH_TaskID;
-extern char * _PREHASH_PickID;
-extern char * _PREHASH_RayEnd;
-extern char * _PREHASH_Throttles;
-extern char * _PREHASH_RebakeAvatarTextures;
-extern char * _PREHASH_UpAxis;
-extern char * _PREHASH_AgentTextures;
-extern char * _PREHASH_NotecardData;
-extern char * _PREHASH_Radius;
-extern char * _PREHASH_OffCircuit;
-extern char * _PREHASH_Access;
-extern char * _PREHASH_TitleRoleID;
-extern char * _PREHASH_SquareMetersCredit;
-extern char * _PREHASH_Filename;
-extern char * _PREHASH_ClassifiedInfoRequest;
-extern char * _PREHASH_ParcelInfoRequest;
-extern char * _PREHASH_ParcelObjectOwnersRequest;
-extern char * _PREHASH_TeleportLandmarkRequest;
-extern char * _PREHASH_EventInfoRequest;
-extern char * _PREHASH_MoneyBalanceRequest;
-extern char * _PREHASH_GroupMembersRequest;
-extern char * _PREHASH_GroupRoleMembersRequest;
-extern char * _PREHASH_ChatFromSimulator;
-extern char * _PREHASH_OldFolderID;
-extern char * _PREHASH_UserInfoRequest;
-extern char * _PREHASH_TextureID;
-extern char * _PREHASH_ProfileURL;
-extern char * _PREHASH_Handle;
-extern char * _PREHASH_ButtonIndex;
-extern char * _PREHASH_GetScriptRunning;
-extern char * _PREHASH_SetScriptRunning;
-extern char * _PREHASH_Health;
-extern char * _PREHASH_CircuitInfo;
-extern char * _PREHASH_ObjectBuy;
-extern char * _PREHASH_ProfileEnd;
-extern char * _PREHASH_Effect;
-extern char * _PREHASH_TestMessage;
-extern char * _PREHASH_ScriptMailRegistration;
-extern char * _PREHASH_AgentSetAppearance;
-extern char * _PREHASH_AvatarAppearance;
-extern char * _PREHASH_RegionData;
-extern char * _PREHASH_RequestingRegionData;
-extern char * _PREHASH_LandingRegionData;
-extern char * _PREHASH_SitTransform;
-extern char * _PREHASH_TerrainBase0;
-extern char * _PREHASH_SkillsMask;
-extern char * _PREHASH_AtAxis;
-extern char * _PREHASH_TerrainBase1;
-extern char * _PREHASH_Reason;
-extern char * _PREHASH_TerrainBase2;
-extern char * _PREHASH_TerrainBase3;
-extern char * _PREHASH_Params;
-extern char * _PREHASH_PingID;
-extern char * _PREHASH_Change;
-extern char * _PREHASH_Height;
-extern char * _PREHASH_Region;
-extern char * _PREHASH_TelehubInfo;
-extern char * _PREHASH_StateSave;
-extern char * _PREHASH_RoleData;
-extern char * _PREHASH_AgentAnimation;
-extern char * _PREHASH_AvatarAnimation;
-extern char * _PREHASH_LogDwellTime;
-extern char * _PREHASH_ParcelGodMarkAsContent;
-extern char * _PREHASH_UsePhysics;
-extern char * _PREHASH_RegionDenyTransacted;
-extern char * _PREHASH_JointType;
-extern char * _PREHASH_ObjectTaxEstimate;
-extern char * _PREHASH_LightTaxEstimate;
-extern char * _PREHASH_LandTaxEstimate;
-extern char * _PREHASH_TeleportLandingStatusChanged;
-extern char * _PREHASH_GroupTaxEstimate;
-extern char * _PREHASH_AvgViewerFPS;
-extern char * _PREHASH_Buttons;
-extern char * _PREHASH_Sender;
-extern char * _PREHASH_Dialog;
-extern char * _PREHASH_TargetData;
-extern char * _PREHASH_DestID;
-extern char * _PREHASH_PricePublicObjectDelete;
-extern char * _PREHASH_ObjectDelete;
-extern char * _PREHASH_Delete;
-extern char * _PREHASH_EventGodDelete;
-extern char * _PREHASH_LastTaxDate;
-extern char * _PREHASH_MapImageID;
-extern char * _PREHASH_EndDateTime;
-extern char * _PREHASH_TerrainDetail0;
-extern char * _PREHASH_TerrainDetail1;
-extern char * _PREHASH_TerrainDetail2;
-extern char * _PREHASH_TerrainDetail3;
-extern char * _PREHASH_Offset;
-extern char * _PREHASH_ObjectDelink;
-extern char * _PREHASH_TargetObject;
-extern char * _PREHASH_IsEstateManager;
-extern char * _PREHASH_CancelAuction;
-extern char * _PREHASH_ObjectDetach;
-extern char * _PREHASH_Compressed;
-extern char * _PREHASH_PathBegin;
-extern char * _PREHASH_BypassRaycast;
-extern char * _PREHASH_WinnerID;
-extern char * _PREHASH_ChannelType;
-extern char * _PREHASH_NonExemptMembers;
-extern char * _PREHASH_Agents;
-extern char * _PREHASH_MemberData;
-extern char * _PREHASH_ToGroupID;
-extern char * _PREHASH_ImageNotInDatabase;
-extern char * _PREHASH_StartDate;
-extern char * _PREHASH_AnimID;
-extern char * _PREHASH_Serial;
-extern char * _PREHASH_AbuseRegionName;
-extern char * _PREHASH_ModifyLand;
-extern char * _PREHASH_Digest;
-extern char * _PREHASH_Victim;
-extern char * _PREHASH_Script;
-extern char * _PREHASH_PickInfoReply;
-extern char * _PREHASH_MoneyBalanceReply;
-extern char * _PREHASH_RoutedMoneyBalanceReply;
-extern char * _PREHASH_RoleID;
-extern char * _PREHASH_RegionInfo;
-extern char * _PREHASH_GodUpdateRegionInfo;
-extern char * _PREHASH_StartAnim;
-extern char * _PREHASH_Action;
-extern char * _PREHASH_Location;
-extern char * _PREHASH_Rights;
-extern char * _PREHASH_SearchDir;
-extern char * _PREHASH_TransferRequest;
-extern char * _PREHASH_ScriptSensorRequest;
-extern char * _PREHASH_MoneyTransferRequest;
-extern char * _PREHASH_EjectGroupMemberRequest;
-extern char * _PREHASH_SkillsText;
-extern char * _PREHASH_Resent;
-extern char * _PREHASH_Center;
-extern char * _PREHASH_SharedData;
-extern char * _PREHASH_PSBlock;
-extern char * _PREHASH_UUIDNameBlock;
-extern char * _PREHASH_GroupTitleUpdate;
-extern char * _PREHASH_Method;
-extern char * _PREHASH_TouchName;
-extern char * _PREHASH_UpdateType;
-extern char * _PREHASH_KickedFromEstateID;
-extern char * _PREHASH_CandidateID;
-extern char * _PREHASH_ParamData;
-extern char * _PREHASH_GodlikeMessage;
-extern char * _PREHASH_SystemMessage;
-extern char * _PREHASH_BodyRotation;
-extern char * _PREHASH_SearchRegions;
-extern char * _PREHASH_AnimationData;
-extern char * _PREHASH_StatID;
-extern char * _PREHASH_ItemID;
-extern char * _PREHASH_ScriptDialogReply;
-extern char * _PREHASH_RegionIDAndHandleReply;
-extern char * _PREHASH_CameraAtOffset;
-extern char * _PREHASH_VoteID;
-extern char * _PREHASH_ParcelGodForceOwner;
-extern char * _PREHASH_Filter;
-extern char * _PREHASH_InviteData;
-extern char * _PREHASH_PCode;
-extern char * _PREHASH_SearchPos;
-extern char * _PREHASH_PreyID;
-extern char * _PREHASH_TerrainLowerLimit;
-extern char * _PREHASH_EventFlags;
-extern char * _PREHASH_TallyVotes;
-extern char * _PREHASH_Result;
-extern char * _PREHASH_LookAt;
-extern char * _PREHASH_SearchOrder;
-extern char * _PREHASH_PayButton;
-extern char * _PREHASH_SelfCount;
-extern char * _PREHASH_PacketCount;
-extern char * _PREHASH_ParcelBuyPass;
-extern char * _PREHASH_OldItemID;
-extern char * _PREHASH_RegionPort;
-extern char * _PREHASH_PriceEnergyUnit;
-extern char * _PREHASH_Bitmap;
-extern char * _PREHASH_CacheMissType;
-extern char * _PREHASH_VFileID;
-extern char * _PREHASH_GroupInsigniaID;
-extern char * _PREHASH_Online;
-extern char * _PREHASH_KickFlags;
-extern char * _PREHASH_CovenantID;
-extern char * _PREHASH_SysCPU;
-extern char * _PREHASH_EMail;
-extern char * _PREHASH_AggregatePermTextures;
-extern char * _PREHASH_ChatChannel;
-extern char * _PREHASH_ReturnID;
-extern char * _PREHASH_ObjectAttach;
-extern char * _PREHASH_TargetPort;
-extern char * _PREHASH_ObjectSpinStop;
-extern char * _PREHASH_FullID;
-extern char * _PREHASH_ActivateGroup;
-extern char * _PREHASH_SysGPU;
-extern char * _PREHASH_AvatarInterestsReply;
-extern char * _PREHASH_StartLure;
-extern char * _PREHASH_SysRAM;
-extern char * _PREHASH_ObjectPosition;
-extern char * _PREHASH_SitPosition;
-extern char * _PREHASH_StartTime;
-extern char * _PREHASH_BornOn;
-extern char * _PREHASH_CameraCollidePlane;
-extern char * _PREHASH_EconomyDataRequest;
-extern char * _PREHASH_TeleportLureRequest;
-extern char * _PREHASH_FolderID;
-extern char * _PREHASH_RegionHandleRequest;
-extern char * _PREHASH_ScriptDataRequest;
-extern char * _PREHASH_GroupRoleDataRequest;
-extern char * _PREHASH_GroupTitlesRequest;
-extern char * _PREHASH_AgentWearablesRequest;
-extern char * _PREHASH_MapBlockRequest;
-extern char * _PREHASH_LureID;
-extern char * _PREHASH_CopyCenters;
-extern char * _PREHASH_ParamList;
-extern char * _PREHASH_InventorySerial;
-extern char * _PREHASH_EdgeDataPacket;
-extern char * _PREHASH_AvatarPickerReply;
-extern char * _PREHASH_ParcelDwellReply;
-extern char * _PREHASH_IsForSale;
-extern char * _PREHASH_MuteID;
-extern char * _PREHASH_MeanCollisionAlert;
-extern char * _PREHASH_CanAcceptTasks;
-extern char * _PREHASH_ItemData;
-extern char * _PREHASH_AnimationList;
-extern char * _PREHASH_Reputation;
-extern char * _PREHASH_IntValue;
-extern char * _PREHASH_TargetType;
-extern char * _PREHASH_Amount;
-extern char * _PREHASH_HasAttachment;
-extern char * _PREHASH_UpdateAttachment;
-extern char * _PREHASH_RemoveAttachment;
-extern char * _PREHASH_HeightWidthBlock;
-extern char * _PREHASH_RequestObjectPropertiesFamily;
-extern char * _PREHASH_ObjectPropertiesFamily;
-extern char * _PREHASH_UserData;
-extern char * _PREHASH_IsReadable;
-extern char * _PREHASH_PathCurve;
-extern char * _PREHASH_Status;
-extern char * _PREHASH_FromGroup;
-extern char * _PREHASH_AlreadyVoted;
-extern char * _PREHASH_PlacesReply;
-extern char * _PREHASH_DirPlacesReply;
-extern char * _PREHASH_ParcelBuy;
-extern char * _PREHASH_DirFindQueryBackend;
-extern char * _PREHASH_DirPlacesQueryBackend;
-extern char * _PREHASH_DirClassifiedQueryBackend;
-extern char * _PREHASH_DirLandQueryBackend;
-extern char * _PREHASH_DirPopularQueryBackend;
-extern char * _PREHASH_HistoryData;
-extern char * _PREHASH_SnapshotID;
-extern char * _PREHASH_Aspect;
-extern char * _PREHASH_ParamSize;
-extern char * _PREHASH_VoteCast;
-extern char * _PREHASH_CastsShadows;
-extern char * _PREHASH_EveryoneMask;
-extern char * _PREHASH_ObjectSpinUpdate;
-extern char * _PREHASH_MaturePublish;
-extern char * _PREHASH_UseExistingAsset;
-extern char * _PREHASH_Powers;
-extern char * _PREHASH_ParcelLocalID;
-extern char * _PREHASH_TeleportCancel;
-extern char * _PREHASH_UnixTime;
-extern char * _PREHASH_QueryFlags;
-extern char * _PREHASH_AlwaysRun;
-extern char * _PREHASH_Bottom;
-extern char * _PREHASH_ButtonData;
-extern char * _PREHASH_SoundData;
-extern char * _PREHASH_ViewerStats;
-extern char * _PREHASH_RegionHandshake;
-extern char * _PREHASH_ObjectDescription;
-extern char * _PREHASH_Description;
-extern char * _PREHASH_ParamType;
-extern char * _PREHASH_UUIDNameReply;
-extern char * _PREHASH_UUIDGroupNameReply;
-extern char * _PREHASH_SaveAssetIntoInventory;
-extern char * _PREHASH_UserInfo;
-extern char * _PREHASH_AnimSequenceID;
-extern char * _PREHASH_NVPairs;
-extern char * _PREHASH_GroupNoticesListRequest;
-extern char * _PREHASH_ParcelAccessListRequest;
-extern char * _PREHASH_MuteListRequest;
-extern char * _PREHASH_RpcChannelRequest;
-extern char * _PREHASH_LandStatRequest;
-extern char * _PREHASH_PlacesQuery;
-extern char * _PREHASH_DirPlacesQuery;
-extern char * _PREHASH_SortOrder;
-extern char * _PREHASH_Hunter;
-extern char * _PREHASH_SunAngVelocity;
-extern char * _PREHASH_BinaryBucket;
-extern char * _PREHASH_ImagePacket;
-extern char * _PREHASH_StartGroupProposal;
-extern char * _PREHASH_EnergyLevel;
-extern char * _PREHASH_PriceForListing;
-extern char * _PREHASH_Scale;
-extern char * _PREHASH_EstateCovenantReply;
-extern char * _PREHASH_ParentEstateID;
-extern char * _PREHASH_Extra2;
-extern char * _PREHASH_Throttle;
-extern char * _PREHASH_SimIP;
-extern char * _PREHASH_GodID;
-extern char * _PREHASH_TeleportMinPrice;
-extern char * _PREHASH_VoteItem;
-extern char * _PREHASH_ObjectRotation;
-extern char * _PREHASH_SitRotation;
-extern char * _PREHASH_SnapSelection;
-extern char * _PREHASH_SoundTrigger;
-extern char * _PREHASH_TerrainRaiseLimit;
-extern char * _PREHASH_Quorum;
-extern char * _PREHASH_AgentBlock;
-extern char * _PREHASH_CommandBlock;
-extern char * _PREHASH_PricePublicObjectDecay;
-extern char * _PREHASH_SpawnPointPos;
-extern char * _PREHASH_VolumeDetail;
-extern char * _PREHASH_FromAgentName;
-extern char * _PREHASH_Range;
-extern char * _PREHASH_DirectoryVisibility;
-extern char * _PREHASH_PublicIP;
-extern char * _PREHASH_TeleportFailed;
-extern char * _PREHASH_PreloadSound;
-extern char * _PREHASH_ScreenshotID;
-extern char * _PREHASH_CovenantTimestamp;
-extern char * _PREHASH_OldestUnacked;
-extern char * _PREHASH_SimulatorIP;
-extern char * _PREHASH_Value;
-extern char * _PREHASH_JointAxisOrAnchor;
-extern char * _PREHASH_Test0;
-extern char * _PREHASH_Test1;
-extern char * _PREHASH_Test2;
-extern char * _PREHASH_SunPhase;
-extern char * _PREHASH_ParcelDivide;
-extern char * _PREHASH_PriceObjectClaim;
-extern char * _PREHASH_Field;
-extern char * _PREHASH_Ratio;
-extern char * _PREHASH_JoinGroupReply;
-extern char * _PREHASH_LiveHelpGroupReply;
-extern char * _PREHASH_Score;
-extern char * _PREHASH_Image;
-extern char * _PREHASH_ObjectClickAction;
-extern char * _PREHASH_Parameter;
-extern char * _PREHASH_Flags;
-extern char * _PREHASH_Plane;
-extern char * _PREHASH_Width;
-extern char * _PREHASH_Right;
-extern char * _PREHASH_DirFindQuery;
-extern char * _PREHASH_Textures;
-extern char * _PREHASH_EventData;
-extern char * _PREHASH_Final;
-extern char * _PREHASH_System;
-extern char * _PREHASH_TelehubPos;
-extern char * _PREHASH_ReportAutosaveCrash;
-extern char * _PREHASH_CreateTrustedCircuit;
-extern char * _PREHASH_DenyTrustedCircuit;
-extern char * _PREHASH_RequestTrustedCircuit;
-extern char * _PREHASH_Codec;
-extern char * _PREHASH_Modal;
-extern char * _PREHASH_ChildAgentUnknown;
-extern char * _PREHASH_LandingType;
-extern char * _PREHASH_ScriptRunningReply;
-extern char * _PREHASH_Reply;
-extern char * _PREHASH_GroupAccountDetailsReply;
-extern char * _PREHASH_TelehubRot;
-extern char * _PREHASH_AcceptFriendship;
-extern char * _PREHASH_ItemType;
-extern char * _PREHASH_DwellInfo;
-extern char * _PREHASH_AgentResume;
-extern char * _PREHASH_MailFilter;
-extern char * _PREHASH_Disconnect;
-extern char * _PREHASH_SimPosition;
-extern char * _PREHASH_SimWideTotalPrims;
-extern char * _PREHASH_Index;
-extern char * _PREHASH_SimFilename;
-extern char * _PREHASH_LastOwnerID;
-extern char * _PREHASH_GroupNoticeRequest;
-extern char * _PREHASH_EmailMessageRequest;
-extern char * _PREHASH_MapItemRequest;
-extern char * _PREHASH_AgentCount;
-extern char * _PREHASH_MessageBlock;
-extern char * _PREHASH_FuseBlock;
-extern char * _PREHASH_AgentGroupData;
-extern char * _PREHASH_ClassifiedInfoUpdate;
-extern char * _PREHASH_RegionPos;
-extern char * _PREHASH_ParcelMediaUpdate;
-extern char * _PREHASH_NoticeID;
-extern char * _PREHASH_GridX;
-extern char * _PREHASH_GridY;
-extern char * _PREHASH_Title;
-extern char * _PREHASH_AuctionID;
-extern char * _PREHASH_VoteType;
-extern char * _PREHASH_CategoryID;
-extern char * _PREHASH_Token;
-extern char * _PREHASH_AggregatePerms;
-extern char * _PREHASH_ObjectSelect;
-extern char * _PREHASH_ForceObjectSelect;
-extern char * _PREHASH_Price;
-extern char * _PREHASH_SunDirection;
-extern char * _PREHASH_FromName;
-extern char * _PREHASH_ChangeInventoryItemFlags;
-extern char * _PREHASH_Force;
-extern char * _PREHASH_TransactionBlock;
-extern char * _PREHASH_PowersMask;
-extern char * _PREHASH_Stamp;
-extern char * _PREHASH_TotalCredits;
-extern char * _PREHASH_State;
-extern char * _PREHASH_TextureIndex;
-extern char * _PREHASH_InviteeID;
-extern char * _PREHASH_ParcelReclaim;
-extern char * _PREHASH_Money;
-extern char * _PREHASH_PathTwist;
-extern char * _PREHASH_AuthBuyerID;
-extern char * _PREHASH_Color;
-extern char * _PREHASH_SourceType;
-extern char * _PREHASH_World;
-extern char * _PREHASH_QueryData;
-extern char * _PREHASH_Users;
-extern char * _PREHASH_SysOS;
-extern char * _PREHASH_Notes;
-extern char * _PREHASH_AvatarID;
-extern char * _PREHASH_FounderID;
-extern char * _PREHASH_EndPointID;
-extern char * _PREHASH_LocationLookAt;
-extern char * _PREHASH_Sound;
-extern char * _PREHASH_Cover;
-extern char * _PREHASH_TotalObjectCount;
-extern char * _PREHASH_TextureEntry;
-extern char * _PREHASH_SquareMetersCommitted;
-extern char * _PREHASH_ChannelID;
-extern char * _PREHASH_Dwell;
-extern char * _PREHASH_North;
-extern char * _PREHASH_AgentUpdate;
-extern char * _PREHASH_PickGodDelete;
-extern char * _PREHASH_HostName;
-extern char * _PREHASH_PriceParcelClaim;
-extern char * _PREHASH_ParcelClaim;
-extern char * _PREHASH_AgentPowers;
-extern char * _PREHASH_ProfileHollow;
-extern char * _PREHASH_GroupRoleChanges;
-extern char * _PREHASH_Count;
-extern char * _PREHASH_South;
-extern char * _PREHASH_ObjectUpdateCompressed;
-extern char * _PREHASH_MuteFlags;
-extern char * _PREHASH_Group;
-extern char * _PREHASH_AgentPause;
-extern char * _PREHASH_LanguagesText;
-extern char * _PREHASH_Error;
-extern char * _PREHASH_InternalScriptMail;
-extern char * _PREHASH_FindAgent;
-extern char * _PREHASH_AgentData;
-extern char * _PREHASH_FolderData;
-extern char * _PREHASH_AssetBlock;
-extern char * _PREHASH_AcceptNotices;
-extern char * _PREHASH_SetGroupAcceptNotices;
-extern char * _PREHASH_CloseCircuit;
-extern char * _PREHASH_TeleportFinish;
-extern char * _PREHASH_PathRevolutions;
-extern char * _PREHASH_ClassifiedInfoReply;
-extern char * _PREHASH_ParcelInfoReply;
-extern char * _PREHASH_AutosaveData;
-extern char * _PREHASH_SetStartLocation;
-extern char * _PREHASH_PassHours;
-extern char * _PREHASH_AttachmentPt;
-extern char * _PREHASH_ParcelFlags;
-extern char * _PREHASH_NumVotes;
-extern char * _PREHASH_AvatarPickerRequest;
-extern char * _PREHASH_TeleportLocationRequest;
-extern char * _PREHASH_DataHomeLocationRequest;
-extern char * _PREHASH_EventNotificationAddRequest;
-extern char * _PREHASH_ParcelDwellRequest;
-extern char * _PREHASH_EventLocationRequest;
-extern char * _PREHASH_SetStartLocationRequest;
-extern char * _PREHASH_QueryStart;
-extern char * _PREHASH_EjectData;
-extern char * _PREHASH_AvatarTextureUpdate;
-extern char * _PREHASH_RPCServerPort;
-extern char * _PREHASH_Bytes;
-extern char * _PREHASH_Extra;
-extern char * _PREHASH_ForceScriptControlRelease;
-extern char * _PREHASH_ParcelRelease;
-extern char * _PREHASH_VFileType;
-extern char * _PREHASH_EjectGroupMemberReply;
-extern char * _PREHASH_ImageData;
-extern char * _PREHASH_SimulatorViewerTimeMessage;
-extern char * _PREHASH_Rotation;
-extern char * _PREHASH_Selection;
-extern char * _PREHASH_TransactionData;
-extern char * _PREHASH_OperationData;
-extern char * _PREHASH_ExpirationDate;
-extern char * _PREHASH_ParcelDeedToGroup;
-extern char * _PREHASH_AvatarPicksReply;
-extern char * _PREHASH_GroupTitlesReply;
-extern char * _PREHASH_AgentInfo;
-extern char * _PREHASH_MoneyTransferBackend;
-extern char * _PREHASH_NextOwnerMask;
-extern char * _PREHASH_MuteData;
-extern char * _PREHASH_PassPrice;
-extern char * _PREHASH_SourceID;
-extern char * _PREHASH_ChangeUserRights;
-extern char * _PREHASH_TeleportFlags;
-extern char * _PREHASH_SlaveParcelData;
-extern char * _PREHASH_AssetData;
-extern char * _PREHASH_MultipleObjectUpdate;
-extern char * _PREHASH_ObjectUpdate;
-extern char * _PREHASH_ImprovedTerseObjectUpdate;
-extern char * _PREHASH_ConfirmXferPacket;
-extern char * _PREHASH_StartPingCheck;
-extern char * _PREHASH_SimWideDeletes;
-extern char * _PREHASH_LandStatReply;
-extern char * _PREHASH_IsPhantom;
-extern char * _PREHASH_AgentList;
-extern char * _PREHASH_SimApproved;
-extern char * _PREHASH_RezObject;
-extern char * _PREHASH_TaskLocalID;
-extern char * _PREHASH_ClaimDate;
-extern char * _PREHASH_MergeParcel;
-extern char * _PREHASH_Priority;
-extern char * _PREHASH_QueryText;
-extern char * _PREHASH_GroupNoticeAdd;
-extern char * _PREHASH_ReturnType;
-extern char * _PREHASH_FetchFolders;
-extern char * _PREHASH_SimulatorPublicHostBlock;
-extern char * _PREHASH_HeaderData;
-extern char * _PREHASH_RequestMultipleObjects;
-extern char * _PREHASH_RetrieveInstantMessages;
-extern char * _PREHASH_OpenCircuit;
-extern char * _PREHASH_CrossedRegion;
-extern char * _PREHASH_DirGroupsReply;
-extern char * _PREHASH_AvatarGroupsReply;
-extern char * _PREHASH_EmailMessageReply;
-extern char * _PREHASH_GroupVoteHistoryItemReply;
-extern char * _PREHASH_ViewerPosition;
-extern char * _PREHASH_Position;
-extern char * _PREHASH_ParentEstate;
-extern char * _PREHASH_EstateName;
-extern char * _PREHASH_MuteName;
-extern char * _PREHASH_ParcelRename;
-extern char * _PREHASH_ViewerFilename;
-extern char * _PREHASH_UserReportInternal;
-extern char * _PREHASH_AvatarPropertiesRequest;
-extern char * _PREHASH_ParcelPropertiesRequest;
-extern char * _PREHASH_GroupProfileRequest;
-extern char * _PREHASH_AgentDataUpdateRequest;
-extern char * _PREHASH_PriceObjectScaleFactor;
-extern char * _PREHASH_OpenEnrollment;
-extern char * _PREHASH_GroupData;
-extern char * _PREHASH_RequestGodlikePowers;
-extern char * _PREHASH_GrantGodlikePowers;
-extern char * _PREHASH_TransactionID;
-extern char * _PREHASH_DestinationID;
-extern char * _PREHASH_Controls;
-extern char * _PREHASH_FirstDetachAll;
-extern char * _PREHASH_EstateID;
-extern char * _PREHASH_ImprovedInstantMessage;
-extern char * _PREHASH_CheckParcelSales;
-extern char * _PREHASH_ParcelSales;
-extern char * _PREHASH_CurrentInterval;
-extern char * _PREHASH_PriceRentLight;
-extern char * _PREHASH_MediaAutoScale;
-extern char * _PREHASH_NeighborBlock;
-extern char * _PREHASH_LayerData;
-extern char * _PREHASH_NVPairData;
-extern char * _PREHASH_TeleportLocal;
-extern char * _PREHASH_EjecteeID;
-extern char * _PREHASH_VoteInitiator;
-extern char * _PREHASH_TypeData;
-extern char * _PREHASH_OwnerIDs;
-extern char * _PREHASH_SystemKickUser;
-extern char * _PREHASH_TransactionTime;
-extern char * _PREHASH_TimeToLive;
-extern char * _PREHASH_OldAgentID;
-extern char * _PREHASH_MusicURL;
-extern char * _PREHASH_ParcelPrimBonus;
-extern char * _PREHASH_EjectUser;
-extern char * _PREHASH_CoarseLocationUpdate;
-extern char * _PREHASH_ChildAgentPositionUpdate;
-extern char * _PREHASH_StoreLocal;
-extern char * _PREHASH_GroupName;
-extern char * _PREHASH_PriceParcelRent;
-extern char * _PREHASH_SimStatus;
-extern char * _PREHASH_TransactionSuccess;
-extern char * _PREHASH_LureType;
-extern char * _PREHASH_GroupMask;
-extern char * _PREHASH_SitObject;
-extern char * _PREHASH_Override;
-extern char * _PREHASH_LocomotionState;
-extern char * _PREHASH_PriceUpload;
-extern char * _PREHASH_RemoveParcel;
-extern char * _PREHASH_ConfirmAuctionStart;
-extern char * _PREHASH_RpcScriptRequestInbound;
-extern char * _PREHASH_ActiveGroupID;
-extern char * _PREHASH_ParcelReturnObjects;
-extern char * _PREHASH_TotalObjects;
-extern char * _PREHASH_ObjectExtraParams;
-extern char * _PREHASH_Questions;
-extern char * _PREHASH_TransferAbort;
-extern char * _PREHASH_TransferInventory;
-extern char * _PREHASH_RayTargetID;
-extern char * _PREHASH_ClaimPrice;
-extern char * _PREHASH_ObjectProperties;
-extern char * _PREHASH_ParcelProperties;
-extern char * _PREHASH_EstateOwnerID;
-extern char * _PREHASH_LogoutRequest;
-extern char * _PREHASH_AssetUploadRequest;
-extern char * _PREHASH_TransactionType;
-extern char * _PREHASH_AvatarPropertiesUpdate;
-extern char * _PREHASH_ParcelPropertiesUpdate;
-extern char * _PREHASH_FetchItems;
-extern char * _PREHASH_AbortXfer;
-extern char * _PREHASH_DeRezAck;
-extern char * _PREHASH_TakeControls;
-extern char * _PREHASH_DirLandReply;
-extern char * _PREHASH_MuteType;
-extern char * _PREHASH_IMViaEMail;
-extern char * _PREHASH_RentPrice;
-extern char * _PREHASH_GenericMessage;
-extern char * _PREHASH_ChildAgentAlive;
-extern char * _PREHASH_AssetType;
-extern char * _PREHASH_SpawnPointBlock;
-extern char * _PREHASH_AttachmentBlock;
-extern char * _PREHASH_ObjectMaterial;
-extern char * _PREHASH_OwnerName;
-extern char * _PREHASH_AvatarNotesReply;
-extern char * _PREHASH_CacheID;
-extern char * _PREHASH_OwnerMask;
-extern char * _PREHASH_TransferInventoryAck;
-extern char * _PREHASH_RegionDenyAgeUnverified;
-extern char * _PREHASH_AgeVerificationBlock;
-extern char * _PREHASH_UCoord;
-extern char * _PREHASH_VCoord;
-extern char * _PREHASH_FaceIndex;
-extern char * _PREHASH_StatusData;
-extern char * _PREHASH_ProductSKU;
+extern char const* const _PREHASH_X;
+extern char const* const _PREHASH_Y;
+extern char const* const _PREHASH_Z;
+extern char const* const _PREHASH_AddFlags;
+extern char const* const _PREHASH_FailureInfo;
+extern char const* const _PREHASH_MapData;
+extern char const* const _PREHASH_AddItem;
+extern char const* const _PREHASH_MeanCollision;
+extern char const* const _PREHASH_RezScript;
+extern char const* const _PREHASH_AvatarSitResponse;
+extern char const* const _PREHASH_InventoryAssetResponse;
+extern char const* const _PREHASH_KillObject;
+extern char const* const _PREHASH_ProposalID;
+extern char const* const _PREHASH_SerialNum;
+extern char const* const _PREHASH_Duration;
+extern char const* const _PREHASH_ScriptQuestion;
+extern char const* const _PREHASH_AddCircuitCode;
+extern char const* const _PREHASH_UseCircuitCode;
+extern char const* const _PREHASH_ViewerCircuitCode;
+extern char const* const _PREHASH_ScriptAnswerYes;
+extern char const* const _PREHASH_PartnerID;
+extern char const* const _PREHASH_DirLandQuery;
+extern char const* const _PREHASH_TeleportStart;
+extern char const* const _PREHASH_AboutText;
+extern char const* const _PREHASH_VisualParam;
+extern char const* const _PREHASH_GroupPrims;
+extern char const* const _PREHASH_SelectedPrims;
+extern char const* const _PREHASH_ID;
+extern char const* const _PREHASH_UUIDNameRequest;
+extern char const* const _PREHASH_UUIDGroupNameRequest;
+extern char const* const _PREHASH_GroupAccountTransactionsRequest;
+extern char const* const _PREHASH_MapNameRequest;
+extern char const* const _PREHASH_UpdateSimulator;
+extern char const* const _PREHASH_BillableFactor;
+extern char const* const _PREHASH_ObjectBonusFactor;
+extern char const* const _PREHASH_EnableSimulator;
+extern char const* const _PREHASH_DisableSimulator;
+extern char const* const _PREHASH_ConfirmEnableSimulator;
+extern char const* const _PREHASH_LayerType;
+extern char const* const _PREHASH_OwnerRole;
+extern char const* const _PREHASH_ParcelOverlay;
+extern char const* const _PREHASH_GroupOwned;
+extern char const* const _PREHASH_IP;
+extern char const* const _PREHASH_ChatFromViewer;
+extern char const* const _PREHASH_AvgAgentsInView;
+extern char const* const _PREHASH_AgentsInView;
+extern char const* const _PREHASH_GroupTitle;
+extern char const* const _PREHASH_MapLayerReply;
+extern char const* const _PREHASH_CompoundMsgID;
+extern char const* const _PREHASH_CameraConstraint;
+extern char const* const _PREHASH_DownloadTotals;
+extern char const* const _PREHASH_GenCounter;
+extern char const* const _PREHASH_FrozenData;
+extern char const* const _PREHASH_ChildAgentDying;
+extern char const* const _PREHASH_To;
+extern char const* const _PREHASH_CopyInventoryFromNotecard;
+extern char const* const _PREHASH_RezObjectFromNotecard;
+extern char const* const _PREHASH_ParcelDirFeeCurrent;
+extern char const* const _PREHASH_SeedCapability;
+extern char const* const _PREHASH_ObjectDuplicate;
+extern char const* const _PREHASH_InventoryData;
+extern char const* const _PREHASH_ReplyData;
+extern char const* const _PREHASH_ResetList;
+extern char const* const _PREHASH_MediaID;
+extern char const* const _PREHASH_RelatedRights;
+extern char const* const _PREHASH_RedirectGridX;
+extern char const* const _PREHASH_RedirectGridY;
+extern char const* const _PREHASH_TransferID;
+extern char const* const _PREHASH_TexturesChanged;
+extern char const* const _PREHASH_UserLookAt;
+extern char const* const _PREHASH_TestBlock1;
+extern char const* const _PREHASH_SensedData;
+extern char const* const _PREHASH_UpdateBlock;
+extern char const* const _PREHASH_ClassifiedGodDelete;
+extern char const* const _PREHASH_ObjectGrabUpdate;
+extern char const* const _PREHASH_LocationPos;
+extern char const* const _PREHASH_TaxDate;
+extern char const* const _PREHASH_StartDateTime;
+extern char const* const _PREHASH_ObjectUpdateCached;
+extern char const* const _PREHASH_Packets;
+extern char const* const _PREHASH_FailureType;
+extern char const* const _PREHASH_UpdateGroupInfo;
+extern char const* const _PREHASH_ObjectPermissions;
+extern char const* const _PREHASH_RevokePermissions;
+extern char const* const _PREHASH_UpdateFlags;
+extern char const* const _PREHASH_ObjectExportSelected;
+extern char const* const _PREHASH_RezSelected;
+extern char const* const _PREHASH_AutoPilot;
+extern char const* const _PREHASH_UpdateMuteListEntry;
+extern char const* const _PREHASH_RemoveMuteListEntry;
+extern char const* const _PREHASH_SetSimStatusInDatabase;
+extern char const* const _PREHASH_SetSimPresenceInDatabase;
+extern char const* const _PREHASH_CameraProperty;
+extern char const* const _PREHASH_BrushSize;
+extern char const* const _PREHASH_SimulatorSetMap;
+extern char const* const _PREHASH_RegionPresenceRequestByRegionID;
+extern char const* const _PREHASH_ParcelObjectOwnersReply;
+extern char const* const _PREHASH_GroupMembersReply;
+extern char const* const _PREHASH_GroupRoleMembersReply;
+extern char const* const _PREHASH_RequestRegionInfo;
+extern char const* const _PREHASH_AABBMax;
+extern char const* const _PREHASH_RequestPayPrice;
+extern char const* const _PREHASH_SimulatorPresentAtLocation;
+extern char const* const _PREHASH_AgentRequestSit;
+extern char const* const _PREHASH_AABBMin;
+extern char const* const _PREHASH_ClassifiedFlags;
+extern char const* const _PREHASH_ControlFlags;
+extern char const* const _PREHASH_TeleportRequest;
+extern char const* const _PREHASH_ScriptTeleportRequest;
+extern char const* const _PREHASH_EstateCovenantRequest;
+extern char const* const _PREHASH_DateUTC;
+extern char const* const _PREHASH_TaskIDs;
+extern char const* const _PREHASH_RequestResult;
+extern char const* const _PREHASH_CanAcceptAgents;
+extern char const* const _PREHASH_ObjectSaleInfo;
+extern char const* const _PREHASH_KillChildAgents;
+extern char const* const _PREHASH_Balance;
+extern char const* const _PREHASH_DerezContainer;
+extern char const* const _PREHASH_ObjectData;
+extern char const* const _PREHASH_CameraAtAxis;
+extern char const* const _PREHASH_InfoBlock;
+extern char const* const _PREHASH_OwnershipCost;
+extern char const* const _PREHASH_AvatarNotesUpdate;
+extern char const* const _PREHASH_PID;
+extern char const* const _PREHASH_DirPopularReply;
+extern char const* const _PREHASH_TerrainHeightRange00;
+extern char const* const _PREHASH_SimData;
+extern char const* const _PREHASH_TerrainHeightRange01;
+extern char const* const _PREHASH_TerrainHeightRange10;
+extern char const* const _PREHASH_TerrainHeightRange11;
+extern char const* const _PREHASH_UpdateInventoryItem;
+extern char const* const _PREHASH_UpdateCreateInventoryItem;
+extern char const* const _PREHASH_MoveInventoryItem;
+extern char const* const _PREHASH_CopyInventoryItem;
+extern char const* const _PREHASH_LinkInventoryItem;
+extern char const* const _PREHASH_RemoveInventoryItem;
+extern char const* const _PREHASH_CreateInventoryItem;
+extern char const* const _PREHASH_PathTwistBegin;
+extern char const* const _PREHASH_CRC;
+extern char const* const _PREHASH_AttachmentPoint;
+extern char const* const _PREHASH_TelehubBlock;
+extern char const* const _PREHASH_FOVBlock;
+extern char const* const _PREHASH_StartLocationData;
+extern char const* const _PREHASH_PositionData;
+extern char const* const _PREHASH_TimeSinceLast;
+extern char const* const _PREHASH_MapImage;
+extern char const* const _PREHASH_Objects;
+extern char const* const _PREHASH_URL;
+extern char const* const _PREHASH_CreationDate;
+extern char const* const _PREHASH_JointPivot;
+extern char const* const _PREHASH_FPS;
+extern char const* const _PREHASH_HasTelehub;
+extern char const* const _PREHASH_PathEnd;
+extern char const* const _PREHASH_ScriptDataReply;
+extern char const* const _PREHASH_MapBlockReply;
+extern char const* const _PREHASH_PropertiesData;
+extern char const* const _PREHASH_ViewerEffect;
+extern char const* const _PREHASH_FreezeUser;
+extern char const* const _PREHASH_OwnerPrims;
+extern char const* const _PREHASH_ObjectGrab;
+extern char const* const _PREHASH_ToAgentID;
+extern char const* const _PREHASH_SimulatorMapUpdate;
+extern char const* const _PREHASH_TransferPacket;
+extern char const* const _PREHASH_ObjectName;
+extern char const* const _PREHASH_GroupPowers;
+extern char const* const _PREHASH_OriginalName;
+extern char const* const _PREHASH_CompletePingCheck;
+extern char const* const _PREHASH_OnlineStatus;
+extern char const* const _PREHASH_ObjectDrop;
+extern char const* const _PREHASH_UseBigPackets;
+extern char const* const _PREHASH_GroupNoticesListReply;
+extern char const* const _PREHASH_ParcelAccessListReply;
+extern char const* const _PREHASH_RpcChannelReply;
+extern char const* const _PREHASH_RegionPresenceResponse;
+extern char const* const _PREHASH_CharterMember;
+extern char const* const _PREHASH_EdgeData;
+extern char const* const _PREHASH_NameData;
+extern char const* const _PREHASH_RegionPushOverride;
+extern char const* const _PREHASH_SimName;
+extern char const* const _PREHASH_UserReport;
+extern char const* const _PREHASH_DownloadPriority;
+extern char const* const _PREHASH_ToAgentId;
+extern char const* const _PREHASH_DirPopularQuery;
+extern char const* const _PREHASH_Mag;
+extern char const* const _PREHASH_ParcelPropertiesRequestByID;
+extern char const* const _PREHASH_ObjectLink;
+extern char const* const _PREHASH_RpcScriptReplyInbound;
+extern char const* const _PREHASH_RezData;
+extern char const* const _PREHASH_RemoveInventoryObjects;
+extern char const* const _PREHASH_GroupProposalBallot;
+extern char const* const _PREHASH_RPCServerIP;
+extern char const* const _PREHASH_Far;
+extern char const* const _PREHASH_GodSessionID;
+extern char const* const _PREHASH_FLAboutText;
+extern char const* const _PREHASH_RegionHandshakeReply;
+extern char const* const _PREHASH_GroupActiveProposalItemReply;
+extern char const* const _PREHASH_MapItemReply;
+extern char const* const _PREHASH_Seconds;
+extern char const* const _PREHASH_UpdateUserInfo;
+extern char const* const _PREHASH_AggregatePermTexturesOwner;
+extern char const* const _PREHASH_Set;
+extern char const* const _PREHASH_NewName;
+extern char const* const _PREHASH_Key;
+extern char const* const _PREHASH_AgentID;
+extern char const* const _PREHASH_EventNotificationRemoveRequest;
+extern char const* const _PREHASH_NewFolderID;
+extern char const* const _PREHASH_Arc;
+extern char const* const _PREHASH_RegionX;
+extern char const* const _PREHASH_RegionY;
+extern char const* const _PREHASH_RequestData;
+extern char const* const _PREHASH_Msg;
+extern char const* const _PREHASH_Top;
+extern char const* const _PREHASH_MiscStats;
+extern char const* const _PREHASH_ImageID;
+extern char const* const _PREHASH_DataPacket;
+extern char const* const _PREHASH_You;
+extern char const* const _PREHASH_ScriptControlChange;
+extern char const* const _PREHASH_LoadURL;
+extern char const* const _PREHASH_SetCPURatio;
+extern char const* const _PREHASH_NameValueData;
+extern char const* const _PREHASH_AtomicPassObject;
+extern char const* const _PREHASH_ErrorMessage;
+extern char const* const _PREHASH_ViewerFrozenMessage;
+extern char const* const _PREHASH_HealthMessage;
+extern char const* const _PREHASH_LogTextMessage;
+extern char const* const _PREHASH_TimeDilation;
+extern char const* const _PREHASH_RemoveContribution;
+extern char const* const _PREHASH_Contribution;
+extern char const* const _PREHASH_SetGroupContribution;
+extern char const* const _PREHASH_Offline;
+extern char const* const _PREHASH_AgentIsNowWearing;
+extern char const* const _PREHASH_Members;
+extern char const* const _PREHASH_FailedResends;
+extern char const* const _PREHASH_SecPerDay;
+extern char const* const _PREHASH_CameraCenter;
+extern char const* const _PREHASH_CameraLeftAxis;
+extern char const* const _PREHASH_ExBlock;
+extern char const* const _PREHASH_Channel;
+extern char const* const _PREHASH_NetTest;
+extern char const* const _PREHASH_DiscardLevel;
+extern char const* const _PREHASH_LayerID;
+extern char const* const _PREHASH_GrabOffset;
+extern char const* const _PREHASH_SimPort;
+extern char const* const _PREHASH_PricePerMeter;
+extern char const* const _PREHASH_RegionFlags;
+extern char const* const _PREHASH_VoteResult;
+extern char const* const _PREHASH_ParcelDirFeeEstimate;
+extern char const* const _PREHASH_ModifyBlock;
+extern char const* const _PREHASH_InventoryBlock;
+extern char const* const _PREHASH_ReplyBlock;
+extern char const* const _PREHASH_ValidUntil;
+extern char const* const _PREHASH_VelocityInterpolateOn;
+extern char const* const _PREHASH_ClassifiedDelete;
+extern char const* const _PREHASH_RegionDenyAnonymous;
+extern char const* const _PREHASH_FLImageID;
+extern char const* const _PREHASH_AllowPublish;
+extern char const* const _PREHASH_SitName;
+extern char const* const _PREHASH_RegionsVisited;
+extern char const* const _PREHASH_DirClassifiedReply;
+extern char const* const _PREHASH_AvatarClassifiedReply;
+extern char const* const _PREHASH_MediaURL;
+extern char const* const _PREHASH_CompleteAgentMovement;
+extern char const* const _PREHASH_ClassifiedID;
+extern char const* const _PREHASH_LocalID;
+extern char const* const _PREHASH_SpaceIP;
+extern char const* const _PREHASH_RemoveItem;
+extern char const* const _PREHASH_LogFailedMoneyTransaction;
+extern char const* const _PREHASH_ViewerStartAuction;
+extern char const* const _PREHASH_StartAuction;
+extern char const* const _PREHASH_DuplicateFlags;
+extern char const* const _PREHASH_RegionInfo2;
+extern char const* const _PREHASH_TextColor;
+extern char const* const _PREHASH_SlaveID;
+extern char const* const _PREHASH_Charter;
+extern char const* const _PREHASH_AlertData;
+extern char const* const _PREHASH_AlertInfo;
+extern char const* const _PREHASH_TargetBlock;
+extern char const* const _PREHASH_CheckParcelAuctions;
+extern char const* const _PREHASH_ParcelAuctions;
+extern char const* const _PREHASH_OwnerIsGroup;
+extern char const* const _PREHASH_NameValuePair;
+extern char const* const _PREHASH_RemoveNameValuePair;
+extern char const* const _PREHASH_BulkUpdateInventory;
+extern char const* const _PREHASH_UpdateTaskInventory;
+extern char const* const _PREHASH_RemoveTaskInventory;
+extern char const* const _PREHASH_MoveTaskInventory;
+extern char const* const _PREHASH_RequestTaskInventory;
+extern char const* const _PREHASH_ReplyTaskInventory;
+extern char const* const _PREHASH_AggregatePermInventory;
+extern char const* const _PREHASH_GroupAccountTransactionsReply;
+extern char const* const _PREHASH_SimulatorInfo;
+extern char const* const _PREHASH_WearableData;
+extern char const* const _PREHASH_Enabled;
+extern char const* const _PREHASH_Savings;
+extern char const* const _PREHASH_SimulatorLoad;
+extern char const* const _PREHASH_InternalRegionIP;
+extern char const* const _PREHASH_ExternalRegionIP;
+extern char const* const _PREHASH_TotalPairs;
+extern char const* const _PREHASH_CreateGroupRequest;
+extern char const* const _PREHASH_JoinGroupRequest;
+extern char const* const _PREHASH_LeaveGroupRequest;
+extern char const* const _PREHASH_InviteGroupRequest;
+extern char const* const _PREHASH_LiveHelpGroupRequest;
+extern char const* const _PREHASH_PriceParcelClaimFactor;
+extern char const* const _PREHASH_BillableArea;
+extern char const* const _PREHASH_ObjectID;
+extern char const* const _PREHASH_ObjectFlagUpdate;
+extern char const* const _PREHASH_GroupRoleUpdate;
+extern char const* const _PREHASH_RequestInventoryAsset;
+extern char const* const _PREHASH_ChangedGrid;
+extern char const* const _PREHASH_AgentDropGroup;
+extern char const* const _PREHASH_Details;
+extern char const* const _PREHASH_LocationX;
+extern char const* const _PREHASH_SaleType;
+extern char const* const _PREHASH_LocationY;
+extern char const* const _PREHASH_LocationZ;
+extern char const* const _PREHASH_EconomyData;
+extern char const* const _PREHASH_HeadRotation;
+extern char const* const _PREHASH_DeleteOnCompletion;
+extern char const* const _PREHASH_PublicPort;
+extern char const* const _PREHASH_DirClassifiedQuery;
+extern char const* const _PREHASH_CallbackID;
+extern char const* const _PREHASH_RequestParcelTransfer;
+extern char const* const _PREHASH_RoleCount;
+extern char const* const _PREHASH_ObjectCapacity;
+extern char const* const _PREHASH_RequestID;
+extern char const* const _PREHASH_RequestXfer;
+extern char const* const _PREHASH_ObjectTaxCurrent;
+extern char const* const _PREHASH_LightTaxCurrent;
+extern char const* const _PREHASH_LandTaxCurrent;
+extern char const* const _PREHASH_GroupTaxCurrent;
+extern char const* const _PREHASH_FetchInventoryDescendents;
+extern char const* const _PREHASH_InventoryDescendents;
+extern char const* const _PREHASH_Descendents;
+extern char const* const _PREHASH_PurgeInventoryDescendents;
+extern char const* const _PREHASH_ShowDir;
+extern char const* const _PREHASH_IsOwner;
+extern char const* const _PREHASH_Timestamp;
+extern char const* const _PREHASH_GlobalPos;
+extern char const* const _PREHASH_GrabOffsetInitial;
+extern char const* const _PREHASH_IsTrial;
+extern char const* const _PREHASH_ObjectDuplicateOnRay;
+extern char const* const _PREHASH_GroupMembershipCount;
+extern char const* const _PREHASH_MethodData;
+extern char const* const _PREHASH_ActivateGestures;
+extern char const* const _PREHASH_DeactivateGestures;
+extern char const* const _PREHASH_ProposalData;
+extern char const* const _PREHASH_PosGlobal;
+extern char const* const _PREHASH_SearchID;
+extern char const* const _PREHASH_RezMultipleAttachmentsFromInv;
+extern char const* const _PREHASH_SearchName;
+extern char const* const _PREHASH_VersionString;
+extern char const* const _PREHASH_CreateGroupReply;
+extern char const* const _PREHASH_LeaveGroupReply;
+extern char const* const _PREHASH_ActualArea;
+extern char const* const _PREHASH_Message;
+extern char const* const _PREHASH_ClickAction;
+extern char const* const _PREHASH_AssetUploadComplete;
+extern char const* const _PREHASH_RequestType;
+extern char const* const _PREHASH_UUID;
+extern char const* const _PREHASH_BaseMask;
+extern char const* const _PREHASH_NetBlock;
+extern char const* const _PREHASH_GlobalX;
+extern char const* const _PREHASH_GlobalY;
+extern char const* const _PREHASH_CopyRotates;
+extern char const* const _PREHASH_KickUserAck;
+extern char const* const _PREHASH_TopPick;
+extern char const* const _PREHASH_SessionID;
+extern char const* const _PREHASH_GlobalZ;
+extern char const* const _PREHASH_DeclineFriendship;
+extern char const* const _PREHASH_FormFriendship;
+extern char const* const _PREHASH_TerminateFriendship;
+extern char const* const _PREHASH_TaskData;
+extern char const* const _PREHASH_SimWideMaxPrims;
+extern char const* const _PREHASH_TotalPrims;
+extern char const* const _PREHASH_ProfileBegin;
+extern char const* const _PREHASH_Request;
+extern char const* const _PREHASH_GroupAccountDetailsRequest;
+extern char const* const _PREHASH_GroupActiveProposalsRequest;
+extern char const* const _PREHASH_StringValue;
+extern char const* const _PREHASH_Version;
+extern char const* const _PREHASH_OtherCount;
+extern char const* const _PREHASH_MemberCount;
+extern char const* const _PREHASH_ChatData;
+extern char const* const _PREHASH_IsGroupOwned;
+extern char const* const _PREHASH_EnergyEfficiency;
+extern char const* const _PREHASH_PickInfoUpdate;
+extern char const* const _PREHASH_PickDelete;
+extern char const* const _PREHASH_ScriptReset;
+extern char const* const _PREHASH_Requester;
+extern char const* const _PREHASH_ForSale;
+extern char const* const _PREHASH_NearestLandingRegionReply;
+extern char const* const _PREHASH_ParcelID;
+extern char const* const _PREHASH_Godlike;
+extern char const* const _PREHASH_TotalDebits;
+extern char const* const _PREHASH_Direction;
+extern char const* const _PREHASH_HealthData;
+extern char const* const _PREHASH_LeftAxis;
+extern char const* const _PREHASH_LocationBlock;
+extern char const* const _PREHASH_ObjectImage;
+extern char const* const _PREHASH_TerrainStartHeight00;
+extern char const* const _PREHASH_TerrainStartHeight01;
+extern char const* const _PREHASH_TerrainStartHeight10;
+extern char const* const _PREHASH_TerrainStartHeight11;
+extern char const* const _PREHASH_WaterHeight;
+extern char const* const _PREHASH_FetchInventoryReply;
+extern char const* const _PREHASH_GroupAccountSummaryReply;
+extern char const* const _PREHASH_AttachedSound;
+extern char const* const _PREHASH_ParamInUse;
+extern char const* const _PREHASH_GodKickUser;
+extern char const* const _PREHASH_PickName;
+extern char const* const _PREHASH_TaskName;
+extern char const* const _PREHASH_ObjectCount;
+extern char const* const _PREHASH_RegionPresenceRequestByHandle;
+extern char const* const _PREHASH_RezSingleAttachmentFromInv;
+extern char const* const _PREHASH_ChildAgentUpdate;
+extern char const* const _PREHASH_IsOwnerGroup;
+extern char const* const _PREHASH_AgentHeightWidth;
+extern char const* const _PREHASH_VerticalAngle;
+extern char const* const _PREHASH_WearableType;
+extern char const* const _PREHASH_AggregatePermNextOwner;
+extern char const* const _PREHASH_ShowInList;
+extern char const* const _PREHASH_UpdateParcel;
+extern char const* const _PREHASH_SetAlwaysRun;
+extern char const* const _PREHASH_NVPair;
+extern char const* const _PREHASH_SearchType;
+extern char const* const _PREHASH_ObjectSpinStart;
+extern char const* const _PREHASH_UseEstateSun;
+extern char const* const _PREHASH_RegionID;
+extern char const* const _PREHASH_AbuseRegionID;
+extern char const* const _PREHASH_Creator;
+extern char const* const _PREHASH_ProposalText;
+extern char const* const _PREHASH_DirEventsReply;
+extern char const* const _PREHASH_EventInfoReply;
+extern char const* const _PREHASH_UserInfoReply;
+extern char const* const _PREHASH_PathRadiusOffset;
+extern char const* const _PREHASH_TextureData;
+extern char const* const _PREHASH_ChatPass;
+extern char const* const _PREHASH_TargetID;
+extern char const* const _PREHASH_DefaultPayPrice;
+extern char const* const _PREHASH_UserLocation;
+extern char const* const _PREHASH_MaxPrims;
+extern char const* const _PREHASH_LandmarkID;
+extern char const* const _PREHASH_InitiateDownload;
+extern char const* const _PREHASH_Name;
+extern char const* const _PREHASH_OtherCleanTime;
+extern char const* const _PREHASH_ParcelSetOtherCleanTime;
+extern char const* const _PREHASH_TeleportPriceExponent;
+extern char const* const _PREHASH_Gain;
+extern char const* const _PREHASH_PacketAck;
+extern char const* const _PREHASH_PathSkew;
+extern char const* const _PREHASH_SimulatorShutdownRequest;
+extern char const* const _PREHASH_NearestLandingRegionRequest;
+extern char const* const _PREHASH_OtherID;
+extern char const* const _PREHASH_MemberID;
+extern char const* const _PREHASH_MapLayerRequest;
+extern char const* const _PREHASH_ObjectScale;
+extern char const* const _PREHASH_TargetIP;
+extern char const* const _PREHASH_Redo;
+extern char const* const _PREHASH_MoneyBalance;
+extern char const* const _PREHASH_TrackAgent;
+extern char const* const _PREHASH_MaxX;
+extern char const* const _PREHASH_Data;
+extern char const* const _PREHASH_MaxY;
+extern char const* const _PREHASH_TextureAnim;
+extern char const* const _PREHASH_ReturnIDs;
+extern char const* const _PREHASH_Date;
+extern char const* const _PREHASH_AgentWearablesUpdate;
+extern char const* const _PREHASH_AgentDataUpdate;
+extern char const* const _PREHASH_GroupDataUpdate;
+extern char const* const _PREHASH_Hash;
+extern char const* const _PREHASH_AgentGroupDataUpdate;
+extern char const* const _PREHASH_Left;
+extern char const* const _PREHASH_Mask;
+extern char const* const _PREHASH_ForceMouselook;
+extern char const* const _PREHASH_Success;
+extern char const* const _PREHASH_ObjectGroup;
+extern char const* const _PREHASH_SunHour;
+extern char const* const _PREHASH_MinX;
+extern char const* const _PREHASH_ScriptSensorReply;
+extern char const* const _PREHASH_MinY;
+extern char const* const _PREHASH_Command;
+extern char const* const _PREHASH_Desc;
+extern char const* const _PREHASH_AttachmentNeedsSave;
+extern char const* const _PREHASH_HistoryItemData;
+extern char const* const _PREHASH_AgentCachedTexture;
+extern char const* const _PREHASH_Subject;
+extern char const* const _PREHASH_East;
+extern char const* const _PREHASH_QueryReplies;
+extern char const* const _PREHASH_ObjectCategory;
+extern char const* const _PREHASH_Time;
+extern char const* const _PREHASH_CreateLandmarkForEvent;
+extern char const* const _PREHASH_ParentID;
+extern char const* const _PREHASH_Ping;
+extern char const* const _PREHASH_Perp;
+extern char const* const _PREHASH_Code;
+extern char const* const _PREHASH_InvType;
+extern char const* const _PREHASH_AgentFOV;
+extern char const* const _PREHASH_Audible;
+extern char const* const _PREHASH_AuctionData;
+extern char const* const _PREHASH_IDBlock;
+extern char const* const _PREHASH_West;
+extern char const* const _PREHASH_Undo;
+extern char const* const _PREHASH_TotalNumItems;
+extern char const* const _PREHASH_Info;
+extern char const* const _PREHASH_Area;
+extern char const* const _PREHASH_SimCrashed;
+extern char const* const _PREHASH_Text;
+extern char const* const _PREHASH_PriceGroupCreate;
+extern char const* const _PREHASH_ObjectShape;
+extern char const* const _PREHASH_GroupRoleDataReply;
+extern char const* const _PREHASH_MuteCRC;
+extern char const* const _PREHASH_Size;
+extern char const* const _PREHASH_FromAddress;
+extern char const* const _PREHASH_Body;
+extern char const* const _PREHASH_FileData;
+extern char const* const _PREHASH_List;
+extern char const* const _PREHASH_KickUser;
+extern char const* const _PREHASH_OtherPrims;
+extern char const* const _PREHASH_RunTime;
+extern char const* const _PREHASH_GrantUserRights;
+extern char const* const _PREHASH_RpcScriptRequestInboundForward;
+extern char const* const _PREHASH_More;
+extern char const* const _PREHASH_Majority;
+extern char const* const _PREHASH_MetersTraveled;
+extern char const* const _PREHASH_Stat;
+extern char const* const _PREHASH_SoundID;
+extern char const* const _PREHASH_Item;
+extern char const* const _PREHASH_User;
+extern char const* const _PREHASH_Prey;
+extern char const* const _PREHASH_RayStart;
+extern char const* const _PREHASH_UsecSinceStart;
+extern char const* const _PREHASH_ParcelData;
+extern char const* const _PREHASH_CameraUpAxis;
+extern char const* const _PREHASH_ScriptDialog;
+extern char const* const _PREHASH_MasterParcelData;
+extern char const* const _PREHASH_Invalid;
+extern char const* const _PREHASH_ProfileCurve;
+extern char const* const _PREHASH_ParcelAccessListUpdate;
+extern char const* const _PREHASH_MuteListUpdate;
+extern char const* const _PREHASH_SendPacket;
+extern char const* const _PREHASH_SendXferPacket;
+extern char const* const _PREHASH_RegionDenyIdentified;
+extern char const* const _PREHASH_NotecardItemID;
+extern char const* const _PREHASH_LastName;
+extern char const* const _PREHASH_From;
+extern char const* const _PREHASH_RoleChange;
+extern char const* const _PREHASH_Port;
+extern char const* const _PREHASH_MemberTitle;
+extern char const* const _PREHASH_LogParcelChanges;
+extern char const* const _PREHASH_AgentCachedTextureResponse;
+extern char const* const _PREHASH_DeRezObject;
+extern char const* const _PREHASH_IsTemporary;
+extern char const* const _PREHASH_InsigniaID;
+extern char const* const _PREHASH_CheckFlags;
+extern char const* const _PREHASH_EventID;
+extern char const* const _PREHASH_Selected;
+extern char const* const _PREHASH_FromAgentId;
+extern char const* const _PREHASH_Type;
+extern char const* const _PREHASH_ChatType;
+extern char const* const _PREHASH_ReportData;
+extern char const* const _PREHASH_RequestBlock;
+extern char const* const _PREHASH_GrantData;
+extern char const* const _PREHASH_DetachAttachmentIntoInv;
+extern char const* const _PREHASH_ParcelDisableObjects;
+extern char const* const _PREHASH_Sections;
+extern char const* const _PREHASH_GodLevel;
+extern char const* const _PREHASH_PayPriceReply;
+extern char const* const _PREHASH_QueryID;
+extern char const* const _PREHASH_CameraEyeOffset;
+extern char const* const _PREHASH_AgentPosition;
+extern char const* const _PREHASH_GrabPosition;
+extern char const* const _PREHASH_OnlineNotification;
+extern char const* const _PREHASH_OfflineNotification;
+extern char const* const _PREHASH_SendPostcard;
+extern char const* const _PREHASH_RequestFlags;
+extern char const* const _PREHASH_GroupAccountSummaryRequest;
+extern char const* const _PREHASH_GroupVoteHistoryRequest;
+extern char const* const _PREHASH_ParamValue;
+extern char const* const _PREHASH_MaxAgents;
+extern char const* const _PREHASH_CreateNewOutfitAttachments;
+extern char const* const _PREHASH_RegionHandle;
+extern char const* const _PREHASH_TeleportProgress;
+extern char const* const _PREHASH_AgentQuitCopy;
+extern char const* const _PREHASH_AvatarInterestsUpdate;
+extern char const* const _PREHASH_GroupNoticeID;
+extern char const* const _PREHASH_ParcelName;
+extern char const* const _PREHASH_PriceObjectRent;
+extern char const* const _PREHASH_OfferCallingCard;
+extern char const* const _PREHASH_AcceptCallingCard;
+extern char const* const _PREHASH_DeclineCallingCard;
+extern char const* const _PREHASH_AgentAccess;
+extern char const* const _PREHASH_AgentLegacyAccess;
+extern char const* const _PREHASH_AgentMaxAccess;
+extern char const* const _PREHASH_DataHomeLocationReply;
+extern char const* const _PREHASH_EventLocationReply;
+extern char const* const _PREHASH_TerseDateID;
+extern char const* const _PREHASH_ObjectOwner;
+extern char const* const _PREHASH_AssetID;
+extern char const* const _PREHASH_AlertMessage;
+extern char const* const _PREHASH_AgentAlertMessage;
+extern char const* const _PREHASH_EstateOwnerMessage;
+extern char const* const _PREHASH_ParcelMediaCommandMessage;
+extern char const* const _PREHASH_Auction;
+extern char const* const _PREHASH_Category;
+extern char const* const _PREHASH_FilePath;
+extern char const* const _PREHASH_ItemFlags;
+extern char const* const _PREHASH_Invoice;
+extern char const* const _PREHASH_IntervalDays;
+extern char const* const _PREHASH_PathScaleX;
+extern char const* const _PREHASH_FromTaskID;
+extern char const* const _PREHASH_PathScaleY;
+extern char const* const _PREHASH_TimeInfo;
+extern char const* const _PREHASH_PublicCount;
+extern char const* const _PREHASH_ParcelJoin;
+extern char const* const _PREHASH_GroupRolesCount;
+extern char const* const _PREHASH_SimulatorBlock;
+extern char const* const _PREHASH_GroupID;
+extern char const* const _PREHASH_AgentVel;
+extern char const* const _PREHASH_RequestImage;
+extern char const* const _PREHASH_NetStats;
+extern char const* const _PREHASH_AgentPos;
+extern char const* const _PREHASH_AgentSit;
+extern char const* const _PREHASH_Material;
+extern char const* const _PREHASH_ObjectDeGrab;
+extern char const* const _PREHASH_VelocityInterpolateOff;
+extern char const* const _PREHASH_AuthorizedBuyerID;
+extern char const* const _PREHASH_AvatarPropertiesReply;
+extern char const* const _PREHASH_GroupProfileReply;
+extern char const* const _PREHASH_SimOwner;
+extern char const* const _PREHASH_SalePrice;
+extern char const* const _PREHASH_Animation;
+extern char const* const _PREHASH_OwnerID;
+extern char const* const _PREHASH_NearestLandingRegionUpdated;
+extern char const* const _PREHASH_PassToAgent;
+extern char const* const _PREHASH_PreyAgent;
+extern char const* const _PREHASH_SimStats;
+extern char const* const _PREHASH_LogoutReply;
+extern char const* const _PREHASH_FeatureDisabled;
+extern char const* const _PREHASH_PhysicalAvatarEventList;
+extern char const* const _PREHASH_ObjectLocalID;
+extern char const* const _PREHASH_Dropped;
+extern char const* const _PREHASH_WebProfilesDisabled;
+extern char const* const _PREHASH_Destination;
+extern char const* const _PREHASH_MasterID;
+extern char const* const _PREHASH_TransferData;
+extern char const* const _PREHASH_WantToMask;
+extern char const* const _PREHASH_ParcelSelectObjects;
+extern char const* const _PREHASH_ExtraParams;
+extern char const* const _PREHASH_CreatorID;
+extern char const* const _PREHASH_Summary;
+extern char const* const _PREHASH_BuyObjectInventory;
+extern char const* const _PREHASH_FetchInventory;
+extern char const* const _PREHASH_InventoryID;
+extern char const* const _PREHASH_PacketNumber;
+extern char const* const _PREHASH_SetFollowCamProperties;
+extern char const* const _PREHASH_ClearFollowCamProperties;
+extern char const* const _PREHASH_SequenceID;
+extern char const* const _PREHASH_DataServerLogout;
+extern char const* const _PREHASH_NameValue;
+extern char const* const _PREHASH_PathShearX;
+extern char const* const _PREHASH_PathShearY;
+extern char const* const _PREHASH_Velocity;
+extern char const* const _PREHASH_SecPerYear;
+extern char const* const _PREHASH_FirstName;
+extern char const* const _PREHASH_AttachedSoundGainChange;
+extern char const* const _PREHASH_LocationID;
+extern char const* const _PREHASH_Running;
+extern char const* const _PREHASH_AgentThrottle;
+extern char const* const _PREHASH_NeighborList;
+extern char const* const _PREHASH_PathTaperX;
+extern char const* const _PREHASH_PathTaperY;
+extern char const* const _PREHASH_AgentRelated;
+extern char const* const _PREHASH_GranterBlock;
+extern char const* const _PREHASH_UseCachedMuteList;
+extern char const* const _PREHASH_FailStats;
+extern char const* const _PREHASH_Tempfile;
+extern char const* const _PREHASH_BuyerID;
+extern char const* const _PREHASH_DirPeopleReply;
+extern char const* const _PREHASH_TransferInfo;
+extern char const* const _PREHASH_AvatarPickerRequestBackend;
+extern char const* const _PREHASH_AvatarPropertiesRequestBackend;
+extern char const* const _PREHASH_UpdateData;
+extern char const* const _PREHASH_SimFPS;
+extern char const* const _PREHASH_ReporterID;
+extern char const* const _PREHASH_ButtonLabel;
+extern char const* const _PREHASH_GranterID;
+extern char const* const _PREHASH_WantToText;
+extern char const* const _PREHASH_ReportType;
+extern char const* const _PREHASH_SimulatorReady;
+extern char const* const _PREHASH_DataBlock;
+extern char const* const _PREHASH_AnimationSourceList;
+extern char const* const _PREHASH_SubscribeLoad;
+extern char const* const _PREHASH_UnsubscribeLoad;
+extern char const* const _PREHASH_Packet;
+extern char const* const _PREHASH_UndoLand;
+extern char const* const _PREHASH_SimAccess;
+extern char const* const _PREHASH_AbuserID;
+extern char const* const _PREHASH_MembershipFee;
+extern char const* const _PREHASH_InviteGroupResponse;
+extern char const* const _PREHASH_CreateInventoryFolder;
+extern char const* const _PREHASH_UpdateInventoryFolder;
+extern char const* const _PREHASH_MoveInventoryFolder;
+extern char const* const _PREHASH_RemoveInventoryFolder;
+extern char const* const _PREHASH_MoneyData;
+extern char const* const _PREHASH_ObjectDeselect;
+extern char const* const _PREHASH_NewAssetID;
+extern char const* const _PREHASH_ObjectAdd;
+extern char const* const _PREHASH_RayEndIsIntersection;
+extern char const* const _PREHASH_CompleteAuction;
+extern char const* const _PREHASH_CircuitCode;
+extern char const* const _PREHASH_AgentMovementComplete;
+extern char const* const _PREHASH_ViewerIP;
+extern char const* const _PREHASH_Header;
+extern char const* const _PREHASH_GestureFlags;
+extern char const* const _PREHASH_XferID;
+extern char const* const _PREHASH_StatValue;
+extern char const* const _PREHASH_TaskID;
+extern char const* const _PREHASH_PickID;
+extern char const* const _PREHASH_RayEnd;
+extern char const* const _PREHASH_Throttles;
+extern char const* const _PREHASH_RebakeAvatarTextures;
+extern char const* const _PREHASH_UpAxis;
+extern char const* const _PREHASH_AgentTextures;
+extern char const* const _PREHASH_NotecardData;
+extern char const* const _PREHASH_Radius;
+extern char const* const _PREHASH_OffCircuit;
+extern char const* const _PREHASH_Access;
+extern char const* const _PREHASH_TitleRoleID;
+extern char const* const _PREHASH_SquareMetersCredit;
+extern char const* const _PREHASH_Filename;
+extern char const* const _PREHASH_ClassifiedInfoRequest;
+extern char const* const _PREHASH_ParcelInfoRequest;
+extern char const* const _PREHASH_ParcelObjectOwnersRequest;
+extern char const* const _PREHASH_TeleportLandmarkRequest;
+extern char const* const _PREHASH_EventInfoRequest;
+extern char const* const _PREHASH_MoneyBalanceRequest;
+extern char const* const _PREHASH_GroupMembersRequest;
+extern char const* const _PREHASH_GroupRoleMembersRequest;
+extern char const* const _PREHASH_ChatFromSimulator;
+extern char const* const _PREHASH_OldFolderID;
+extern char const* const _PREHASH_UserInfoRequest;
+extern char const* const _PREHASH_TextureID;
+extern char const* const _PREHASH_ProfileURL;
+extern char const* const _PREHASH_Handle;
+extern char const* const _PREHASH_ButtonIndex;
+extern char const* const _PREHASH_GetScriptRunning;
+extern char const* const _PREHASH_SetScriptRunning;
+extern char const* const _PREHASH_Health;
+extern char const* const _PREHASH_CircuitInfo;
+extern char const* const _PREHASH_ObjectBuy;
+extern char const* const _PREHASH_ProfileEnd;
+extern char const* const _PREHASH_Effect;
+extern char const* const _PREHASH_TestMessage;
+extern char const* const _PREHASH_ScriptMailRegistration;
+extern char const* const _PREHASH_AgentSetAppearance;
+extern char const* const _PREHASH_AvatarAppearance;
+extern char const* const _PREHASH_RegionData;
+extern char const* const _PREHASH_RequestingRegionData;
+extern char const* const _PREHASH_LandingRegionData;
+extern char const* const _PREHASH_SitTransform;
+extern char const* const _PREHASH_TerrainBase0;
+extern char const* const _PREHASH_SkillsMask;
+extern char const* const _PREHASH_AtAxis;
+extern char const* const _PREHASH_TerrainBase1;
+extern char const* const _PREHASH_Reason;
+extern char const* const _PREHASH_TerrainBase2;
+extern char const* const _PREHASH_TerrainBase3;
+extern char const* const _PREHASH_Params;
+extern char const* const _PREHASH_PingID;
+extern char const* const _PREHASH_Change;
+extern char const* const _PREHASH_Height;
+extern char const* const _PREHASH_Region;
+extern char const* const _PREHASH_TelehubInfo;
+extern char const* const _PREHASH_StateSave;
+extern char const* const _PREHASH_RoleData;
+extern char const* const _PREHASH_AgentAnimation;
+extern char const* const _PREHASH_AvatarAnimation;
+extern char const* const _PREHASH_LogDwellTime;
+extern char const* const _PREHASH_ParcelGodMarkAsContent;
+extern char const* const _PREHASH_UsePhysics;
+extern char const* const _PREHASH_RegionDenyTransacted;
+extern char const* const _PREHASH_JointType;
+extern char const* const _PREHASH_ObjectTaxEstimate;
+extern char const* const _PREHASH_LightTaxEstimate;
+extern char const* const _PREHASH_LandTaxEstimate;
+extern char const* const _PREHASH_TeleportLandingStatusChanged;
+extern char const* const _PREHASH_GroupTaxEstimate;
+extern char const* const _PREHASH_AvgViewerFPS;
+extern char const* const _PREHASH_Buttons;
+extern char const* const _PREHASH_Sender;
+extern char const* const _PREHASH_Dialog;
+extern char const* const _PREHASH_TargetData;
+extern char const* const _PREHASH_DestID;
+extern char const* const _PREHASH_PricePublicObjectDelete;
+extern char const* const _PREHASH_ObjectDelete;
+extern char const* const _PREHASH_Delete;
+extern char const* const _PREHASH_EventGodDelete;
+extern char const* const _PREHASH_LastTaxDate;
+extern char const* const _PREHASH_MapImageID;
+extern char const* const _PREHASH_EndDateTime;
+extern char const* const _PREHASH_TerrainDetail0;
+extern char const* const _PREHASH_TerrainDetail1;
+extern char const* const _PREHASH_TerrainDetail2;
+extern char const* const _PREHASH_TerrainDetail3;
+extern char const* const _PREHASH_Offset;
+extern char const* const _PREHASH_ObjectDelink;
+extern char const* const _PREHASH_TargetObject;
+extern char const* const _PREHASH_IsEstateManager;
+extern char const* const _PREHASH_CancelAuction;
+extern char const* const _PREHASH_ObjectDetach;
+extern char const* const _PREHASH_Compressed;
+extern char const* const _PREHASH_PathBegin;
+extern char const* const _PREHASH_BypassRaycast;
+extern char const* const _PREHASH_WinnerID;
+extern char const* const _PREHASH_ChannelType;
+extern char const* const _PREHASH_NonExemptMembers;
+extern char const* const _PREHASH_Agents;
+extern char const* const _PREHASH_MemberData;
+extern char const* const _PREHASH_ToGroupID;
+extern char const* const _PREHASH_ImageNotInDatabase;
+extern char const* const _PREHASH_StartDate;
+extern char const* const _PREHASH_AnimID;
+extern char const* const _PREHASH_Serial;
+extern char const* const _PREHASH_AbuseRegionName;
+extern char const* const _PREHASH_ModifyLand;
+extern char const* const _PREHASH_Digest;
+extern char const* const _PREHASH_Victim;
+extern char const* const _PREHASH_Script;
+extern char const* const _PREHASH_PickInfoReply;
+extern char const* const _PREHASH_MoneyBalanceReply;
+extern char const* const _PREHASH_RoutedMoneyBalanceReply;
+extern char const* const _PREHASH_RoleID;
+extern char const* const _PREHASH_RegionInfo;
+extern char const* const _PREHASH_GodUpdateRegionInfo;
+extern char const* const _PREHASH_StartAnim;
+extern char const* const _PREHASH_Action;
+extern char const* const _PREHASH_Location;
+extern char const* const _PREHASH_Rights;
+extern char const* const _PREHASH_SearchDir;
+extern char const* const _PREHASH_TransferRequest;
+extern char const* const _PREHASH_ScriptSensorRequest;
+extern char const* const _PREHASH_MoneyTransferRequest;
+extern char const* const _PREHASH_EjectGroupMemberRequest;
+extern char const* const _PREHASH_SkillsText;
+extern char const* const _PREHASH_Resent;
+extern char const* const _PREHASH_Center;
+extern char const* const _PREHASH_SharedData;
+extern char const* const _PREHASH_PSBlock;
+extern char const* const _PREHASH_UUIDNameBlock;
+extern char const* const _PREHASH_GroupTitleUpdate;
+extern char const* const _PREHASH_Method;
+extern char const* const _PREHASH_TouchName;
+extern char const* const _PREHASH_UpdateType;
+extern char const* const _PREHASH_KickedFromEstateID;
+extern char const* const _PREHASH_CandidateID;
+extern char const* const _PREHASH_ParamData;
+extern char const* const _PREHASH_GodlikeMessage;
+extern char const* const _PREHASH_SystemMessage;
+extern char const* const _PREHASH_BodyRotation;
+extern char const* const _PREHASH_SearchRegions;
+extern char const* const _PREHASH_AnimationData;
+extern char const* const _PREHASH_StatID;
+extern char const* const _PREHASH_ItemID;
+extern char const* const _PREHASH_ScriptDialogReply;
+extern char const* const _PREHASH_RegionIDAndHandleReply;
+extern char const* const _PREHASH_CameraAtOffset;
+extern char const* const _PREHASH_VoteID;
+extern char const* const _PREHASH_ParcelGodForceOwner;
+extern char const* const _PREHASH_Filter;
+extern char const* const _PREHASH_InviteData;
+extern char const* const _PREHASH_PCode;
+extern char const* const _PREHASH_SearchPos;
+extern char const* const _PREHASH_PreyID;
+extern char const* const _PREHASH_TerrainLowerLimit;
+extern char const* const _PREHASH_EventFlags;
+extern char const* const _PREHASH_TallyVotes;
+extern char const* const _PREHASH_Result;
+extern char const* const _PREHASH_LookAt;
+extern char const* const _PREHASH_SearchOrder;
+extern char const* const _PREHASH_PayButton;
+extern char const* const _PREHASH_SelfCount;
+extern char const* const _PREHASH_PacketCount;
+extern char const* const _PREHASH_ParcelBuyPass;
+extern char const* const _PREHASH_OldItemID;
+extern char const* const _PREHASH_RegionPort;
+extern char const* const _PREHASH_PriceEnergyUnit;
+extern char const* const _PREHASH_Bitmap;
+extern char const* const _PREHASH_CacheMissType;
+extern char const* const _PREHASH_VFileID;
+extern char const* const _PREHASH_GroupInsigniaID;
+extern char const* const _PREHASH_Online;
+extern char const* const _PREHASH_KickFlags;
+extern char const* const _PREHASH_CovenantID;
+extern char const* const _PREHASH_SysCPU;
+extern char const* const _PREHASH_EMail;
+extern char const* const _PREHASH_AggregatePermTextures;
+extern char const* const _PREHASH_ChatChannel;
+extern char const* const _PREHASH_ReturnID;
+extern char const* const _PREHASH_ObjectAttach;
+extern char const* const _PREHASH_TargetPort;
+extern char const* const _PREHASH_ObjectSpinStop;
+extern char const* const _PREHASH_FullID;
+extern char const* const _PREHASH_ActivateGroup;
+extern char const* const _PREHASH_SysGPU;
+extern char const* const _PREHASH_AvatarInterestsReply;
+extern char const* const _PREHASH_StartLure;
+extern char const* const _PREHASH_SysRAM;
+extern char const* const _PREHASH_ObjectPosition;
+extern char const* const _PREHASH_SitPosition;
+extern char const* const _PREHASH_StartTime;
+extern char const* const _PREHASH_BornOn;
+extern char const* const _PREHASH_CameraCollidePlane;
+extern char const* const _PREHASH_EconomyDataRequest;
+extern char const* const _PREHASH_TeleportLureRequest;
+extern char const* const _PREHASH_FolderID;
+extern char const* const _PREHASH_RegionHandleRequest;
+extern char const* const _PREHASH_ScriptDataRequest;
+extern char const* const _PREHASH_GroupRoleDataRequest;
+extern char const* const _PREHASH_GroupTitlesRequest;
+extern char const* const _PREHASH_AgentWearablesRequest;
+extern char const* const _PREHASH_MapBlockRequest;
+extern char const* const _PREHASH_LureID;
+extern char const* const _PREHASH_CopyCenters;
+extern char const* const _PREHASH_ParamList;
+extern char const* const _PREHASH_InventorySerial;
+extern char const* const _PREHASH_EdgeDataPacket;
+extern char const* const _PREHASH_AvatarPickerReply;
+extern char const* const _PREHASH_ParcelDwellReply;
+extern char const* const _PREHASH_IsForSale;
+extern char const* const _PREHASH_MuteID;
+extern char const* const _PREHASH_MeanCollisionAlert;
+extern char const* const _PREHASH_CanAcceptTasks;
+extern char const* const _PREHASH_ItemData;
+extern char const* const _PREHASH_AnimationList;
+extern char const* const _PREHASH_Reputation;
+extern char const* const _PREHASH_IntValue;
+extern char const* const _PREHASH_TargetType;
+extern char const* const _PREHASH_Amount;
+extern char const* const _PREHASH_HasAttachment;
+extern char const* const _PREHASH_UpdateAttachment;
+extern char const* const _PREHASH_RemoveAttachment;
+extern char const* const _PREHASH_HeightWidthBlock;
+extern char const* const _PREHASH_RequestObjectPropertiesFamily;
+extern char const* const _PREHASH_ObjectPropertiesFamily;
+extern char const* const _PREHASH_UserData;
+extern char const* const _PREHASH_IsReadable;
+extern char const* const _PREHASH_PathCurve;
+extern char const* const _PREHASH_Status;
+extern char const* const _PREHASH_FromGroup;
+extern char const* const _PREHASH_AlreadyVoted;
+extern char const* const _PREHASH_PlacesReply;
+extern char const* const _PREHASH_DirPlacesReply;
+extern char const* const _PREHASH_ParcelBuy;
+extern char const* const _PREHASH_DirFindQueryBackend;
+extern char const* const _PREHASH_DirPlacesQueryBackend;
+extern char const* const _PREHASH_DirClassifiedQueryBackend;
+extern char const* const _PREHASH_DirLandQueryBackend;
+extern char const* const _PREHASH_DirPopularQueryBackend;
+extern char const* const _PREHASH_HistoryData;
+extern char const* const _PREHASH_SnapshotID;
+extern char const* const _PREHASH_Aspect;
+extern char const* const _PREHASH_ParamSize;
+extern char const* const _PREHASH_VoteCast;
+extern char const* const _PREHASH_CastsShadows;
+extern char const* const _PREHASH_EveryoneMask;
+extern char const* const _PREHASH_ObjectSpinUpdate;
+extern char const* const _PREHASH_MaturePublish;
+extern char const* const _PREHASH_UseExistingAsset;
+extern char const* const _PREHASH_Powers;
+extern char const* const _PREHASH_ParcelLocalID;
+extern char const* const _PREHASH_TeleportCancel;
+extern char const* const _PREHASH_UnixTime;
+extern char const* const _PREHASH_QueryFlags;
+extern char const* const _PREHASH_AlwaysRun;
+extern char const* const _PREHASH_Bottom;
+extern char const* const _PREHASH_ButtonData;
+extern char const* const _PREHASH_SoundData;
+extern char const* const _PREHASH_ViewerStats;
+extern char const* const _PREHASH_RegionHandshake;
+extern char const* const _PREHASH_ObjectDescription;
+extern char const* const _PREHASH_Description;
+extern char const* const _PREHASH_ParamType;
+extern char const* const _PREHASH_UUIDNameReply;
+extern char const* const _PREHASH_UUIDGroupNameReply;
+extern char const* const _PREHASH_SaveAssetIntoInventory;
+extern char const* const _PREHASH_UserInfo;
+extern char const* const _PREHASH_AnimSequenceID;
+extern char const* const _PREHASH_NVPairs;
+extern char const* const _PREHASH_GroupNoticesListRequest;
+extern char const* const _PREHASH_ParcelAccessListRequest;
+extern char const* const _PREHASH_MuteListRequest;
+extern char const* const _PREHASH_RpcChannelRequest;
+extern char const* const _PREHASH_LandStatRequest;
+extern char const* const _PREHASH_PlacesQuery;
+extern char const* const _PREHASH_DirPlacesQuery;
+extern char const* const _PREHASH_SortOrder;
+extern char const* const _PREHASH_Hunter;
+extern char const* const _PREHASH_SunAngVelocity;
+extern char const* const _PREHASH_BinaryBucket;
+extern char const* const _PREHASH_ImagePacket;
+extern char const* const _PREHASH_StartGroupProposal;
+extern char const* const _PREHASH_EnergyLevel;
+extern char const* const _PREHASH_PriceForListing;
+extern char const* const _PREHASH_Scale;
+extern char const* const _PREHASH_EstateCovenantReply;
+extern char const* const _PREHASH_ParentEstateID;
+extern char const* const _PREHASH_Extra2;
+extern char const* const _PREHASH_Throttle;
+extern char const* const _PREHASH_SimIP;
+extern char const* const _PREHASH_GodID;
+extern char const* const _PREHASH_TeleportMinPrice;
+extern char const* const _PREHASH_VoteItem;
+extern char const* const _PREHASH_ObjectRotation;
+extern char const* const _PREHASH_SitRotation;
+extern char const* const _PREHASH_SnapSelection;
+extern char const* const _PREHASH_SoundTrigger;
+extern char const* const _PREHASH_TerrainRaiseLimit;
+extern char const* const _PREHASH_Quorum;
+extern char const* const _PREHASH_AgentBlock;
+extern char const* const _PREHASH_CommandBlock;
+extern char const* const _PREHASH_PricePublicObjectDecay;
+extern char const* const _PREHASH_SpawnPointPos;
+extern char const* const _PREHASH_VolumeDetail;
+extern char const* const _PREHASH_FromAgentName;
+extern char const* const _PREHASH_Range;
+extern char const* const _PREHASH_DirectoryVisibility;
+extern char const* const _PREHASH_PublicIP;
+extern char const* const _PREHASH_TeleportFailed;
+extern char const* const _PREHASH_PreloadSound;
+extern char const* const _PREHASH_ScreenshotID;
+extern char const* const _PREHASH_CovenantTimestamp;
+extern char const* const _PREHASH_OldestUnacked;
+extern char const* const _PREHASH_SimulatorIP;
+extern char const* const _PREHASH_Value;
+extern char const* const _PREHASH_JointAxisOrAnchor;
+extern char const* const _PREHASH_Test0;
+extern char const* const _PREHASH_Test1;
+extern char const* const _PREHASH_Test2;
+extern char const* const _PREHASH_SunPhase;
+extern char const* const _PREHASH_ParcelDivide;
+extern char const* const _PREHASH_PriceObjectClaim;
+extern char const* const _PREHASH_Field;
+extern char const* const _PREHASH_Ratio;
+extern char const* const _PREHASH_JoinGroupReply;
+extern char const* const _PREHASH_LiveHelpGroupReply;
+extern char const* const _PREHASH_Score;
+extern char const* const _PREHASH_Image;
+extern char const* const _PREHASH_ObjectClickAction;
+extern char const* const _PREHASH_Parameter;
+extern char const* const _PREHASH_Flags;
+extern char const* const _PREHASH_Plane;
+extern char const* const _PREHASH_Width;
+extern char const* const _PREHASH_Right;
+extern char const* const _PREHASH_DirFindQuery;
+extern char const* const _PREHASH_Textures;
+extern char const* const _PREHASH_EventData;
+extern char const* const _PREHASH_Final;
+extern char const* const _PREHASH_System;
+extern char const* const _PREHASH_TelehubPos;
+extern char const* const _PREHASH_ReportAutosaveCrash;
+extern char const* const _PREHASH_CreateTrustedCircuit;
+extern char const* const _PREHASH_DenyTrustedCircuit;
+extern char const* const _PREHASH_RequestTrustedCircuit;
+extern char const* const _PREHASH_Codec;
+extern char const* const _PREHASH_Modal;
+extern char const* const _PREHASH_ChildAgentUnknown;
+extern char const* const _PREHASH_LandingType;
+extern char const* const _PREHASH_ScriptRunningReply;
+extern char const* const _PREHASH_Reply;
+extern char const* const _PREHASH_GroupAccountDetailsReply;
+extern char const* const _PREHASH_TelehubRot;
+extern char const* const _PREHASH_AcceptFriendship;
+extern char const* const _PREHASH_ItemType;
+extern char const* const _PREHASH_DwellInfo;
+extern char const* const _PREHASH_AgentResume;
+extern char const* const _PREHASH_MailFilter;
+extern char const* const _PREHASH_Disconnect;
+extern char const* const _PREHASH_SimPosition;
+extern char const* const _PREHASH_SimWideTotalPrims;
+extern char const* const _PREHASH_Index;
+extern char const* const _PREHASH_SimFilename;
+extern char const* const _PREHASH_LastOwnerID;
+extern char const* const _PREHASH_GroupNoticeRequest;
+extern char const* const _PREHASH_EmailMessageRequest;
+extern char const* const _PREHASH_MapItemRequest;
+extern char const* const _PREHASH_AgentCount;
+extern char const* const _PREHASH_MessageBlock;
+extern char const* const _PREHASH_FuseBlock;
+extern char const* const _PREHASH_AgentGroupData;
+extern char const* const _PREHASH_ClassifiedInfoUpdate;
+extern char const* const _PREHASH_RegionPos;
+extern char const* const _PREHASH_ParcelMediaUpdate;
+extern char const* const _PREHASH_NoticeID;
+extern char const* const _PREHASH_GridX;
+extern char const* const _PREHASH_GridY;
+extern char const* const _PREHASH_Title;
+extern char const* const _PREHASH_AuctionID;
+extern char const* const _PREHASH_VoteType;
+extern char const* const _PREHASH_CategoryID;
+extern char const* const _PREHASH_Token;
+extern char const* const _PREHASH_AggregatePerms;
+extern char const* const _PREHASH_ObjectSelect;
+extern char const* const _PREHASH_ForceObjectSelect;
+extern char const* const _PREHASH_Price;
+extern char const* const _PREHASH_SunDirection;
+extern char const* const _PREHASH_FromName;
+extern char const* const _PREHASH_ChangeInventoryItemFlags;
+extern char const* const _PREHASH_Force;
+extern char const* const _PREHASH_TransactionBlock;
+extern char const* const _PREHASH_PowersMask;
+extern char const* const _PREHASH_Stamp;
+extern char const* const _PREHASH_TotalCredits;
+extern char const* const _PREHASH_State;
+extern char const* const _PREHASH_TextureIndex;
+extern char const* const _PREHASH_InviteeID;
+extern char const* const _PREHASH_ParcelReclaim;
+extern char const* const _PREHASH_Money;
+extern char const* const _PREHASH_PathTwist;
+extern char const* const _PREHASH_AuthBuyerID;
+extern char const* const _PREHASH_Color;
+extern char const* const _PREHASH_SourceType;
+extern char const* const _PREHASH_World;
+extern char const* const _PREHASH_QueryData;
+extern char const* const _PREHASH_Users;
+extern char const* const _PREHASH_SysOS;
+extern char const* const _PREHASH_Notes;
+extern char const* const _PREHASH_AvatarID;
+extern char const* const _PREHASH_FounderID;
+extern char const* const _PREHASH_EndPointID;
+extern char const* const _PREHASH_LocationLookAt;
+extern char const* const _PREHASH_Sound;
+extern char const* const _PREHASH_Cover;
+extern char const* const _PREHASH_TotalObjectCount;
+extern char const* const _PREHASH_TextureEntry;
+extern char const* const _PREHASH_SquareMetersCommitted;
+extern char const* const _PREHASH_ChannelID;
+extern char const* const _PREHASH_Dwell;
+extern char const* const _PREHASH_North;
+extern char const* const _PREHASH_AgentUpdate;
+extern char const* const _PREHASH_PickGodDelete;
+extern char const* const _PREHASH_HostName;
+extern char const* const _PREHASH_PriceParcelClaim;
+extern char const* const _PREHASH_ParcelClaim;
+extern char const* const _PREHASH_AgentPowers;
+extern char const* const _PREHASH_ProfileHollow;
+extern char const* const _PREHASH_GroupRoleChanges;
+extern char const* const _PREHASH_Count;
+extern char const* const _PREHASH_South;
+extern char const* const _PREHASH_ObjectUpdateCompressed;
+extern char const* const _PREHASH_MuteFlags;
+extern char const* const _PREHASH_Group;
+extern char const* const _PREHASH_AgentPause;
+extern char const* const _PREHASH_LanguagesText;
+extern char const* const _PREHASH_Error;
+extern char const* const _PREHASH_InternalScriptMail;
+extern char const* const _PREHASH_FindAgent;
+extern char const* const _PREHASH_AgentData;
+extern char const* const _PREHASH_FolderData;
+extern char const* const _PREHASH_AssetBlock;
+extern char const* const _PREHASH_AcceptNotices;
+extern char const* const _PREHASH_SetGroupAcceptNotices;
+extern char const* const _PREHASH_CloseCircuit;
+extern char const* const _PREHASH_TeleportFinish;
+extern char const* const _PREHASH_PathRevolutions;
+extern char const* const _PREHASH_ClassifiedInfoReply;
+extern char const* const _PREHASH_ParcelInfoReply;
+extern char const* const _PREHASH_AutosaveData;
+extern char const* const _PREHASH_SetStartLocation;
+extern char const* const _PREHASH_PassHours;
+extern char const* const _PREHASH_AttachmentPt;
+extern char const* const _PREHASH_ParcelFlags;
+extern char const* const _PREHASH_NumVotes;
+extern char const* const _PREHASH_AvatarPickerRequest;
+extern char const* const _PREHASH_TeleportLocationRequest;
+extern char const* const _PREHASH_DataHomeLocationRequest;
+extern char const* const _PREHASH_EventNotificationAddRequest;
+extern char const* const _PREHASH_ParcelDwellRequest;
+extern char const* const _PREHASH_EventLocationRequest;
+extern char const* const _PREHASH_SetStartLocationRequest;
+extern char const* const _PREHASH_QueryStart;
+extern char const* const _PREHASH_EjectData;
+extern char const* const _PREHASH_AvatarTextureUpdate;
+extern char const* const _PREHASH_RPCServerPort;
+extern char const* const _PREHASH_Bytes;
+extern char const* const _PREHASH_Extra;
+extern char const* const _PREHASH_ForceScriptControlRelease;
+extern char const* const _PREHASH_ParcelRelease;
+extern char const* const _PREHASH_VFileType;
+extern char const* const _PREHASH_EjectGroupMemberReply;
+extern char const* const _PREHASH_ImageData;
+extern char const* const _PREHASH_SimulatorViewerTimeMessage;
+extern char const* const _PREHASH_Rotation;
+extern char const* const _PREHASH_Selection;
+extern char const* const _PREHASH_TransactionData;
+extern char const* const _PREHASH_OperationData;
+extern char const* const _PREHASH_ExpirationDate;
+extern char const* const _PREHASH_ParcelDeedToGroup;
+extern char const* const _PREHASH_AvatarPicksReply;
+extern char const* const _PREHASH_GroupTitlesReply;
+extern char const* const _PREHASH_AgentInfo;
+extern char const* const _PREHASH_MoneyTransferBackend;
+extern char const* const _PREHASH_NextOwnerMask;
+extern char const* const _PREHASH_MuteData;
+extern char const* const _PREHASH_PassPrice;
+extern char const* const _PREHASH_SourceID;
+extern char const* const _PREHASH_ChangeUserRights;
+extern char const* const _PREHASH_TeleportFlags;
+extern char const* const _PREHASH_SlaveParcelData;
+extern char const* const _PREHASH_AssetData;
+extern char const* const _PREHASH_MultipleObjectUpdate;
+extern char const* const _PREHASH_ObjectUpdate;
+extern char const* const _PREHASH_ImprovedTerseObjectUpdate;
+extern char const* const _PREHASH_ConfirmXferPacket;
+extern char const* const _PREHASH_StartPingCheck;
+extern char const* const _PREHASH_SimWideDeletes;
+extern char const* const _PREHASH_LandStatReply;
+extern char const* const _PREHASH_IsPhantom;
+extern char const* const _PREHASH_AgentList;
+extern char const* const _PREHASH_SimApproved;
+extern char const* const _PREHASH_RezObject;
+extern char const* const _PREHASH_TaskLocalID;
+extern char const* const _PREHASH_ClaimDate;
+extern char const* const _PREHASH_MergeParcel;
+extern char const* const _PREHASH_Priority;
+extern char const* const _PREHASH_QueryText;
+extern char const* const _PREHASH_GroupNoticeAdd;
+extern char const* const _PREHASH_ReturnType;
+extern char const* const _PREHASH_FetchFolders;
+extern char const* const _PREHASH_SimulatorPublicHostBlock;
+extern char const* const _PREHASH_HeaderData;
+extern char const* const _PREHASH_RequestMultipleObjects;
+extern char const* const _PREHASH_RetrieveInstantMessages;
+extern char const* const _PREHASH_OpenCircuit;
+extern char const* const _PREHASH_CrossedRegion;
+extern char const* const _PREHASH_DirGroupsReply;
+extern char const* const _PREHASH_AvatarGroupsReply;
+extern char const* const _PREHASH_EmailMessageReply;
+extern char const* const _PREHASH_GroupVoteHistoryItemReply;
+extern char const* const _PREHASH_ViewerPosition;
+extern char const* const _PREHASH_Position;
+extern char const* const _PREHASH_ParentEstate;
+extern char const* const _PREHASH_EstateName;
+extern char const* const _PREHASH_MuteName;
+extern char const* const _PREHASH_ParcelRename;
+extern char const* const _PREHASH_ViewerFilename;
+extern char const* const _PREHASH_UserReportInternal;
+extern char const* const _PREHASH_AvatarPropertiesRequest;
+extern char const* const _PREHASH_ParcelPropertiesRequest;
+extern char const* const _PREHASH_GroupProfileRequest;
+extern char const* const _PREHASH_AgentDataUpdateRequest;
+extern char const* const _PREHASH_PriceObjectScaleFactor;
+extern char const* const _PREHASH_OpenEnrollment;
+extern char const* const _PREHASH_GroupData;
+extern char const* const _PREHASH_RequestGodlikePowers;
+extern char const* const _PREHASH_GrantGodlikePowers;
+extern char const* const _PREHASH_TransactionID;
+extern char const* const _PREHASH_DestinationID;
+extern char const* const _PREHASH_Controls;
+extern char const* const _PREHASH_FirstDetachAll;
+extern char const* const _PREHASH_EstateID;
+extern char const* const _PREHASH_ImprovedInstantMessage;
+extern char const* const _PREHASH_CheckParcelSales;
+extern char const* const _PREHASH_ParcelSales;
+extern char const* const _PREHASH_CurrentInterval;
+extern char const* const _PREHASH_PriceRentLight;
+extern char const* const _PREHASH_MediaAutoScale;
+extern char const* const _PREHASH_NeighborBlock;
+extern char const* const _PREHASH_LayerData;
+extern char const* const _PREHASH_NVPairData;
+extern char const* const _PREHASH_TeleportLocal;
+extern char const* const _PREHASH_EjecteeID;
+extern char const* const _PREHASH_VoteInitiator;
+extern char const* const _PREHASH_TypeData;
+extern char const* const _PREHASH_OwnerIDs;
+extern char const* const _PREHASH_SystemKickUser;
+extern char const* const _PREHASH_TransactionTime;
+extern char const* const _PREHASH_TimeToLive;
+extern char const* const _PREHASH_OldAgentID;
+extern char const* const _PREHASH_MusicURL;
+extern char const* const _PREHASH_ParcelPrimBonus;
+extern char const* const _PREHASH_EjectUser;
+extern char const* const _PREHASH_CoarseLocationUpdate;
+extern char const* const _PREHASH_ChildAgentPositionUpdate;
+extern char const* const _PREHASH_StoreLocal;
+extern char const* const _PREHASH_GroupName;
+extern char const* const _PREHASH_PriceParcelRent;
+extern char const* const _PREHASH_SimStatus;
+extern char const* const _PREHASH_TransactionSuccess;
+extern char const* const _PREHASH_LureType;
+extern char const* const _PREHASH_GroupMask;
+extern char const* const _PREHASH_SitObject;
+extern char const* const _PREHASH_Override;
+extern char const* const _PREHASH_LocomotionState;
+extern char const* const _PREHASH_PriceUpload;
+extern char const* const _PREHASH_RemoveParcel;
+extern char const* const _PREHASH_ConfirmAuctionStart;
+extern char const* const _PREHASH_RpcScriptRequestInbound;
+extern char const* const _PREHASH_ActiveGroupID;
+extern char const* const _PREHASH_ParcelReturnObjects;
+extern char const* const _PREHASH_TotalObjects;
+extern char const* const _PREHASH_ObjectExtraParams;
+extern char const* const _PREHASH_Questions;
+extern char const* const _PREHASH_TransferAbort;
+extern char const* const _PREHASH_TransferInventory;
+extern char const* const _PREHASH_RayTargetID;
+extern char const* const _PREHASH_ClaimPrice;
+extern char const* const _PREHASH_ObjectProperties;
+extern char const* const _PREHASH_ParcelProperties;
+extern char const* const _PREHASH_EstateOwnerID;
+extern char const* const _PREHASH_LogoutRequest;
+extern char const* const _PREHASH_AssetUploadRequest;
+extern char const* const _PREHASH_TransactionType;
+extern char const* const _PREHASH_AvatarPropertiesUpdate;
+extern char const* const _PREHASH_ParcelPropertiesUpdate;
+extern char const* const _PREHASH_FetchItems;
+extern char const* const _PREHASH_AbortXfer;
+extern char const* const _PREHASH_DeRezAck;
+extern char const* const _PREHASH_TakeControls;
+extern char const* const _PREHASH_DirLandReply;
+extern char const* const _PREHASH_MuteType;
+extern char const* const _PREHASH_IMViaEMail;
+extern char const* const _PREHASH_RentPrice;
+extern char const* const _PREHASH_GenericMessage;
+extern char const* const _PREHASH_ChildAgentAlive;
+extern char const* const _PREHASH_AssetType;
+extern char const* const _PREHASH_SpawnPointBlock;
+extern char const* const _PREHASH_AttachmentBlock;
+extern char const* const _PREHASH_ObjectMaterial;
+extern char const* const _PREHASH_OwnerName;
+extern char const* const _PREHASH_AvatarNotesReply;
+extern char const* const _PREHASH_CacheID;
+extern char const* const _PREHASH_OwnerMask;
+extern char const* const _PREHASH_TransferInventoryAck;
+extern char const* const _PREHASH_RegionDenyAgeUnverified;
+extern char const* const _PREHASH_AgeVerificationBlock;
+extern char const* const _PREHASH_UCoord;
+extern char const* const _PREHASH_VCoord;
+extern char const* const _PREHASH_FaceIndex;
+extern char const* const _PREHASH_StatusData;
+extern char const* const _PREHASH_ProductSKU;
#endif
diff --git a/indra/llmessage/tests/commtest.h b/indra/llmessage/tests/commtest.h
index 32035783e2..0fef596df2 100644
--- a/indra/llmessage/tests/commtest.h
+++ b/indra/llmessage/tests/commtest.h
@@ -35,6 +35,13 @@
#include "llhost.h"
#include "stringize.h"
#include <string>
+#include <stdexcept>
+#include <boost/lexical_cast.hpp>
+
+struct CommtestError: public std::runtime_error
+{
+ CommtestError(const std::string& what): std::runtime_error(what) {}
+};
/**
* This struct is shared by a couple of standalone comm tests (ADD_COMM_BUILD_TEST).
@@ -55,13 +62,24 @@ struct commtest_data
replyPump("reply"),
errorPump("error"),
success(false),
- host("127.0.0.1", 8000),
+ host("127.0.0.1", getport("PORT")),
server(STRINGIZE("http://" << host.getString() << "/"))
{
replyPump.listen("self", boost::bind(&commtest_data::outcome, this, _1, true));
errorPump.listen("self", boost::bind(&commtest_data::outcome, this, _1, false));
}
+ static int getport(const std::string& var)
+ {
+ const char* port = getenv(var.c_str());
+ if (! port)
+ {
+ throw CommtestError("missing $PORT environment variable");
+ }
+ // This will throw, too, if the value of PORT isn't numeric.
+ return boost::lexical_cast<int>(port);
+ }
+
bool outcome(const LLSD& _result, bool _success)
{
// std::cout << "commtest_data::outcome(" << _result << ", " << _success << ")\n";
diff --git a/indra/llmessage/tests/llhost_test.cpp b/indra/llmessage/tests/llhost_test.cpp
index b20bceae1d..eadf83c428 100644
--- a/indra/llmessage/tests/llhost_test.cpp
+++ b/indra/llmessage/tests/llhost_test.cpp
@@ -151,8 +151,9 @@ namespace tut
template<> template<>
void host_object::test<9>()
{
+ skip("this test is flaky, but we should figure out why...");
// skip("setHostByName(\"google.com\"); getHostName() -> (e.g.) \"yx-in-f100.1e100.net\"");
- std::string hostStr = "linux.org";
+ std::string hostStr = "lindenlab.com";
LLHost host;
host.setHostByName(hostStr);
diff --git a/indra/llmessage/tests/llsdmessage_test.cpp b/indra/llmessage/tests/llsdmessage_test.cpp
index 9998a1b8bb..0f2c069303 100644
--- a/indra/llmessage/tests/llsdmessage_test.cpp
+++ b/indra/llmessage/tests/llsdmessage_test.cpp
@@ -61,6 +61,7 @@ namespace tut
llsdmessage_data():
httpPump(pumps.obtain("LLHTTPClient"))
{
+ LLCurl::initClass();
LLSDMessage::link();
}
};
diff --git a/indra/llmessage/tests/test_llsdmessage_peer.py b/indra/llmessage/tests/test_llsdmessage_peer.py
index 7eb198bb34..cea5032111 100644
--- a/indra/llmessage/tests/test_llsdmessage_peer.py
+++ b/indra/llmessage/tests/test_llsdmessage_peer.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
"""\
@file test_llsdmessage_peer.py
@author Nat Goodspeed
@@ -38,7 +38,7 @@ mydir = os.path.dirname(__file__) # expected to be .../indra/llmessage/tes
sys.path.insert(0, os.path.join(mydir, os.pardir, os.pardir, "lib", "python"))
from indra.util.fastest_elementtree import parse as xml_parse
from indra.base import llsd
-from testrunner import run, debug
+from testrunner import freeport, run, debug
class TestHTTPRequestHandler(BaseHTTPRequestHandler):
"""This subclass of BaseHTTPRequestHandler is to receive and echo
@@ -97,6 +97,10 @@ class TestHTTPRequestHandler(BaseHTTPRequestHandler):
self.wfile.write(response)
else: # fail requested
status = data.get("status", 500)
+ # self.responses maps an int status to a (short, long) pair of
+ # strings. We want the longer string. That's why we pass a string
+ # pair to get(): the [1] will select the second string, whether it
+ # came from self.responses or from our default pair.
reason = data.get("reason",
self.responses.get(status,
("fail requested",
@@ -113,11 +117,17 @@ class TestHTTPRequestHandler(BaseHTTPRequestHandler):
# Suppress error output as well
pass
-class TestHTTPServer(Thread):
- def run(self):
- httpd = HTTPServer(('127.0.0.1', 8000), TestHTTPRequestHandler)
- debug("Starting HTTP server...\n")
- httpd.serve_forever()
-
if __name__ == "__main__":
- sys.exit(run(server=TestHTTPServer(name="httpd"), *sys.argv[1:]))
+ # Instantiate an HTTPServer(TestHTTPRequestHandler) on the first free port
+ # in the specified port range. Doing this inline is better than in a
+ # daemon thread: if it blows up here, we'll get a traceback. If it blew up
+ # in some other thread, the traceback would get eaten and we'd run the
+ # subject test program anyway.
+ httpd, port = freeport(xrange(8000, 8020),
+ lambda port: HTTPServer(('127.0.0.1', port), TestHTTPRequestHandler))
+ # Pass the selected port number to the subject test program via the
+ # environment. We don't want to impose requirements on the test program's
+ # command-line parsing -- and anyway, for C++ integration tests, that's
+ # performed in TUT code rather than our own.
+ os.environ["PORT"] = str(port)
+ sys.exit(run(server=Thread(name="httpd", target=httpd.serve_forever), *sys.argv[1:]))
diff --git a/indra/llmessage/tests/testrunner.py b/indra/llmessage/tests/testrunner.py
index 4d58ef7130..8ff13e0426 100644
--- a/indra/llmessage/tests/testrunner.py
+++ b/indra/llmessage/tests/testrunner.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
"""\
@file testrunner.py
@author Nat Goodspeed
@@ -29,6 +29,8 @@ $/LicenseInfo$
import os
import sys
+import errno
+import socket
def debug(*args):
sys.stdout.writelines(args)
@@ -36,6 +38,85 @@ def debug(*args):
# comment out the line below to enable debug output
debug = lambda *args: None
+def freeport(portlist, expr):
+ """
+ Find a free server port to use. Specifically, evaluate 'expr' (a
+ callable(port)) until it stops raising EADDRINUSE exception.
+
+ Pass:
+
+ portlist: an iterable (e.g. xrange()) of ports to try. If you exhaust the
+ range, freeport() lets the socket.error exception propagate. If you want
+ unbounded, you could pass itertools.count(baseport), though of course in
+ practice the ceiling is 2^16-1 anyway. But it seems prudent to constrain
+ the range much more sharply: if we're iterating an absurd number of times,
+ probably something else is wrong.
+
+ expr: a callable accepting a port number, specifically one of the items
+ from portlist. If calling that callable raises socket.error with
+ EADDRINUSE, freeport() retrieves the next item from portlist and retries.
+
+ Returns: (expr(port), port)
+
+ port: the value from portlist for which expr(port) succeeded
+
+ Raises:
+
+ Any exception raised by expr(port) other than EADDRINUSE.
+
+ socket.error if, for every item from portlist, expr(port) raises
+ socket.error. The exception you see is the one from the last item in
+ portlist.
+
+ StopIteration if portlist is completely empty.
+
+ Example:
+
+ server, port = freeport(xrange(8000, 8010),
+ lambda port: HTTPServer(("localhost", port),
+ MyRequestHandler))
+ # pass 'port' to client code
+ # call server.serve_forever()
+ """
+ # If portlist is completely empty, let StopIteration propagate: that's an
+ # error because we can't return meaningful values. We have no 'port',
+ # therefore no 'expr(port)'.
+ portiter = iter(portlist)
+ port = portiter.next()
+
+ while True:
+ try:
+ # If this value of port works, return as promised.
+ return expr(port), port
+
+ except socket.error, err:
+ # Anything other than 'Address already in use', propagate
+ if err.args[0] != errno.EADDRINUSE:
+ raise
+
+ # Here we want the next port from portiter. But on StopIteration,
+ # we want to raise the original exception rather than
+ # StopIteration. So save the original exc_info().
+ type, value, tb = sys.exc_info()
+ try:
+ try:
+ port = portiter.next()
+ except StopIteration:
+ raise type, value, tb
+ finally:
+ # Clean up local traceback, see docs for sys.exc_info()
+ del tb
+
+ # Recap of the control flow above:
+ # If expr(port) doesn't raise, return as promised.
+ # If expr(port) raises anything but EADDRINUSE, propagate that
+ # exception.
+ # If portiter.next() raises StopIteration -- that is, if the port
+ # value we just passed to expr(port) was the last available -- reraise
+ # the EADDRINUSE exception.
+ # If we've actually arrived at this point, portiter.next() delivered a
+ # new port value. Loop back to pass that to expr(port).
+
def run(*args, **kwds):
"""All positional arguments collectively form a command line, executed as
a synchronous child process.
diff --git a/indra/llplugin/CMakeLists.txt b/indra/llplugin/CMakeLists.txt
index d3a73058c4..2f28673c07 100644
--- a/indra/llplugin/CMakeLists.txt
+++ b/indra/llplugin/CMakeLists.txt
@@ -20,6 +20,7 @@ include_directories(
${LLRENDER_INCLUDE_DIRS}
${LLXML_INCLUDE_DIRS}
${LLWINDOW_INCLUDE_DIRS}
+ ${LLQTWEBKIT_INCLUDE_DIR}
)
set(llplugin_SOURCE_FILES
@@ -65,21 +66,20 @@ add_library (llplugin ${llplugin_SOURCE_FILES})
add_subdirectory(slplugin)
+# Add tests
if (LL_TESTS)
- # Add tests
- include(LLAddBuildTest)
+ include(LLAddBuildTest)
+ # UNIT TESTS
+ SET(llplugin_TEST_SOURCE_FILES
+ llplugincookiestore.cpp
+ )
- # UNIT TESTS
- SET(llplugin_TEST_SOURCE_FILES
- llplugincookiestore.cpp
- )
+ # llplugincookiestore has a dependency on curl, so we need to link the curl library into the test.
+ set_source_files_properties(
+ llplugincookiestore.cpp
+ PROPERTIES
+ LL_TEST_ADDITIONAL_LIBRARIES "${CURL_LIBRARIES}"
+ )
- # llplugincookiestore has a dependency on curl, so we need to link the curl library into the test.
- set_source_files_properties(
- llplugincookiestore.cpp
- PROPERTIES
- LL_TEST_ADDITIONAL_LIBRARIES "${CURL_LIBRARIES}"
- )
-
- LL_ADD_PROJECT_UNIT_TESTS(llplugin "${llplugin_TEST_SOURCE_FILES}")
+ LL_ADD_PROJECT_UNIT_TESTS(llplugin "${llplugin_TEST_SOURCE_FILES}")
endif (LL_TESTS)
diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp
index 69ed0fb09c..2103216536 100644
--- a/indra/llplugin/llpluginclassmedia.cpp
+++ b/indra/llplugin/llpluginclassmedia.cpp
@@ -64,9 +64,10 @@ LLPluginClassMedia::~LLPluginClassMedia()
reset();
}
-bool LLPluginClassMedia::init(const std::string &launcher_filename, const std::string &plugin_filename, bool debug)
+bool LLPluginClassMedia::init(const std::string &launcher_filename, const std::string &plugin_dir, const std::string &plugin_filename, bool debug)
{
LL_DEBUGS("Plugin") << "launcher: " << launcher_filename << LL_ENDL;
+ LL_DEBUGS("Plugin") << "dir: " << plugin_dir << LL_ENDL;
LL_DEBUGS("Plugin") << "plugin: " << plugin_filename << LL_ENDL;
mPlugin = new LLPluginProcessParent(this);
@@ -77,7 +78,7 @@ bool LLPluginClassMedia::init(const std::string &launcher_filename, const std::s
message.setValue("target", mTarget);
sendMessage(message);
- mPlugin->init(launcher_filename, plugin_filename, debug);
+ mPlugin->init(launcher_filename, plugin_dir, plugin_filename, debug);
return true;
}
@@ -143,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;
@@ -160,7 +163,7 @@ void LLPluginClassMedia::idle(void)
mPlugin->idle();
}
- if((mMediaWidth == -1) || (!mTextureParamsReceived) || (mPlugin == NULL) || (mPlugin->isBlocked()))
+ if((mMediaWidth == -1) || (!mTextureParamsReceived) || (mPlugin == NULL) || (mPlugin->isBlocked()) || (mOwner == NULL))
{
// Can't process a size change at this time
}
@@ -522,7 +525,15 @@ bool LLPluginClassMedia::keyEvent(EKeyEventType type, int key_code, MASK modifie
}
break;
}
-
+
+#if LL_DARWIN
+ if(modifiers & MASK_ALT)
+ {
+ // Option-key modified characters should be handled by the unicode input path instead of this one.
+ result = false;
+ }
+#endif
+
if(result)
{
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "key_event");
@@ -674,7 +685,21 @@ void LLPluginClassMedia::sendPickFileResponse(const std::string &file)
{
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "pick_file_response");
message.setValue("file", file);
- if(mPlugin->isBlocked())
+ if(mPlugin && mPlugin->isBlocked())
+ {
+ // If the plugin sent a blocking pick-file request, the response should unblock it.
+ message.setValueBoolean("blocking_response", true);
+ }
+ sendMessage(message);
+}
+
+void LLPluginClassMedia::sendAuthResponse(bool ok, const std::string &username, const std::string &password)
+{
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "auth_response");
+ message.setValueBoolean("ok", ok);
+ message.setValue("username", username);
+ message.setValue("password", password);
+ if(mPlugin && mPlugin->isBlocked())
{
// If the plugin sent a blocking pick-file request, the response should unblock it.
message.setValueBoolean("blocking_response", true);
@@ -947,6 +972,12 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
{
mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PICK_FILE_REQUEST);
}
+ else if(message_name == "auth_request")
+ {
+ mAuthURL = message.getValue("url");
+ mAuthRealm = message.getValue("realm");
+ mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_AUTH_REQUEST);
+ }
else
{
LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL;
@@ -995,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)
@@ -1019,6 +1056,15 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_GEOMETRY_CHANGE);
}
+ else if(message_name == "link_hovered")
+ {
+ // text is not currently used -- the tooltip hover text is taken from the "title".
+ mHoverLink = message.getValue("link");
+ mHoverText = message.getValue("title");
+ // message.getValue("text");
+
+ mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_LINK_HOVERED);
+ }
else
{
LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL;
@@ -1154,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");
@@ -1192,6 +1228,20 @@ void LLPluginClassMedia::proxyWindowClosed(const std::string &uuid)
sendMessage(message);
}
+void LLPluginClassMedia::ignore_ssl_cert_errors(bool ignore)
+{
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "ignore_ssl_cert_errors");
+ message.setValueBoolean("ignore", ignore);
+ sendMessage(message);
+}
+
+void LLPluginClassMedia::addCertificateFilePath(const std::string& path)
+{
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "add_certificate_file_path");
+ message.setValue("path", path);
+ sendMessage(message);
+}
+
void LLPluginClassMedia::crashPlugin()
{
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "crash");
diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h
index 9cb67fe909..cf8d8b26b9 100644
--- a/indra/llplugin/llpluginclassmedia.h
+++ b/indra/llplugin/llpluginclassmedia.h
@@ -45,6 +45,7 @@ public:
// local initialization, called by the media manager when creating a source
virtual bool init(const std::string &launcher_filename,
+ const std::string &plugin_dir,
const std::string &plugin_filename,
bool debug);
@@ -85,6 +86,8 @@ public:
void setBackgroundColor(LLColor4 color) { mBackgroundColor = color; };
+ void setOwner(LLPluginClassMediaOwner *owner) { mOwner = owner; };
+
// Returns true if all of the texture parameters (depth, format, size, and texture size) are set up and consistent.
// This will initially be false, and will also be false for some time after setSize while the resize is processed.
// Note that if this returns true, it is safe to use all the get() functions above without checking for invalid return values
@@ -159,6 +162,8 @@ public:
void sendPickFileResponse(const std::string &file);
+ void sendAuthResponse(bool ok, const std::string &username, const std::string &password);
+
// Valid after a MEDIA_EVENT_CURSOR_CHANGED event
std::string getCursorName() const { return mCursorName; };
@@ -194,10 +199,11 @@ 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);
+ void ignore_ssl_cert_errors(bool ignore);
+ void addCertificateFilePath(const std::string& path);
// This is valid after MEDIA_EVENT_NAVIGATE_BEGIN or MEDIA_EVENT_NAVIGATE_COMPLETE
std::string getNavigateURI() const { return mNavigateURI; };
@@ -220,18 +226,32 @@ 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; };
S32 getGeometryY() const { return mGeometryY; };
S32 getGeometryWidth() const { return mGeometryWidth; };
S32 getGeometryHeight() const { return mGeometryHeight; };
+
+ // These are valid during MEDIA_EVENT_AUTH_REQUEST
+ std::string getAuthURL() const { return mAuthURL; };
+ std::string getAuthRealm() const { return mAuthRealm; };
+ // These are valid during MEDIA_EVENT_LINK_HOVERED
+ std::string getHoverText() const { return mHoverText; };
+ std::string getHoverLink() const { return mHoverLink; };
+
std::string getMediaName() const { return mMediaName; };
std::string getMediaDescription() const { return mMediaDescription; };
@@ -363,12 +383,18 @@ 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;
+ std::string mHoverLink;
/////////////////////////////////////////
// media_time class
diff --git a/indra/llplugin/llpluginclassmediaowner.h b/indra/llplugin/llpluginclassmediaowner.h
index c9efff216c..5a4fb1ce90 100644
--- a/indra/llplugin/llpluginclassmediaowner.h
+++ b/indra/llplugin/llpluginclassmediaowner.h
@@ -52,14 +52,19 @@ 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
+ MEDIA_EVENT_PLUGIN_FAILED, // The plugin died unexpectedly
+
+ MEDIA_EVENT_AUTH_REQUEST, // The plugin wants to display an auth dialog
+
+ MEDIA_EVENT_LINK_HOVERED // Got a "link hovered" event from the plugin
} EMediaEvent;
diff --git a/indra/llplugin/llplugininstance.cpp b/indra/llplugin/llplugininstance.cpp
index c326961db4..7cde82a20e 100644
--- a/indra/llplugin/llplugininstance.cpp
+++ b/indra/llplugin/llplugininstance.cpp
@@ -32,6 +32,10 @@
#include "llapr.h"
+#if LL_WINDOWS
+#include "direct.h" // needed for _chdir()
+#endif
+
/** Virtual destructor. */
LLPluginInstanceMessageListener::~LLPluginInstanceMessageListener()
{
@@ -73,10 +77,24 @@ LLPluginInstance::~LLPluginInstance()
* @param[in] plugin_file Name of plugin dll/dylib/so. TODO:DOC is this correct? see .h
* @return 0 if successful, APR error code or error code from the plugin's init function on failure.
*/
-int LLPluginInstance::load(std::string &plugin_file)
+int LLPluginInstance::load(const std::string& plugin_dir, std::string &plugin_file)
{
pluginInitFunction init_function = NULL;
+ if ( plugin_dir.length() )
+ {
+#if LL_WINDOWS
+ // VWR-21275:
+ // *SOME* Windows systems fail to load the Qt plugins if the current working
+ // directory is not the same as the directory with the Qt DLLs in.
+ // This should not cause any run time issues since we are changing the cwd for the
+ // plugin shell process and not the viewer.
+ // Changing back to the previous directory is not necessary since the plugin shell
+ // quits once the plugin exits.
+ _chdir( plugin_dir.c_str() );
+#endif
+ };
+
int result = apr_dso_load(&mDSOHandle,
plugin_file.c_str(),
gAPRPoolp);
diff --git a/indra/llplugin/llplugininstance.h b/indra/llplugin/llplugininstance.h
index 50531ca77f..e6926c3e37 100644
--- a/indra/llplugin/llplugininstance.h
+++ b/indra/llplugin/llplugininstance.h
@@ -56,7 +56,7 @@ public:
// Load a plugin dll/dylib/so
// Returns 0 if successful, APR error code or error code returned from the plugin's init function on failure.
- int load(std::string &plugin_file);
+ int load(const std::string& plugin_dir, std::string &plugin_file);
// Sends a message to the plugin.
void sendMessage(const std::string &message);
diff --git a/indra/llplugin/llpluginprocesschild.cpp b/indra/llplugin/llpluginprocesschild.cpp
index 45a86476ac..0beb46d0e5 100644
--- a/indra/llplugin/llpluginprocesschild.cpp
+++ b/indra/llplugin/llpluginprocesschild.cpp
@@ -139,7 +139,7 @@ void LLPluginProcessChild::idle(void)
if(!mPluginFile.empty())
{
mInstance = new LLPluginInstance(this);
- if(mInstance->load(mPluginFile) == 0)
+ if(mInstance->load(mPluginDir, mPluginFile) == 0)
{
mHeartbeat.start();
mHeartbeat.setTimerExpirySec(HEARTBEAT_SECONDS);
@@ -348,6 +348,7 @@ void LLPluginProcessChild::receiveMessageRaw(const std::string &message)
if(message_name == "load_plugin")
{
mPluginFile = parsed.getValue("file");
+ mPluginDir = parsed.getValue("dir");
}
else if(message_name == "shm_add")
{
diff --git a/indra/llplugin/llpluginprocesschild.h b/indra/llplugin/llpluginprocesschild.h
index 22ff403ad6..a9d6794e40 100644
--- a/indra/llplugin/llpluginprocesschild.h
+++ b/indra/llplugin/llpluginprocesschild.h
@@ -92,6 +92,7 @@ private:
LLSocket::ptr_t mSocket;
std::string mPluginFile;
+ std::string mPluginDir;
LLPluginInstance *mInstance;
diff --git a/indra/llplugin/llpluginprocessparent.cpp b/indra/llplugin/llpluginprocessparent.cpp
index c002de0462..315096d4fd 100644
--- a/indra/llplugin/llpluginprocessparent.cpp
+++ b/indra/llplugin/llpluginprocessparent.cpp
@@ -157,10 +157,12 @@ void LLPluginProcessParent::errorState(void)
setState(STATE_ERROR);
}
-void LLPluginProcessParent::init(const std::string &launcher_filename, const std::string &plugin_filename, bool debug)
+void LLPluginProcessParent::init(const std::string &launcher_filename, const std::string &plugin_dir, const std::string &plugin_filename, bool debug)
{
mProcess.setExecutable(launcher_filename);
+ mProcess.setWorkingDirectory(plugin_dir);
mPluginFile = plugin_filename;
+ mPluginDir = plugin_dir;
mCPUUsage = 0.0f;
mDebug = debug;
setState(STATE_INITIALIZED);
@@ -445,6 +447,7 @@ void LLPluginProcessParent::idle(void)
{
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "load_plugin");
message.setValue("file", mPluginFile);
+ message.setValue("dir", mPluginDir);
sendMessage(message);
}
diff --git a/indra/llplugin/llpluginprocessparent.h b/indra/llplugin/llpluginprocessparent.h
index 32394809ef..c66723f175 100644
--- a/indra/llplugin/llpluginprocessparent.h
+++ b/indra/llplugin/llpluginprocessparent.h
@@ -57,6 +57,7 @@ public:
~LLPluginProcessParent();
void init(const std::string &launcher_filename,
+ const std::string &plugin_dir,
const std::string &plugin_filename,
bool debug);
@@ -151,6 +152,7 @@ private:
LLProcessLauncher mProcess;
std::string mPluginFile;
+ std::string mPluginDir;
LLPluginProcessParentOwner *mOwner;
diff --git a/indra/llprimitive/CMakeLists.txt b/indra/llprimitive/CMakeLists.txt
index f4d21308b3..97e1ebde47 100644
--- a/indra/llprimitive/CMakeLists.txt
+++ b/indra/llprimitive/CMakeLists.txt
@@ -13,11 +13,14 @@ include_directories(
${LLMATH_INCLUDE_DIRS}
${LLMESSAGE_INCLUDE_DIRS}
${LLXML_INCLUDE_DIRS}
+ ${LIBS_PREBUILT_DIR}/include/collada
+ ${LIBS_PREBUILT_DIR}/include/collada/1.4
)
set(llprimitive_SOURCE_FILES
llmaterialtable.cpp
llmediaentry.cpp
+ llmodel.cpp
llprimitive.cpp
llprimtexturelist.cpp
lltextureanim.cpp
@@ -34,6 +37,7 @@ set(llprimitive_HEADER_FILES
legacy_object_types.h
llmaterialtable.h
llmediaentry.h
+ llmodel.h
llprimitive.h
llprimtexturelist.h
lltextureanim.h
@@ -53,11 +57,11 @@ list(APPEND llprimitive_SOURCE_FILES ${llprimitive_HEADER_FILES})
add_library (llprimitive ${llprimitive_SOURCE_FILES})
-if(LL_TESTS)
- #add unit tests
- INCLUDE(LLAddBuildTest)
- SET(llprimitive_TEST_SOURCE_FILES
- llmediaentry.cpp
- )
- LL_ADD_PROJECT_UNIT_TESTS(llprimitive "${llprimitive_TEST_SOURCE_FILES}")
-endif(LL_TESTS)
+#add unit tests
+if (LL_TESTS)
+ INCLUDE(LLAddBuildTest)
+ SET(llprimitive_TEST_SOURCE_FILES
+ llmediaentry.cpp
+ )
+ LL_ADD_PROJECT_UNIT_TESTS(llprimitive "${llprimitive_TEST_SOURCE_FILES}")
+endif (LL_TESTS)
diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp
new file mode 100644
index 0000000000..794cdb83d5
--- /dev/null
+++ b/indra/llprimitive/llmodel.cpp
@@ -0,0 +1,2292 @@
+/**
+ * @file llmodel.cpp
+ * @brief Model handling implementation
+ *
+ * $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 "llmodel.h"
+#include "llconvexdecomposition.h"
+#include "llsdserialize.h"
+#include "llvector4a.h"
+
+#include "dae.h"
+#include "dae/daeErrorHandler.h"
+#include "dom/domConstants.h"
+#include "dom/domMesh.h"
+
+#ifdef LL_STANDALONE
+# include <zlib.h>
+#else
+# include "zlib/zlib.h"
+#endif
+
+
+
+std::string model_names[] =
+{
+ "lowest_lod",
+ "low_lod",
+ "medium_lod",
+ "high_lod",
+ "physics_shape"
+};
+
+const int MODEL_NAMES_LENGTH = sizeof(model_names) / sizeof(std::string);
+
+LLModel::LLModel(LLVolumeParams& params, F32 detail)
+ : LLVolume(params, detail), mNormalizedScale(1,1,1), mNormalizedTranslation(0,0,0)
+ , mPelvisOffset( 0.0f ), mStatus(NO_ERRORS)
+{
+ mDecompID = -1;
+ mLocalID = -1;
+}
+
+LLModel::~LLModel()
+{
+ if (mDecompID >= 0)
+ {
+ LLConvexDecomposition::getInstance()->deleteDecomposition(mDecompID);
+ }
+}
+
+void load_face_from_dom_inputs(LLVolumeFace& face, const domInputLocalOffset_Array& inputs, U32 min_idx, U32 max_idx)
+{
+ for (U32 j = 0; j < inputs.getCount(); ++j)
+ {
+ if (strcmp(COMMON_PROFILE_INPUT_VERTEX, inputs[j]->getSemantic()) == 0)
+ { //found vertex array
+ const domURIFragmentType& uri = inputs[j]->getSource();
+ daeElementRef elem = uri.getElement();
+ domVertices* vertices = (domVertices*) elem.cast();
+
+ domInputLocal_Array& v_inp = vertices->getInput_array();
+ if (inputs[j]->getOffset() != 0)
+ {
+ llerrs << "WTF?" << llendl;
+ }
+
+ for (U32 k = 0; k < v_inp.getCount(); ++k)
+ {
+ if (strcmp(COMMON_PROFILE_INPUT_POSITION, v_inp[k]->getSemantic()) == 0)
+ {
+ const domURIFragmentType& uri = v_inp[k]->getSource();
+
+ daeElementRef elem = uri.getElement();
+ domSource* src = (domSource*) elem.cast();
+
+ if (src->getTechnique_common()->getAccessor()->getStride() != 3)
+ {
+ llerrs << "WTF?" << llendl;
+ }
+
+ domListOfFloats& v = src->getFloat_array()->getValue();
+
+ LLVector4a min;
+ min.set(v[min_idx], v[min_idx+1], v[min_idx+2]);
+ LLVector4a max = min;
+
+ for (U32 j = min_idx; j <= max_idx; ++j)
+ { //copy vertex array
+ face.mPositions[j-min_idx].set(v[j*3+0], v[j*3+1], v[j*3+2]);
+ update_min_max(min, max, face.mPositions[j-min_idx]);
+ }
+
+ face.mExtents[0] = min;
+ face.mExtents[1] = max;
+ }
+ }
+ }
+
+ if (strcmp(COMMON_PROFILE_INPUT_NORMAL, inputs[j]->getSemantic()) == 0)
+ {
+ //found normal array for this triangle list
+ const domURIFragmentType& uri = inputs[j]->getSource();
+ daeElementRef elem = uri.getElement();
+ domSource* src = (domSource*) elem.cast();
+ domListOfFloats& n = src->getFloat_array()->getValue();
+
+ for (U32 j = min_idx; j <= max_idx; ++j)
+ {
+ LLVector4a* norm = (LLVector4a*) face.mNormals + (j-min_idx);
+ norm->set(n[j*3+0], n[j*3+1], n[j*3+2]);
+ norm->normalize3();
+ }
+ }
+ else if (strcmp(COMMON_PROFILE_INPUT_TEXCOORD, inputs[j]->getSemantic()) == 0)
+ { //found texCoords
+ const domURIFragmentType& uri = inputs[j]->getSource();
+ daeElementRef elem = uri.getElement();
+ domSource* src = (domSource*) elem.cast();
+ domListOfFloats& u = src->getFloat_array()->getValue();
+
+ for (U32 j = min_idx; j <= max_idx; ++j)
+ {
+ face.mTexCoords[j-min_idx].setVec(u[j*2+0], u[j*2+1]);
+ }
+ }
+ }
+}
+
+void get_dom_sources(const domInputLocalOffset_Array& inputs, S32& pos_offset, S32& tc_offset, S32& norm_offset, S32 &idx_stride,
+ domSource* &pos_source, domSource* &tc_source, domSource* &norm_source)
+{
+ idx_stride = 0;
+
+ for (U32 j = 0; j < inputs.getCount(); ++j)
+ {
+ idx_stride = llmax((S32) inputs[j]->getOffset(), idx_stride);
+
+ if (strcmp(COMMON_PROFILE_INPUT_VERTEX, inputs[j]->getSemantic()) == 0)
+ { //found vertex array
+ const domURIFragmentType& uri = inputs[j]->getSource();
+ daeElementRef elem = uri.getElement();
+ domVertices* vertices = (domVertices*) elem.cast();
+
+ domInputLocal_Array& v_inp = vertices->getInput_array();
+
+
+ for (U32 k = 0; k < v_inp.getCount(); ++k)
+ {
+ if (strcmp(COMMON_PROFILE_INPUT_POSITION, v_inp[k]->getSemantic()) == 0)
+ {
+ pos_offset = inputs[j]->getOffset();
+
+ const domURIFragmentType& uri = v_inp[k]->getSource();
+ daeElementRef elem = uri.getElement();
+ pos_source = (domSource*) elem.cast();
+ }
+
+ if (strcmp(COMMON_PROFILE_INPUT_NORMAL, v_inp[k]->getSemantic()) == 0)
+ {
+ norm_offset = inputs[j]->getOffset();
+
+ const domURIFragmentType& uri = v_inp[k]->getSource();
+ daeElementRef elem = uri.getElement();
+ norm_source = (domSource*) elem.cast();
+ }
+ }
+ }
+
+ if (strcmp(COMMON_PROFILE_INPUT_NORMAL, inputs[j]->getSemantic()) == 0)
+ {
+ //found normal array for this triangle list
+ norm_offset = inputs[j]->getOffset();
+ const domURIFragmentType& uri = inputs[j]->getSource();
+ daeElementRef elem = uri.getElement();
+ norm_source = (domSource*) elem.cast();
+ }
+ else if (strcmp(COMMON_PROFILE_INPUT_TEXCOORD, inputs[j]->getSemantic()) == 0)
+ { //found texCoords
+ tc_offset = inputs[j]->getOffset();
+ const domURIFragmentType& uri = inputs[j]->getSource();
+ daeElementRef elem = uri.getElement();
+ tc_source = (domSource*) elem.cast();
+ }
+ }
+
+ idx_stride += 1;
+}
+
+LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& face_list, std::vector<std::string>& materials, domTrianglesRef& tri)
+{
+ LLVolumeFace face;
+ std::vector<LLVolumeFace::VertexData> verts;
+ std::vector<U16> indices;
+
+ const domInputLocalOffset_Array& inputs = tri->getInput_array();
+
+ S32 pos_offset = -1;
+ S32 tc_offset = -1;
+ S32 norm_offset = -1;
+
+ domSource* pos_source = NULL;
+ domSource* tc_source = NULL;
+ domSource* norm_source = NULL;
+
+ S32 idx_stride = 0;
+
+ get_dom_sources(inputs, pos_offset, tc_offset, norm_offset, idx_stride, pos_source, tc_source, norm_source);
+
+ domPRef p = tri->getP();
+ domListOfUInts& idx = p->getValue();
+
+ domListOfFloats dummy ;
+ domListOfFloats& v = pos_source ? pos_source->getFloat_array()->getValue() : dummy ;
+ domListOfFloats& tc = tc_source ? tc_source->getFloat_array()->getValue() : dummy ;
+ domListOfFloats& n = norm_source ? norm_source->getFloat_array()->getValue() : dummy ;
+
+ if (pos_source)
+ {
+ face.mExtents[0].set(v[0], v[1], v[2]);
+ face.mExtents[1].set(v[0], v[1], v[2]);
+ }
+
+ LLVolumeFace::VertexMapData::PointMap point_map;
+
+ for (U32 i = 0; i < idx.getCount(); i += idx_stride)
+ {
+ LLVolumeFace::VertexData cv;
+ if (pos_source)
+ {
+ cv.setPosition(LLVector4a(v[idx[i+pos_offset]*3+0],
+ v[idx[i+pos_offset]*3+1],
+ v[idx[i+pos_offset]*3+2]));
+ }
+
+ if (tc_source)
+ {
+ cv.mTexCoord.setVec(tc[idx[i+tc_offset]*2+0],
+ tc[idx[i+tc_offset]*2+1]);
+ }
+
+ if (norm_source)
+ {
+ cv.setNormal(LLVector4a(n[idx[i+norm_offset]*3+0],
+ n[idx[i+norm_offset]*3+1],
+ n[idx[i+norm_offset]*3+2]));
+ }
+
+
+ BOOL found = FALSE;
+
+ LLVolumeFace::VertexMapData::PointMap::iterator point_iter;
+ point_iter = point_map.find(LLVector3(cv.getPosition().getF32ptr()));
+
+ if (point_iter != point_map.end())
+ {
+ for (U32 j = 0; j < point_iter->second.size(); ++j)
+ {
+ if ((point_iter->second)[j] == cv)
+ {
+ found = TRUE;
+ indices.push_back((point_iter->second)[j].mIndex);
+ break;
+ }
+ }
+ }
+
+ if (!found)
+ {
+ update_min_max(face.mExtents[0], face.mExtents[1], cv.getPosition());
+ verts.push_back(cv);
+ if (verts.size() >= 65535)
+ {
+ //llerrs << "Attempted to write model exceeding 16-bit index buffer limitation." << llendl;
+ return LLModel::VERTEX_NUMBER_OVERFLOW ;
+ }
+ U16 index = (U16) (verts.size()-1);
+ indices.push_back(index);
+
+ LLVolumeFace::VertexMapData d;
+ d.setPosition(cv.getPosition());
+ d.mTexCoord = cv.mTexCoord;
+ d.setNormal(cv.getNormal());
+ d.mIndex = index;
+ if (point_iter != point_map.end())
+ {
+ point_iter->second.push_back(d);
+ }
+ else
+ {
+ point_map[LLVector3(d.getPosition().getF32ptr())].push_back(d);
+ }
+ }
+
+ if (indices.size()%3 == 0 && verts.size() >= 65532)
+ {
+ face_list.push_back(face);
+ face_list.rbegin()->fillFromLegacyData(verts, indices);
+ face = LLVolumeFace();
+ point_map.clear();
+ }
+
+ }
+
+ if (!verts.empty())
+ {
+ std::string material;
+
+ if (tri->getMaterial())
+ {
+ material = std::string(tri->getMaterial());
+ }
+
+ materials.push_back(material);
+ face_list.push_back(face);
+
+ face_list.rbegin()->fillFromLegacyData(verts, indices);
+ }
+
+ return LLModel::NO_ERRORS ;
+}
+
+LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& face_list, std::vector<std::string>& materials, domPolylistRef& poly)
+{
+ domPRef p = poly->getP();
+ domListOfUInts& idx = p->getValue();
+
+ if (idx.getCount() == 0)
+ {
+ return LLModel::NO_ERRORS ;
+ }
+
+ const domInputLocalOffset_Array& inputs = poly->getInput_array();
+
+
+ domListOfUInts& vcount = poly->getVcount()->getValue();
+
+ S32 pos_offset = -1;
+ S32 tc_offset = -1;
+ S32 norm_offset = -1;
+
+ domSource* pos_source = NULL;
+ domSource* tc_source = NULL;
+ domSource* norm_source = NULL;
+
+ S32 idx_stride = 0;
+
+ get_dom_sources(inputs, pos_offset, tc_offset, norm_offset, idx_stride, pos_source, tc_source, norm_source);
+
+ LLVolumeFace face;
+
+ std::vector<U16> indices;
+ std::vector<LLVolumeFace::VertexData> verts;
+
+ domListOfFloats v;
+ domListOfFloats tc;
+ domListOfFloats n;
+
+ if (pos_source)
+ {
+ v = pos_source->getFloat_array()->getValue();
+ face.mExtents[0].set(v[0], v[1], v[2]);
+ face.mExtents[1].set(v[0], v[1], v[2]);
+ }
+
+ if (tc_source)
+ {
+ tc = tc_source->getFloat_array()->getValue();
+ }
+
+ if (norm_source)
+ {
+ n = norm_source->getFloat_array()->getValue();
+ }
+
+ LLVolumeFace::VertexMapData::PointMap point_map;
+
+ U32 cur_idx = 0;
+ for (U32 i = 0; i < vcount.getCount(); ++i)
+ { //for each polygon
+ U32 first_index = 0;
+ U32 last_index = 0;
+ for (U32 j = 0; j < vcount[i]; ++j)
+ { //for each vertex
+
+ LLVolumeFace::VertexData cv;
+
+ if (pos_source)
+ {
+ cv.getPosition().set(v[idx[cur_idx+pos_offset]*3+0],
+ v[idx[cur_idx+pos_offset]*3+1],
+ v[idx[cur_idx+pos_offset]*3+2]);
+ }
+
+ if (tc_source)
+ {
+ cv.mTexCoord.setVec(tc[idx[cur_idx+tc_offset]*2+0],
+ tc[idx[cur_idx+tc_offset]*2+1]);
+ }
+
+ if (norm_source)
+ {
+ cv.getNormal().set(n[idx[cur_idx+norm_offset]*3+0],
+ n[idx[cur_idx+norm_offset]*3+1],
+ n[idx[cur_idx+norm_offset]*3+2]);
+ }
+
+ cur_idx += idx_stride;
+
+ BOOL found = FALSE;
+
+ LLVolumeFace::VertexMapData::PointMap::iterator point_iter;
+ LLVector3 pos3(cv.getPosition().getF32ptr());
+ point_iter = point_map.find(pos3);
+
+ if (point_iter != point_map.end())
+ {
+ for (U32 k = 0; k < point_iter->second.size(); ++k)
+ {
+ if ((point_iter->second)[k] == cv)
+ {
+ found = TRUE;
+ U32 index = (point_iter->second)[k].mIndex;
+ if (j == 0)
+ {
+ first_index = index;
+ }
+ else if (j == 1)
+ {
+ last_index = index;
+ }
+ else
+ {
+ indices.push_back(first_index);
+ indices.push_back(last_index);
+ indices.push_back(index);
+ last_index = index;
+ }
+
+ break;
+ }
+ }
+ }
+
+ if (!found)
+ {
+ update_min_max(face.mExtents[0], face.mExtents[1], cv.getPosition());
+ verts.push_back(cv);
+ if (verts.size() >= 65535)
+ {
+ //llerrs << "Attempted to write model exceeding 16-bit index buffer limitation." << llendl;
+ return LLModel::VERTEX_NUMBER_OVERFLOW ;
+ }
+ U16 index = (U16) (verts.size()-1);
+
+ if (j == 0)
+ {
+ first_index = index;
+ }
+ else if (j == 1)
+ {
+ last_index = index;
+ }
+ else
+ {
+ indices.push_back(first_index);
+ indices.push_back(last_index);
+ indices.push_back(index);
+ last_index = index;
+ }
+
+ LLVolumeFace::VertexMapData d;
+ d.setPosition(cv.getPosition());
+ d.mTexCoord = cv.mTexCoord;
+ d.setNormal(cv.getNormal());
+ d.mIndex = index;
+ if (point_iter != point_map.end())
+ {
+ point_iter->second.push_back(d);
+ }
+ else
+ {
+ point_map[pos3].push_back(d);
+ }
+ }
+
+ if (indices.size()%3 == 0 && indices.size() >= 65532)
+ {
+ face_list.push_back(face);
+ face_list.rbegin()->fillFromLegacyData(verts, indices);
+ face = LLVolumeFace();
+ verts.clear();
+ indices.clear();
+ point_map.clear();
+ }
+ }
+ }
+
+ if (!verts.empty())
+ {
+ std::string material;
+
+ if (poly->getMaterial())
+ {
+ material = std::string(poly->getMaterial());
+ }
+
+ materials.push_back(material);
+ face_list.push_back(face);
+ face_list.rbegin()->fillFromLegacyData(verts, indices);
+ }
+
+ return LLModel::NO_ERRORS ;
+}
+
+LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& face_list, std::vector<std::string>& materials, domPolygonsRef& poly)
+{
+ LLVolumeFace face;
+ std::vector<U16> indices;
+ std::vector<LLVolumeFace::VertexData> verts;
+
+ const domInputLocalOffset_Array& inputs = poly->getInput_array();
+
+
+ S32 v_offset = -1;
+ S32 n_offset = -1;
+ S32 t_offset = -1;
+
+ domListOfFloats* v = NULL;
+ domListOfFloats* n = NULL;
+ domListOfFloats* t = NULL;
+
+ U32 stride = 0;
+ for (U32 i = 0; i < inputs.getCount(); ++i)
+ {
+ stride = llmax((U32) inputs[i]->getOffset()+1, stride);
+
+ if (strcmp(COMMON_PROFILE_INPUT_VERTEX, inputs[i]->getSemantic()) == 0)
+ { //found vertex array
+ v_offset = inputs[i]->getOffset();
+
+ const domURIFragmentType& uri = inputs[i]->getSource();
+ daeElementRef elem = uri.getElement();
+ domVertices* vertices = (domVertices*) elem.cast();
+
+ domInputLocal_Array& v_inp = vertices->getInput_array();
+
+ for (U32 k = 0; k < v_inp.getCount(); ++k)
+ {
+ if (strcmp(COMMON_PROFILE_INPUT_POSITION, v_inp[k]->getSemantic()) == 0)
+ {
+ const domURIFragmentType& uri = v_inp[k]->getSource();
+ daeElementRef elem = uri.getElement();
+ domSource* src = (domSource*) elem.cast();
+ v = &(src->getFloat_array()->getValue());
+ }
+ }
+ }
+ else if (strcmp(COMMON_PROFILE_INPUT_NORMAL, inputs[i]->getSemantic()) == 0)
+ {
+ n_offset = inputs[i]->getOffset();
+ //found normal array for this triangle list
+ const domURIFragmentType& uri = inputs[i]->getSource();
+ daeElementRef elem = uri.getElement();
+ domSource* src = (domSource*) elem.cast();
+ n = &(src->getFloat_array()->getValue());
+ }
+ else if (strcmp(COMMON_PROFILE_INPUT_TEXCOORD, inputs[i]->getSemantic()) == 0 && inputs[i]->getSet() == 0)
+ { //found texCoords
+ t_offset = inputs[i]->getOffset();
+ const domURIFragmentType& uri = inputs[i]->getSource();
+ daeElementRef elem = uri.getElement();
+ domSource* src = (domSource*) elem.cast();
+ t = &(src->getFloat_array()->getValue());
+ }
+ }
+
+ domP_Array& ps = poly->getP_array();
+
+ //make a triangle list in <verts>
+ for (U32 i = 0; i < ps.getCount(); ++i)
+ { //for each polygon
+ domListOfUInts& idx = ps[i]->getValue();
+ for (U32 j = 0; j < idx.getCount()/stride; ++j)
+ { //for each vertex
+ if (j > 2)
+ {
+ U32 size = verts.size();
+ LLVolumeFace::VertexData v0 = verts[size-3];
+ LLVolumeFace::VertexData v1 = verts[size-1];
+
+ verts.push_back(v0);
+ verts.push_back(v1);
+ }
+
+ LLVolumeFace::VertexData vert;
+
+
+ if (v)
+ {
+ U32 v_idx = idx[j*stride+v_offset]*3;
+ vert.getPosition().set(v->get(v_idx),
+ v->get(v_idx+1),
+ v->get(v_idx+2));
+ }
+
+ if (n)
+ {
+ U32 n_idx = idx[j*stride+n_offset]*3;
+ vert.getNormal().set(n->get(n_idx),
+ n->get(n_idx+1),
+ n->get(n_idx+2));
+ }
+
+ if (t)
+ {
+ U32 t_idx = idx[j*stride+t_offset]*2;
+ vert.mTexCoord.setVec(t->get(t_idx),
+ t->get(t_idx+1));
+ }
+
+
+ verts.push_back(vert);
+ }
+ }
+
+ if (verts.empty())
+ {
+ return LLModel::NO_ERRORS;
+ }
+
+ face.mExtents[0] = verts[0].getPosition();
+ face.mExtents[1] = verts[0].getPosition();
+
+ //create a map of unique vertices to indices
+ std::map<LLVolumeFace::VertexData, U32> vert_idx;
+
+ U32 cur_idx = 0;
+ for (U32 i = 0; i < verts.size(); ++i)
+ {
+ std::map<LLVolumeFace::VertexData, U32>::iterator iter = vert_idx.find(verts[i]);
+ if (iter == vert_idx.end())
+ {
+ vert_idx[verts[i]] = cur_idx++;
+ }
+ }
+
+ if (cur_idx != vert_idx.size())
+ {
+ llerrs << "WTF?" << llendl;
+ }
+
+ //build vertex array from map
+ std::vector<LLVolumeFace::VertexData> new_verts;
+ new_verts.resize(vert_idx.size());
+
+ for (std::map<LLVolumeFace::VertexData, U32>::iterator iter = vert_idx.begin(); iter != vert_idx.end(); ++iter)
+ {
+ new_verts[iter->second] = iter->first;
+ update_min_max(face.mExtents[0], face.mExtents[1], iter->first.getPosition());
+ }
+
+ //build index array from map
+ indices.resize(verts.size());
+
+ for (U32 i = 0; i < verts.size(); ++i)
+ {
+ indices[i] = vert_idx[verts[i]];
+ }
+
+ // DEBUG just build an expanded triangle list
+ /*for (U32 i = 0; i < verts.size(); ++i)
+ {
+ indices.push_back((U16) i);
+ update_min_max(face.mExtents[0], face.mExtents[1], verts[i].getPosition());
+ }*/
+
+ if (!new_verts.empty())
+ {
+ std::string material;
+
+ if (poly->getMaterial())
+ {
+ material = std::string(poly->getMaterial());
+ }
+
+ materials.push_back(material);
+ face_list.push_back(face);
+ face_list.rbegin()->fillFromLegacyData(new_verts, indices);
+ }
+
+ return LLModel::NO_ERRORS ;
+}
+
+//static
+std::string LLModel::getStatusString(U32 status)
+{
+ const static std::string status_strings[(S32)INVALID_STATUS] = {"status_no_error", "status_vertex_number_overflow"};
+
+ if(status < INVALID_STATUS)
+ {
+ if(status_strings[status] == std::string())
+ {
+ llerrs << "No valid status string for this status: " << (U32)status << llendl ;
+ }
+ return status_strings[status] ;
+ }
+
+ llerrs << "Invalid model status: " << (U32)status << llendl ;
+
+ return std::string() ;
+}
+
+void LLModel::addVolumeFacesFromDomMesh(domMesh* mesh)
+{
+ domTriangles_Array& tris = mesh->getTriangles_array();
+
+ for (U32 i = 0; i < tris.getCount(); ++i)
+ {
+ domTrianglesRef& tri = tris.get(i);
+
+ mStatus = load_face_from_dom_triangles(mVolumeFaces, mMaterialList, tri);
+
+ if(mStatus != NO_ERRORS)
+ {
+ mVolumeFaces.clear() ;
+ mMaterialList.clear() ;
+ return ; //abort
+ }
+ }
+
+ domPolylist_Array& polys = mesh->getPolylist_array();
+ for (U32 i = 0; i < polys.getCount(); ++i)
+ {
+ domPolylistRef& poly = polys.get(i);
+
+ mStatus = load_face_from_dom_polylist(mVolumeFaces, mMaterialList, poly);
+
+ if(mStatus != NO_ERRORS)
+ {
+ mVolumeFaces.clear() ;
+ mMaterialList.clear() ;
+ return ; //abort
+ }
+ }
+
+ domPolygons_Array& polygons = mesh->getPolygons_array();
+ for (U32 i = 0; i < polygons.getCount(); ++i)
+ {
+ domPolygonsRef& poly = polygons.get(i);
+
+ mStatus = load_face_from_dom_polygons(mVolumeFaces, mMaterialList, poly);
+
+ if(mStatus != NO_ERRORS)
+ {
+ mVolumeFaces.clear() ;
+ mMaterialList.clear() ;
+ return ; //abort
+ }
+ }
+
+}
+
+BOOL LLModel::createVolumeFacesFromDomMesh(domMesh* mesh)
+{
+ if (mesh)
+ {
+ mVolumeFaces.clear();
+ mMaterialList.clear();
+
+ addVolumeFacesFromDomMesh(mesh);
+
+ if (getNumVolumeFaces() > 0)
+ {
+ optimizeVolumeFaces();
+ normalizeVolumeFaces();
+
+ if (getNumVolumeFaces() > 0)
+ {
+ return TRUE;
+ }
+ }
+ }
+ else
+ {
+ llwarns << "no mesh found" << llendl;
+ }
+
+ return FALSE;
+}
+
+void LLModel::offsetMesh( const LLVector3& pivotPoint )
+{
+ LLVector4a pivot( pivotPoint[VX], pivotPoint[VY], pivotPoint[VZ] );
+
+ for (std::vector<LLVolumeFace>::iterator faceIt = mVolumeFaces.begin(); faceIt != mVolumeFaces.end(); )
+ {
+ std::vector<LLVolumeFace>:: iterator currentFaceIt = faceIt++;
+ LLVolumeFace& face = *currentFaceIt;
+ LLVector4a *pos = (LLVector4a*) face.mPositions;
+
+ for (U32 i=0; i<face.mNumVertices; ++i )
+ {
+ pos[i].add( pivot );
+ }
+ }
+}
+
+void LLModel::optimizeVolumeFaces()
+{
+#if 0 //VECTORIZE ?
+ for (std::vector<LLVolumeFace>::iterator iter = mVolumeFaces.begin(); iter != mVolumeFaces.end(); )
+ {
+ std::vector<LLVolumeFace>::iterator cur_iter = iter++;
+ LLVolumeFace& face = *cur_iter;
+
+ for (S32 i = 0; i < (S32) face.mNumIndices; i += 3)
+ { //remove zero area triangles
+ U16 i0 = face.mIndices[i+0];
+ U16 i1 = face.mIndices[i+1];
+ U16 i2 = face.mIndices[i+2];
+
+ if (i0 == i1 ||
+ i1 == i2 ||
+ i0 == i2)
+ { //duplicate index in triangle, remove triangle
+ face.mIndices.erase(face.mIndices.begin()+i, face.mIndices.begin()+i+3);
+ i -= 3;
+ }
+ else
+ {
+ LLVolumeFace::VertexData& v0 = face.mVertices[i0];
+ LLVolumeFace::VertexData& v1 = face.mVertices[i1];
+ LLVolumeFace::VertexData& v2 = face.mVertices[i2];
+
+ if (v0.mPosition == v1.mPosition ||
+ v1.mPosition == v2.mPosition ||
+ v2.mPosition == v0.mPosition)
+ { //zero area triangle, delete
+ face.mIndices.erase(face.mIndices.begin()+i, face.mIndices.begin()+i+3);
+ i-=3;
+ }
+ }
+ }
+
+ //remove unreference vertices
+ std::vector<bool> ref;
+ ref.resize(face.mNumVertices);
+
+ for (U32 i = 0; i < ref.size(); ++i)
+ {
+ ref[i] = false;
+ }
+
+ for (U32 i = 0; i < face.mNumIndices; ++i)
+ {
+ ref[face.mIndices[i]] = true;
+ }
+
+ U32 unref_count = 0;
+ for (U32 i = 0; i < ref.size(); ++i)
+ {
+ if (!ref[i])
+ {
+ //vertex is unreferenced
+ face.mVertices.erase(face.mVertices.begin()+(i-unref_count));
+ U16 idx = (U16) (i-unref_count);
+
+ for (U32 j = 0; j < face.mNumIndices; ++j)
+ { //decrement every index array value greater than idx
+ if (face.mIndices[j] > idx)
+ {
+ --face.mIndices[j];
+ }
+ }
+ ++unref_count;
+ }
+ }
+
+ if (face.mVertices.empty() || face.mIndices.empty())
+ { //face is empty, remove it
+ iter = mVolumeFaces.erase(cur_iter);
+ }
+ }
+#endif
+}
+
+// Shrink the model to fit
+// on a 1x1x1 cube centered at the origin.
+// The positions and extents
+// multiplied by mNormalizedScale
+// and offset by mNormalizedTranslation
+// to be the "original" extents and position.
+// Also, the positions will fit
+// within the unit cube.
+void LLModel::normalizeVolumeFaces()
+{
+
+ // ensure we don't have too many faces
+ if (mVolumeFaces.size() > LL_SCULPT_MESH_MAX_FACES)
+ mVolumeFaces.resize(LL_SCULPT_MESH_MAX_FACES);
+
+ if (!mVolumeFaces.empty())
+ {
+ LLVector4a min, max;
+
+ if (mVolumeFaces[0].mNumVertices <= 0)
+ {
+ llerrs << "WTF?" << llendl;
+ }
+
+ // For all of the volume faces
+ // in the model, loop over
+ // them and see what the extents
+ // of the volume along each axis.
+ min = mVolumeFaces[0].mExtents[0];
+ max = mVolumeFaces[0].mExtents[1];
+
+ for (U32 i = 1; i < mVolumeFaces.size(); ++i)
+ {
+ LLVolumeFace& face = mVolumeFaces[i];
+
+ if (face.mNumVertices <= 0)
+ {
+ llerrs << "WTF?" << llendl;
+ }
+
+ update_min_max(min, max, face.mExtents[0]);
+ update_min_max(min, max, face.mExtents[1]);
+ }
+
+ // Now that we have the extents of the model
+ // we can compute the offset needed to center
+ // the model at the origin.
+
+ // Compute center of the model
+ // and make it negative to get translation
+ // needed to center at origin.
+ LLVector4a trans;
+ trans.setAdd(min, max);
+ trans.mul(-0.5f);
+
+ // Compute the total size along all
+ // axes of the model.
+ LLVector4a size;
+ size.setSub(max, min);
+
+ // Prevent division by zero.
+ F32 x = size[0];
+ F32 y = size[1];
+ F32 z = size[2];
+ F32 w = size[3];
+ if (fabs(x)<F_APPROXIMATELY_ZERO)
+ {
+ x = 1.0;
+ }
+ if (fabs(y)<F_APPROXIMATELY_ZERO)
+ {
+ y = 1.0;
+ }
+ if (fabs(z)<F_APPROXIMATELY_ZERO)
+ {
+ z = 1.0;
+ }
+ size.set(x,y,z,w);
+
+ // Compute scale as reciprocal of size
+ LLVector4a scale;
+ scale.splat(1.f);
+ scale.div(size);
+
+ for (U32 i = 0; i < mVolumeFaces.size(); ++i)
+ {
+ LLVolumeFace& face = mVolumeFaces[i];
+
+ // We shrink the extents so
+ // that they fall within
+ // the unit cube.
+ face.mExtents[0].add(trans);
+ face.mExtents[0].mul(scale);
+
+ face.mExtents[1].add(trans);
+ face.mExtents[1].mul(scale);
+
+ // For all the positions, we scale
+ // the positions to fit within the unit cube.
+ LLVector4a* pos = (LLVector4a*) face.mPositions;
+ for (U32 j = 0; j < face.mNumVertices; ++j)
+ {
+ pos[j].add(trans);
+ pos[j].mul(scale);
+ }
+ }
+
+ // mNormalizedScale is the scale at which
+ // we would need to multiply the model
+ // by to get the original size of the
+ // model instead of the normalized size.
+ LLVector4a normalized_scale;
+ normalized_scale.splat(1.f);
+ normalized_scale.div(scale);
+ mNormalizedScale.set(normalized_scale.getF32ptr());
+ mNormalizedTranslation.set(trans.getF32ptr());
+ mNormalizedTranslation *= -1.f;
+ }
+}
+
+void LLModel::getNormalizedScaleTranslation(LLVector3& scale_out, LLVector3& translation_out)
+{
+ scale_out = mNormalizedScale;
+ translation_out = mNormalizedTranslation;
+}
+
+void LLModel::setNumVolumeFaces(S32 count)
+{
+ mVolumeFaces.resize(count);
+}
+
+void LLModel::setVolumeFaceData(
+ S32 f,
+ LLStrider<LLVector3> pos,
+ LLStrider<LLVector3> norm,
+ LLStrider<LLVector2> tc,
+ LLStrider<U16> ind,
+ U32 num_verts,
+ U32 num_indices)
+{
+ LLVolumeFace& face = mVolumeFaces[f];
+
+ face.resizeVertices(num_verts);
+ face.resizeIndices(num_indices);
+
+ LLVector4a::memcpyNonAliased16((F32*) face.mPositions, (F32*) pos.get(), num_verts*4*sizeof(F32));
+ LLVector4a::memcpyNonAliased16((F32*) face.mNormals, (F32*) norm.get(), num_verts*4*sizeof(F32));
+ LLVector4a::memcpyNonAliased16((F32*) face.mTexCoords, (F32*) tc.get(), num_verts*2*sizeof(F32));
+ U32 size = (num_indices*2+0xF)&~0xF;
+ LLVector4a::memcpyNonAliased16((F32*) face.mIndices, (F32*) ind.get(), size);
+}
+
+void LLModel::appendFaces(LLModel *model, LLMatrix4 &transform, LLMatrix4& norm_mat)
+{
+ if (mVolumeFaces.empty())
+ {
+ setNumVolumeFaces(1);
+ }
+
+ LLVolumeFace& face = mVolumeFaces[mVolumeFaces.size()-1];
+
+
+ for (S32 i = 0; i < model->getNumFaces(); ++i)
+ {
+ face.appendFace(model->getVolumeFace(i), transform, norm_mat);
+ }
+
+}
+
+void LLModel::appendFace(const LLVolumeFace& src_face, std::string src_material, LLMatrix4& mat, LLMatrix4& norm_mat)
+{
+ S32 rindex = getNumVolumeFaces()-1;
+ if (rindex == -1 ||
+ mVolumeFaces[rindex].mNumVertices + src_face.mNumVertices >= 65536)
+ { //empty or overflow will occur, append new face
+ LLVolumeFace cur_face;
+ cur_face.appendFace(src_face, mat, norm_mat);
+ addFace(cur_face);
+ mMaterialList.push_back(src_material);
+ }
+ else
+ { //append to existing end face
+ mVolumeFaces.rbegin()->appendFace(src_face, mat, norm_mat);
+ }
+}
+
+void LLModel::addFace(const LLVolumeFace& face)
+{
+ if (face.mNumVertices == 0)
+ {
+ llerrs << "Cannot add empty face." << llendl;
+ }
+
+ mVolumeFaces.push_back(face);
+
+ if (mVolumeFaces.size() > MAX_MODEL_FACES)
+ {
+ llerrs << "Model prims cannot have more than " << MAX_MODEL_FACES << " faces!" << llendl;
+ }
+}
+
+
+void LLModel::generateNormals(F32 angle_cutoff)
+{
+ //generate normals for all faces by:
+ // 1 - Create faceted copy of face with no texture coordinates
+ // 2 - Weld vertices in faceted copy that are shared between triangles with less than "angle_cutoff" difference between normals
+ // 3 - Generate smoothed set of normals based on welding results
+ // 4 - Create faceted copy of face with texture coordinates
+ // 5 - Copy smoothed normals to faceted copy, using closest normal to triangle normal where more than one normal exists for a given position
+ // 6 - Remove redundant vertices from new faceted (now smooth) copy
+
+ angle_cutoff = cosf(angle_cutoff);
+ for (U32 j = 0; j < mVolumeFaces.size(); ++j)
+ {
+ LLVolumeFace& vol_face = mVolumeFaces[j];
+
+ if (vol_face.mNumIndices > 65535)
+ {
+ llwarns << "Too many vertices for normal generation to work." << llendl;
+ continue;
+ }
+
+ //create faceted copy of current face with no texture coordinates (step 1)
+ LLVolumeFace faceted;
+
+ LLVector4a* src_pos = (LLVector4a*) vol_face.mPositions;
+ //LLVector4a* src_norm = (LLVector4a*) vol_face.mNormals;
+
+
+ faceted.resizeVertices(vol_face.mNumIndices);
+ faceted.resizeIndices(vol_face.mNumIndices);
+ //bake out triangles into temporary face, clearing texture coordinates
+ for (U32 i = 0; i < vol_face.mNumIndices; ++i)
+ {
+ U32 idx = vol_face.mIndices[i];
+
+ faceted.mPositions[i] = src_pos[idx];
+ faceted.mTexCoords[i] = LLVector2(0,0);
+ faceted.mIndices[i] = i;
+ }
+
+ //generate normals for temporary face
+ for (U32 i = 0; i < faceted.mNumIndices; i += 3)
+ { //for each triangle
+ U16 i0 = faceted.mIndices[i+0];
+ U16 i1 = faceted.mIndices[i+1];
+ U16 i2 = faceted.mIndices[i+2];
+
+ LLVector4a& p0 = faceted.mPositions[i0];
+ LLVector4a& p1 = faceted.mPositions[i1];
+ LLVector4a& p2 = faceted.mPositions[i2];
+
+ LLVector4a& n0 = faceted.mNormals[i0];
+ LLVector4a& n1 = faceted.mNormals[i1];
+ LLVector4a& n2 = faceted.mNormals[i2];
+
+ LLVector4a lhs, rhs;
+ lhs.setSub(p1, p0);
+ rhs.setSub(p2, p0);
+
+ n0.setCross3(lhs, rhs);
+ n0.normalize3();
+ n1 = n0;
+ n2 = n0;
+ }
+
+ //weld vertices in temporary face, respecting angle_cutoff (step 2)
+ faceted.optimize(angle_cutoff);
+
+ //generate normals for welded face based on new topology (step 3)
+
+ for (U32 i = 0; i < faceted.mNumVertices; i++)
+ {
+ faceted.mNormals[i].clear();
+ }
+
+ for (U32 i = 0; i < faceted.mNumIndices; i += 3)
+ { //for each triangle
+ U16 i0 = faceted.mIndices[i+0];
+ U16 i1 = faceted.mIndices[i+1];
+ U16 i2 = faceted.mIndices[i+2];
+
+ LLVector4a& p0 = faceted.mPositions[i0];
+ LLVector4a& p1 = faceted.mPositions[i1];
+ LLVector4a& p2 = faceted.mPositions[i2];
+
+ LLVector4a& n0 = faceted.mNormals[i0];
+ LLVector4a& n1 = faceted.mNormals[i1];
+ LLVector4a& n2 = faceted.mNormals[i2];
+
+ LLVector4a lhs, rhs;
+ lhs.setSub(p1, p0);
+ rhs.setSub(p2, p0);
+
+ LLVector4a n;
+ n.setCross3(lhs, rhs);
+
+ n0.add(n);
+ n1.add(n);
+ n2.add(n);
+ }
+
+ //normalize normals and build point map
+ LLVolumeFace::VertexMapData::PointMap point_map;
+
+ for (U32 i = 0; i < faceted.mNumVertices; ++i)
+ {
+ faceted.mNormals[i].normalize3();
+
+ LLVolumeFace::VertexMapData v;
+ v.setPosition(faceted.mPositions[i]);
+ v.setNormal(faceted.mNormals[i]);
+
+ point_map[LLVector3(v.getPosition().getF32ptr())].push_back(v);
+ }
+
+ //create faceted copy of current face with texture coordinates (step 4)
+ LLVolumeFace new_face;
+
+ //bake out triangles into new face
+ new_face.resizeIndices(vol_face.mNumIndices);
+ new_face.resizeVertices(vol_face.mNumIndices);
+
+ for (U32 i = 0; i < vol_face.mNumIndices; ++i)
+ {
+ U32 idx = vol_face.mIndices[i];
+ LLVolumeFace::VertexData v;
+ new_face.mPositions[i] = vol_face.mPositions[idx];
+ new_face.mNormals[i].clear();
+ new_face.mTexCoords[i] = vol_face.mTexCoords[idx];
+ new_face.mIndices[i] = i;
+ }
+
+ //generate normals for new face
+ for (U32 i = 0; i < new_face.mNumIndices; i += 3)
+ { //for each triangle
+ U16 i0 = new_face.mIndices[i+0];
+ U16 i1 = new_face.mIndices[i+1];
+ U16 i2 = new_face.mIndices[i+2];
+
+ LLVector4a& p0 = new_face.mPositions[i0];
+ LLVector4a& p1 = new_face.mPositions[i1];
+ LLVector4a& p2 = new_face.mPositions[i2];
+
+ LLVector4a& n0 = new_face.mNormals[i0];
+ LLVector4a& n1 = new_face.mNormals[i1];
+ LLVector4a& n2 = new_face.mNormals[i2];
+
+ LLVector4a lhs, rhs;
+ lhs.setSub(p1, p0);
+ rhs.setSub(p2, p0);
+
+ n0.setCross3(lhs, rhs);
+ n0.normalize3();
+ n1 = n0;
+ n2 = n0;
+ }
+
+ //swap out normals in new_face with best match from point map (step 5)
+ for (U32 i = 0; i < new_face.mNumVertices; ++i)
+ {
+ //LLVolumeFace::VertexData v = new_face.mVertices[i];
+
+ LLVector4a ref_norm = new_face.mNormals[i];
+
+ LLVolumeFace::VertexMapData::PointMap::iterator iter = point_map.find(LLVector3(new_face.mPositions[i].getF32ptr()));
+
+ if (iter != point_map.end())
+ {
+ F32 best = -2.f;
+ for (U32 k = 0; k < iter->second.size(); ++k)
+ {
+ LLVector4a& n = iter->second[k].getNormal();
+
+ if (!iter->second[k].getPosition().equals3(new_face.mPositions[i]))
+ {
+ llerrs << "WTF?" << llendl;
+ }
+
+ F32 cur = n.dot3(ref_norm).getF32();
+
+ if (cur > best)
+ {
+ best = cur;
+ new_face.mNormals[i] = n;
+ }
+ }
+ }
+ }
+
+ //remove redundant vertices from new face (step 6)
+ new_face.optimize();
+
+ mVolumeFaces[j] = new_face;
+ }
+}
+
+//static
+std::string LLModel::getElementLabel(daeElement *element)
+{ // try to get a decent label for this element
+ // if we have a name attribute, use it
+ std::string name = element->getAttribute("name");
+ if (name.length())
+ {
+ return name;
+ }
+
+ // if we have an ID attribute, use it
+ if (element->getID())
+ {
+ return std::string(element->getID());
+ }
+
+ // if we have a parent, use it
+ daeElement* parent = element->getParent();
+ if (parent)
+ {
+ // if parent has a name, use it
+ std::string name = parent->getAttribute("name");
+ if (name.length())
+ {
+ return name;
+ }
+
+ // if parent has an ID, use it
+ if (parent->getID())
+ {
+ return std::string(parent->getID());
+ }
+ }
+
+ // try to use our type
+ daeString element_name = element->getElementName();
+ if (element_name)
+ {
+ return std::string(element_name);
+ }
+
+ // if all else fails, use "object"
+ return std::string("object");
+}
+
+//static
+LLModel* LLModel::loadModelFromDomMesh(domMesh *mesh)
+{
+ LLVolumeParams volume_params;
+ volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
+ LLModel* ret = new LLModel(volume_params, 0.f);
+ ret->createVolumeFacesFromDomMesh(mesh);
+ ret->mLabel = getElementLabel(mesh);
+ return ret;
+}
+
+std::string LLModel::getName() const
+{
+ if (!mRequestedLabel.empty())
+ return mRequestedLabel;
+ else
+ return mLabel;
+}
+
+//static
+LLSD LLModel::writeModel(
+ std::ostream& ostr,
+ LLModel* physics,
+ LLModel* high,
+ LLModel* medium,
+ LLModel* low,
+ LLModel* impostor,
+ const LLModel::Decomposition& decomp,
+ BOOL upload_skin,
+ BOOL upload_joints,
+ BOOL nowrite)
+{
+ LLSD mdl;
+
+ LLModel* model[] =
+ {
+ impostor,
+ low,
+ medium,
+ high,
+ physics
+ };
+
+ bool skinning = upload_skin && high && !high->mSkinWeights.empty();
+
+ if (skinning)
+ { //write skinning block
+ mdl["skin"] = high->mSkinInfo.asLLSD(upload_joints);
+ }
+
+ if (!decomp.mBaseHull.empty() ||
+ !decomp.mHull.empty())
+ {
+ mdl["decomposition"] = decomp.asLLSD();
+ }
+
+ for (U32 idx = 0; idx < MODEL_NAMES_LENGTH; ++idx)
+ {
+ if (model[idx] && model[idx]->getNumVolumeFaces() > 0)
+ {
+ LLVector3 min_pos = LLVector3(model[idx]->getVolumeFace(0).mPositions[0].getF32ptr());
+ LLVector3 max_pos = min_pos;
+
+ //find position domain
+ for (S32 i = 0; i < model[idx]->getNumVolumeFaces(); ++i)
+ { //for each face
+ const LLVolumeFace& face = model[idx]->getVolumeFace(i);
+ for (U32 j = 0; j < face.mNumVertices; ++j)
+ {
+ update_min_max(min_pos, max_pos, face.mPositions[j].getF32ptr());
+ }
+ }
+
+ LLVector3 pos_range = max_pos - min_pos;
+
+ for (S32 i = 0; i < model[idx]->getNumVolumeFaces(); ++i)
+ { //for each face
+ const LLVolumeFace& face = model[idx]->getVolumeFace(i);
+ if (!face.mNumVertices)
+ { //don't export an empty face
+ continue;
+ }
+ LLSD::Binary verts(face.mNumVertices*3*2);
+ LLSD::Binary tc(face.mNumVertices*2*2);
+ LLSD::Binary normals(face.mNumVertices*3*2);
+ LLSD::Binary indices(face.mNumIndices*2);
+
+ U32 vert_idx = 0;
+ U32 norm_idx = 0;
+ U32 tc_idx = 0;
+
+ LLVector2* ftc = (LLVector2*) face.mTexCoords;
+ LLVector2 min_tc = ftc[0];
+ LLVector2 max_tc = min_tc;
+
+ //get texture coordinate domain
+ for (U32 j = 0; j < face.mNumVertices; ++j)
+ {
+ update_min_max(min_tc, max_tc, ftc[j]);
+ }
+
+ LLVector2 tc_range = max_tc - min_tc;
+
+ for (U32 j = 0; j < face.mNumVertices; ++j)
+ { //for each vert
+
+ F32* pos = face.mPositions[j].getF32ptr();
+ F32* norm = face.mNormals[j].getF32ptr();
+
+ //position + normal
+ for (U32 k = 0; k < 3; ++k)
+ { //for each component
+
+ //convert to 16-bit normalized across domain
+ U16 val = (U16) (((pos[k]-min_pos.mV[k])/pos_range.mV[k])*65535);
+
+ U8* buff = (U8*) &val;
+ //write to binary buffer
+ verts[vert_idx++] = buff[0];
+ verts[vert_idx++] = buff[1];
+
+ //convert to 16-bit normalized
+ val = (U16) ((norm[k]+1.f)*0.5f*65535);
+
+ //write to binary buffer
+ normals[norm_idx++] = buff[0];
+ normals[norm_idx++] = buff[1];
+ }
+
+ F32* src_tc = (F32*) face.mTexCoords[j].mV;
+
+ //texcoord
+ for (U32 k = 0; k < 2; ++k)
+ { //for each component
+ //convert to 16-bit normalized
+ U16 val = (U16) ((src_tc[k]-min_tc.mV[k])/tc_range.mV[k]*65535);
+
+ U8* buff = (U8*) &val;
+ //write to binary buffer
+ tc[tc_idx++] = buff[0];
+ tc[tc_idx++] = buff[1];
+ }
+
+ }
+
+ U32 idx_idx = 0;
+ for (U32 j = 0; j < face.mNumIndices; ++j)
+ {
+ U8* buff = (U8*) &(face.mIndices[j]);
+ indices[idx_idx++] = buff[0];
+ indices[idx_idx++] = buff[1];
+ }
+
+ //write out face data
+ mdl[model_names[idx]][i]["PositionDomain"]["Min"] = min_pos.getValue();
+ mdl[model_names[idx]][i]["PositionDomain"]["Max"] = max_pos.getValue();
+
+ mdl[model_names[idx]][i]["TexCoord0Domain"]["Min"] = min_tc.getValue();
+ mdl[model_names[idx]][i]["TexCoord0Domain"]["Max"] = max_tc.getValue();
+
+ mdl[model_names[idx]][i]["Position"] = verts;
+ mdl[model_names[idx]][i]["Normal"] = normals;
+ mdl[model_names[idx]][i]["TexCoord0"] = tc;
+ mdl[model_names[idx]][i]["TriangleList"] = indices;
+
+ if (skinning)
+ {
+ //write out skin weights
+
+ //each influence list entry is up to 4 24-bit values
+ // first 8 bits is bone index
+ // last 16 bits is bone influence weight
+ // a bone index of 0xFF signifies no more influences for this vertex
+
+ std::stringstream ostr;
+
+ for (U32 j = 0; j < face.mNumVertices; ++j)
+ {
+ LLVector3 pos(face.mPositions[j].getF32ptr());
+
+ weight_list& weights = high->getJointInfluences(pos);
+
+ if (weights.size() > 4)
+ {
+ llerrs << "WTF?" << llendl;
+ }
+
+ S32 count = 0;
+ for (weight_list::iterator iter = weights.begin(); iter != weights.end(); ++iter)
+ {
+ if (iter->mJointIdx < 255 && iter->mJointIdx >= 0)
+ {
+ U8 idx = (U8) iter->mJointIdx;
+ ostr.write((const char*) &idx, 1);
+
+ U16 influence = (U16) (iter->mWeight*65535);
+ ostr.write((const char*) &influence, 2);
+
+ ++count;
+ }
+ }
+ U8 end_list = 0xFF;
+ if (count < 4)
+ {
+ ostr.write((const char*) &end_list, 1);
+ }
+ }
+
+ //copy ostr to binary buffer
+ std::string data = ostr.str();
+ const U8* buff = (U8*) data.data();
+ U32 bytes = data.size();
+
+ LLSD::Binary w(bytes);
+ for (U32 j = 0; j < bytes; ++j)
+ {
+ w[j] = buff[j];
+ }
+
+ mdl[model_names[idx]][i]["Weights"] = w;
+ }
+ }
+ }
+ }
+
+ return writeModelToStream(ostr, mdl, nowrite);
+}
+
+LLSD LLModel::writeModelToStream(std::ostream& ostr, LLSD& mdl, BOOL nowrite)
+{
+ U32 bytes = 0;
+
+ std::string::size_type cur_offset = 0;
+
+ LLSD header;
+
+ std::string skin;
+
+ if (mdl.has("skin"))
+ { //write out skin block
+ skin = zip_llsd(mdl["skin"]);
+
+ U32 size = skin.size();
+ if (size > 0)
+ {
+ header["skin"]["offset"] = (LLSD::Integer) cur_offset;
+ header["skin"]["size"] = (LLSD::Integer) size;
+ cur_offset += size;
+ bytes += size;
+ }
+ else
+ {
+ llerrs << "WTF?" << llendl;
+ }
+ }
+
+ std::string decomposition;
+
+ if (mdl.has("decomposition"))
+ { //write out convex decomposition
+ decomposition = zip_llsd(mdl["decomposition"]);
+
+ U32 size = decomposition.size();
+ if (size > 0)
+ {
+ header["decomposition"]["offset"] = (LLSD::Integer) cur_offset;
+ header["decomposition"]["size"] = (LLSD::Integer) size;
+ cur_offset += size;
+ bytes += size;
+ }
+ }
+
+ std::string out[MODEL_NAMES_LENGTH];
+
+ for (S32 i = 0; i < MODEL_NAMES_LENGTH; i++)
+ {
+ if (mdl.has(model_names[i]))
+ {
+ out[i] = zip_llsd(mdl[model_names[i]]);
+
+ U32 size = out[i].size();
+
+ header[model_names[i]]["offset"] = (LLSD::Integer) cur_offset;
+ header[model_names[i]]["size"] = (LLSD::Integer) size;
+ cur_offset += size;
+ bytes += size;
+ }
+ else
+ {
+ header[model_names[i]]["offset"] = -1;
+ header[model_names[i]]["size"] = 0;
+ }
+ }
+
+ if (!nowrite)
+ {
+ LLSDSerialize::toBinary(header, ostr);
+
+ if (!skin.empty())
+ { //write skin block
+ ostr.write((const char*) skin.data(), header["skin"]["size"].asInteger());
+ }
+
+ if (!decomposition.empty())
+ { //write decomposition block
+ ostr.write((const char*) decomposition.data(), header["decomposition"]["size"].asInteger());
+ }
+
+ for (S32 i = 0; i < MODEL_NAMES_LENGTH; i++)
+ {
+ if (!out[i].empty())
+ {
+ ostr.write((const char*) out[i].data(), header[model_names[i]]["size"].asInteger());
+ }
+ }
+ }
+
+ return header;
+}
+
+LLModel::weight_list& LLModel::getJointInfluences(const LLVector3& pos)
+{
+ weight_map::iterator iter = mSkinWeights.find(pos);
+
+ if (iter != mSkinWeights.end())
+ {
+ if ((iter->first - pos).magVec() > 0.1f)
+ {
+ llerrs << "WTF?" << llendl;
+ }
+
+ return iter->second;
+ }
+ else
+ { //no exact match found, get closest point
+ const F32 epsilon = 2.f/65536;
+ weight_map::iterator iter_up = mSkinWeights.lower_bound(pos);
+ weight_map::iterator iter_down = ++iter_up;
+
+ weight_map::iterator best = iter_up;
+
+ F32 min_dist = (iter->first - pos).magVecSquared();
+
+ bool done = false;
+ while (!done)
+ { //search up and down mSkinWeights from lower bound of pos until a
+ //match is found within epsilon. If no match is found within epsilon,
+ //return closest match
+ done = true;
+ if (iter_up != mSkinWeights.end() && ++iter_up != mSkinWeights.end())
+ {
+ done = false;
+ F32 dist = (iter_up->first - pos).magVecSquared();
+
+ if (dist < epsilon)
+ {
+ return iter_up->second;
+ }
+
+ if (dist < min_dist)
+ {
+ best = iter_up;
+ min_dist = dist;
+ }
+ }
+
+ if (iter_down != mSkinWeights.begin() && --iter_down != mSkinWeights.begin())
+ {
+ done = false;
+
+ F32 dist = (iter_down->first - pos).magVecSquared();
+
+ if (dist < epsilon)
+ {
+ return iter_down->second;
+ }
+
+ if (dist < min_dist)
+ {
+ best = iter_down;
+ min_dist = dist;
+ }
+
+ }
+ }
+
+ return best->second;
+ }
+}
+
+void LLModel::setConvexHullDecomposition(
+ const LLModel::convex_hull_decomposition& decomp)
+{
+ mPhysics.mHull = decomp;
+ mPhysics.mMesh.clear();
+ updateHullCenters();
+}
+
+void LLModel::updateHullCenters()
+{
+ mHullCenter.resize(mPhysics.mHull.size());
+ mHullPoints = 0;
+ mCenterOfHullCenters.clear();
+
+ for (U32 i = 0; i < mPhysics.mHull.size(); ++i)
+ {
+ LLVector3 cur_center;
+
+ for (U32 j = 0; j < mPhysics.mHull[i].size(); ++j)
+ {
+ cur_center += mPhysics.mHull[i][j];
+ }
+ mCenterOfHullCenters += cur_center;
+ cur_center *= 1.f/mPhysics.mHull[i].size();
+ mHullCenter[i] = cur_center;
+ mHullPoints += mPhysics.mHull[i].size();
+ }
+
+ if (mHullPoints > 0)
+ {
+ mCenterOfHullCenters *= 1.f / mHullPoints;
+ llassert(mPhysics.asLLSD().has("HullList"));
+ }
+}
+
+bool LLModel::loadModel(std::istream& is)
+{
+ mSculptLevel = -1; // default is an error occured
+
+ LLSD header;
+ {
+ if (!LLSDSerialize::fromBinary(header, is, 1024*1024*1024))
+ {
+ llwarns << "Mesh header parse error. Not a valid mesh asset!" << llendl;
+ return false;
+ }
+ }
+
+ std::string nm[] =
+ {
+ "lowest_lod",
+ "low_lod",
+ "medium_lod",
+ "high_lod",
+ "physics_shape",
+ };
+
+ const S32 MODEL_LODS = 5;
+
+ S32 lod = llclamp((S32) mDetail, 0, MODEL_LODS);
+
+ if (header[nm[lod]]["offset"].asInteger() == -1 ||
+ header[nm[lod]]["size"].asInteger() == 0 )
+ { //cannot load requested LOD
+ return false;
+ }
+
+ bool has_skin = header["skin"]["offset"].asInteger() >=0 &&
+ header["skin"]["size"].asInteger() > 0;
+
+ if (lod == LLModel::LOD_HIGH)
+ { //try to load skin info and decomp info
+ std::ios::pos_type cur_pos = is.tellg();
+ loadSkinInfo(header, is);
+ is.seekg(cur_pos);
+ }
+
+ if (lod == LLModel::LOD_PHYSICS)
+ {
+ std::ios::pos_type cur_pos = is.tellg();
+ loadDecomposition(header, is);
+ is.seekg(cur_pos);
+ }
+
+ is.seekg(header[nm[lod]]["offset"].asInteger(), std::ios_base::cur);
+
+ if (unpackVolumeFaces(is, header[nm[lod]]["size"].asInteger()))
+ {
+ if (has_skin)
+ {
+ //build out mSkinWeight from face info
+ for (S32 i = 0; i < getNumVolumeFaces(); ++i)
+ {
+ const LLVolumeFace& face = getVolumeFace(i);
+
+ if (face.mWeights)
+ {
+ for (S32 j = 0; j < face.mNumVertices; ++j)
+ {
+ LLVector4a& w = face.mWeights[j];
+
+ std::vector<JointWeight> wght;
+
+ for (S32 k = 0; k < 4; ++k)
+ {
+ S32 idx = (S32) w[k];
+ F32 f = w[k] - idx;
+ if (f > 0.f)
+ {
+ wght.push_back(JointWeight(idx, f));
+ }
+ }
+
+ if (!wght.empty())
+ {
+ LLVector3 pos(face.mPositions[j].getF32ptr());
+ mSkinWeights[pos] = wght;
+ }
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ return false;
+
+}
+
+
+bool LLModel::loadSkinInfo(LLSD& header, std::istream &is)
+{
+ S32 offset = header["skin"]["offset"].asInteger();
+ S32 size = header["skin"]["size"].asInteger();
+
+ if (offset >= 0 && size > 0)
+ {
+ is.seekg(offset, std::ios_base::cur);
+
+ LLSD skin_data;
+
+ if (unzip_llsd(skin_data, is, size))
+ {
+ mSkinInfo.fromLLSD(skin_data);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool LLModel::loadDecomposition(LLSD& header, std::istream& is)
+{
+ S32 offset = header["decomposition"]["offset"].asInteger();
+ S32 size = header["decomposition"]["size"].asInteger();
+
+ if (offset >= 0 && size > 0)
+ {
+ is.seekg(offset, std::ios_base::cur);
+
+ LLSD data;
+
+ if (unzip_llsd(data, is, size))
+ {
+ mPhysics.fromLLSD(data);
+ updateHullCenters();
+ }
+ }
+
+ return true;
+}
+
+
+LLMeshSkinInfo::LLMeshSkinInfo(LLSD& skin)
+{
+ fromLLSD(skin);
+}
+
+void LLMeshSkinInfo::fromLLSD(LLSD& skin)
+{
+ if (skin.has("joint_names"))
+ {
+ for (U32 i = 0; i < skin["joint_names"].size(); ++i)
+ {
+ mJointNames.push_back(skin["joint_names"][i]);
+ }
+ }
+
+ if (skin.has("inverse_bind_matrix"))
+ {
+ for (U32 i = 0; i < skin["inverse_bind_matrix"].size(); ++i)
+ {
+ LLMatrix4 mat;
+ for (U32 j = 0; j < 4; j++)
+ {
+ for (U32 k = 0; k < 4; k++)
+ {
+ mat.mMatrix[j][k] = skin["inverse_bind_matrix"][i][j*4+k].asReal();
+ }
+ }
+
+ mInvBindMatrix.push_back(mat);
+ }
+ }
+
+ if (skin.has("bind_shape_matrix"))
+ {
+ for (U32 j = 0; j < 4; j++)
+ {
+ for (U32 k = 0; k < 4; k++)
+ {
+ mBindShapeMatrix.mMatrix[j][k] = skin["bind_shape_matrix"][j*4+k].asReal();
+ }
+ }
+ }
+
+ if (skin.has("alt_inverse_bind_matrix"))
+ {
+ for (U32 i = 0; i < skin["alt_inverse_bind_matrix"].size(); ++i)
+ {
+ LLMatrix4 mat;
+ for (U32 j = 0; j < 4; j++)
+ {
+ for (U32 k = 0; k < 4; k++)
+ {
+ mat.mMatrix[j][k] = skin["alt_inverse_bind_matrix"][i][j*4+k].asReal();
+ }
+ }
+
+ mAlternateBindMatrix.push_back(mat);
+ }
+ }
+
+ if (skin.has("pelvis_offset"))
+ {
+ mPelvisOffset = skin["pelvis_offset"].asReal();
+ }
+}
+
+LLSD LLMeshSkinInfo::asLLSD(bool include_joints) const
+{
+ LLSD ret;
+
+ for (U32 i = 0; i < mJointNames.size(); ++i)
+ {
+ ret["joint_names"][i] = mJointNames[i];
+
+ for (U32 j = 0; j < 4; j++)
+ {
+ for (U32 k = 0; k < 4; k++)
+ {
+ ret["inverse_bind_matrix"][i][j*4+k] = mInvBindMatrix[i].mMatrix[j][k];
+ }
+ }
+ }
+
+ for (U32 i = 0; i < 4; i++)
+ {
+ for (U32 j = 0; j < 4; j++)
+ {
+ ret["bind_shape_matrix"][i*4+j] = mBindShapeMatrix.mMatrix[i][j];
+ }
+ }
+
+ if ( include_joints && mAlternateBindMatrix.size() > 0 )
+ {
+ for (U32 i = 0; i < mJointNames.size(); ++i)
+ {
+ for (U32 j = 0; j < 4; j++)
+ {
+ for (U32 k = 0; k < 4; k++)
+ {
+ ret["alt_inverse_bind_matrix"][i][j*4+k] = mAlternateBindMatrix[i].mMatrix[j][k];
+ }
+ }
+ }
+
+ ret["pelvis_offset"] = mPelvisOffset;
+ }
+
+ return ret;
+}
+
+LLModel::Decomposition::Decomposition(LLSD& data)
+{
+ fromLLSD(data);
+}
+
+void LLModel::Decomposition::fromLLSD(LLSD& decomp)
+{
+ if (decomp.has("HullList"))
+ {
+ // updated for const-correctness. gcc is picky about this type of thing - Nyx
+ const LLSD::Binary& hulls = decomp["HullList"].asBinary();
+ const LLSD::Binary& position = decomp["Position"].asBinary();
+
+ U16* p = (U16*) &position[0];
+
+ mHull.resize(hulls.size());
+
+ LLVector3 min;
+ LLVector3 max;
+ LLVector3 range;
+
+ min.setValue(decomp["Min"]);
+ max.setValue(decomp["Max"]);
+ range = max-min;
+
+
+ for (U32 i = 0; i < hulls.size(); ++i)
+ {
+ U16 count = (hulls[i] == 0) ? 256 : hulls[i];
+
+ std::set<U64> valid;
+
+ //must have at least 4 points
+ //llassert(count > 3);
+
+ for (U32 j = 0; j < count; ++j)
+ {
+ U64 test = (U64) p[0] | ((U64) p[1] << 16) | ((U64) p[2] << 32);
+ //point must be unique
+ //llassert(valid.find(test) == valid.end());
+ valid.insert(test);
+ mHull[i].push_back(LLVector3(
+ (F32) p[0]/65535.f*range.mV[0]+min.mV[0],
+ (F32) p[1]/65535.f*range.mV[1]+min.mV[1],
+ (F32) p[2]/65535.f*range.mV[2]+min.mV[2]));
+ p += 3;
+
+
+ }
+
+ //each hull must contain at least 4 unique points
+ //llassert(valid.size() > 3);
+ }
+ }
+
+ if (decomp.has("Hull"))
+ {
+ const LLSD::Binary& position = decomp["Hull"].asBinary();
+
+ U16* p = (U16*) &position[0];
+
+ LLVector3 min;
+ LLVector3 max;
+ LLVector3 range;
+
+ if (decomp.has("Min"))
+ {
+ min.setValue(decomp["Min"]);
+ max.setValue(decomp["Max"]);
+ }
+ else
+ {
+ min.set(-0.5f, -0.5f, -0.5f);
+ max.set(0.5f, 0.5f, 0.5f);
+ }
+
+ range = max-min;
+
+ U16 count = position.size()/6;
+
+ for (U32 j = 0; j < count; ++j)
+ {
+ mBaseHull.push_back(LLVector3(
+ (F32) p[0]/65535.f*range.mV[0]+min.mV[0],
+ (F32) p[1]/65535.f*range.mV[1]+min.mV[1],
+ (F32) p[2]/65535.f*range.mV[2]+min.mV[2]));
+ p += 3;
+ }
+ }
+ else
+ {
+ //empty base hull mesh to indicate decomposition has been loaded
+ //but contains no base hull
+ mBaseHullMesh.clear();;
+ }
+}
+
+LLSD LLModel::Decomposition::asLLSD() const
+{
+ LLSD ret;
+
+ if (mBaseHull.empty() && mHull.empty())
+ { //nothing to write
+ return ret;
+ }
+
+ //write decomposition block
+ // ["decomposition"]["HullList"] -- list of 8 bit integers, each entry represents a hull with specified number of points
+ // ["decomposition"]["PositionDomain"]["Min"/"Max"]
+ // ["decomposition"]["Position"] -- list of 16-bit integers to be decoded to given domain, encoded 3D points
+ // ["decomposition"]["Hull"] -- list of 16-bit integers to be decoded to given domain, encoded 3D points representing a single hull approximation of given shape
+
+
+ //get minimum and maximum
+ LLVector3 min;
+
+ if (mHull.empty())
+ {
+ min = mBaseHull[0];
+ }
+ else
+ {
+ min = mHull[0][0];
+ }
+
+ LLVector3 max = min;
+
+ LLSD::Binary hulls(mHull.size());
+
+ U32 total = 0;
+
+ for (U32 i = 0; i < mHull.size(); ++i)
+ {
+ U32 size = mHull[i].size();
+ total += size;
+ hulls[i] = (U8) (size);
+
+ for (U32 j = 0; j < mHull[i].size(); ++j)
+ {
+ update_min_max(min, max, mHull[i][j]);
+ }
+ }
+
+ for (U32 i = 0; i < mBaseHull.size(); ++i)
+ {
+ update_min_max(min, max, mBaseHull[i]);
+ }
+
+ ret["Min"] = min.getValue();
+ ret["Max"] = max.getValue();
+
+ if (!hulls.empty())
+ {
+ ret["HullList"] = hulls;
+ }
+
+ if (total > 0)
+ {
+ LLSD::Binary p(total*3*2);
+
+ LLVector3 range = max-min;
+
+ U32 vert_idx = 0;
+
+ for (U32 i = 0; i < mHull.size(); ++i)
+ {
+ std::set<U64> valid;
+
+ llassert(!mHull[i].empty());
+
+ for (U32 j = 0; j < mHull[i].size(); ++j)
+ {
+ U64 test = 0;
+ for (U32 k = 0; k < 3; k++)
+ {
+ //convert to 16-bit normalized across domain
+ U16 val = (U16) (((mHull[i][j].mV[k]-min.mV[k])/range.mV[k])*65535);
+
+ switch (k)
+ {
+ case 0: test = test | (U64) val; break;
+ case 1: test = test | ((U64) val << 16); break;
+ case 2: test = test | ((U64) val << 32); break;
+ };
+
+ valid.insert(test);
+
+ U8* buff = (U8*) &val;
+ //write to binary buffer
+ p[vert_idx++] = buff[0];
+ p[vert_idx++] = buff[1];
+
+ //makes sure we haven't run off the end of the array
+ llassert(vert_idx <= p.size());
+ }
+ }
+
+ //must have at least 4 unique points
+ llassert(valid.size() > 3);
+ }
+
+ ret["Position"] = p;
+ }
+
+ if (!mBaseHull.empty())
+ {
+ LLSD::Binary p(mBaseHull.size()*3*2);
+
+ LLVector3 range = max-min;
+
+ U32 vert_idx = 0;
+ for (U32 j = 0; j < mBaseHull.size(); ++j)
+ {
+ for (U32 k = 0; k < 3; k++)
+ {
+ //convert to 16-bit normalized across domain
+ U16 val = (U16) (((mBaseHull[j].mV[k]-min.mV[k])/range.mV[k])*65535);
+
+ U8* buff = (U8*) &val;
+ //write to binary buffer
+ p[vert_idx++] = buff[0];
+ p[vert_idx++] = buff[1];
+
+ if (vert_idx > p.size())
+ {
+ llerrs << "WTF?" << llendl;
+ }
+ }
+ }
+
+ ret["Hull"] = p;
+ }
+
+ return ret;
+}
+
+void LLModel::Decomposition::merge(const LLModel::Decomposition* rhs)
+{
+ if (!rhs)
+ {
+ return;
+ }
+
+ if (mMeshID != rhs->mMeshID)
+ {
+ llerrs << "Attempted to merge with decomposition of some other mesh." << llendl;
+ }
+
+ if (mBaseHull.empty())
+ { //take base hull and decomposition from rhs
+ mHull = rhs->mHull;
+ mBaseHull = rhs->mBaseHull;
+ mMesh = rhs->mMesh;
+ mBaseHullMesh = rhs->mBaseHullMesh;
+ }
+
+ if (mPhysicsShapeMesh.empty())
+ { //take physics shape mesh from rhs
+ mPhysicsShapeMesh = rhs->mPhysicsShapeMesh;
+ }
+
+ if (!mHull.empty())
+ { //verify
+ llassert(asLLSD().has("HullList"));
+ }
+}
+
diff --git a/indra/llprimitive/llmodel.h b/indra/llprimitive/llmodel.h
new file mode 100644
index 0000000000..23f4b5cb42
--- /dev/null
+++ b/indra/llprimitive/llmodel.h
@@ -0,0 +1,255 @@
+/**
+ * @file llmodel.h
+ * @brief Model handling class definitions
+ *
+ * $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_LLMODEL_H
+#define LL_LLMODEL_H
+
+#include "llpointer.h"
+#include "llvolume.h"
+#include "v4math.h"
+#include "m4math.h"
+
+class daeElement;
+class domMesh;
+
+#define MAX_MODEL_FACES 8
+
+
+class LLMeshSkinInfo
+{
+public:
+ LLUUID mMeshID;
+ std::vector<std::string> mJointNames;
+ std::vector<LLMatrix4> mInvBindMatrix;
+ std::vector<LLMatrix4> mAlternateBindMatrix;
+ std::map<std::string, U32> mJointMap;
+
+ LLMeshSkinInfo() { }
+ LLMeshSkinInfo(LLSD& data);
+ void fromLLSD(LLSD& data);
+ LLSD asLLSD(bool include_joints) const;
+ LLMatrix4 mBindShapeMatrix;
+ float mPelvisOffset;
+};
+
+class LLModel : public LLVolume
+{
+public:
+
+ enum
+ {
+ LOD_IMPOSTOR = 0,
+ LOD_LOW,
+ LOD_MEDIUM,
+ LOD_HIGH,
+ LOD_PHYSICS,
+ NUM_LODS
+ };
+
+ enum EModelStatus
+ {
+ NO_ERRORS = 0,
+ VERTEX_NUMBER_OVERFLOW, //vertex number is >= 65535.
+ INVALID_STATUS
+ } ;
+
+ //convex_hull_decomposition is a vector of convex hulls
+ //each convex hull is a set of points
+ typedef std::vector<std::vector<LLVector3> > convex_hull_decomposition;
+ typedef std::vector<LLVector3> hull;
+
+ class PhysicsMesh
+ {
+ public:
+ std::vector<LLVector3> mPositions;
+ std::vector<LLVector3> mNormals;
+
+ void clear()
+ {
+ mPositions.clear();
+ mNormals.clear();
+ }
+
+ bool empty() const
+ {
+ return mPositions.empty();
+ }
+ };
+
+ class Decomposition
+ {
+ public:
+ Decomposition() { }
+ Decomposition(LLSD& data);
+ void fromLLSD(LLSD& data);
+ LLSD asLLSD() const;
+
+ void merge(const Decomposition* rhs);
+
+ LLUUID mMeshID;
+ LLModel::convex_hull_decomposition mHull;
+ LLModel::hull mBaseHull;
+
+ std::vector<LLModel::PhysicsMesh> mMesh;
+ LLModel::PhysicsMesh mBaseHullMesh;
+ LLModel::PhysicsMesh mPhysicsShapeMesh;
+ };
+
+ LLModel(LLVolumeParams& params, F32 detail);
+ ~LLModel();
+
+ bool loadModel(std::istream& is);
+ bool loadSkinInfo(LLSD& header, std::istream& is);
+ bool loadDecomposition(LLSD& header, std::istream& is);
+
+ static LLSD writeModel(
+ std::ostream& ostr,
+ LLModel* physics,
+ LLModel* high,
+ LLModel* medium,
+ LLModel* low,
+ LLModel* imposotr,
+ const LLModel::Decomposition& decomp,
+ BOOL upload_skin,
+ BOOL upload_joints,
+ BOOL nowrite = FALSE);
+
+ static LLSD writeModelToStream(
+ std::ostream& ostr,
+ LLSD& mdl,
+ BOOL nowrite = FALSE);
+
+ static LLModel* loadModelFromDomMesh(domMesh* mesh);
+ static std::string getElementLabel(daeElement* element);
+ std::string getName() const;
+ EModelStatus getStatus() const {return mStatus;}
+ static std::string getStatusString(U32 status) ;
+
+ void appendFaces(LLModel* model, LLMatrix4& transform, LLMatrix4& normal_transform);
+ void appendFace(const LLVolumeFace& src_face, std::string src_material, LLMatrix4& mat, LLMatrix4& norm_mat);
+
+ void setNumVolumeFaces(S32 count);
+ void setVolumeFaceData(
+ S32 f,
+ LLStrider<LLVector3> pos,
+ LLStrider<LLVector3> norm,
+ LLStrider<LLVector2> tc,
+ LLStrider<U16> ind,
+ U32 num_verts,
+ U32 num_indices);
+
+ void generateNormals(F32 angle_cutoff);
+
+ void addFace(const LLVolumeFace& face);
+
+ void normalizeVolumeFaces();
+ void optimizeVolumeFaces();
+ void offsetMesh( const LLVector3& pivotPoint );
+ void getNormalizedScaleTranslation(LLVector3& scale_out, LLVector3& translation_out);
+ std::vector<std::string> mMaterialList;
+
+ //data used for skin weights
+ class JointWeight
+ {
+ public:
+ S32 mJointIdx;
+ F32 mWeight;
+
+ JointWeight()
+ {
+ mJointIdx = 0;
+ mWeight = 0.f;
+ }
+
+ JointWeight(S32 idx, F32 weight)
+ : mJointIdx(idx), mWeight(weight)
+ {
+ }
+
+ bool operator<(const JointWeight& rhs) const
+ {
+ if (mWeight == rhs.mWeight)
+ {
+ return mJointIdx < rhs.mJointIdx;
+ }
+
+ return mWeight < rhs.mWeight;
+ }
+
+ };
+
+ struct CompareWeightGreater
+ {
+ bool operator()(const JointWeight& lhs, const JointWeight& rhs)
+ {
+ return rhs < lhs; // strongest = first
+ }
+ };
+
+ //copy of position array for this model -- mPosition[idx].mV[X,Y,Z]
+ std::vector<LLVector3> mPosition;
+
+ //map of positions to skin weights --- mSkinWeights[pos].mV[0..4] == <joint_index>.<weight>
+ //joint_index corresponds to mJointList
+ typedef std::vector<JointWeight> weight_list;
+ typedef std::map<LLVector3, weight_list > weight_map;
+ weight_map mSkinWeights;
+
+ //get list of weight influences closest to given position
+ weight_list& getJointInfluences(const LLVector3& pos);
+
+ LLMeshSkinInfo mSkinInfo;
+
+ std::string mRequestedLabel; // name requested in UI, if any.
+ std::string mLabel; // name computed from dae.
+
+ LLVector3 mNormalizedScale;
+ LLVector3 mNormalizedTranslation;
+
+ float mPelvisOffset;
+ // convex hull decomposition
+ S32 mDecompID;
+
+ void setConvexHullDecomposition(
+ const convex_hull_decomposition& decomp);
+ void updateHullCenters();
+
+ LLVector3 mCenterOfHullCenters;
+ std::vector<LLVector3> mHullCenter;
+ U32 mHullPoints;
+
+ //ID for storing this model in a .slm file
+ S32 mLocalID;
+
+ Decomposition mPhysics;
+
+ EModelStatus mStatus ;
+protected:
+ void addVolumeFacesFromDomMesh(domMesh* mesh);
+ virtual BOOL createVolumeFacesFromDomMesh(domMesh *mesh);
+};
+
+#endif //LL_LLMODEL_H
diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp
index 258c0c3c15..30532247ac 100644
--- a/indra/llprimitive/llprimitive.cpp
+++ b/indra/llprimitive/llprimitive.cpp
@@ -738,7 +738,11 @@ BOOL LLPrimitive::setVolume(const LLVolumeParams &volume_params, const S32 detai
setNumTEs(mVolumep->getNumFaces());
return TRUE;
}
-
+
+#if 0
+ // #if 0'd out by davep
+ // this is a lot of cruft to set texture entry values that just stay the same for LOD switch
+ // or immediately get overridden by an object update message, also crashes occasionally
U32 old_face_mask = mVolumep->mFaceMask;
S32 face_bit = 0;
@@ -936,6 +940,13 @@ BOOL LLPrimitive::setVolume(const LLVolumeParams &volume_params, const S32 detai
setTE(te_num, *(old_tes.getTexture(face_mapping[face_bit])));
}
}
+#else
+ // build the new object
+ sVolumeManager->unrefVolume(mVolumep);
+ mVolumep = volumep;
+
+ setNumTEs(mVolumep->getNumFaces());
+#endif
return TRUE;
}
@@ -1078,7 +1089,7 @@ BOOL LLPrimitive::packTEMessage(LLMessageSystem *mesgsys) const
U8 packed_buffer[MAX_TE_BUFFER];
U8 *cur_ptr = packed_buffer;
- S32 last_face_index = getNumTEs() - 1;
+ S32 last_face_index = llmin((U32) getNumTEs(), MAX_TES) - 1;
if (last_face_index > -1)
{
@@ -1216,12 +1227,12 @@ BOOL LLPrimitive::packTEMessage(LLDataPacker &dp) const
return FALSE;
}
-S32 LLPrimitive::unpackTEMessage(LLMessageSystem *mesgsys, char *block_name)
+S32 LLPrimitive::unpackTEMessage(LLMessageSystem* mesgsys, char const* block_name)
{
return(unpackTEMessage(mesgsys,block_name,-1));
}
-S32 LLPrimitive::unpackTEMessage(LLMessageSystem *mesgsys, char *block_name, const S32 block_num)
+S32 LLPrimitive::unpackTEMessage(LLMessageSystem* mesgsys, char const* block_name, const S32 block_num)
{
// use a negative block_num to indicate a single-block read (a non-variable block)
S32 retval = 0;
@@ -1359,7 +1370,7 @@ S32 LLPrimitive::unpackTEMessage(LLDataPacker &dp)
return retval;
}
- face_count = getNumTEs();
+ face_count = llmin((U32) getNumTEs(), MAX_TES);
U32 i;
cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)image_data, 16, face_count, MVT_LLUUID);
diff --git a/indra/llprimitive/llprimitive.h b/indra/llprimitive/llprimitive.h
index f535fb1672..76faa1b8c5 100644
--- a/indra/llprimitive/llprimitive.h
+++ b/indra/llprimitive/llprimitive.h
@@ -323,7 +323,7 @@ public:
const LLVolume *getVolumeConst() const { return mVolumep; } // HACK for Windoze confusion about ostream operator in LLVolume
LLVolume *getVolume() const { return mVolumep; }
virtual BOOL setVolume(const LLVolumeParams &volume_params, const S32 detail, bool unique_volume = false);
-
+
// Modify texture entry properties
inline BOOL validTE(const U8 te_num) const;
LLTextureEntry* getTE(const U8 te_num) const;
@@ -358,8 +358,8 @@ public:
S32 unpackTEField(U8 *cur_ptr, U8 *buffer_end, U8 *data_ptr, U8 data_size, U8 face_count, EMsgVariableType type);
BOOL packTEMessage(LLMessageSystem *mesgsys) const;
BOOL packTEMessage(LLDataPacker &dp) const;
- S32 unpackTEMessage(LLMessageSystem *mesgsys, char *block_name);
- S32 unpackTEMessage(LLMessageSystem *mesgsys, char *block_name, const S32 block_num); // Variable num of blocks
+ S32 unpackTEMessage(LLMessageSystem* mesgsys, char const* block_name);
+ S32 unpackTEMessage(LLMessageSystem* mesgsys, char const* block_name, const S32 block_num); // Variable num of blocks
BOOL unpackTEMessage(LLDataPacker &dp);
#ifdef CHECK_FOR_FINITE
@@ -444,6 +444,7 @@ protected:
U8 mNumTEs; // # of faces on the primitve
U32 mMiscFlags; // home for misc bools
+public:
static LLVolumeMgr* sVolumeManager;
};
diff --git a/indra/llprimitive/lltextureentry.cpp b/indra/llprimitive/lltextureentry.cpp
index 3c1d031ff5..34eff17519 100644
--- a/indra/llprimitive/lltextureentry.cpp
+++ b/indra/llprimitive/lltextureentry.cpp
@@ -403,7 +403,7 @@ S32 LLTextureEntry::setOffsetT(F32 t)
S32 LLTextureEntry::setRotation(F32 theta)
{
- if (mRotation != theta)
+ if (mRotation != theta && llfinite(theta))
{
mRotation = theta;
return TEM_CHANGE_TEXTURE;
@@ -423,24 +423,10 @@ S32 LLTextureEntry::setBumpShinyFullbright(U8 bump)
S32 LLTextureEntry::setMediaTexGen(U8 media)
{
- if (mMediaFlags != media)
- {
- mMediaFlags = media;
-
- // Special code for media handling
- if( hasMedia() && mMediaEntry == NULL)
- {
- mMediaEntry = new LLMediaEntry;
- }
- else if ( ! hasMedia() && mMediaEntry != NULL)
- {
- delete mMediaEntry;
- mMediaEntry = NULL;
- }
-
- return TEM_CHANGE_MEDIA;
- }
- return TEM_CHANGE_NONE;
+ S32 result = TEM_CHANGE_NONE;
+ result |= setTexGen(media & TEM_TEX_GEN_MASK);
+ result |= setMediaFlags(media & TEM_MEDIA_MASK);
+ return result;
}
S32 LLTextureEntry::setBumpmap(U8 bump)
diff --git a/indra/llprimitive/llvolumemessage.cpp b/indra/llprimitive/llvolumemessage.cpp
index b6cae5c4df..58b23bebd2 100644
--- a/indra/llprimitive/llvolumemessage.cpp
+++ b/indra/llprimitive/llvolumemessage.cpp
@@ -94,7 +94,7 @@ bool LLVolumeMessage::packProfileParams(
bool LLVolumeMessage::unpackProfileParams(
LLProfileParams* params,
LLMessageSystem* mesgsys,
- char* block_name,
+ char const* block_name,
S32 block_num)
{
bool ok = true;
@@ -322,7 +322,7 @@ bool LLVolumeMessage::packPathParams(
bool LLVolumeMessage::unpackPathParams(
LLPathParams* params,
LLMessageSystem* mesgsys,
- char* block_name,
+ char const* block_name,
S32 block_num)
{
U8 curve;
@@ -522,7 +522,7 @@ bool LLVolumeMessage::packVolumeParams(const LLVolumeParams* params, LLDataPacke
bool LLVolumeMessage::unpackVolumeParams(
LLVolumeParams* params,
LLMessageSystem* mesgsys,
- char* block_name,
+ char const* block_name,
S32 block_num)
{
bool ok = true;
diff --git a/indra/llprimitive/llvolumemessage.h b/indra/llprimitive/llvolumemessage.h
index 33562323c3..f59ee79c60 100644
--- a/indra/llprimitive/llvolumemessage.h
+++ b/indra/llprimitive/llvolumemessage.h
@@ -49,7 +49,7 @@ protected:
static bool unpackProfileParams(
LLProfileParams* params,
LLMessageSystem* mesgsys,
- char* block_name,
+ char const* block_name,
S32 block_num = 0);
static bool unpackProfileParams(LLProfileParams* params, LLDataPacker& dp);
@@ -60,7 +60,7 @@ protected:
static bool unpackPathParams(
LLPathParams* params,
LLMessageSystem* mesgsys,
- char* block_name,
+ char const* block_name,
S32 block_num = 0);
static bool unpackPathParams(LLPathParams* params, LLDataPacker& dp);
@@ -83,7 +83,7 @@ public:
static bool unpackVolumeParams(
LLVolumeParams* params,
LLMessageSystem* mesgsys,
- char* block_name,
+ char const* block_name,
S32 block_num = 0);
static bool unpackVolumeParams(LLVolumeParams* params, LLDataPacker &dp);
};
diff --git a/indra/llrender/llfontfreetype.cpp b/indra/llrender/llfontfreetype.cpp
index b84e696e2d..91c8a37022 100644
--- a/indra/llrender/llfontfreetype.cpp
+++ b/indra/llrender/llfontfreetype.cpp
@@ -482,7 +482,7 @@ void LLFontFreetype::renderGlyph(U32 glyph_index) const
if (mFTFace == NULL)
return;
- int error = FT_Load_Glyph(mFTFace, glyph_index, FT_LOAD_DEFAULT );
+ int error = FT_Load_Glyph(mFTFace, glyph_index, FT_LOAD_FORCE_AUTOHINT );
llassert(!error);
error = FT_Render_Glyph(mFTFace->glyph, gFontRenderMode);
diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp
index 13008292f6..d6a31dc862 100644
--- a/indra/llrender/llfontgl.cpp
+++ b/indra/llrender/llfontgl.cpp
@@ -271,7 +271,6 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
}
}
-
const LLFontGlyphInfo* next_glyph = NULL;
const S32 GLYPH_BATCH_SIZE = 30;
diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index c0edd92bc1..f29ee0e57e 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;
@@ -102,7 +105,6 @@ LLMatrix4 gGLObliqueProjectionInverse;
#define LL_GL_NAME_POOLING 0
-LLGLNamePool::pool_list_t LLGLNamePool::sInstances;
std::list<LLGLUpdate*> LLGLUpdate::sGLQ;
#if (LL_WINDOWS || LL_LINUX || LL_SOLARIS) && !LL_MESA_HEADLESS
@@ -154,30 +156,27 @@ PFNGLGETQUERYOBJECTUIVARBPROC glGetQueryObjectuivARB = NULL;
PFNGLPOINTPARAMETERFARBPROC glPointParameterfARB = NULL;
PFNGLPOINTPARAMETERFVARBPROC glPointParameterfvARB = NULL;
-// GL_EXT_framebuffer_object
-PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT = NULL;
-PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT = NULL;
-PFNGLDELETERENDERBUFFERSEXTPROC glDeleteRenderbuffersEXT = NULL;
-PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffersEXT = NULL;
-PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorageEXT = NULL;
-PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glGetRenderbufferParameterivEXT = NULL;
-PFNGLISFRAMEBUFFEREXTPROC glIsFramebufferEXT = NULL;
-PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT = NULL;
-PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT = NULL;
-PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT = NULL;
-PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT = NULL;
-PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glFramebufferTexture1DEXT = NULL;
-PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT = NULL;
-PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glFramebufferTexture3DEXT = NULL;
-PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT = NULL;
-PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glGetFramebufferAttachmentParameterivEXT = NULL;
-PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT = NULL;
-
-// GL_EXT_framebuffer_multisample
-PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glRenderbufferStorageMultisampleEXT = NULL;
-
-// GL_EXT_framebuffer_blit
-PFNGLBLITFRAMEBUFFEREXTPROC glBlitFramebufferEXT = NULL;
+// GL_ARB_framebuffer_object
+PFNGLISRENDERBUFFERPROC glIsRenderbuffer = NULL;
+PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer = NULL;
+PFNGLDELETERENDERBUFFERSPROC glDeleteRenderbuffers = NULL;
+PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers = NULL;
+PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage = NULL;
+PFNGLGETRENDERBUFFERPARAMETERIVPROC glGetRenderbufferParameteriv = NULL;
+PFNGLISFRAMEBUFFERPROC glIsFramebuffer = NULL;
+PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer = NULL;
+PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers = NULL;
+PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers = NULL;
+PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus = NULL;
+PFNGLFRAMEBUFFERTEXTURE1DPROC glFramebufferTexture1D = NULL;
+PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D = NULL;
+PFNGLFRAMEBUFFERTEXTURE3DPROC glFramebufferTexture3D = NULL;
+PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer = NULL;
+PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glGetFramebufferAttachmentParameteriv = NULL;
+PFNGLGENERATEMIPMAPPROC glGenerateMipmap = NULL;
+PFNGLBLITFRAMEBUFFERPROC glBlitFramebuffer = NULL;
+PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glRenderbufferStorageMultisample = NULL;
+PFNGLFRAMEBUFFERTEXTURELAYERPROC glFramebufferTextureLayer = NULL;
// GL_EXT_blend_func_separate
PFNGLBLENDFUNCSEPARATEEXTPROC glBlendFuncSeparateEXT = NULL;
@@ -316,11 +315,12 @@ LLGLManager::LLGLManager() :
mIsDisabled(FALSE),
mHasMultitexture(FALSE),
+ mHasATIMemInfo(FALSE),
+ mHasNVXMemInfo(FALSE),
mNumTextureUnits(1),
mHasMipMapGeneration(FALSE),
mHasCompressedTextures(FALSE),
mHasFramebufferObject(FALSE),
- mHasFramebufferMultisample(FALSE),
mHasBlendFuncSeparate(FALSE),
mHasVertexBufferObject(FALSE),
@@ -329,6 +329,7 @@ LLGLManager::LLGLManager() :
mHasVertexShader(FALSE),
mHasFragmentShader(FALSE),
mHasOcclusionQuery(FALSE),
+ mHasOcclusionQuery2(FALSE),
mHasPointParameters(FALSE),
mHasDrawBuffers(FALSE),
mHasTextureRectangle(FALSE),
@@ -500,6 +501,20 @@ bool LLGLManager::initGL()
// This is called here because it depends on the setting of mIsGF2or4MX, and sets up mHasMultitexture.
initExtensions();
+ if (mHasATIMemInfo)
+ { //ask the gl how much vram is free at startup and attempt to use no more than half of that
+ S32 meminfo[4];
+ glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, meminfo);
+
+ mVRAM = meminfo[0]/1024;
+ }
+ else if (mHasNVXMemInfo)
+ {
+ S32 dedicated_memory;
+ glGetIntegerv(GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX, &dedicated_memory);
+ mVRAM = dedicated_memory/1024;
+ }
+
if (mHasMultitexture)
{
GLint num_tex_units;
@@ -538,9 +553,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);
@@ -556,14 +581,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
@@ -573,15 +606,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
@@ -590,7 +629,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;
}
@@ -610,46 +656,46 @@ void LLGLManager::shutdownGL()
void LLGLManager::initExtensions()
{
#if LL_MESA_HEADLESS
-# if GL_ARB_multitexture
+# ifdef GL_ARB_multitexture
mHasMultitexture = TRUE;
# else
mHasMultitexture = FALSE;
-# endif
-# if GL_ARB_texture_env_combine
+# endif // GL_ARB_multitexture
+# ifdef GL_ARB_texture_env_combine
mHasARBEnvCombine = TRUE;
# else
mHasARBEnvCombine = FALSE;
-# endif
-# if GL_ARB_texture_compression
+# endif // GL_ARB_texture_env_combine
+# ifdef GL_ARB_texture_compression
mHasCompressedTextures = TRUE;
# else
mHasCompressedTextures = FALSE;
-# endif
-# if GL_ARB_vertex_buffer_object
+# endif // GL_ARB_texture_compression
+# ifdef GL_ARB_vertex_buffer_object
mHasVertexBufferObject = TRUE;
# else
mHasVertexBufferObject = FALSE;
-# endif
-# if GL_EXT_framebuffer_object
+# endif // GL_ARB_vertex_buffer_object
+# ifdef GL_EXT_framebuffer_object
mHasFramebufferObject = TRUE;
# else
mHasFramebufferObject = FALSE;
-# endif
-# if GL_EXT_framebuffer_multisample
- mHasFramebufferMultisample = TRUE;
-# else
- mHasFramebufferMultisample = FALSE;
-# endif
-# if GL_ARB_draw_buffers
+# 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 // 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;
@@ -662,6 +708,8 @@ void LLGLManager::initExtensions()
mHasTextureRectangle = FALSE;
#else // LL_MESA_HEADLESS
mHasMultitexture = glh_init_extensions("GL_ARB_multitexture");
+ mHasATIMemInfo = ExtensionExists("GL_ATI_meminfo", gGLHExts.mSysExts);
+ mHasNVXMemInfo = ExtensionExists("GL_NVX_gpu_memory_info", gGLHExts.mSysExts);
mHasMipMapGeneration = glh_init_extensions("GL_SGIS_generate_mipmap");
mHasSeparateSpecularColor = glh_init_extensions("GL_EXT_separate_specular_color");
mHasAnisotropic = glh_init_extensions("GL_EXT_texture_filter_anisotropic");
@@ -670,11 +718,19 @@ void LLGLManager::initExtensions()
mHasARBEnvCombine = ExtensionExists("GL_ARB_texture_env_combine", gGLHExts.mSysExts);
mHasCompressedTextures = glh_init_extensions("GL_ARB_texture_compression");
mHasOcclusionQuery = ExtensionExists("GL_ARB_occlusion_query", gGLHExts.mSysExts);
+ mHasOcclusionQuery2 = ExtensionExists("GL_ARB_occlusion_query2", gGLHExts.mSysExts);
mHasVertexBufferObject = ExtensionExists("GL_ARB_vertex_buffer_object", gGLHExts.mSysExts);
+ mHasDepthClamp = ExtensionExists("GL_ARB_depth_clamp", gGLHExts.mSysExts) || ExtensionExists("GL_NV_depth_clamp", gGLHExts.mSysExts);
// mask out FBO support when packed_depth_stencil isn't there 'cause we need it for LLRenderTarget -Brad
- mHasFramebufferObject = ExtensionExists("GL_EXT_framebuffer_object", gGLHExts.mSysExts)
- && ExtensionExists("GL_EXT_packed_depth_stencil", gGLHExts.mSysExts);
- mHasFramebufferMultisample = mHasFramebufferObject && ExtensionExists("GL_EXT_framebuffer_multisample", gGLHExts.mSysExts);
+#ifdef GL_ARB_framebuffer_object
+ mHasFramebufferObject = ExtensionExists("GL_ARB_framebuffer_object", gGLHExts.mSysExts);
+#else
+ mHasFramebufferObject = ExtensionExists("GL_EXT_framebuffer_object", gGLHExts.mSysExts) &&
+ ExtensionExists("GL_EXT_framebuffer_blit", gGLHExts.mSysExts) &&
+ ExtensionExists("GL_EXT_framebuffer_multisample", gGLHExts.mSysExts) &&
+ ExtensionExists("GL_EXT_packed_depth_stencil", gGLHExts.mSysExts);
+#endif
+
mHasDrawBuffers = ExtensionExists("GL_ARB_draw_buffers", gGLHExts.mSysExts);
mHasBlendFuncSeparate = ExtensionExists("GL_EXT_blend_func_separate", gGLHExts.mSysExts);
mHasTextureRectangle = ExtensionExists("GL_ARB_texture_rectangle", gGLHExts.mSysExts);
@@ -694,11 +750,11 @@ void LLGLManager::initExtensions()
if (getenv("LL_GL_NOEXT"))
{
//mHasMultitexture = FALSE; // NEEDED!
+ mHasDepthClamp = FALSE;
mHasARBEnvCombine = FALSE;
mHasCompressedTextures = FALSE;
mHasVertexBufferObject = FALSE;
mHasFramebufferObject = FALSE;
- mHasFramebufferMultisample = FALSE;
mHasDrawBuffers = FALSE;
mHasBlendFuncSeparate = FALSE;
mHasMipMapGeneration = FALSE;
@@ -752,9 +808,9 @@ void LLGLManager::initExtensions()
if (strchr(blacklist,'p')) mHasPointParameters = FALSE;//S
if (strchr(blacklist,'q')) mHasFramebufferObject = FALSE;//S
if (strchr(blacklist,'r')) mHasDrawBuffers = FALSE;//S
- if (strchr(blacklist,'s')) mHasFramebufferMultisample = FALSE;
- if (strchr(blacklist,'t')) mHasTextureRectangle = FALSE;
- if (strchr(blacklist,'u')) mHasBlendFuncSeparate = FALSE;//S
+ if (strchr(blacklist,'s')) mHasTextureRectangle = FALSE;
+ if (strchr(blacklist,'t')) mHasBlendFuncSeparate = FALSE;//S
+ if (strchr(blacklist,'u')) mHasDepthClamp = FALSE;
}
#endif // LL_LINUX || LL_SOLARIS
@@ -787,6 +843,10 @@ void LLGLManager::initExtensions()
{
LL_INFOS("RenderInit") << "Couldn't initialize GL_ARB_occlusion_query" << LL_ENDL;
}
+ if (!mHasOcclusionQuery2)
+ {
+ LL_INFOS("RenderInit") << "Couldn't initialize GL_ARB_occlusion_query2" << LL_ENDL;
+ }
if (!mHasPointParameters)
{
LL_INFOS("RenderInit") << "Couldn't initialize GL_ARB_point_parameters" << LL_ENDL;
@@ -854,28 +914,26 @@ void LLGLManager::initExtensions()
if (mHasFramebufferObject)
{
llinfos << "initExtensions() FramebufferObject-related procs..." << llendl;
- glIsRenderbufferEXT = (PFNGLISRENDERBUFFEREXTPROC) GLH_EXT_GET_PROC_ADDRESS("glIsRenderbufferEXT");
- glBindRenderbufferEXT = (PFNGLBINDRENDERBUFFEREXTPROC) GLH_EXT_GET_PROC_ADDRESS("glBindRenderbufferEXT");
- glDeleteRenderbuffersEXT = (PFNGLDELETERENDERBUFFERSEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteRenderbuffersEXT");
- glGenRenderbuffersEXT = (PFNGLGENRENDERBUFFERSEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glGenRenderbuffersEXT");
- glRenderbufferStorageEXT = (PFNGLRENDERBUFFERSTORAGEEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glRenderbufferStorageEXT");
- glGetRenderbufferParameterivEXT = (PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glGetRenderbufferParameterivEXT");
- glIsFramebufferEXT = (PFNGLISFRAMEBUFFEREXTPROC) GLH_EXT_GET_PROC_ADDRESS("glIsFramebufferEXT");
- glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC) GLH_EXT_GET_PROC_ADDRESS("glBindFramebufferEXT");
- glDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteFramebuffersEXT");
- glGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glGenFramebuffersEXT");
- glCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glCheckFramebufferStatusEXT");
- glFramebufferTexture1DEXT = (PFNGLFRAMEBUFFERTEXTURE1DEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferTexture1DEXT");
- glFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferTexture2DEXT");
- glFramebufferTexture3DEXT = (PFNGLFRAMEBUFFERTEXTURE3DEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferTexture3DEXT");
- glFramebufferRenderbufferEXT = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferRenderbufferEXT");
- glGetFramebufferAttachmentParameterivEXT = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glGetFramebufferAttachmentParameterivEXT");
- glGenerateMipmapEXT = (PFNGLGENERATEMIPMAPEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glGenerateMipmapEXT");
- }
- if (mHasFramebufferMultisample)
- {
- glRenderbufferStorageMultisampleEXT = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glRenderbufferStorageMultisampleEXT");
- glBlitFramebufferEXT = (PFNGLBLITFRAMEBUFFEREXTPROC) GLH_EXT_GET_PROC_ADDRESS("glBlitFramebufferEXT");
+ glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC) GLH_EXT_GET_PROC_ADDRESS("glIsRenderbuffer");
+ glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC) GLH_EXT_GET_PROC_ADDRESS("glBindRenderbuffer");
+ glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteRenderbuffers");
+ glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC) GLH_EXT_GET_PROC_ADDRESS("glGenRenderbuffers");
+ glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC) GLH_EXT_GET_PROC_ADDRESS("glRenderbufferStorage");
+ glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC) GLH_EXT_GET_PROC_ADDRESS("glGetRenderbufferParameteriv");
+ glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC) GLH_EXT_GET_PROC_ADDRESS("glIsFramebuffer");
+ glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC) GLH_EXT_GET_PROC_ADDRESS("glBindFramebuffer");
+ glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteFramebuffers");
+ glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC) GLH_EXT_GET_PROC_ADDRESS("glGenFramebuffers");
+ glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC) GLH_EXT_GET_PROC_ADDRESS("glCheckFramebufferStatus");
+ glFramebufferTexture1D = (PFNGLFRAMEBUFFERTEXTURE1DPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferTexture1D");
+ glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferTexture2D");
+ glFramebufferTexture3D = (PFNGLFRAMEBUFFERTEXTURE3DPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferTexture3D");
+ glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferRenderbuffer");
+ glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) GLH_EXT_GET_PROC_ADDRESS("glGetFramebufferAttachmentParameteriv");
+ glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC) GLH_EXT_GET_PROC_ADDRESS("glGenerateMipmap");
+ glBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC) GLH_EXT_GET_PROC_ADDRESS("glBlitFramebuffer");
+ glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC) GLH_EXT_GET_PROC_ADDRESS("glRenderbufferStorageMultisample");
+ glFramebufferTextureLayer = (PFNGLFRAMEBUFFERTEXTURELAYERPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferTextureLayer");
}
if (mHasDrawBuffers)
{
@@ -1047,6 +1105,33 @@ void flush_glerror()
glGetError();
}
+//this function outputs gl error to the log file, does not crash the code.
+void log_glerror()
+{
+ if (LL_UNLIKELY(!gGLManager.mInited))
+ {
+ return ;
+ }
+ // Create or update texture to be used with this data
+ GLenum error;
+ error = glGetError();
+ while (LL_UNLIKELY(error))
+ {
+ GLubyte const * gl_error_msg = gluErrorString(error);
+ if (NULL != gl_error_msg)
+ {
+ llwarns << "GL Error: " << error << " GL Error String: " << gl_error_msg << llendl ;
+ }
+ else
+ {
+ // gluErrorString returns NULL for some extensions' error codes.
+ // you'll probably have to grep for the number in glext.h.
+ llwarns << "GL Error: UNKNOWN 0x" << std::hex << error << std::dec << llendl;
+ }
+ error = glGetError();
+ }
+}
+
void do_assert_glerror()
{
if (LL_UNLIKELY(!gGLManager.mInited))
@@ -1110,7 +1195,7 @@ void assert_glerror()
}
}
- if (!gNoRender && gDebugGL)
+ if (gDebugGL)
{
do_assert_glerror();
}
@@ -1806,12 +1891,17 @@ void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor
}
}
-LLGLUserClipPlane::LLGLUserClipPlane(const LLPlane& p, const glh::matrix4f& modelview, const glh::matrix4f& projection)
+LLGLUserClipPlane::LLGLUserClipPlane(const LLPlane& p, const glh::matrix4f& modelview, const glh::matrix4f& projection, bool apply)
{
- mModelview = modelview;
- mProjection = projection;
+ mApply = apply;
+
+ if (mApply)
+ {
+ mModelview = modelview;
+ mProjection = projection;
- setPlane(p.mV[0], p.mV[1], p.mV[2], p.mV[3]);
+ setPlane(p[0], p[1], p[2], p[3]);
+ }
}
void LLGLUserClipPlane::setPlane(F32 a, F32 b, F32 c, F32 d)
@@ -1842,31 +1932,20 @@ void LLGLUserClipPlane::setPlane(F32 a, F32 b, F32 c, F32 d)
LLGLUserClipPlane::~LLGLUserClipPlane()
{
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
+ if (mApply)
+ {
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ }
}
LLGLNamePool::LLGLNamePool()
{
}
-void LLGLNamePool::registerPool(LLGLNamePool* pool)
-{
- pool_list_t::iterator iter = std::find(sInstances.begin(), sInstances.end(), pool);
- if (iter == sInstances.end())
- {
- sInstances.push_back(pool);
- }
-}
-
LLGLNamePool::~LLGLNamePool()
{
- pool_list_t::iterator iter = std::find(sInstances.begin(), sInstances.end(), this);
- if (iter != sInstances.end())
- {
- sInstances.erase(iter);
- }
}
void LLGLNamePool::upkeep()
@@ -1935,20 +2014,22 @@ void LLGLNamePool::release(GLuint name)
void LLGLNamePool::upkeepPools()
{
LLMemType mt(LLMemType::MTYPE_UPKEEP_POOLS);
- for (pool_list_t::iterator iter = sInstances.begin(); iter != sInstances.end(); ++iter)
+ tracker_t::LLInstanceTrackerScopedGuard guard;
+ for (tracker_t::instance_iter iter = guard.beginInstances(); iter != guard.endInstances(); ++iter)
{
- LLGLNamePool* pool = *iter;
- pool->upkeep();
+ LLGLNamePool & pool = *iter;
+ pool.upkeep();
}
}
//static
void LLGLNamePool::cleanupPools()
{
- for (pool_list_t::iterator iter = sInstances.begin(); iter != sInstances.end(); ++iter)
+ tracker_t::LLInstanceTrackerScopedGuard guard;
+ for (tracker_t::instance_iter iter = guard.beginInstances(); iter != guard.endInstances(); ++iter)
{
- LLGLNamePool* pool = *iter;
- pool->cleanup();
+ LLGLNamePool & pool = *iter;
+ pool.cleanup();
}
}
@@ -2037,11 +2118,14 @@ void LLGLDepthTest::checkState()
}
}
-LLGLClampToFarClip::LLGLClampToFarClip(glh::matrix4f P)
+LLGLSquashToFarClip::LLGLSquashToFarClip(glh::matrix4f P, U32 layer)
{
+
+ F32 depth = 0.99999f - 0.0001f * layer;
+
for (U32 i = 0; i < 4; i++)
{
- P.element(2, i) = P.element(3, i) * 0.99999f;
+ P.element(2, i) = P.element(3, i) * depth;
}
glMatrixMode(GL_PROJECTION);
@@ -2050,7 +2134,7 @@ LLGLClampToFarClip::LLGLClampToFarClip(glh::matrix4f P)
glMatrixMode(GL_MODELVIEW);
}
-LLGLClampToFarClip::~LLGLClampToFarClip()
+LLGLSquashToFarClip::~LLGLSquashToFarClip()
{
glMatrixMode(GL_PROJECTION);
glPopMatrix();
diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h
index 5e8965c06a..3d002fd8c4 100644
--- a/indra/llrender/llgl.h
+++ b/indra/llrender/llgl.h
@@ -40,6 +40,7 @@
#include "v4math.h"
#include "llplane.h"
#include "llgltypes.h"
+#include "llinstancetracker.h"
#include "llglheaders.h"
#include "glh/glh_linear.h"
@@ -76,11 +77,12 @@ public:
// Extensions used by everyone
BOOL mHasMultitexture;
+ BOOL mHasATIMemInfo;
+ BOOL mHasNVXMemInfo;
S32 mNumTextureUnits;
BOOL mHasMipMapGeneration;
BOOL mHasCompressedTextures;
BOOL mHasFramebufferObject;
- BOOL mHasFramebufferMultisample;
BOOL mHasBlendFuncSeparate;
// ARB Extensions
@@ -90,8 +92,10 @@ public:
BOOL mHasVertexShader;
BOOL mHasFragmentShader;
BOOL mHasOcclusionQuery;
+ BOOL mHasOcclusionQuery2;
BOOL mHasPointParameters;
BOOL mHasDrawBuffers;
+ BOOL mHasDepthClamp;
BOOL mHasTextureRectangle;
// Other extensions.
@@ -157,6 +161,7 @@ void rotate_quat(LLQuaternion& rotation);
void flush_glerror(); // Flush GL errors when we know we're handling them correctly.
+void log_glerror();
void assert_glerror();
void clear_glerror();
@@ -297,12 +302,14 @@ class LLGLUserClipPlane
{
public:
- LLGLUserClipPlane(const LLPlane& plane, const glh::matrix4f& modelview, const glh::matrix4f& projection);
+ LLGLUserClipPlane(const LLPlane& plane, const glh::matrix4f& modelview, const glh::matrix4f& projection, bool apply = true);
~LLGLUserClipPlane();
void setPlane(F32 a, F32 b, F32 c, F32 d);
private:
+ bool mApply;
+
glh::matrix4f mProjection;
glh::matrix4f mModelview;
};
@@ -315,20 +322,22 @@ private:
leaves this class.
Does not stack.
*/
-class LLGLClampToFarClip
+class LLGLSquashToFarClip
{
public:
- LLGLClampToFarClip(glh::matrix4f projection);
- ~LLGLClampToFarClip();
+ LLGLSquashToFarClip(glh::matrix4f projection, U32 layer = 0);
+ ~LLGLSquashToFarClip();
};
/*
Generic pooling scheme for things which use GL names (used for occlusion queries and vertex buffer objects).
Prevents thrashing of GL name caches by avoiding calls to glGenFoo and glDeleteFoo.
*/
-class LLGLNamePool
+class LLGLNamePool : public LLInstanceTracker<LLGLNamePool>
{
public:
+ typedef LLInstanceTracker<LLGLNamePool> tracker_t;
+
struct NameEntry
{
GLuint name;
@@ -355,13 +364,11 @@ public:
GLuint allocate();
void release(GLuint name);
- static void registerPool(LLGLNamePool* pool);
static void upkeepPools();
static void cleanupPools();
protected:
typedef std::vector<LLGLNamePool*> pool_list_t;
- static pool_list_t sInstances;
virtual GLuint allocateName() = 0;
virtual void releaseName(GLuint name) = 0;
@@ -413,7 +420,70 @@ 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
+// with MAC OSX 10.5 -> 10.6
+
+
+#ifndef GL_DEPTH_ATTACHMENT
+#define GL_DEPTH_ATTACHMENT GL_DEPTH_ATTACHMENT_EXT
+#endif
+
+#ifndef GL_STENCIL_ATTACHMENT
+#define GL_STENCIL_ATTACHMENT GL_STENCIL_ATTACHMENT_EXT
+#endif
+
+#ifndef GL_FRAMEBUFFER
+#define GL_FRAMEBUFFER GL_FRAMEBUFFER_EXT
+#define GL_DRAW_FRAMEBUFFER GL_DRAW_FRAMEBUFFER_EXT
+#define GL_READ_FRAMEBUFFER GL_READ_FRAMEBUFFER_EXT
+#define GL_FRAMEBUFFER_COMPLETE GL_FRAMEBUFFER_COMPLETE_EXT
+#define GL_FRAMEBUFFER_UNSUPPORTED GL_FRAMEBUFFER_UNSUPPORTED_EXT
+#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT
+#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT
+#define glGenFramebuffers glGenFramebuffersEXT
+#define glBindFramebuffer glBindFramebufferEXT
+#define glCheckFramebufferStatus glCheckFramebufferStatusEXT
+#define glBlitFramebuffer glBlitFramebufferEXT
+#define glDeleteFramebuffers glDeleteFramebuffersEXT
+#define glFramebufferRenderbuffer glFramebufferRenderbufferEXT
+#define glFramebufferTexture2D glFramebufferTexture2DEXT
+#endif
+
+#ifndef GL_RENDERBUFFER
+#define GL_RENDERBUFFER GL_RENDERBUFFER_EXT
+#define glGenRenderbuffers glGenRenderbuffersEXT
+#define glBindRenderbuffer glBindRenderbufferEXT
+#define glRenderbufferStorage glRenderbufferStorageEXT
+#define glRenderbufferStorageMultisample glRenderbufferStorageMultisampleEXT
+#define glDeleteRenderbuffers glDeleteRenderbuffersEXT
+#endif
+
+#ifndef GL_COLOR_ATTACHMENT
+#define GL_COLOR_ATTACHMENT GL_COLOR_ATTACHMENT_EXT
+#endif
+
+#ifndef GL_COLOR_ATTACHMENT0
+#define GL_COLOR_ATTACHMENT0 GL_COLOR_ATTACHMENT0_EXT
+#endif
+
+#ifndef GL_COLOR_ATTACHMENT1
+#define GL_COLOR_ATTACHMENT1 GL_COLOR_ATTACHMENT1_EXT
+#endif
+
+#ifndef GL_COLOR_ATTACHMENT2
+#define GL_COLOR_ATTACHMENT2 GL_COLOR_ATTACHMENT2_EXT
+#endif
+
+#ifndef GL_COLOR_ATTACHMENT3
+#define GL_COLOR_ATTACHMENT3 GL_COLOR_ATTACHMENT3_EXT
+#endif
+
+
+#ifndef GL_DEPTH24_STENCIL8
+#define GL_DEPTH24_STENCIL8 GL_DEPTH24_STENCIL8_EXT
+#endif
+
#endif // LL_LLGL_H
diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h
index 5a34b46d0c..d8140a124d 100644
--- a/indra/llrender/llglheaders.h
+++ b/indra/llrender/llglheaders.h
@@ -1,25 +1,25 @@
-/**
+/**
* @file llglheaders.h
* @brief LLGL definitions
*
* $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$
*/
@@ -449,30 +449,27 @@ extern PFNGLGETCOMPRESSEDTEXIMAGEARBPROC glGetCompressedTexImageARB;
//GL_EXT_blend_func_separate
extern PFNGLBLENDFUNCSEPARATEEXTPROC glBlendFuncSeparateEXT;
-//GL_EXT_framebuffer_object
-extern PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT;
-extern PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT;
-extern PFNGLDELETERENDERBUFFERSEXTPROC glDeleteRenderbuffersEXT;
-extern PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffersEXT;
-extern PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorageEXT;
-extern PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glGetRenderbufferParameterivEXT;
-extern PFNGLISFRAMEBUFFEREXTPROC glIsFramebufferEXT;
-extern PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT;
-extern PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT;
-extern PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT;
-extern PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT;
-extern PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glFramebufferTexture1DEXT;
-extern PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT;
-extern PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glFramebufferTexture3DEXT;
-extern PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT;
-extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glGetFramebufferAttachmentParameterivEXT;
-extern PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT;
-
-// GL_EXT_framebuffer_multisample
-extern PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glRenderbufferStorageMultisampleEXT;
-
-// GL_EXT_framebuffer_blit
-extern PFNGLBLITFRAMEBUFFEREXTPROC glBlitFramebufferEXT;
+//GL_ARB_framebuffer_object
+extern PFNGLISRENDERBUFFERPROC glIsRenderbuffer;
+extern PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer;
+extern PFNGLDELETERENDERBUFFERSPROC glDeleteRenderbuffers;
+extern PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers;
+extern PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage;
+extern PFNGLGETRENDERBUFFERPARAMETERIVPROC glGetRenderbufferParameteriv;
+extern PFNGLISFRAMEBUFFERPROC glIsFramebuffer;
+extern PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer;
+extern PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers;
+extern PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers;
+extern PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus;
+extern PFNGLFRAMEBUFFERTEXTURE1DPROC glFramebufferTexture1D;
+extern PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D;
+extern PFNGLFRAMEBUFFERTEXTURE3DPROC glFramebufferTexture3D;
+extern PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer;
+extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glGetFramebufferAttachmentParameteriv;
+extern PFNGLGENERATEMIPMAPPROC glGenerateMipmap;
+extern PFNGLBLITFRAMEBUFFERPROC glBlitFramebuffer;
+extern PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glRenderbufferStorageMultisample;
+extern PFNGLFRAMEBUFFERTEXTURELAYERPROC glFramebufferTextureLayer;
//GL_ARB_draw_buffers
extern PFNGLDRAWBUFFERSARBPROC glDrawBuffersARB;
@@ -651,30 +648,27 @@ extern PFNGLGETATTRIBLOCATIONARBPROC glGetAttribLocationARB;
//GL_EXT_blend_func_separate
extern PFNGLBLENDFUNCSEPARATEEXTPROC glBlendFuncSeparateEXT;
-//GL_EXT_framebuffer_object
-extern PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT;
-extern PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT;
-extern PFNGLDELETERENDERBUFFERSEXTPROC glDeleteRenderbuffersEXT;
-extern PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffersEXT;
-extern PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorageEXT;
-extern PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glGetRenderbufferParameterivEXT;
-extern PFNGLISFRAMEBUFFEREXTPROC glIsFramebufferEXT;
-extern PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT;
-extern PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT;
-extern PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT;
-extern PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT;
-extern PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glFramebufferTexture1DEXT;
-extern PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT;
-extern PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glFramebufferTexture3DEXT;
-extern PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT;
-extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glGetFramebufferAttachmentParameterivEXT;
-extern PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT;
-
-// GL_EXT_framebuffer_multisample
-extern PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glRenderbufferStorageMultisampleEXT;
-
-// GL_EXT_framebuffer_blit
-extern PFNGLBLITFRAMEBUFFEREXTPROC glBlitFramebufferEXT;
+//GL_ARB_framebuffer_object
+extern PFNGLISRENDERBUFFERPROC glIsRenderbuffer;
+extern PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer;
+extern PFNGLDELETERENDERBUFFERSPROC glDeleteRenderbuffers;
+extern PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers;
+extern PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage;
+extern PFNGLGETRENDERBUFFERPARAMETERIVPROC glGetRenderbufferParameteriv;
+extern PFNGLISFRAMEBUFFERPROC glIsFramebuffer;
+extern PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer;
+extern PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers;
+extern PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers;
+extern PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus;
+extern PFNGLFRAMEBUFFERTEXTURE1DPROC glFramebufferTexture1D;
+extern PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D;
+extern PFNGLFRAMEBUFFERTEXTURE3DPROC glFramebufferTexture3D;
+extern PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer;
+extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glGetFramebufferAttachmentParameteriv;
+extern PFNGLGENERATEMIPMAPPROC glGenerateMipmap;
+extern PFNGLBLITFRAMEBUFFERPROC glBlitFramebuffer;
+extern PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glRenderbufferStorageMultisample;
+extern PFNGLFRAMEBUFFERTEXTURELAYERPROC glFramebufferTextureLayer;
//GL_ARB_draw_buffers
extern PFNGLDRAWBUFFERSARBPROC glDrawBuffersARB;
@@ -697,7 +691,7 @@ extern PFNGLDRAWBUFFERSARBPROC glDrawBuffersARB;
#include <AvailabilityMacros.h>
//GL_EXT_blend_func_separate
-extern void glBlendFuncSeparateEXT(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER;
+extern void glBlendFuncSeparateEXT(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) ;
// GL_EXT_framebuffer_object
extern GLboolean glIsRenderbufferEXT(GLuint renderbuffer) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER;
@@ -718,6 +712,9 @@ extern void glFramebufferRenderbufferEXT(GLenum target, GLenum attachment, GLenu
extern void glGetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, GLenum pname, GLint *params) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER;
extern void glGenerateMipmapEXT(GLenum target) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER;
+#ifndef GL_ARB_framebuffer_object
+#define glGenerateMipmap glGenerateMipmapEXT
+#endif
// GL_ARB_draw_buffers
extern void glDrawBuffersARB(GLsizei n, const GLenum* bufs) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER;
@@ -829,5 +826,33 @@ extern void glGetBufferPointervARB (GLenum, GLenum, GLvoid* *);
#endif // LL_MESA / LL_WINDOWS / LL_DARWIN
+// Even when GL_ARB_depth_clamp is available in the driver, the (correct)
+// headers, and therefore GL_DEPTH_CLAMP might not be defined.
+// In that case GL_DEPTH_CLAMP_NV should be defined, but why not just
+// use the known numeric.
+//
+// To avoid #ifdef's in the code. Just define this here.
+#ifndef GL_DEPTH_CLAMP
+// Probably (still) called GL_DEPTH_CLAMP_NV.
+#define GL_DEPTH_CLAMP 0x864F
+#endif
+
+//GL_NVX_gpu_memory_info constants
+#ifndef GL_NVX_gpu_memory_info
+#define GL_NVX_gpu_memory_info
+#define GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX 0x9047
+#define GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX 0x9048
+#define GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX 0x9049
+#define GL_GPU_MEMORY_INFO_EVICTION_COUNT_NVX 0x904A
+#define GL_GPU_MEMORY_INFO_EVICTED_MEMORY_NVX 0x904B
+#endif
+
+//GL_ATI_meminfo constants
+#ifndef GL_ATI_meminfo
+#define GL_ATI_meminfo
+#define GL_VBO_FREE_MEMORY_ATI 0x87FB
+#define GL_TEXTURE_FREE_MEMORY_ATI 0x87FC
+#define GL_RENDERBUFFER_FREE_MEMORY_ATI 0x87FD
+#endif
#endif // LL_LLGLHEADERS_H
diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp
index 16534fa9a5..257bcd9380 100644
--- a/indra/llrender/llglslshader.cpp
+++ b/indra/llrender/llglslshader.cpp
@@ -55,7 +55,7 @@ BOOL shouldChange(const LLVector4& v1, const LLVector4& v2)
LLShaderFeatures::LLShaderFeatures()
: calculatesLighting(false), isShiny(false), isFullbright(false), hasWaterFog(false),
-hasTransport(false), hasSkinning(false), hasAtmospherics(false), isSpecular(false),
+hasTransport(false), hasSkinning(false), hasObjectSkinning(false), hasAtmospherics(false), isSpecular(false),
hasGamma(false), hasLighting(false), calculatesAtmospherics(false)
{
}
@@ -118,7 +118,7 @@ BOOL LLGLSLShader::createShader(vector<string> * attributes,
{
GLhandleARB shaderhandle = LLShaderMgr::instance()->loadShaderFile((*fileIter).first, mShaderLevel, (*fileIter).second);
LL_DEBUGS("ShaderLoading") << "SHADER FILE: " << (*fileIter).first << " mShaderLevel=" << mShaderLevel << LL_ENDL;
- if (mShaderLevel > 0)
+ if (shaderhandle > 0)
{
attachObject(shaderhandle);
}
@@ -698,17 +698,46 @@ void LLGLSLShader::uniformMatrix4fv(U32 index, U32 count, GLboolean transpose, c
GLint LLGLSLShader::getUniformLocation(const string& uniform)
{
+ GLint ret = -1;
if (mProgramObject > 0)
{
std::map<string, GLint>::iterator iter = mUniformMap.find(uniform);
if (iter != mUniformMap.end())
{
- llassert(iter->second == glGetUniformLocationARB(mProgramObject, uniform.c_str()));
- return iter->second;
+ if (gDebugGL)
+ {
+ stop_glerror();
+ if (iter->second != glGetUniformLocationARB(mProgramObject, uniform.c_str()))
+ {
+ llerrs << "Uniform does not match." << llendl;
+ }
+ stop_glerror();
+ }
+ ret = iter->second;
}
}
- return -1;
+ /*if (gDebugGL)
+ {
+ if (ret == -1 && ret != glGetUniformLocationARB(mProgramObject, uniform.c_str()))
+ {
+ llerrs << "Uniform map invalid." << llendl;
+ }
+ }*/
+
+ return ret;
+}
+
+GLint LLGLSLShader::getAttribLocation(U32 attrib)
+{
+ if (attrib < mAttribute.size())
+ {
+ return mAttribute[attrib];
+ }
+ else
+ {
+ return -1;
+ }
}
void LLGLSLShader::uniform1i(const string& uniform, GLint v)
@@ -882,7 +911,9 @@ void LLGLSLShader::uniformMatrix4fv(const string& uniform, U32 count, GLboolean
if (location >= 0)
{
+ stop_glerror();
glUniformMatrix4fvARB(location, count, transpose, v);
+ stop_glerror();
}
}
diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h
index c11bd50716..d46ddbbe18 100644
--- a/indra/llrender/llglslshader.h
+++ b/indra/llrender/llglslshader.h
@@ -42,6 +42,7 @@ public:
bool hasWaterFog; // implies no gamma
bool hasTransport; // implies no lighting (it's possible to have neither though)
bool hasSkinning;
+ bool hasObjectSkinning;
bool hasAtmospherics;
bool hasGamma;
@@ -103,7 +104,7 @@ public:
void vertexAttrib4fv(U32 index, GLfloat* v);
GLint getUniformLocation(const std::string& uniform);
-
+ GLint getAttribLocation(U32 attrib);
GLint mapUniformTextureChannel(GLint location, GLenum type);
diff --git a/indra/llrender/llglstates.h b/indra/llrender/llglstates.h
index d5a29dcd0c..e26aead676 100644
--- a/indra/llrender/llglstates.h
+++ b/indra/llrender/llglstates.h
@@ -238,9 +238,11 @@ public:
class LLGLSSpecular
{
public:
+ F32 mShininess;
LLGLSSpecular(const LLColor4& color, F32 shininess)
{
- if (shininess > 0.0f)
+ mShininess = shininess;
+ if (mShininess > 0.0f)
{
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, color.mV);
S32 shiny = (S32)(shininess*128.f);
@@ -250,32 +252,14 @@ public:
}
~LLGLSSpecular()
{
- glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, LLColor4(0.f,0.f,0.f,0.f).mV);
- glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 0);
+ if (mShininess > 0.f)
+ {
+ glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, LLColor4(0.f,0.f,0.f,0.f).mV);
+ glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 0);
+ }
}
};
//----------------------------------------------------------------------------
-
-class LLGLSBlendFunc : public LLGLSPipeline {
-protected:
- GLint mSavedSrc, mSavedDst;
- LLGLEnable mBlend;
-
-public:
- LLGLSBlendFunc(GLenum srcFunc, GLenum dstFunc) :
- mBlend(GL_BLEND)
- {
- glGetIntegerv(GL_BLEND_SRC, &mSavedSrc);
- glGetIntegerv(GL_BLEND_DST, &mSavedDst);
- glBlendFunc(srcFunc, dstFunc);
- }
-
- ~LLGLSBlendFunc(void) {
- glBlendFunc(mSavedSrc, mSavedDst);
- }
-};
-
-
#endif
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index 72dd283bc7..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;
}
@@ -1063,14 +1065,6 @@ BOOL LLImageGL::setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_
{
if (gGL.getTexUnit(0)->bind(this, false, true))
{
- if(gGLManager.mDebugGPU)
- {
- llinfos << "Calling glCopyTexSubImage2D(...)" << llendl ;
- checkTexSize(true) ;
- llcallstacks << fb_x << " : " << fb_y << " : " << x_pos << " : " << y_pos << " : " << width << " : " << height <<
- " : " << (S32)mComponents << llcallstacksendl ;
- }
-
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, fb_x, fb_y, x_pos, y_pos, width, height);
mGLTextureCreated = true;
stop_glerror();
@@ -1108,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;
@@ -1136,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;
@@ -1714,6 +1710,7 @@ void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h)
sample[asum/(16*4)] += 4;
}
+
rowstart += 2 * w * mAlphaStride;
}
length *= 2; // we sampled everything twice, essentially
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index e26acd53a3..49e10c4790 100644
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -47,6 +47,7 @@ U32 LLRender::sUICalls = 0;
U32 LLRender::sUIVerts = 0;
static const U32 LL_NUM_TEXTURE_LAYERS = 16;
+static const U32 LL_NUM_LIGHT_UNITS = 8;
static GLenum sGLTextureType[] =
{
@@ -431,6 +432,9 @@ void LLTexUnit::setTextureFilteringOption(LLTexUnit::eTextureFilterOptions optio
if (gGL.mMaxAnisotropy < 1.f)
{
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &gGL.mMaxAnisotropy);
+
+ llinfos << "gGL.mMaxAnisotropy: " << gGL.mMaxAnisotropy << llendl ;
+ gGL.mMaxAnisotropy = llmax(1.f, gGL.mMaxAnisotropy) ;
}
glTexParameterf(sGLTextureType[mCurrTexType], GL_TEXTURE_MAX_ANISOTROPY_EXT, gGL.mMaxAnisotropy);
}
@@ -744,6 +748,130 @@ void LLTexUnit::debugTextureUnit(void)
}
}
+LLLightState::LLLightState(S32 index)
+: mIndex(index),
+ mEnabled(false),
+ mConstantAtten(1.f),
+ mLinearAtten(0.f),
+ mQuadraticAtten(0.f),
+ mSpotExponent(0.f),
+ mSpotCutoff(180.f)
+{
+ if (mIndex == 0)
+ {
+ mDiffuse.set(1,1,1,1);
+ mSpecular.set(1,1,1,1);
+ }
+
+ mAmbient.set(0,0,0,1);
+ mPosition.set(0,0,1,0);
+ mSpotDirection.set(0,0,-1);
+
+}
+
+void LLLightState::enable()
+{
+ if (!mEnabled)
+ {
+ glEnable(GL_LIGHT0+mIndex);
+ mEnabled = true;
+ }
+}
+
+void LLLightState::disable()
+{
+ if (mEnabled)
+ {
+ glDisable(GL_LIGHT0+mIndex);
+ mEnabled = false;
+ }
+}
+
+void LLLightState::setDiffuse(const LLColor4& diffuse)
+{
+ if (mDiffuse != diffuse)
+ {
+ mDiffuse = diffuse;
+ glLightfv(GL_LIGHT0+mIndex, GL_DIFFUSE, mDiffuse.mV);
+ }
+}
+
+void LLLightState::setAmbient(const LLColor4& ambient)
+{
+ if (mAmbient != ambient)
+ {
+ mAmbient = ambient;
+ glLightfv(GL_LIGHT0+mIndex, GL_AMBIENT, mAmbient.mV);
+ }
+}
+
+void LLLightState::setSpecular(const LLColor4& specular)
+{
+ if (mSpecular != specular)
+ {
+ mSpecular = specular;
+ glLightfv(GL_LIGHT0+mIndex, GL_SPECULAR, mSpecular.mV);
+ }
+}
+
+void LLLightState::setPosition(const LLVector4& position)
+{
+ //always set position because modelview matrix may have changed
+ mPosition = position;
+ glLightfv(GL_LIGHT0+mIndex, GL_POSITION, mPosition.mV);
+}
+
+void LLLightState::setConstantAttenuation(const F32& atten)
+{
+ if (mConstantAtten != atten)
+ {
+ mConstantAtten = atten;
+ glLightf(GL_LIGHT0+mIndex, GL_CONSTANT_ATTENUATION, atten);
+ }
+}
+
+void LLLightState::setLinearAttenuation(const F32& atten)
+{
+ if (mLinearAtten != atten)
+ {
+ mLinearAtten = atten;
+ glLightf(GL_LIGHT0+mIndex, GL_LINEAR_ATTENUATION, atten);
+ }
+}
+
+void LLLightState::setQuadraticAttenuation(const F32& atten)
+{
+ if (mQuadraticAtten != atten)
+ {
+ mQuadraticAtten = atten;
+ glLightf(GL_LIGHT0+mIndex, GL_QUADRATIC_ATTENUATION, atten);
+ }
+}
+
+void LLLightState::setSpotExponent(const F32& exponent)
+{
+ if (mSpotExponent != exponent)
+ {
+ mSpotExponent = exponent;
+ glLightf(GL_LIGHT0+mIndex, GL_SPOT_EXPONENT, exponent);
+ }
+}
+
+void LLLightState::setSpotCutoff(const F32& cutoff)
+{
+ if (mSpotCutoff != cutoff)
+ {
+ mSpotCutoff = cutoff;
+ glLightf(GL_LIGHT0+mIndex, GL_SPOT_CUTOFF, cutoff);
+ }
+}
+
+void LLLightState::setSpotDirection(const LLVector3& direction)
+{
+ //always set direction because modelview matrix may have changed
+ mSpotDirection = direction;
+ glLightfv(GL_LIGHT0+mIndex, GL_SPOT_DIRECTION, direction.mV);
+}
LLRender::LLRender()
: mDirty(false),
@@ -765,6 +893,11 @@ LLRender::LLRender()
}
mDummyTexUnit = new LLTexUnit(-1);
+ for (U32 i = 0; i < LL_NUM_LIGHT_UNITS; ++i)
+ {
+ mLightState.push_back(new LLLightState(i));
+ }
+
for (U32 i = 0; i < 4; i++)
{
mCurrColorMask[i] = true;
@@ -792,6 +925,12 @@ void LLRender::shutdown()
mTexUnits.clear();
delete mDummyTexUnit;
mDummyTexUnit = NULL;
+
+ for (U32 i = 0; i < mLightState.size(); ++i)
+ {
+ delete mLightState[i];
+ }
+ mLightState.clear();
}
void LLRender::refreshState(void)
@@ -895,7 +1034,7 @@ LLVector3 LLRender::getUITranslation()
{
if (mUIOffset.empty())
{
- return LLVector3::zero;
+ return LLVector3(0,0,0);
}
return mUIOffset.back();
}
@@ -904,7 +1043,7 @@ LLVector3 LLRender::getUIScale()
{
if (mUIScale.empty())
{
- return LLVector3(1.f, 1.f, 1.f);
+ return LLVector3(1,1,1);
}
return mUIScale.back();
}
@@ -929,15 +1068,21 @@ void LLRender::setColorMask(bool writeColorR, bool writeColorG, bool writeColorB
{
flush();
- mCurrColorMask[0] = writeColorR;
- mCurrColorMask[1] = writeColorG;
- mCurrColorMask[2] = writeColorB;
- mCurrColorMask[3] = writeAlpha;
+ if (mCurrColorMask[0] != writeColorR ||
+ mCurrColorMask[1] != writeColorG ||
+ mCurrColorMask[2] != writeColorB ||
+ mCurrColorMask[3] != writeAlpha)
+ {
+ mCurrColorMask[0] = writeColorR;
+ mCurrColorMask[1] = writeColorG;
+ mCurrColorMask[2] = writeColorB;
+ mCurrColorMask[3] = writeAlpha;
- glColorMask(writeColorR ? GL_TRUE : GL_FALSE,
- writeColorG ? GL_TRUE : GL_FALSE,
- writeColorB ? GL_TRUE : GL_FALSE,
- writeAlpha ? GL_TRUE : GL_FALSE);
+ glColorMask(writeColorR ? GL_TRUE : GL_FALSE,
+ writeColorG ? GL_TRUE : GL_FALSE,
+ writeColorB ? GL_TRUE : GL_FALSE,
+ writeAlpha ? GL_TRUE : GL_FALSE);
+ }
}
void LLRender::setSceneBlendType(eBlendType type)
@@ -975,15 +1120,19 @@ void LLRender::setAlphaRejectSettings(eCompareFunc func, F32 value)
{
flush();
- mCurrAlphaFunc = func;
- mCurrAlphaFuncVal = value;
- if (func == CF_DEFAULT)
- {
- glAlphaFunc(GL_GREATER, 0.01f);
- }
- else
+ if (mCurrAlphaFunc != func ||
+ mCurrAlphaFuncVal != value)
{
- glAlphaFunc(sGLCompareFunc[func], value);
+ mCurrAlphaFunc = func;
+ mCurrAlphaFuncVal = value;
+ if (func == CF_DEFAULT)
+ {
+ glAlphaFunc(GL_GREATER, 0.01f);
+ }
+ else
+ {
+ glAlphaFunc(sGLCompareFunc[func], value);
+ }
}
}
@@ -1042,6 +1191,16 @@ LLTexUnit* LLRender::getTexUnit(U32 index)
}
}
+LLLightState* LLRender::getLight(U32 index)
+{
+ if (index < mLightState.size())
+ {
+ return mLightState[index];
+ }
+
+ return NULL;
+}
+
bool LLRender::verifyTexUnitActive(U32 unitToVerify)
{
if (mCurrTextureUnitIndex == unitToVerify)
diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h
index 2767aa64a8..7ba14f7b40 100644
--- a/indra/llrender/llrender.h
+++ b/indra/llrender/llrender.h
@@ -37,6 +37,7 @@
#include "v2math.h"
#include "v3math.h"
#include "v4coloru.h"
+#include "v4math.h"
#include "llstrider.h"
#include "llpointer.h"
#include "llglheaders.h"
@@ -212,6 +213,41 @@ protected:
void setTextureCombiner(eTextureBlendOp op, eTextureBlendSrc src1, eTextureBlendSrc src2, bool isAlpha = false);
};
+class LLLightState
+{
+public:
+ LLLightState(S32 index);
+
+ void enable();
+ void disable();
+ void setDiffuse(const LLColor4& diffuse);
+ void setAmbient(const LLColor4& ambient);
+ void setSpecular(const LLColor4& specular);
+ void setPosition(const LLVector4& position);
+ void setConstantAttenuation(const F32& atten);
+ void setLinearAttenuation(const F32& atten);
+ void setQuadraticAttenuation(const F32& atten);
+ void setSpotExponent(const F32& exponent);
+ void setSpotCutoff(const F32& cutoff);
+ void setSpotDirection(const LLVector3& direction);
+
+protected:
+ S32 mIndex;
+ bool mEnabled;
+ LLColor4 mDiffuse;
+ LLColor4 mAmbient;
+ LLColor4 mSpecular;
+ LLVector4 mPosition;
+ LLVector3 mSpotDirection;
+
+ F32 mConstantAtten;
+ F32 mLinearAtten;
+ F32 mQuadraticAtten;
+
+ F32 mSpotExponent;
+ F32 mSpotCutoff;
+};
+
class LLRender
{
friend class LLTexUnit;
@@ -327,6 +363,8 @@ public:
void blendFunc(eBlendFactor color_sfactor, eBlendFactor color_dfactor,
eBlendFactor alpha_sfactor, eBlendFactor alpha_dfactor);
+ LLLightState* getLight(U32 index);
+
LLTexUnit* getTexUnit(U32 index);
U32 getCurrentTexUnitIndex(void) const { return mCurrTextureUnitIndex; }
@@ -363,6 +401,7 @@ private:
LLStrider<LLColor4U> mColorsp;
std::vector<LLTexUnit*> mTexUnits;
LLTexUnit* mDummyTexUnit;
+ std::vector<LLLightState*> mLightState;
eBlendFactor mCurrBlendColorSFactor;
eBlendFactor mCurrBlendColorDFactor;
diff --git a/indra/llrender/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp
index 7205210fcc..cd2556d435 100644
--- a/indra/llrender/llrendertarget.cpp
+++ b/indra/llrender/llrendertarget.cpp
@@ -38,10 +38,10 @@ void check_framebuffer_status()
{
if (gDebugGL)
{
- GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
+ GLenum status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
switch (status)
{
- case GL_FRAMEBUFFER_COMPLETE_EXT:
+ case GL_FRAMEBUFFER_COMPLETE:
break;
default:
ll_fail("check_framebuffer_status failed");
@@ -50,7 +50,7 @@ void check_framebuffer_status()
}
}
-BOOL LLRenderTarget::sUseFBO = FALSE;
+bool LLRenderTarget::sUseFBO = false;
LLRenderTarget::LLRenderTarget() :
mResX(0),
@@ -59,8 +59,8 @@ LLRenderTarget::LLRenderTarget() :
mFBO(0),
mDepth(0),
mStencil(0),
- mUseDepth(FALSE),
- mRenderDepth(FALSE),
+ mUseDepth(false),
+ mRenderDepth(false),
mUsage(LLTexUnit::TT_TEXTURE),
mSamples(0),
mSampleBuffer(NULL)
@@ -78,7 +78,7 @@ void LLRenderTarget::setSampleBuffer(LLMultisampleBuffer* buffer)
mSampleBuffer = buffer;
}
-void LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, BOOL depth, BOOL stencil, LLTexUnit::eTextureType usage, BOOL use_fbo)
+void LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, bool stencil, LLTexUnit::eTextureType usage, bool use_fbo)
{
stop_glerror();
mResX = resx;
@@ -99,24 +99,24 @@ void LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, BOOL depth, BOO
stop_glerror();
}
- glGenFramebuffersEXT(1, (GLuint *) &mFBO);
+ glGenFramebuffers(1, (GLuint *) &mFBO);
if (mDepth)
{
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO);
+ glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
if (mStencil)
{
- glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, mDepth);
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, mDepth);
stop_glerror();
- glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, mDepth);
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, mDepth);
stop_glerror();
}
else
{
- glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, LLTexUnit::getInternalType(mUsage), mDepth, 0);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, LLTexUnit::getInternalType(mUsage), mDepth, 0);
stop_glerror();
}
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
stop_glerror();
@@ -168,14 +168,14 @@ void LLRenderTarget::addColorAttachment(U32 color_fmt)
}
if (mFBO)
{
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO);
- glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT+offset,
+ glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+offset,
LLTexUnit::getInternalType(mUsage), tex, 0);
stop_glerror();
check_framebuffer_status();
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
mTex.push_back(tex);
@@ -187,10 +187,10 @@ void LLRenderTarget::allocateDepth()
if (mStencil)
{
//use render buffers where stencil buffers are in play
- glGenRenderbuffersEXT(1, (GLuint *) &mDepth);
- glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, mDepth);
- glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, mResX, mResY);
- glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
+ glGenRenderbuffers(1, (GLuint *) &mDepth);
+ glBindRenderbuffer(GL_RENDERBUFFER, mDepth);
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, mResX, mResY);
+ glBindRenderbuffer(GL_RENDERBUFFER, 0);
}
else
{
@@ -198,7 +198,7 @@ void LLRenderTarget::allocateDepth()
gGL.getTexUnit(0)->bindManual(mUsage, mDepth);
U32 internal_type = LLTexUnit::getInternalType(mUsage);
gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
- LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT32_ARB, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
+ LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT32, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
}
}
@@ -209,54 +209,48 @@ void LLRenderTarget::shareDepthBuffer(LLRenderTarget& target)
llerrs << "Cannot share depth buffer between non FBO render targets." << llendl;
}
+ if (target.mDepth)
+ {
+ llerrs << "Attempting to override existing depth buffer. Detach existing buffer first." << llendl;
+ }
+
+ if (target.mUseDepth)
+ {
+ llerrs << "Attempting to override existing shared depth buffer. Detach existing buffer first." << llendl;
+ }
+
if (mDepth)
{
stop_glerror();
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, target.mFBO);
+ glBindFramebuffer(GL_FRAMEBUFFER, target.mFBO);
stop_glerror();
if (mStencil)
{
- glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, mDepth);
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, mDepth);
stop_glerror();
- glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, mDepth);
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, mDepth);
stop_glerror();
+ target.mStencil = true;
}
else
{
- glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, LLTexUnit::getInternalType(mUsage), mDepth, 0);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, LLTexUnit::getInternalType(mUsage), mDepth, 0);
stop_glerror();
- if (mStencil)
- {
- glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, LLTexUnit::getInternalType(mUsage), mDepth, 0);
- stop_glerror();
- }
}
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
- target.mUseDepth = TRUE;
+ target.mUseDepth = true;
}
}
void LLRenderTarget::release()
{
- if (mFBO)
- {
- glDeleteFramebuffersEXT(1, (GLuint *) &mFBO);
- mFBO = 0;
- }
-
- if (mTex.size() > 0)
- {
- LLImageGL::deleteTextures(mTex.size(), &mTex[0]);
- mTex.clear();
- }
-
if (mDepth)
{
if (mStencil)
{
- glDeleteRenderbuffersEXT(1, (GLuint*) &mDepth);
+ glDeleteRenderbuffers(1, (GLuint*) &mDepth);
stop_glerror();
}
else
@@ -266,6 +260,33 @@ void LLRenderTarget::release()
}
mDepth = 0;
}
+ else if (mUseDepth && mFBO)
+ { //detach shared depth buffer
+ glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
+ if (mStencil)
+ { //attached as a renderbuffer
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
+ mStencil = false;
+ }
+ else
+ { //attached as a texture
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, LLTexUnit::getInternalType(mUsage), 0, 0);
+ }
+ mUseDepth = false;
+ }
+
+ if (mFBO)
+ {
+ glDeleteFramebuffers(1, (GLuint *) &mFBO);
+ mFBO = 0;
+ }
+
+ if (mTex.size() > 0)
+ {
+ LLImageGL::deleteTextures(mTex.size(), &mTex[0]);
+ mTex.clear();
+ }
mSampleBuffer = NULL;
sBoundTarget = NULL;
@@ -283,14 +304,14 @@ void LLRenderTarget::bindTarget()
}
else
{
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO);
+ glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
stop_glerror();
if (gGLManager.mHasDrawBuffers)
{ //setup multiple render targets
- GLenum drawbuffers[] = {GL_COLOR_ATTACHMENT0_EXT,
- GL_COLOR_ATTACHMENT1_EXT,
- GL_COLOR_ATTACHMENT2_EXT,
- GL_COLOR_ATTACHMENT3_EXT};
+ GLenum drawbuffers[] = {GL_COLOR_ATTACHMENT0,
+ GL_COLOR_ATTACHMENT1,
+ GL_COLOR_ATTACHMENT2,
+ GL_COLOR_ATTACHMENT3};
glDrawBuffersARB(mTex.size(), drawbuffers);
}
@@ -315,7 +336,7 @@ void LLRenderTarget::unbindTarget()
{
if (gGLManager.mHasFramebufferObject)
{
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
sBoundTarget = NULL;
}
@@ -349,19 +370,19 @@ U32 LLRenderTarget::getTexture(U32 attachment) const
{
llerrs << "Invalid attachment index." << llendl;
}
+ if (mTex.empty())
+ {
+ return 0;
+ }
return mTex[attachment];
}
void LLRenderTarget::bindTexture(U32 index, S32 channel)
{
- if (index > mTex.size()-1)
- {
- llerrs << "Invalid attachment index." << llendl;
- }
- gGL.getTexUnit(channel)->bindManual(mUsage, mTex[index]);
+ gGL.getTexUnit(channel)->bindManual(mUsage, getTexture(index));
}
-void LLRenderTarget::flush(BOOL fetch_depth)
+void LLRenderTarget::flush(bool fetch_depth)
{
gGL.flush();
if (!mFBO)
@@ -377,7 +398,7 @@ void LLRenderTarget::flush(BOOL fetch_depth)
}
gGL.getTexUnit(0)->bind(this);
- glCopyTexImage2D(LLTexUnit::getInternalType(mUsage), 0, GL_DEPTH24_STENCIL8_EXT, 0, 0, mResX, mResY, 0);
+ glCopyTexImage2D(LLTexUnit::getInternalType(mUsage), 0, GL_DEPTH24_STENCIL8, 0, 0, mResX, mResY, 0);
}
gGL.getTexUnit(0)->disable();
@@ -386,55 +407,59 @@ void LLRenderTarget::flush(BOOL fetch_depth)
{
stop_glerror();
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
stop_glerror();
if (mSampleBuffer)
{
- LLGLEnable multisample(GL_MULTISAMPLE_ARB);
+ LLGLEnable multisample(GL_MULTISAMPLE);
stop_glerror();
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO);
+ glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
stop_glerror();
check_framebuffer_status();
- glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, mSampleBuffer->mFBO);
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, mSampleBuffer->mFBO);
check_framebuffer_status();
stop_glerror();
- glBlitFramebufferEXT(0, 0, mResX, mResY, 0, 0, mResX, mResY, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
+ glBlitFramebuffer(0, 0, mResX, mResY, 0, 0, mResX, mResY, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
stop_glerror();
if (mTex.size() > 1)
{
for (U32 i = 1; i < mTex.size(); ++i)
{
- glFramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
LLTexUnit::getInternalType(mUsage), mTex[i], 0);
stop_glerror();
- glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, mSampleBuffer->mTex[i]);
+ glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, mSampleBuffer->mTex[i]);
stop_glerror();
- glBlitFramebufferEXT(0, 0, mResX, mResY, 0, 0, mResX, mResY, GL_COLOR_BUFFER_BIT, GL_NEAREST);
+ glBlitFramebuffer(0, 0, mResX, mResY, 0, 0, mResX, mResY, GL_COLOR_BUFFER_BIT, GL_NEAREST);
stop_glerror();
}
for (U32 i = 0; i < mTex.size(); ++i)
{
- glFramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT+i,
+ glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+i,
LLTexUnit::getInternalType(mUsage), mTex[i], 0);
stop_glerror();
- glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT+i, GL_RENDERBUFFER_EXT, mSampleBuffer->mTex[i]);
+ glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+i, GL_RENDERBUFFER, mSampleBuffer->mTex[i]);
stop_glerror();
}
}
}
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
}
void LLRenderTarget::copyContents(LLRenderTarget& source, S32 srcX0, S32 srcY0, S32 srcX1, S32 srcY1,
S32 dstX0, S32 dstY0, S32 dstX1, S32 dstY1, U32 mask, U32 filter)
{
+ GLboolean write_depth = mask & GL_DEPTH_BUFFER_BIT ? TRUE : FALSE;
+
+ LLGLDepthTest depth(write_depth, write_depth);
+
gGL.flush();
if (!source.mFBO || !mFBO)
{
@@ -451,25 +476,25 @@ void LLRenderTarget::copyContents(LLRenderTarget& source, S32 srcX0, S32 srcY0,
{
stop_glerror();
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, source.mFBO);
+ glBindFramebuffer(GL_FRAMEBUFFER, source.mFBO);
gGL.getTexUnit(0)->bind(this, true);
stop_glerror();
glCopyTexSubImage2D(LLTexUnit::getInternalType(mUsage), 0, srcX0, srcY0, dstX0, dstY0, dstX1, dstY1);
stop_glerror();
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
stop_glerror();
}
else
{
- glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, source.mFBO);
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, source.mFBO);
stop_glerror();
- glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, mFBO);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mFBO);
stop_glerror();
check_framebuffer_status();
stop_glerror();
- glBlitFramebufferEXT(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
+ glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
stop_glerror();
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
stop_glerror();
}
}
@@ -484,22 +509,26 @@ void LLRenderTarget::copyContentsToFramebuffer(LLRenderTarget& source, S32 srcX0
llerrs << "Cannot copy framebuffer contents for non FBO render targets." << llendl;
}
{
- glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, source.mFBO);
+ GLboolean write_depth = mask & GL_DEPTH_BUFFER_BIT ? TRUE : FALSE;
+
+ LLGLDepthTest depth(write_depth, write_depth);
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, source.mFBO);
stop_glerror();
- glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
stop_glerror();
check_framebuffer_status();
stop_glerror();
- glBlitFramebufferEXT(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
+ glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
stop_glerror();
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
stop_glerror();
}
}
-BOOL LLRenderTarget::isComplete() const
+bool LLRenderTarget::isComplete() const
{
- return (!mTex.empty() || mDepth) ? TRUE : FALSE;
+ return (!mTex.empty() || mDepth) ? true : false;
}
void LLRenderTarget::getViewport(S32* viewport)
@@ -520,26 +549,26 @@ LLMultisampleBuffer::LLMultisampleBuffer()
LLMultisampleBuffer::~LLMultisampleBuffer()
{
- releaseSampleBuffer();
+ release();
}
-void LLMultisampleBuffer::releaseSampleBuffer()
+void LLMultisampleBuffer::release()
{
if (mFBO)
{
- glDeleteFramebuffersEXT(1, (GLuint *) &mFBO);
+ glDeleteFramebuffers(1, (GLuint *) &mFBO);
mFBO = 0;
}
if (mTex.size() > 0)
{
- glDeleteRenderbuffersEXT(mTex.size(), (GLuint *) &mTex[0]);
+ glDeleteRenderbuffers(mTex.size(), (GLuint *) &mTex[0]);
mTex.clear();
}
if (mDepth)
{
- glDeleteRenderbuffersEXT(1, (GLuint *) &mDepth);
+ glDeleteRenderbuffers(1, (GLuint *) &mDepth);
mDepth = 0;
}
}
@@ -556,13 +585,13 @@ void LLMultisampleBuffer::bindTarget(LLRenderTarget* ref)
ref = this;
}
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO);
+ glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
if (gGLManager.mHasDrawBuffers)
{ //setup multiple render targets
- GLenum drawbuffers[] = {GL_COLOR_ATTACHMENT0_EXT,
- GL_COLOR_ATTACHMENT1_EXT,
- GL_COLOR_ATTACHMENT2_EXT,
- GL_COLOR_ATTACHMENT3_EXT};
+ GLenum drawbuffers[] = {GL_COLOR_ATTACHMENT0,
+ GL_COLOR_ATTACHMENT1,
+ GL_COLOR_ATTACHMENT2,
+ GL_COLOR_ATTACHMENT3};
glDrawBuffersARB(ref->mTex.size(), drawbuffers);
}
@@ -573,12 +602,12 @@ void LLMultisampleBuffer::bindTarget(LLRenderTarget* ref)
sBoundTarget = this;
}
-void LLMultisampleBuffer::allocate(U32 resx, U32 resy, U32 color_fmt, BOOL depth, BOOL stencil, LLTexUnit::eTextureType usage, BOOL use_fbo )
+void LLMultisampleBuffer::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, bool stencil, LLTexUnit::eTextureType usage, bool use_fbo )
{
allocate(resx,resy,color_fmt,depth,stencil,usage,use_fbo,2);
}
-void LLMultisampleBuffer::allocate(U32 resx, U32 resy, U32 color_fmt, BOOL depth, BOOL stencil, LLTexUnit::eTextureType usage, BOOL use_fbo, U32 samples )
+void LLMultisampleBuffer::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, bool stencil, LLTexUnit::eTextureType usage, bool use_fbo, U32 samples )
{
stop_glerror();
mResX = resx;
@@ -588,12 +617,7 @@ void LLMultisampleBuffer::allocate(U32 resx, U32 resy, U32 color_fmt, BOOL depth
mUseDepth = depth;
mStencil = stencil;
- releaseSampleBuffer();
-
- if (!gGLManager.mHasFramebufferMultisample)
- {
- llerrs << "Attempting to allocate unsupported render target type!" << llendl;
- }
+ release();
mSamples = samples;
@@ -614,23 +638,21 @@ void LLMultisampleBuffer::allocate(U32 resx, U32 resy, U32 color_fmt, BOOL depth
stop_glerror();
}
- glGenFramebuffersEXT(1, (GLuint *) &mFBO);
+ glGenFramebuffers(1, (GLuint *) &mFBO);
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO);
+ glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
if (mDepth)
{
- glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, mDepth);
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, mDepth);
if (mStencil)
{
- glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, mDepth);
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, mDepth);
}
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
}
-
+
stop_glerror();
-
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
stop_glerror();
}
@@ -652,30 +674,28 @@ void LLMultisampleBuffer::addColorAttachment(U32 color_fmt)
}
U32 tex;
- glGenRenderbuffersEXT(1, &tex);
+ glGenRenderbuffers(1, &tex);
- glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, tex);
- glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, mSamples, color_fmt, mResX, mResY);
+ glBindRenderbuffer(GL_RENDERBUFFER, tex);
+ glRenderbufferStorageMultisample(GL_RENDERBUFFER, mSamples, color_fmt, mResX, mResY);
stop_glerror();
if (mFBO)
{
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO);
- glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT+offset, GL_RENDERBUFFER_EXT, tex);
+ glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+offset, GL_RENDERBUFFER, tex);
stop_glerror();
- GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
switch (status)
{
- case GL_FRAMEBUFFER_COMPLETE_EXT:
- break;
- case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
- llerrs << "WTF?" << llendl;
+ case GL_FRAMEBUFFER_COMPLETE:
break;
default:
- llerrs << "WTF?" << llendl;
+ llerrs << "WTF? " << std::hex << status << llendl;
+ break;
}
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
mTex.push_back(tex);
@@ -683,15 +703,15 @@ void LLMultisampleBuffer::addColorAttachment(U32 color_fmt)
void LLMultisampleBuffer::allocateDepth()
{
- glGenRenderbuffersEXT(1, (GLuint* ) &mDepth);
- glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, mDepth);
+ glGenRenderbuffers(1, (GLuint* ) &mDepth);
+ glBindRenderbuffer(GL_RENDERBUFFER, mDepth);
if (mStencil)
{
- glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, mSamples, GL_DEPTH24_STENCIL8_EXT, mResX, mResY);
+ glRenderbufferStorageMultisample(GL_RENDERBUFFER, mSamples, GL_DEPTH24_STENCIL8, mResX, mResY);
}
else
{
- glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, mSamples, GL_DEPTH_COMPONENT16_ARB, mResX, mResY);
+ glRenderbufferStorageMultisample(GL_RENDERBUFFER, mSamples, GL_DEPTH_COMPONENT16, mResX, mResY);
}
}
diff --git a/indra/llrender/llrendertarget.h b/indra/llrender/llrendertarget.h
index ae8613d9be..12dd1c8b90 100644
--- a/indra/llrender/llrendertarget.h
+++ b/indra/llrender/llrendertarget.h
@@ -63,7 +63,7 @@ class LLRenderTarget
{
public:
//whether or not to use FBO implementation
- static BOOL sUseFBO;
+ static bool sUseFBO;
LLRenderTarget();
virtual ~LLRenderTarget();
@@ -71,7 +71,7 @@ public:
//allocate resources for rendering
//must be called before use
//multiple calls will release previously allocated resources
- void allocate(U32 resx, U32 resy, U32 color_fmt, BOOL depth, BOOL stencil, LLTexUnit::eTextureType usage = LLTexUnit::TT_TEXTURE, BOOL use_fbo = FALSE);
+ void allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, bool stencil, LLTexUnit::eTextureType usage = LLTexUnit::TT_TEXTURE, bool use_fbo = FALSE);
//provide this render target with a multisample resource.
void setSampleBuffer(LLMultisampleBuffer* buffer);
@@ -88,7 +88,7 @@ public:
//free any allocated resources
//safe to call redundantly
- void release();
+ virtual void release();
//bind target for rendering
//applies appropriate viewport
@@ -115,7 +115,7 @@ public:
U32 getTexture(U32 attachment = 0) const;
U32 getDepth(void) const { return mDepth; }
- BOOL hasStencil() const { return mStencil; }
+ bool hasStencil() const { return mStencil; }
void bindTexture(U32 index, S32 channel);
@@ -125,7 +125,7 @@ public:
// call bindTarget once, do all your rendering, call flush once
// if fetch_depth is TRUE, every effort will be made to copy the depth buffer into
// the current depth texture. A depth texture will be allocated if needed.
- void flush(BOOL fetch_depth = FALSE);
+ void flush(bool fetch_depth = FALSE);
void copyContents(LLRenderTarget& source, S32 srcX0, S32 srcY0, S32 srcX1, S32 srcY1,
S32 dstX0, S32 dstY0, S32 dstX1, S32 dstY1, U32 mask, U32 filter);
@@ -136,7 +136,7 @@ public:
//Returns TRUE if target is ready to be rendered into.
//That is, if the target has been allocated with at least
//one renderable attachment (i.e. color buffer, depth buffer).
- BOOL isComplete() const;
+ bool isComplete() const;
static LLRenderTarget* getCurrentBoundTarget() { return sBoundTarget; }
@@ -147,9 +147,9 @@ protected:
std::vector<U32> mTex;
U32 mFBO;
U32 mDepth;
- BOOL mStencil;
- BOOL mUseDepth;
- BOOL mRenderDepth;
+ bool mStencil;
+ bool mUseDepth;
+ bool mRenderDepth;
LLTexUnit::eTextureType mUsage;
U32 mSamples;
LLMultisampleBuffer* mSampleBuffer;
@@ -164,12 +164,12 @@ public:
LLMultisampleBuffer();
virtual ~LLMultisampleBuffer();
- void releaseSampleBuffer();
+ virtual void release();
virtual void bindTarget();
void bindTarget(LLRenderTarget* ref);
- virtual void allocate(U32 resx, U32 resy, U32 color_fmt, BOOL depth, BOOL stencil, LLTexUnit::eTextureType usage, BOOL use_fbo);
- void allocate(U32 resx, U32 resy, U32 color_fmt, BOOL depth, BOOL stencil, LLTexUnit::eTextureType usage, BOOL use_fbo, U32 samples);
+ virtual void allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, bool stencil, LLTexUnit::eTextureType usage, bool use_fbo);
+ void allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, bool stencil, LLTexUnit::eTextureType usage, bool use_fbo, U32 samples);
virtual void addColorAttachment(U32 color_fmt);
virtual void allocateDepth();
};
diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp
index c859d41e17..98a0a93084 100644
--- a/indra/llrender/llshadermgr.cpp
+++ b/indra/llrender/llshadermgr.cpp
@@ -146,6 +146,14 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
return FALSE;
}
}
+
+ if (features->hasObjectSkinning)
+ {
+ if (!shader->attachObject("avatar/objectSkinV.glsl"))
+ {
+ return FALSE;
+ }
+ }
///////////////////////////////////////
// Attach Fragment Shader Features Next
@@ -220,7 +228,14 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
else if (features->isFullbright)
{
- if (features->hasWaterFog)
+ if (features->isShiny && features->hasWaterFog)
+ {
+ if (!shader->attachObject("lighting/lightFullbrightShinyWaterF.glsl"))
+ {
+ return FALSE;
+ }
+ }
+ else if (features->hasWaterFog)
{
if (!shader->attachObject("lighting/lightFullbrightWaterF.glsl"))
{
@@ -300,18 +315,21 @@ void LLShaderMgr::dumpObjectLog(GLhandleARB ret, BOOL warns)
}
else
{
- LL_DEBUGS("ShaderLoading") << log << LL_ENDL;
+ LL_INFOS("ShaderLoading") << log << LL_ENDL;
}
}
}
GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type)
{
- GLenum error;
- error = glGetError();
- if (error != GL_NO_ERROR)
+ GLenum error = GL_NO_ERROR;
+ if (gDebugGL)
{
- LL_WARNS("ShaderLoading") << "GL ERROR entering loadShaderFile(): " << error << LL_ENDL;
+ error = glGetError();
+ if (error != GL_NO_ERROR)
+ {
+ LL_WARNS("ShaderLoading") << "GL ERROR entering loadShaderFile(): " << error << LL_ENDL;
+ }
}
LL_DEBUGS("ShaderLoading") << "Loading shader file: " << filename << " class " << shader_level << LL_ENDL;
@@ -366,31 +384,39 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
//create shader object
GLhandleARB ret = glCreateShaderObjectARB(type);
- error = glGetError();
- if (error != GL_NO_ERROR)
+ if (gDebugGL)
{
- LL_WARNS("ShaderLoading") << "GL ERROR in glCreateShaderObjectARB: " << error << LL_ENDL;
+ error = glGetError();
+ if (error != GL_NO_ERROR)
+ {
+ LL_WARNS("ShaderLoading") << "GL ERROR in glCreateShaderObjectARB: " << error << LL_ENDL;
+ }
}
- else
+
+ //load source
+ glShaderSourceARB(ret, count, (const GLcharARB**) text, NULL);
+
+ if (gDebugGL)
{
- //load source
- glShaderSourceARB(ret, count, (const GLcharARB**) text, NULL);
error = glGetError();
if (error != GL_NO_ERROR)
{
LL_WARNS("ShaderLoading") << "GL ERROR in glShaderSourceARB: " << error << LL_ENDL;
}
- else
+ }
+
+ //compile source
+ glCompileShaderARB(ret);
+
+ if (gDebugGL)
+ {
+ error = glGetError();
+ if (error != GL_NO_ERROR)
{
- //compile source
- glCompileShaderARB(ret);
- error = glGetError();
- if (error != GL_NO_ERROR)
- {
- LL_WARNS("ShaderLoading") << "GL ERROR in glCompileShaderARB: " << error << LL_ENDL;
- }
+ LL_WARNS("ShaderLoading") << "GL ERROR in glCompileShaderARB: " << error << LL_ENDL;
}
}
+
//free memory
for (GLuint i = 0; i < count; i++)
{
@@ -401,13 +427,16 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
//check for errors
GLint success = GL_TRUE;
glGetObjectParameterivARB(ret, GL_OBJECT_COMPILE_STATUS_ARB, &success);
- error = glGetError();
- if (error != GL_NO_ERROR || success == GL_FALSE)
+ if (gDebugGL || success == GL_FALSE)
{
- //an error occured, print log
- LL_WARNS("ShaderLoading") << "GLSL Compilation Error: (" << error << ") in " << filename << LL_ENDL;
- dumpObjectLog(ret);
- ret = 0;
+ error = glGetError();
+ if (error != GL_NO_ERROR || success == GL_FALSE)
+ {
+ //an error occured, print log
+ LL_WARNS("ShaderLoading") << "GLSL Compilation Error: (" << error << ") in " << filename << LL_ENDL;
+ dumpObjectLog(ret);
+ ret = 0;
+ }
}
}
else
diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp
index de4501dd0f..8c9171ccf4 100644
--- a/indra/llrender/llvertexbuffer.cpp
+++ b/indra/llrender/llvertexbuffer.cpp
@@ -25,14 +25,16 @@
*/
#include "linden_common.h"
+#include "llmemory.h"
#include <boost/static_assert.hpp>
-
+#include "llsys.h"
#include "llvertexbuffer.h"
// #include "llrender.h"
#include "llglheaders.h"
#include "llmemtype.h"
#include "llrender.h"
+#include "llvector4a.h"
//============================================================================
@@ -47,6 +49,7 @@ U32 LLVertexBuffer::sSetCount = 0;
S32 LLVertexBuffer::sCount = 0;
S32 LLVertexBuffer::sGLCount = 0;
S32 LLVertexBuffer::sMappedCount = 0;
+BOOL LLVertexBuffer::sDisableVBOMapping = FALSE ;
BOOL LLVertexBuffer::sEnableVBOs = TRUE;
U32 LLVertexBuffer::sGLRenderBuffer = 0;
U32 LLVertexBuffer::sGLRenderIndices = 0;
@@ -56,20 +59,24 @@ BOOL LLVertexBuffer::sIBOActive = FALSE;
U32 LLVertexBuffer::sAllocatedBytes = 0;
BOOL LLVertexBuffer::sMapped = FALSE;
BOOL LLVertexBuffer::sUseStreamDraw = TRUE;
+BOOL LLVertexBuffer::sPreferStreamDraw = FALSE;
+S32 LLVertexBuffer::sWeight4Loc = -1;
std::vector<U32> LLVertexBuffer::sDeleteList;
-S32 LLVertexBuffer::sTypeOffsets[LLVertexBuffer::TYPE_MAX] =
+
+S32 LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_MAX] =
{
- sizeof(LLVector3), // TYPE_VERTEX,
- sizeof(LLVector3), // TYPE_NORMAL,
+ sizeof(LLVector4), // TYPE_VERTEX,
+ sizeof(LLVector4), // TYPE_NORMAL,
sizeof(LLVector2), // TYPE_TEXCOORD0,
sizeof(LLVector2), // TYPE_TEXCOORD1,
sizeof(LLVector2), // TYPE_TEXCOORD2,
sizeof(LLVector2), // TYPE_TEXCOORD3,
sizeof(LLColor4U), // TYPE_COLOR,
- sizeof(LLVector3), // TYPE_BINORMAL,
+ sizeof(LLVector4), // TYPE_BINORMAL,
sizeof(F32), // TYPE_WEIGHT,
+ sizeof(LLVector4), // TYPE_WEIGHT4,
sizeof(LLVector4), // TYPE_CLOTHWEIGHT,
};
@@ -138,11 +145,11 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask)
}
else
{ //was disabled
- if (data_mask & mask[i])
+ if (data_mask & mask[i] && i > 0)
{ //needs to be enabled
glEnableClientState(array[i]);
}
- else if (gDebugGL && glIsEnabled(array[i]))
+ else if (gDebugGL && i > 0 && glIsEnabled(array[i]))
{ //needs to be disabled, make sure it was (DEBUG TEMPORARY)
if (gDebugSession)
{
@@ -204,18 +211,53 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask)
glClientActiveTextureARB(GL_TEXTURE0_ARB);
}
+ if (sLastMask & MAP_WEIGHT4)
+ {
+ if (sWeight4Loc < 0)
+ {
+ llerrs << "Weighting disabled but vertex buffer still bound!" << llendl;
+ }
+
+ if (!(data_mask & MAP_WEIGHT4))
+ { //disable 4-component skin weight
+ glDisableVertexAttribArrayARB(sWeight4Loc);
+ }
+ }
+ else if (data_mask & MAP_WEIGHT4)
+ {
+ if (sWeight4Loc >= 0)
+ { //enable 4-component skin weight
+ glEnableVertexAttribArrayARB(sWeight4Loc);
+ }
+ }
+
+
sLastMask = data_mask;
}
}
-void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const
+//static
+void LLVertexBuffer::drawArrays(U32 mode, const std::vector<LLVector3>& pos, const std::vector<LLVector3>& norm)
{
- llassert(mRequestedNumVerts >= 0);
+ U32 count = pos.size();
+ llassert(norm.size() >= pos.size());
+ unbind();
+
+ setupClientArrays(MAP_VERTEX | MAP_NORMAL);
+
+ glVertexPointer(3, GL_FLOAT, 0, pos[0].mV);
+ glNormalPointer(GL_FLOAT, 0, norm[0].mV);
+
+ glDrawArrays(sGLMode[mode], 0, count);
+}
+
+void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_offset) const
+{
if (start >= (U32) mRequestedNumVerts ||
end >= (U32) mRequestedNumVerts)
{
- llerrs << "Bad vertex buffer draw range: [" << start << ", " << end << "]" << llendl;
+ llerrs << "Bad vertex buffer draw range: [" << start << ", " << end << "] vs " << mRequestedNumVerts << llendl;
}
llassert(mRequestedNumIndices >= 0);
@@ -226,6 +268,25 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi
llerrs << "Bad index buffer draw range: [" << indices_offset << ", " << indices_offset+count << "]" << llendl;
}
+ if (gDebugGL && !useVBOs())
+ {
+ U16* idx = ((U16*) getIndicesPointer())+indices_offset;
+ for (U32 i = 0; i < count; ++i)
+ {
+ if (idx[i] < start || idx[i] > end)
+ {
+ llerrs << "Index out of range: " << idx[i] << " not in [" << start << ", " << end << "]" << llendl;
+ }
+ }
+ }
+}
+
+void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const
+{
+ validateRange(start, end, count, indices_offset);
+
+ llassert(mRequestedNumVerts >= 0);
+
if (mGLIndices != sGLRenderIndices)
{
llerrs << "Wrong index buffer bound." << llendl;
@@ -242,9 +303,11 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi
return;
}
+ U16* idx = ((U16*) getIndicesPointer())+indices_offset;
+
stop_glerror();
glDrawRangeElements(sGLMode[mode], start, end, count, GL_UNSIGNED_SHORT,
- ((U16*) getIndicesPointer()) + indices_offset);
+ idx);
stop_glerror();
}
@@ -305,13 +368,21 @@ void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const
}
//static
-void LLVertexBuffer::initClass(bool use_vbo)
+void LLVertexBuffer::initClass(bool use_vbo, bool no_vbo_mapping)
{
- sEnableVBOs = use_vbo;
- LLGLNamePool::registerPool(&sDynamicVBOPool);
- LLGLNamePool::registerPool(&sDynamicIBOPool);
- LLGLNamePool::registerPool(&sStreamVBOPool);
- LLGLNamePool::registerPool(&sStreamIBOPool);
+ sEnableVBOs = use_vbo && gGLManager.mHasVertexBufferObject ;
+ if(sEnableVBOs)
+ {
+ //llassert_always(glBindBufferARB) ; //double check the extention for VBO is loaded.
+
+ llinfos << "VBO is enabled." << llendl ;
+ }
+ else
+ {
+ llinfos << "VBO is disabled." << llendl ;
+ }
+
+ sDisableVBOMapping = sEnableVBOs && no_vbo_mapping ;
}
//static
@@ -340,6 +411,8 @@ void LLVertexBuffer::cleanupClass()
LLMemType mt2(LLMemType::MTYPE_VERTEX_CLEANUP_CLASS);
unbind();
clientCopy(); // deletes GL buffers
+
+ //llassert_always(!sCount) ;
}
void LLVertexBuffer::clientCopy(F64 max_time)
@@ -364,7 +437,9 @@ LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) :
mGLBuffer(0),
mGLIndices(0),
mMappedData(NULL),
- mMappedIndexData(NULL), mLocked(FALSE),
+ mMappedIndexData(NULL),
+ mVertexLocked(FALSE),
+ mIndexLocked(FALSE),
mFinal(FALSE),
mFilthy(FALSE),
mEmpty(TRUE),
@@ -382,22 +457,29 @@ LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) :
mUsage = 0;
}
- if (mUsage == GL_STREAM_DRAW_ARB && !sUseStreamDraw)
+ if (mUsage == GL_DYNAMIC_DRAW_ARB && sPreferStreamDraw)
{
- mUsage = 0;
+ mUsage = GL_STREAM_DRAW_ARB;
}
- S32 stride = calcStride(typemask, mOffsets);
+ //zero out offsets
+ for (U32 i = 0; i < TYPE_MAX; i++)
+ {
+ mOffsets[i] = 0;
+ }
mTypeMask = typemask;
- mStride = stride;
+ mSize = 0;
+ mAlignedOffset = 0;
+ mAlignedIndexOffset = 0;
+
sCount++;
}
//static
-S32 LLVertexBuffer::calcStride(const U32& typemask, S32* offsets)
+S32 LLVertexBuffer::calcOffsets(const U32& typemask, S32* offsets, S32 num_vertices)
{
- S32 stride = 0;
+ S32 offset = 0;
for (S32 i=0; i<TYPE_MAX; i++)
{
U32 mask = 1<<i;
@@ -405,13 +487,35 @@ S32 LLVertexBuffer::calcStride(const U32& typemask, S32* offsets)
{
if (offsets)
{
- offsets[i] = stride;
+ offsets[i] = offset;
+ offset += LLVertexBuffer::sTypeSize[i]*num_vertices;
+ offset = (offset + 0xF) & ~0xF;
}
- stride += sTypeOffsets[i];
}
}
- return stride;
+ return offset+16;
+}
+
+//static
+S32 LLVertexBuffer::calcVertexSize(const U32& typemask)
+{
+ S32 size = 0;
+ for (S32 i = 0; i < TYPE_MAX; i++)
+ {
+ U32 mask = 1<<i;
+ if (typemask & mask)
+ {
+ size += LLVertexBuffer::sTypeSize[i];
+ }
+ }
+
+ return size;
+}
+
+S32 LLVertexBuffer::getSize() const
+{
+ return mSize;
}
// protected, use unref()
@@ -422,6 +526,8 @@ LLVertexBuffer::~LLVertexBuffer()
destroyGLBuffer();
destroyGLIndices();
sCount--;
+
+ llassert_always(!mMappedData && !mMappedIndexData) ;
};
//----------------------------------------------------------------------------
@@ -523,8 +629,7 @@ void LLVertexBuffer::createGLBuffer()
{
static int gl_buffer_idx = 0;
mGLBuffer = ++gl_buffer_idx;
- mMappedData = new U8[size];
- memset(mMappedData, 0, size);
+ mMappedData = (U8*) ll_aligned_malloc_16(size);
}
}
@@ -545,16 +650,20 @@ void LLVertexBuffer::createGLIndices()
mEmpty = TRUE;
+ //pad by 16 bytes for aligned copies
+ size += 16;
+
if (useVBOs())
{
+ //pad by another 16 bytes for VBO pointer adjustment
+ size += 16;
mMappedIndexData = NULL;
genIndices();
mResized = TRUE;
}
else
{
- mMappedIndexData = new U8[size];
- memset(mMappedIndexData, 0, size);
+ mMappedIndexData = (U8*) ll_aligned_malloc_16(size);
static int gl_buffer_idx = 0;
mGLIndices = ++gl_buffer_idx;
}
@@ -567,6 +676,8 @@ void LLVertexBuffer::destroyGLBuffer()
{
if (useVBOs())
{
+ freeClientBuffer() ;
+
if (mMappedData || mMappedIndexData)
{
llerrs << "Vertex buffer destroyed while mapped!" << llendl;
@@ -575,7 +686,7 @@ void LLVertexBuffer::destroyGLBuffer()
}
else
{
- delete [] mMappedData;
+ ll_aligned_free_16(mMappedData);
mMappedData = NULL;
mEmpty = TRUE;
}
@@ -584,7 +695,7 @@ void LLVertexBuffer::destroyGLBuffer()
}
mGLBuffer = 0;
- unbind();
+ //unbind();
}
void LLVertexBuffer::destroyGLIndices()
@@ -594,6 +705,8 @@ void LLVertexBuffer::destroyGLIndices()
{
if (useVBOs())
{
+ freeClientBuffer() ;
+
if (mMappedData || mMappedIndexData)
{
llerrs << "Vertex buffer destroyed while mapped." << llendl;
@@ -602,7 +715,7 @@ void LLVertexBuffer::destroyGLIndices()
}
else
{
- delete [] mMappedIndexData;
+ ll_aligned_free_16(mMappedIndexData);
mMappedIndexData = NULL;
mEmpty = TRUE;
}
@@ -611,7 +724,7 @@ void LLVertexBuffer::destroyGLIndices()
}
mGLIndices = 0;
- unbind();
+ //unbind();
}
void LLVertexBuffer::updateNumVerts(S32 nverts)
@@ -627,7 +740,7 @@ void LLVertexBuffer::updateNumVerts(S32 nverts)
}
mRequestedNumVerts = nverts;
-
+
if (!mDynamicSize)
{
mNumVerts = nverts;
@@ -642,7 +755,7 @@ void LLVertexBuffer::updateNumVerts(S32 nverts)
}
mNumVerts = nverts;
}
-
+ mSize = calcOffsets(mTypeMask, mOffsets, mNumVerts);
}
void LLVertexBuffer::updateNumIndices(S32 nindices)
@@ -673,6 +786,12 @@ void LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create)
{
LLMemType mt2(LLMemType::MTYPE_VERTEX_ALLOCATE_BUFFER);
+ if (nverts < 0 || nindices < 0 ||
+ nverts > 65536)
+ {
+ llerrs << "Bad vertex buffer allocation: " << nverts << " : " << nindices << llendl;
+ }
+
updateNumVerts(nverts);
updateNumIndices(nindices);
@@ -711,9 +830,6 @@ void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices)
{
sAllocatedBytes -= getSize() + getIndicesSize();
- S32 oldsize = getSize();
- S32 old_index_size = getIndicesSize();
-
updateNumVerts(newnverts);
updateNumIndices(newnindices);
@@ -730,26 +846,10 @@ void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices)
}
else
{
- //delete old buffer, keep GL buffer for now
if (!useVBOs())
{
- U8* old = mMappedData;
- mMappedData = new U8[newsize];
- if (old)
- {
- memcpy(mMappedData, old, llmin(newsize, oldsize));
- if (newsize > oldsize)
- {
- memset(mMappedData+oldsize, 0, newsize-oldsize);
- }
-
- delete [] old;
- }
- else
- {
- memset(mMappedData, 0, newsize);
- mEmpty = TRUE;
- }
+ ll_aligned_free_16(mMappedData);
+ mMappedData = (U8*) ll_aligned_malloc_16(newsize);
}
mResized = TRUE;
}
@@ -769,24 +869,8 @@ void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices)
{
if (!useVBOs())
{
- //delete old buffer, keep GL buffer for now
- U8* old = mMappedIndexData;
- mMappedIndexData = new U8[new_index_size];
-
- if (old)
- {
- memcpy(mMappedIndexData, old, llmin(new_index_size, old_index_size));
- if (new_index_size > old_index_size)
- {
- memset(mMappedIndexData+old_index_size, 0, new_index_size - old_index_size);
- }
- delete [] old;
- }
- else
- {
- memset(mMappedIndexData, 0, new_index_size);
- mEmpty = TRUE;
- }
+ ll_aligned_free_16(mMappedIndexData);
+ mMappedIndexData = (U8*) ll_aligned_malloc_16(new_index_size);
}
mResized = TRUE;
}
@@ -799,6 +883,7 @@ void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices)
if (mResized && useVBOs())
{
+ freeClientBuffer() ;
setBuffer(0);
}
}
@@ -822,110 +907,240 @@ BOOL LLVertexBuffer::useVBOs() const
}
//----------------------------------------------------------------------------
+void LLVertexBuffer::freeClientBuffer()
+{
+ if(useVBOs() && sDisableVBOMapping && (mMappedData || mMappedIndexData))
+ {
+ ll_aligned_free_16(mMappedData) ;
+ ll_aligned_free_16(mMappedIndexData) ;
+ mMappedData = NULL ;
+ mMappedIndexData = NULL ;
+ }
+}
+
+void LLVertexBuffer::allocateClientVertexBuffer()
+{
+ if(!mMappedData)
+ {
+ mMappedData = (U8*)ll_aligned_malloc_16(getSize());
+ }
+}
+
+void LLVertexBuffer::allocateClientIndexBuffer()
+{
+ if(!mMappedIndexData)
+ {
+ mMappedIndexData = (U8*)ll_aligned_malloc_16(getIndicesSize());
+ }
+}
// Map for data access
-U8* LLVertexBuffer::mapBuffer(S32 access)
+U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 access)
{
LLMemType mt2(LLMemType::MTYPE_VERTEX_MAP_BUFFER);
if (mFinal)
{
- llerrs << "LLVertexBuffer::mapBuffer() called on a finalized buffer." << llendl;
+ llerrs << "LLVertexBuffer::mapVeretxBuffer() called on a finalized buffer." << llendl;
}
if (!useVBOs() && !mMappedData && !mMappedIndexData)
{
- llerrs << "LLVertexBuffer::mapBuffer() called on unallocated buffer." << llendl;
+ llerrs << "LLVertexBuffer::mapVertexBuffer() called on unallocated buffer." << llendl;
}
- if (!mLocked && useVBOs())
+ if (!mVertexLocked && useVBOs())
{
{
LLMemType mt_v(LLMemType::MTYPE_VERTEX_MAP_BUFFER_VERTICES);
- setBuffer(0);
- mLocked = TRUE;
+ setBuffer(0, type);
+ mVertexLocked = TRUE;
stop_glerror();
- mMappedData = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
- stop_glerror();
+
+ if(sDisableVBOMapping)
+ {
+ allocateClientVertexBuffer() ;
+ }
+ else
+ {
+ U8* src = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
+ mMappedData = LL_NEXT_ALIGNED_ADDRESS<U8>(src);
+ mAlignedOffset = mMappedData - src;
+
+ stop_glerror();
+ }
}
+
+
+ if (!mMappedData)
{
- LLMemType mt_v(LLMemType::MTYPE_VERTEX_MAP_BUFFER_INDICES);
- mMappedIndexData = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
- stop_glerror();
+ log_glerror();
+
+ //check the availability of memory
+ U32 avail_phy_mem, avail_vir_mem;
+ LLMemoryInfo::getAvailableMemoryKB(avail_phy_mem, avail_vir_mem) ;
+ llinfos << "Available physical mwmory(KB): " << avail_phy_mem << llendl ;
+ llinfos << "Available virtual memory(KB): " << avail_vir_mem << llendl;
+
+ if(!sDisableVBOMapping)
+ {
+ //--------------------
+ //print out more debug info before crash
+ llinfos << "vertex buffer size: (num verts : num indices) = " << getNumVerts() << " : " << getNumIndices() << llendl ;
+ GLint size ;
+ glGetBufferParameterivARB(GL_ARRAY_BUFFER_ARB, GL_BUFFER_SIZE_ARB, &size) ;
+ llinfos << "GL_ARRAY_BUFFER_ARB size is " << size << llendl ;
+ //--------------------
+
+ GLint buff;
+ glGetIntegerv(GL_ARRAY_BUFFER_BINDING_ARB, &buff);
+ if ((GLuint)buff != mGLBuffer)
+ {
+ llerrs << "Invalid GL vertex buffer bound: " << buff << llendl;
+ }
+
+
+ llerrs << "glMapBuffer returned NULL (no vertex data)" << llendl;
+ }
+ else
+ {
+ llerrs << "memory allocation for vertex data failed." << llendl ;
+ }
}
+ sMappedCount++;
+ }
+
+ return mMappedData;
+}
- if (!mMappedData)
+U8* LLVertexBuffer::mapIndexBuffer(S32 access)
+{
+ LLMemType mt2(LLMemType::MTYPE_VERTEX_MAP_BUFFER);
+ if (mFinal)
+ {
+ llerrs << "LLVertexBuffer::mapIndexBuffer() called on a finalized buffer." << llendl;
+ }
+ if (!useVBOs() && !mMappedData && !mMappedIndexData)
+ {
+ llerrs << "LLVertexBuffer::mapIndexBuffer() called on unallocated buffer." << llendl;
+ }
+
+ if (!mIndexLocked && useVBOs())
+ {
{
- //--------------------
- //print out more debug info before crash
- llinfos << "vertex buffer size: (num verts : num indices) = " << getNumVerts() << " : " << getNumIndices() << llendl ;
- GLint size ;
- glGetBufferParameterivARB(GL_ARRAY_BUFFER_ARB, GL_BUFFER_SIZE_ARB, &size) ;
- llinfos << "GL_ARRAY_BUFFER_ARB size is " << size << llendl ;
- //--------------------
+ LLMemType mt_v(LLMemType::MTYPE_VERTEX_MAP_BUFFER_INDICES);
- GLint buff;
- glGetIntegerv(GL_ARRAY_BUFFER_BINDING_ARB, &buff);
- if ((GLuint)buff != mGLBuffer)
+ setBuffer(0, TYPE_INDEX);
+ mIndexLocked = TRUE;
+ stop_glerror();
+
+ if(sDisableVBOMapping)
{
- llerrs << "Invalid GL vertex buffer bound: " << buff << llendl;
+ allocateClientIndexBuffer() ;
+ }
+ else
+ {
+ U8* src = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
+ mMappedIndexData = LL_NEXT_ALIGNED_ADDRESS<U8>(src);
+ mAlignedIndexOffset = mMappedIndexData - src;
+ stop_glerror();
}
-
-
- llerrs << "glMapBuffer returned NULL (no vertex data)" << llendl;
}
if (!mMappedIndexData)
{
- GLint buff;
- glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff);
- if ((GLuint)buff != mGLIndices)
+ log_glerror();
+
+ if(!sDisableVBOMapping)
{
- llerrs << "Invalid GL index buffer bound: " << buff << llendl;
- }
+ GLint buff;
+ glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff);
+ if ((GLuint)buff != mGLIndices)
+ {
+ llerrs << "Invalid GL index buffer bound: " << buff << llendl;
+ }
- llerrs << "glMapBuffer returned NULL (no index data)" << llendl;
+ llerrs << "glMapBuffer returned NULL (no index data)" << llendl;
+ }
+ else
+ {
+ llerrs << "memory allocation for Index data failed. " << llendl ;
+ }
}
sMappedCount++;
}
-
- return mMappedData;
+
+ return mMappedIndexData ;
}
-void LLVertexBuffer::unmapBuffer()
+void LLVertexBuffer::unmapBuffer(S32 type)
{
LLMemType mt2(LLMemType::MTYPE_VERTEX_UNMAP_BUFFER);
- if (mMappedData || mMappedIndexData)
+ if (!useVBOs())
{
- if (useVBOs() && mLocked)
+ return ; //nothing to unmap
+ }
+
+ bool updated_all = false ;
+ if (mMappedData && mVertexLocked && type != TYPE_INDEX)
+ {
+ updated_all = (mIndexLocked && type < 0) ; //both vertex and index buffers done updating
+
+ if(sDisableVBOMapping)
+ {
+ stop_glerror();
+ glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, getSize(), mMappedData);
+ stop_glerror();
+ }
+ else
{
stop_glerror();
glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
stop_glerror();
+
+ mMappedData = NULL;
+ }
+
+ mVertexLocked = FALSE ;
+ sMappedCount--;
+ }
+
+ if(mMappedIndexData && mIndexLocked && (type < 0 || type == TYPE_INDEX))
+ {
+ if(sDisableVBOMapping)
+ {
+ stop_glerror();
+ glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, getIndicesSize(), mMappedIndexData);
+ stop_glerror();
+ }
+ else
+ {
+ stop_glerror();
glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB);
stop_glerror();
- /*if (!sMapped)
- {
- llerrs << "Redundantly unmapped VBO!" << llendl;
- }
- sMapped = FALSE;*/
- sMappedCount--;
-
- if (mUsage == GL_STATIC_DRAW_ARB)
- { //static draw buffers can only be mapped a single time
- //throw out client data (we won't be using it again)
- mEmpty = TRUE;
- mFinal = TRUE;
- }
- else
+ mMappedIndexData = NULL ;
+ }
+
+ mIndexLocked = FALSE ;
+ sMappedCount--;
+ }
+
+ if(updated_all)
+ {
+ if(mUsage == GL_STATIC_DRAW_ARB)
+ {
+ //static draw buffers can only be mapped a single time
+ //throw out client data (we won't be using it again)
+ mEmpty = TRUE;
+ mFinal = TRUE;
+ if(sDisableVBOMapping)
{
- mEmpty = FALSE;
+ freeClientBuffer() ;
}
-
- mMappedIndexData = NULL;
- mMappedData = NULL;
-
- mLocked = FALSE;
+ }
+ else
+ {
+ mEmpty = FALSE;
}
}
}
@@ -939,23 +1154,31 @@ template <class T,S32 type> struct VertexBufferStrider
strider_t& strider,
S32 index)
{
- if (vbo.mapBuffer() == NULL)
- {
- llwarns << "mapBuffer failed!" << llendl;
- return FALSE;
- }
-
if (type == LLVertexBuffer::TYPE_INDEX)
{
S32 stride = sizeof(T);
+
+ if (vbo.mapIndexBuffer() == NULL)
+ {
+ llwarns << "mapIndexBuffer failed!" << llendl;
+ return FALSE;
+ }
+
strider = (T*)(vbo.getMappedIndices() + index*stride);
strider.setStride(0);
return TRUE;
}
else if (vbo.hasDataType(type))
{
- S32 stride = vbo.getStride();
- strider = (T*)(vbo.getMappedData() + vbo.getOffset(type) + index*stride);
+ S32 stride = LLVertexBuffer::sTypeSize[type];
+
+ if (vbo.mapVertexBuffer(type) == NULL)
+ {
+ llwarns << "mapVertexBuffer failed!" << llendl;
+ return FALSE;
+ }
+
+ strider = (T*)(vbo.getMappedData() + vbo.getOffset(type)+index*stride);
strider.setStride(stride);
return TRUE;
}
@@ -967,7 +1190,6 @@ template <class T,S32 type> struct VertexBufferStrider
}
};
-
bool LLVertexBuffer::getVertexStrider(LLStrider<LLVector3>& strider, S32 index)
{
return VertexBufferStrider<LLVector3,TYPE_VERTEX>::get(*this, strider, index);
@@ -1008,34 +1230,21 @@ bool LLVertexBuffer::getWeightStrider(LLStrider<F32>& strider, S32 index)
{
return VertexBufferStrider<F32,TYPE_WEIGHT>::get(*this, strider, index);
}
-bool LLVertexBuffer::getClothWeightStrider(LLStrider<LLVector4>& strider, S32 index)
+
+bool LLVertexBuffer::getWeight4Strider(LLStrider<LLVector4>& strider, S32 index)
{
- return VertexBufferStrider<LLVector4,TYPE_CLOTHWEIGHT>::get(*this, strider, index);
+ return VertexBufferStrider<LLVector4,TYPE_WEIGHT4>::get(*this, strider, index);
}
-void LLVertexBuffer::setStride(S32 type, S32 new_stride)
+bool LLVertexBuffer::getClothWeightStrider(LLStrider<LLVector4>& strider, S32 index)
{
- LLMemType mt2(LLMemType::MTYPE_VERTEX_SET_STRIDE);
- if (mNumVerts)
- {
- llerrs << "LLVertexBuffer::setOffset called with mNumVerts = " << mNumVerts << llendl;
- }
- // This code assumes that setStride() will only be called once per VBO per type.
- S32 delta = new_stride - sTypeOffsets[type];
- for (S32 i=type+1; i<TYPE_MAX; i++)
- {
- if (mTypeMask & (1<<i))
- {
- mOffsets[i] += delta;
- }
- }
- mStride += delta;
+ return VertexBufferStrider<LLVector4,TYPE_CLOTHWEIGHT>::get(*this, strider, index);
}
//----------------------------------------------------------------------------
// Set for rendering
-void LLVertexBuffer::setBuffer(U32 data_mask)
+void LLVertexBuffer::setBuffer(U32 data_mask, S32 type)
{
LLMemType mt2(LLMemType::MTYPE_VERTEX_SET_BUFFER);
//set up pointers if the data mask is different ...
@@ -1176,7 +1385,7 @@ void LLVertexBuffer::setBuffer(U32 data_mask)
{
ll_fail("LLVertexBuffer::mapBuffer failed");
}
- unmapBuffer();
+ unmapBuffer(type);
}
else
{
@@ -1228,8 +1437,7 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) const
{
LLMemType mt2(LLMemType::MTYPE_VERTEX_SETUP_VERTEX_BUFFER);
stop_glerror();
- U8* base = useVBOs() ? NULL : mMappedData;
- S32 stride = mStride;
+ U8* base = useVBOs() ? (U8*) mAlignedOffset : mMappedData;
if ((data_mask & mTypeMask) != data_mask)
{
@@ -1238,52 +1446,58 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) const
if (data_mask & MAP_NORMAL)
{
- glNormalPointer(GL_FLOAT, stride, (void*)(base + mOffsets[TYPE_NORMAL]));
+ glNormalPointer(GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_NORMAL], (void*)(base + mOffsets[TYPE_NORMAL]));
}
if (data_mask & MAP_TEXCOORD3)
{
glClientActiveTextureARB(GL_TEXTURE3_ARB);
- glTexCoordPointer(2,GL_FLOAT, stride, (void*)(base + mOffsets[TYPE_TEXCOORD3]));
+ glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD3], (void*)(base + mOffsets[TYPE_TEXCOORD3]));
glClientActiveTextureARB(GL_TEXTURE0_ARB);
}
if (data_mask & MAP_TEXCOORD2)
{
glClientActiveTextureARB(GL_TEXTURE2_ARB);
- glTexCoordPointer(2,GL_FLOAT, stride, (void*)(base + mOffsets[TYPE_TEXCOORD2]));
+ glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD2], (void*)(base + mOffsets[TYPE_TEXCOORD2]));
glClientActiveTextureARB(GL_TEXTURE0_ARB);
}
if (data_mask & MAP_TEXCOORD1)
{
glClientActiveTextureARB(GL_TEXTURE1_ARB);
- glTexCoordPointer(2,GL_FLOAT, stride, (void*)(base + mOffsets[TYPE_TEXCOORD1]));
+ glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], (void*)(base + mOffsets[TYPE_TEXCOORD1]));
glClientActiveTextureARB(GL_TEXTURE0_ARB);
}
if (data_mask & MAP_BINORMAL)
{
glClientActiveTextureARB(GL_TEXTURE2_ARB);
- glTexCoordPointer(3,GL_FLOAT, stride, (void*)(base + mOffsets[TYPE_BINORMAL]));
+ glTexCoordPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_BINORMAL], (void*)(base + mOffsets[TYPE_BINORMAL]));
glClientActiveTextureARB(GL_TEXTURE0_ARB);
}
if (data_mask & MAP_TEXCOORD0)
{
- glTexCoordPointer(2,GL_FLOAT, stride, (void*)(base + mOffsets[TYPE_TEXCOORD0]));
+ glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], (void*)(base + mOffsets[TYPE_TEXCOORD0]));
}
if (data_mask & MAP_COLOR)
{
- glColorPointer(4, GL_UNSIGNED_BYTE, stride, (void*)(base + mOffsets[TYPE_COLOR]));
+ glColorPointer(4, GL_UNSIGNED_BYTE, LLVertexBuffer::sTypeSize[TYPE_COLOR], (void*)(base + mOffsets[TYPE_COLOR]));
}
if (data_mask & MAP_WEIGHT)
{
- glVertexAttribPointerARB(1, 1, GL_FLOAT, FALSE, stride, (void*)(base + mOffsets[TYPE_WEIGHT]));
+ glVertexAttribPointerARB(1, 1, GL_FLOAT, FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT], (void*)(base + mOffsets[TYPE_WEIGHT]));
}
+
+ if (data_mask & MAP_WEIGHT4 && sWeight4Loc != -1)
+ {
+ glVertexAttribPointerARB(sWeight4Loc, 4, GL_FLOAT, FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT4], (void*)(base+mOffsets[TYPE_WEIGHT4]));
+ }
+
if (data_mask & MAP_CLOTHWEIGHT)
{
- glVertexAttribPointerARB(4, 4, GL_FLOAT, TRUE, stride, (void*)(base + mOffsets[TYPE_CLOTHWEIGHT]));
+ glVertexAttribPointerARB(4, 4, GL_FLOAT, TRUE, LLVertexBuffer::sTypeSize[TYPE_CLOTHWEIGHT], (void*)(base + mOffsets[TYPE_CLOTHWEIGHT]));
}
if (data_mask & MAP_VERTEX)
{
- glVertexPointer(3,GL_FLOAT, stride, (void*)(base + 0));
+ glVertexPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_VERTEX], (void*)(base + 0));
}
llglassertok();
diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h
index 94fa790957..a9f22193f8 100644
--- a/indra/llrender/llvertexbuffer.h
+++ b/indra/llrender/llvertexbuffer.h
@@ -56,42 +56,65 @@ protected:
virtual GLuint allocateName()
{
GLuint name;
+ stop_glerror();
glGenBuffersARB(1, &name);
+ stop_glerror();
return name;
}
virtual void releaseName(GLuint name)
{
+ stop_glerror();
glDeleteBuffersARB(1, &name);
+ stop_glerror();
}
};
//============================================================================
-// base class
+// base class
class LLVertexBuffer : public LLRefCount
{
public:
+ LLVertexBuffer(const LLVertexBuffer& rhs)
+ {
+ *this = rhs;
+ }
+
+ const LLVertexBuffer& operator=(const LLVertexBuffer& rhs)
+ {
+ llerrs << "Illegal operation!" << llendl;
+ return *this;
+ }
+
static LLVBOPool sStreamVBOPool;
static LLVBOPool sDynamicVBOPool;
static LLVBOPool sStreamIBOPool;
static LLVBOPool sDynamicIBOPool;
+ static S32 sWeight4Loc;
+
static BOOL sUseStreamDraw;
+ static BOOL sPreferStreamDraw;
- static void initClass(bool use_vbo);
+ static void initClass(bool use_vbo, bool no_vbo_mapping);
static void cleanupClass();
static void setupClientArrays(U32 data_mask);
+ static void drawArrays(U32 mode, const std::vector<LLVector3>& pos, const std::vector<LLVector3>& norm);
+
static void clientCopy(F64 max_time = 0.005); //copy data from client to GL
static void unbind(); //unbind any bound vertex buffer
//get the size of a vertex with the given typemask
- //if offsets is not NULL, its contents will be filled
- //with the offset of each vertex component in the buffer,
+ static S32 calcVertexSize(const U32& typemask);
+
+ //get the size of a buffer with the given typemask and vertex count
+ //fill offsets with the offset of each vertex component array into the buffer
// indexed by the following enum
- static S32 calcStride(const U32& typemask, S32* offsets = NULL);
+ static S32 calcOffsets(const U32& typemask, S32* offsets, S32 num_vertices);
+
enum {
TYPE_VERTEX,
TYPE_NORMAL,
@@ -103,6 +126,7 @@ public:
// These use VertexAttribPointer and should possibly be made generic
TYPE_BINORMAL,
TYPE_WEIGHT,
+ TYPE_WEIGHT4,
TYPE_CLOTHWEIGHT,
TYPE_MAX,
TYPE_INDEX,
@@ -118,6 +142,7 @@ public:
// These use VertexAttribPointer and should possibly be made generic
MAP_BINORMAL = (1<<TYPE_BINORMAL),
MAP_WEIGHT = (1<<TYPE_WEIGHT),
+ MAP_WEIGHT4 = (1<<TYPE_WEIGHT4),
MAP_CLOTHWEIGHT = (1<<TYPE_CLOTHWEIGHT),
};
@@ -139,19 +164,24 @@ protected:
void updateNumVerts(S32 nverts);
void updateNumIndices(S32 nindices);
virtual BOOL useVBOs() const;
- void unmapBuffer();
-
+ void unmapBuffer(S32 type);
+ void freeClientBuffer() ;
+ void allocateClientVertexBuffer() ;
+ void allocateClientIndexBuffer() ;
+
public:
LLVertexBuffer(U32 typemask, S32 usage);
// map for data access
- U8* mapBuffer(S32 access = -1);
+ U8* mapVertexBuffer(S32 type = -1, S32 access = -1);
+ U8* mapIndexBuffer(S32 access = -1);
+
// set for rendering
- virtual void setBuffer(U32 data_mask); // calls setupVertexBuffer() if data_mask is not 0
+ virtual void setBuffer(U32 data_mask, S32 type = -1); // calls setupVertexBuffer() if data_mask is not 0
// allocate buffer
void allocateBuffer(S32 nverts, S32 nindices, bool create);
virtual void resizeBuffer(S32 newnverts, S32 newnindices);
-
+
// Only call each getVertexPointer, etc, once before calling unmapBuffer()
// call unmapBuffer() after calls to getXXXStrider() before any cals to setBuffer()
// example:
@@ -167,55 +197,61 @@ public:
bool getBinormalStrider(LLStrider<LLVector3>& strider, S32 index=0);
bool getColorStrider(LLStrider<LLColor4U>& strider, S32 index=0);
bool getWeightStrider(LLStrider<F32>& strider, S32 index=0);
+ bool getWeight4Strider(LLStrider<LLVector4>& strider, S32 index=0);
bool getClothWeightStrider(LLStrider<LLVector4>& strider, S32 index=0);
BOOL isEmpty() const { return mEmpty; }
- BOOL isLocked() const { return mLocked; }
+ BOOL isLocked() const { return mVertexLocked || mIndexLocked; }
S32 getNumVerts() const { return mNumVerts; }
S32 getNumIndices() const { return mNumIndices; }
S32 getRequestedVerts() const { return mRequestedNumVerts; }
S32 getRequestedIndices() const { return mRequestedNumIndices; }
- U8* getIndicesPointer() const { return useVBOs() ? NULL : mMappedIndexData; }
- U8* getVerticesPointer() const { return useVBOs() ? NULL : mMappedData; }
- S32 getStride() const { return mStride; }
- S32 getTypeMask() const { return mTypeMask; }
- BOOL hasDataType(S32 type) const { return ((1 << type) & getTypeMask()) ? TRUE : FALSE; }
- S32 getSize() const { return mNumVerts*mStride; }
+ U8* getIndicesPointer() const { return useVBOs() ? (U8*) mAlignedIndexOffset : mMappedIndexData; }
+ U8* getVerticesPointer() const { return useVBOs() ? (U8*) mAlignedOffset : mMappedData; }
+ U32 getTypeMask() const { return mTypeMask; }
+ bool hasDataType(S32 type) const { return ((1 << type) & getTypeMask()); }
+ S32 getSize() const;
S32 getIndicesSize() const { return mNumIndices * sizeof(U16); }
U8* getMappedData() const { return mMappedData; }
U8* getMappedIndices() const { return mMappedIndexData; }
S32 getOffset(S32 type) const { return mOffsets[type]; }
S32 getUsage() const { return mUsage; }
- void setStride(S32 type, S32 new_stride);
-
void markDirty(U32 vert_index, U32 vert_count, U32 indices_index, U32 indices_count);
void draw(U32 mode, U32 count, U32 indices_offset) const;
void drawArrays(U32 mode, U32 offset, U32 count) const;
void drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const;
+ //for debugging, validate data in given range is valid
+ void validateRange(U32 start, U32 end, U32 count, U32 offset) const;
+
+
+
protected:
S32 mNumVerts; // Number of vertices allocated
S32 mNumIndices; // Number of indices allocated
S32 mRequestedNumVerts; // Number of vertices requested
S32 mRequestedNumIndices; // Number of indices requested
- S32 mStride;
+ ptrdiff_t mAlignedOffset;
+ ptrdiff_t mAlignedIndexOffset;
+ S32 mSize;
U32 mTypeMask;
S32 mUsage; // GL usage
U32 mGLBuffer; // GL VBO handle
U32 mGLIndices; // GL IBO handle
U8* mMappedData; // pointer to currently mapped data (NULL if unmapped)
U8* mMappedIndexData; // pointer to currently mapped indices (NULL if unmapped)
- BOOL mLocked; // if TRUE, buffer is being or has been written to in client memory
+ BOOL mVertexLocked; // if TRUE, vertex buffer is being or has been written to in client memory
+ BOOL mIndexLocked; // if TRUE, index buffer is being or has been written to in client memory
BOOL mFinal; // if TRUE, buffer can not be mapped again
BOOL mFilthy; // if TRUE, entire buffer must be copied (used to prevent redundant dirty flags)
- BOOL mEmpty; // if TRUE, client buffer is empty (or NULL). Old values have been discarded.
- S32 mOffsets[TYPE_MAX];
+ BOOL mEmpty; // if TRUE, client buffer is empty (or NULL). Old values have been discarded.
BOOL mResized; // if TRUE, client buffer has been resized and GL buffer has not
BOOL mDynamicSize; // if TRUE, buffer has been resized at least once (and should be padded)
+ S32 mOffsets[TYPE_MAX];
class DirtyRegion
{
@@ -240,8 +276,9 @@ public:
static std::vector<U32> sDeleteList;
typedef std::list<LLVertexBuffer*> buffer_list_t;
+ static BOOL sDisableVBOMapping; //disable glMapBufferARB
static BOOL sEnableVBOs;
- static S32 sTypeOffsets[TYPE_MAX];
+ static S32 sTypeSize[TYPE_MAX];
static U32 sGLMode[LLRender::NUM_MODES];
static U32 sGLRenderBuffer;
static U32 sGLRenderIndices;
diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt
index e98201ea63..684e393cba 100644
--- a/indra/llui/CMakeLists.txt
+++ b/indra/llui/CMakeLists.txt
@@ -111,6 +111,7 @@ set(llui_SOURCE_FILES
llviewmodel.cpp
llview.cpp
llviewquery.cpp
+ llwindowshade.cpp
)
set(llui_HEADER_FILES
@@ -159,6 +160,7 @@ set(llui_HEADER_FILES
llnotificationslistener.h
llnotificationsutil.h
llnotificationtemplate.h
+ llnotificationvisibilityrule.h
llpanel.h
llprogressbar.h
llradiogroup.h
@@ -209,6 +211,7 @@ set(llui_HEADER_FILES
llviewmodel.h
llview.h
llviewquery.h
+ llwindowshade.h
)
set_source_files_properties(${llui_HEADER_FILES}
@@ -241,12 +244,12 @@ target_link_libraries(llui
${LLCOMMON_LIBRARIES} # must be after llimage, llwindow, llrender
)
-if(LL_TESTS)
- # Add tests
- include(LLAddBuildTest)
- SET(llui_TEST_SOURCE_FILES
- llurlmatch.cpp
- llurlentry.cpp
- )
- LL_ADD_PROJECT_UNIT_TESTS(llui "${llui_TEST_SOURCE_FILES}")
-endif(LL_TESTS)
+# Add tests
+if (LL_TESTS)
+ include(LLAddBuildTest)
+ SET(llui_TEST_SOURCE_FILES
+ llurlmatch.cpp
+ llurlentry.cpp
+ )
+ LL_ADD_PROJECT_UNIT_TESTS(llui "${llui_TEST_SOURCE_FILES}")
+endif (LL_TESTS) \ No newline at end of file
diff --git a/indra/llui/llaccordionctrltab.cpp b/indra/llui/llaccordionctrltab.cpp
index 179b32098a..9e4849c58b 100644
--- a/indra/llui/llaccordionctrltab.cpp
+++ b/indra/llui/llaccordionctrltab.cpp
@@ -203,7 +203,8 @@ void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::draw()
S32 width = getRect().getWidth();
S32 height = getRect().getHeight();
- gl_rect_2d(0,0,width - 1 ,height - 1,mHeaderBGColor.get(),true);
+ F32 alpha = getCurrentTransparency();
+ gl_rect_2d(0,0,width - 1 ,height - 1,mHeaderBGColor.get() % alpha,true);
LLAccordionCtrlTab* parent = dynamic_cast<LLAccordionCtrlTab*>(getParent());
bool collapsible = (parent && parent->getCollapsible());
@@ -456,8 +457,7 @@ BOOL LLAccordionCtrlTab::handleMouseDown(S32 x, S32 y, MASK mask)
{
if(y >= (getRect().getHeight() - HEADER_HEIGHT) )
{
- LLAccordionCtrlTabHeader* header = getChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
- header->setFocus(true);
+ mHeader->setFocus(true);
changeOpenClose(getDisplayChildren());
//reset stored state
@@ -509,10 +509,9 @@ void LLAccordionCtrlTab::setAccordionView(LLView* panel)
std::string LLAccordionCtrlTab::getTitle() const
{
- LLAccordionCtrlTabHeader* header = findChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
- if (header)
+ if (mHeader)
{
- return header->getTitle();
+ return mHeader->getTitle();
}
else
{
@@ -522,57 +521,51 @@ std::string LLAccordionCtrlTab::getTitle() const
void LLAccordionCtrlTab::setTitle(const std::string& title, const std::string& hl)
{
- LLAccordionCtrlTabHeader* header = findChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
- if (header)
+ if (mHeader)
{
- header->setTitle(title, hl);
+ mHeader->setTitle(title, hl);
}
}
void LLAccordionCtrlTab::setTitleFontStyle(std::string style)
{
- LLAccordionCtrlTabHeader* header = findChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
- if (header)
+ if (mHeader)
{
- header->setTitleFontStyle(style);
+ mHeader->setTitleFontStyle(style);
}
}
void LLAccordionCtrlTab::setTitleColor(LLUIColor color)
{
- LLAccordionCtrlTabHeader* header = findChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
- if (header)
+ if (mHeader)
{
- header->setTitleColor(color);
+ mHeader->setTitleColor(color);
}
}
boost::signals2::connection LLAccordionCtrlTab::setFocusReceivedCallback(const focus_signal_t::slot_type& cb)
{
- LLAccordionCtrlTabHeader* header = findChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
- if (header)
+ if (mHeader)
{
- return header->setFocusReceivedCallback(cb);
+ return mHeader->setFocusReceivedCallback(cb);
}
return boost::signals2::connection();
}
boost::signals2::connection LLAccordionCtrlTab::setFocusLostCallback(const focus_signal_t::slot_type& cb)
{
- LLAccordionCtrlTabHeader* header = findChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
- if (header)
+ if (mHeader)
{
- return header->setFocusLostCallback(cb);
+ return mHeader->setFocusLostCallback(cb);
}
return boost::signals2::connection();
}
void LLAccordionCtrlTab::setSelected(bool is_selected)
{
- LLAccordionCtrlTabHeader* header = findChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
- if (header)
+ if (mHeader)
{
- header->setSelected(is_selected);
+ mHeader->setSelected(is_selected);
}
}
@@ -776,8 +769,7 @@ S32 LLAccordionCtrlTab::notify(const LLSD& info)
BOOL LLAccordionCtrlTab::handleKey(KEY key, MASK mask, BOOL called_from_parent)
{
- LLAccordionCtrlTabHeader* header = getChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
- if( !header->hasFocus() )
+ if( !mHeader->hasFocus() )
return LLUICtrl::handleKey(key, mask, called_from_parent);
if ( (key == KEY_RETURN )&& mask == MASK_NONE)
@@ -830,15 +822,19 @@ BOOL LLAccordionCtrlTab::handleKey(KEY key, MASK mask, BOOL called_from_parent)
void LLAccordionCtrlTab::showAndFocusHeader()
{
- LLAccordionCtrlTabHeader* header = getChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
- header->setFocus(true);
- header->setSelected(mSelectionEnabled);
+ mHeader->setFocus(true);
+ mHeader->setSelected(mSelectionEnabled);
LLRect screen_rc;
- LLRect selected_rc = header->getRect();
+ LLRect selected_rc = mHeader->getRect();
localRectToScreen(selected_rc, &screen_rc);
- notifyParent(LLSD().with("scrollToShowRect",screen_rc.getValue()));
+ // This call to notifyParent() is intended to deliver "scrollToShowRect" command
+ // to the parent LLAccordionCtrl so by calling it from the direct parent of this
+ // accordion tab (assuming that the parent is an LLAccordionCtrl) the calls chain
+ // is shortened and messages from inside the collapsed tabs are avoided.
+ // See STORM-536.
+ getParent()->notifyParent(LLSD().with("scrollToShowRect",screen_rc.getValue()));
}
void LLAccordionCtrlTab::storeOpenCloseState()
{
diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp
index 65ef3e5f8f..45ceaff696 100644
--- a/indra/llui/llbutton.cpp
+++ b/indra/llui/llbutton.cpp
@@ -98,7 +98,8 @@ LLButton::Params::Params()
is_toggle("is_toggle", false),
scale_image("scale_image", true),
hover_glow_amount("hover_glow_amount"),
- commit_on_return("commit_on_return", true)
+ commit_on_return("commit_on_return", true),
+ use_draw_context_alpha("use_draw_context_alpha", true)
{
addSynonym(is_toggle, "toggle");
held_down_delay.seconds = 0.5f;
@@ -158,7 +159,8 @@ LLButton::LLButton(const LLButton::Params& p)
mLastDrawCharsCount(0),
mMouseDownSignal(NULL),
mMouseUpSignal(NULL),
- mHeldDownSignal(NULL)
+ mHeldDownSignal(NULL),
+ mUseDrawContextAlpha(p.use_draw_context_alpha)
{
static LLUICachedControl<S32> llbutton_orig_h_pad ("UIButtonOrigHPad", 0);
@@ -539,7 +541,7 @@ BOOL LLButton::handleHover(S32 x, S32 y, MASK mask)
// virtual
void LLButton::draw()
{
- F32 alpha = getDrawContext().mAlpha;
+ F32 alpha = mUseDrawContextAlpha ? getDrawContext().mAlpha : getCurrentTransparency();
bool flash = FALSE;
static LLUICachedControl<F32> button_flash_rate("ButtonFlashRate", 0);
static LLUICachedControl<S32> button_flash_count("ButtonFlashCount", 0);
diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h
index 2d5fefa78c..0cfc393e05 100644
--- a/indra/llui/llbutton.h
+++ b/indra/llui/llbutton.h
@@ -27,7 +27,6 @@
#ifndef LL_LLBUTTON_H
#define LL_LLBUTTON_H
-#include "lluuid.h"
#include "llcontrol.h"
#include "lluictrl.h"
#include "v4color.h"
@@ -53,6 +52,8 @@ S32 round_up(S32 grid, S32 value);
class LLUICtrlFactory;
+class LLUIImage;
+class LLUUID;
//
// Classes
@@ -124,6 +125,8 @@ public:
Optional<F32> hover_glow_amount;
Optional<TimeIntervalParam> held_down_delay;
+ Optional<bool> use_draw_context_alpha;
+
Params();
};
@@ -338,6 +341,8 @@ private:
S32 mImageOverlayTopPad;
S32 mImageOverlayBottomPad;
+ bool mUseDrawContextAlpha;
+
/*
* Space between image_overlay and label
*/
diff --git a/indra/llui/llcheckboxctrl.cpp b/indra/llui/llcheckboxctrl.cpp
index bbd8db2645..4fe444c1a4 100644
--- a/indra/llui/llcheckboxctrl.cpp
+++ b/indra/llui/llcheckboxctrl.cpp
@@ -88,27 +88,19 @@ LLCheckBoxCtrl::LLCheckBoxCtrl(const LLCheckBoxCtrl::Params& p)
tbparams.font(p.font);
}
mLabel = LLUICtrlFactory::create<LLTextBox> (tbparams);
+ mLabel->reshapeToFitText();
addChild(mLabel);
- S32 text_width = mLabel->getTextBoundingRect().getWidth();
- S32 text_height = llround(mFont->getLineHeight());
- LLRect label_rect;
- label_rect.setOriginAndSize(
- llcheckboxctrl_hpad + llcheckboxctrl_btn_size + llcheckboxctrl_spacing,
- llcheckboxctrl_vpad + 1, // padding to get better alignment
- text_width + llcheckboxctrl_hpad,
- text_height );
- mLabel->setShape(label_rect);
-
+ LLRect label_rect = mLabel->getRect();
// Button
// Note: button cover the label by extending all the way to the right.
- LLRect btn_rect;
+ LLRect btn_rect = p.check_button.rect();
btn_rect.setOriginAndSize(
- llcheckboxctrl_hpad,
- llcheckboxctrl_vpad,
- llcheckboxctrl_btn_size + llcheckboxctrl_spacing + text_width + llcheckboxctrl_hpad,
- llmax( text_height, llcheckboxctrl_btn_size() ) + llcheckboxctrl_vpad);
+ btn_rect.mLeft,
+ btn_rect.mBottom,
+ llmax(btn_rect.mRight, label_rect.mRight - btn_rect.mLeft),
+ llmax( label_rect.getHeight(), btn_rect.mTop));
std::string active_true_id, active_false_id;
std::string inactive_true_id, inactive_false_id;
@@ -174,31 +166,20 @@ void LLCheckBoxCtrl::clear()
void LLCheckBoxCtrl::reshape(S32 width, S32 height, BOOL called_from_parent)
{
- //stretch or shrink bounding rectangle of label when rebuilding UI at new scale
- static LLUICachedControl<S32> llcheckboxctrl_spacing ("UICheckboxctrlSpacing", 0);
- static LLUICachedControl<S32> llcheckboxctrl_hpad ("UICheckboxctrlHPad", 0);
- static LLUICachedControl<S32> llcheckboxctrl_vpad ("UICheckboxctrlVPad", 0);
- static LLUICachedControl<S32> llcheckboxctrl_btn_size ("UICheckboxctrlBtnSize", 0);
- S32 text_width = mLabel->getTextBoundingRect().getWidth();
- S32 text_height = llround(mFont->getLineHeight());
- LLRect label_rect;
- label_rect.setOriginAndSize(
- llcheckboxctrl_hpad + llcheckboxctrl_btn_size + llcheckboxctrl_spacing,
- llcheckboxctrl_vpad,
- text_width,
- text_height );
- mLabel->setShape(label_rect);
-
- LLRect btn_rect;
+ mLabel->reshapeToFitText();
+
+ LLRect label_rect = mLabel->getRect();
+
+ // Button
+ // Note: button cover the label by extending all the way to the right.
+ LLRect btn_rect = mButton->getRect();
btn_rect.setOriginAndSize(
- llcheckboxctrl_hpad,
- llcheckboxctrl_vpad,
- llcheckboxctrl_btn_size + llcheckboxctrl_spacing + text_width,
- llmax( text_height, llcheckboxctrl_btn_size() ) );
- mButton->setShape( btn_rect );
-
- LLUICtrl::reshape(width, height, called_from_parent);
+ btn_rect.mLeft,
+ btn_rect.mBottom,
+ llmax(btn_rect.getWidth(), label_rect.mRight - btn_rect.mLeft),
+ llmax(label_rect.mTop - btn_rect.mBottom, btn_rect.getHeight()));
+ mButton->setShape(btn_rect);
}
//virtual
diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp
index 2dabbc7767..a4d1854bc8 100644
--- a/indra/llui/llcombobox.cpp
+++ b/indra/llui/llcombobox.cpp
@@ -94,6 +94,7 @@ LLComboBox::LLComboBox(const LLComboBox::Params& p)
mMaxChars(p.max_chars),
mPrearrangeCallback(p.prearrange_callback()),
mTextEntryCallback(p.text_entry_callback()),
+ mTextChangedCallback(p.text_changed_callback()),
mListPosition(p.list_position),
mLastSelectedIndex(-1),
mLabel(p.label)
@@ -230,6 +231,10 @@ void LLComboBox::resetDirty()
}
}
+bool LLComboBox::itemExists(const std::string& name)
+{
+ return mList->getItemByLabel(name);
+}
// add item "name" to menu
LLScrollListItem* LLComboBox::add(const std::string& name, EAddPosition pos, BOOL enabled)
@@ -315,7 +320,7 @@ void LLComboBox::setValue(const LLSD& value)
LLScrollListItem* item = mList->getFirstSelected();
if (item)
{
- setLabel(getSelectedItemLabel());
+ updateLabel();
}
mLastSelectedIndex = mList->getFirstSelectedIndex();
}
@@ -383,6 +388,23 @@ void LLComboBox::setLabel(const LLStringExplicit& name)
}
}
+void LLComboBox::updateLabel()
+{
+ // Update the combo editor with the selected
+ // item label.
+ if (mTextEntry)
+ {
+ mTextEntry->setText(getSelectedItemLabel());
+ mTextEntry->setTentative(FALSE);
+ }
+
+ // If combo box doesn't allow text entry update
+ // the combo button label.
+ if (!mAllowTextEntry)
+ {
+ mButton->setLabel(getSelectedItemLabel());
+ }
+}
BOOL LLComboBox::remove(const std::string& name)
{
@@ -700,13 +722,13 @@ void LLComboBox::onItemSelected(const LLSD& data)
mLastSelectedIndex = getCurrentIndex();
if (mLastSelectedIndex != -1)
{
- setLabel(getSelectedItemLabel());
+ updateLabel();
if (mAllowTextEntry)
- {
- gFocusMgr.setKeyboardFocus(mTextEntry);
- mTextEntry->selectAll();
- }
+ {
+ gFocusMgr.setKeyboardFocus(mTextEntry);
+ mTextEntry->selectAll();
+ }
}
// hiding the list reasserts the old value stored in the text editor/dropdown button
hideList();
@@ -769,7 +791,8 @@ BOOL LLComboBox::handleKeyHere(KEY key, MASK mask)
return FALSE;
}
// if selection has changed, pop open list
- else if (mList->getLastSelectedItem() != last_selected_item)
+ else if (mList->getLastSelectedItem() != last_selected_item ||
+ (key == KEY_DOWN || key == KEY_UP) && !mList->isEmpty())
{
showList();
}
@@ -833,6 +856,10 @@ void LLComboBox::onTextEntry(LLLineEditor* line_editor)
mList->deselectAllItems();
mLastSelectedIndex = -1;
}
+ if (mTextChangedCallback != NULL)
+ {
+ (mTextChangedCallback)(line_editor, LLSD());
+ }
return;
}
@@ -877,6 +904,10 @@ void LLComboBox::onTextEntry(LLLineEditor* line_editor)
// RN: presumably text entry
updateSelection();
}
+ if (mTextChangedCallback != NULL)
+ {
+ (mTextChangedCallback)(line_editor, LLSD());
+ }
}
void LLComboBox::updateSelection()
diff --git a/indra/llui/llcombobox.h b/indra/llui/llcombobox.h
index 5f0e4a6843..64dbaea306 100644
--- a/indra/llui/llcombobox.h
+++ b/indra/llui/llcombobox.h
@@ -73,7 +73,8 @@ public:
allow_new_values;
Optional<S32> max_chars;
Optional<commit_callback_t> prearrange_callback,
- text_entry_callback;
+ text_entry_callback,
+ text_changed_callback;
Optional<EPreferredPosition, PreferredPositionValues> list_position;
@@ -133,6 +134,7 @@ public:
LLScrollListItem* addSeparator(EAddPosition pos = ADD_BOTTOM);
BOOL remove( S32 index ); // remove item by index, return TRUE if found and removed
void removeall() { clearRows(); }
+ bool itemExists(const std::string& name);
void sortByName(BOOL ascending = TRUE); // Sort the entries in the combobox by name
@@ -147,6 +149,9 @@ public:
// This is probably a UI abuse.
void setLabel(const LLStringExplicit& name);
+ // Updates the combobox label to match the selected list item.
+ void updateLabel();
+
BOOL remove(const std::string& name); // remove item "name", return TRUE if found and removed
BOOL setCurrentByIndex( S32 index );
@@ -190,6 +195,7 @@ public:
void setPrearrangeCallback( commit_callback_t cb ) { mPrearrangeCallback = cb; }
void setTextEntryCallback( commit_callback_t cb ) { mTextEntryCallback = cb; }
+ void setTextChangedCallback( commit_callback_t cb ) { mTextChangedCallback = cb; }
void setButtonVisible(BOOL visible);
@@ -220,6 +226,7 @@ private:
BOOL mTextEntryTentative;
commit_callback_t mPrearrangeCallback;
commit_callback_t mTextEntryCallback;
+ commit_callback_t mTextChangedCallback;
commit_callback_t mSelectionCallback;
boost::signals2::connection mTopLostSignalConnection;
S32 mLastSelectedIndex;
diff --git a/indra/llui/lldockcontrol.cpp b/indra/llui/lldockcontrol.cpp
index d48674f306..b1c27126d9 100644
--- a/indra/llui/lldockcontrol.cpp
+++ b/indra/llui/lldockcontrol.cpp
@@ -160,8 +160,10 @@ bool LLDockControl::isDockVisible()
case TOP:
{
// check is dock inside parent rect
+ // assume that parent for all dockable flaoters
+ // is the root view
LLRect dockParentRect =
- mDockWidget->getParent()->calcScreenRect();
+ mDockWidget->getRootView()->calcScreenRect();
if (dockRect.mRight <= dockParentRect.mLeft
|| dockRect.mLeft >= dockParentRect.mRight)
{
@@ -220,10 +222,15 @@ void LLDockControl::moveDockable()
case TOP:
x = dockRect.getCenterX() - dockableRect.getWidth() / 2;
y = dockRect.mTop + dockableRect.getHeight();
- // unique docking used with dock tongue, so add tongue height o the Y coordinate
+ // unique docking used with dock tongue, so add tongue height to the Y coordinate
if (use_tongue)
{
y += mDockTongue->getHeight();
+
+ if ( y > rootRect.mTop)
+ {
+ y = rootRect.mTop;
+ }
}
// check is dockable inside root view rect
@@ -257,7 +264,7 @@ void LLDockControl::moveDockable()
case BOTTOM:
x = dockRect.getCenterX() - dockableRect.getWidth() / 2;
y = dockRect.mBottom;
- // unique docking used with dock tongue, so add tongue height o the Y coordinate
+ // unique docking used with dock tongue, so add tongue height to the Y coordinate
if (use_tongue)
{
y -= mDockTongue->getHeight();
@@ -292,9 +299,21 @@ void LLDockControl::moveDockable()
break;
}
- // move dockable
- dockableRect.setLeftTopAndSize(x, y, dockableRect.getWidth(),
- dockableRect.getHeight());
+ S32 max_available_height = rootRect.getHeight() - (rootRect.mBottom - mDockTongueY) - mDockTongue->getHeight();
+
+ // A floater should be shrunk so it doesn't cover a part of its docking tongue and
+ // there is a space between a dockable floater and a control to which it is docked.
+ if (use_tongue && dockableRect.getHeight() >= max_available_height)
+ {
+ dockableRect.setLeftTopAndSize(x, y, dockableRect.getWidth(), max_available_height);
+ mDockableFloater->reshape(dockableRect.getWidth(), dockableRect.getHeight());
+ }
+ else
+ {
+ // move dockable
+ dockableRect.setLeftTopAndSize(x, y, dockableRect.getWidth(),
+ dockableRect.getHeight());
+ }
LLRect localDocableParentRect;
mDockableFloater->getParent()->screenRectToLocal(dockableRect,
&localDocableParentRect);
diff --git a/indra/llui/llflatlistview.cpp b/indra/llui/llflatlistview.cpp
index c57c02f4b1..97a52fada4 100644
--- a/indra/llui/llflatlistview.cpp
+++ b/indra/llui/llflatlistview.cpp
@@ -87,9 +87,6 @@ bool LLFlatListView::addItem(LLPanel * item, const LLSD& value /*= LLUUID::null*
mItemsPanel->addChild(item);
break;
default:
- LL_WARNS("") << "Unsupported position." << LL_ENDL;
- delete new_pair;
- return false;
break;
}
diff --git a/indra/llui/llflatlistview.h b/indra/llui/llflatlistview.h
index 0515853698..92bf429031 100644
--- a/indra/llui/llflatlistview.h
+++ b/indra/llui/llflatlistview.h
@@ -450,8 +450,9 @@ private:
*/
class LLFlatListViewEx : public LLFlatListView
{
- LOG_CLASS(LLFlatListViewEx);
public:
+ LOG_CLASS(LLFlatListViewEx);
+
struct Params : public LLInitParam::Block<Params, LLFlatListView::Params>
{
/**
diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp
index b758070419..d19e33ea55 100644
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -1,4 +1,5 @@
/**
+
* @file llfloater.cpp
* @brief LLFloater base class
*
@@ -61,7 +62,6 @@
// use this to control "jumping" behavior when Ctrl-Tabbing
const S32 TABBED_FLOATER_OFFSET = 0;
-
std::string LLFloater::sButtonNames[BUTTON_COUNT] =
{
"llfloater_close_btn", //BUTTON_CLOSE
@@ -200,6 +200,21 @@ void LLFloater::initClass()
{
sButtonToolTips[i] = LLTrans::getString( sButtonToolTipsIndex[i] );
}
+
+ LLControlVariable* ctrl = LLUI::sSettingGroups["config"]->getControl("ActiveFloaterTransparency").get();
+ if (ctrl)
+ {
+ ctrl->getSignal()->connect(boost::bind(&LLFloater::updateActiveFloaterTransparency));
+ updateActiveFloaterTransparency();
+ }
+
+ ctrl = LLUI::sSettingGroups["config"]->getControl("InactiveFloaterTransparency").get();
+ if (ctrl)
+ {
+ ctrl->getSignal()->connect(boost::bind(&LLFloater::updateInactiveFloaterTransparency));
+ updateInactiveFloaterTransparency();
+ }
+
}
// defaults for floater param block pulled from widgets/floater.xml
@@ -207,7 +222,7 @@ static LLWidgetNameRegistry::StaticRegistrar sRegisterFloaterParams(&typeid(LLFl
LLFloater::LLFloater(const LLSD& key, const LLFloater::Params& p)
: LLPanel(), // intentionally do not pass params here, see initFromParams
- mDragHandle(NULL),
+ mDragHandle(NULL),
mTitle(p.title),
mShortTitle(p.short_title),
mSingleInstance(p.single_instance),
@@ -257,9 +272,6 @@ LLFloater::LLFloater(const LLSD& key, const LLFloater::Params& p)
initFromParams(p);
- // chrome floaters don't take focus at all
- setFocusRoot(!getIsChrome());
-
initFloater(p);
}
@@ -347,6 +359,18 @@ void LLFloater::layoutDragHandle()
updateTitleButtons();
}
+// static
+void LLFloater::updateActiveFloaterTransparency()
+{
+ sActiveControlTransparency = LLUI::sSettingGroups["config"]->getF32("ActiveFloaterTransparency");
+}
+
+// static
+void LLFloater::updateInactiveFloaterTransparency()
+{
+ sInactiveControlTransparency = LLUI::sSettingGroups["config"]->getF32("InactiveFloaterTransparency");
+}
+
void LLFloater::addResizeCtrls()
{
// Resize bars (sides)
@@ -1163,6 +1187,7 @@ void LLFloater::setFocus( BOOL b )
last_focus->setFocus(TRUE);
}
}
+ updateTransparency(b ? TT_ACTIVE : TT_INACTIVE);
}
// virtual
@@ -1435,6 +1460,9 @@ void LLFloater::setFrontmost(BOOL take_focus)
// there are more than one floater view
// so we need to query our parent directly
((LLFloaterView*)getParent())->bringToFront(this, take_focus);
+
+ // Make sure to set the appropriate transparency type (STORM-732).
+ updateTransparency(hasFocus() || getIsChrome() ? TT_ACTIVE : TT_INACTIVE);
}
}
@@ -1622,7 +1650,8 @@ void LLFloater::onClickCloseBtn()
// virtual
void LLFloater::draw()
{
- F32 alpha = getDrawContext().mAlpha;
+ const F32 alpha = getCurrentTransparency();
+
// draw background
if( isBackgroundVisible() )
{
@@ -1720,7 +1749,6 @@ void LLFloater::draw()
void LLFloater::drawShadow(LLPanel* panel)
{
- F32 alpha = panel->getDrawContext().mAlpha;
S32 left = LLPANEL_BORDER_WIDTH;
S32 top = panel->getRect().getHeight() - LLPANEL_BORDER_WIDTH;
S32 right = panel->getRect().getWidth() - LLPANEL_BORDER_WIDTH;
@@ -1737,10 +1765,32 @@ void LLFloater::drawShadow(LLPanel* panel)
shadow_color.mV[VALPHA] *= 0.5f;
}
gl_drop_shadow(left, top, right, bottom,
- shadow_color % alpha,
+ shadow_color % getCurrentTransparency(),
llround(shadow_offset));
}
+void LLFloater::updateTransparency(LLView* view, ETypeTransparency transparency_type)
+{
+ child_list_t children = *view->getChildList();
+ child_list_t::iterator it = children.begin();
+
+ LLUICtrl* ctrl = dynamic_cast<LLUICtrl*>(view);
+ if (ctrl)
+ {
+ ctrl->setTransparencyType(transparency_type);
+ }
+
+ for(; it != children.end(); ++it)
+ {
+ updateTransparency(*it, transparency_type);
+ }
+}
+
+void LLFloater::updateTransparency(ETypeTransparency transparency_type)
+{
+ updateTransparency(this, transparency_type);
+}
+
void LLFloater::setCanMinimize(BOOL can_minimize)
{
// if removing minimize/restore button programmatically,
@@ -2540,9 +2590,13 @@ void LLFloaterView::draw()
LLRect LLFloaterView::getSnapRect() const
{
- LLRect snap_rect = getRect();
- snap_rect.mBottom += mSnapOffsetBottom;
- snap_rect.mRight -= mSnapOffsetRight;
+ LLRect snap_rect = getLocalRect();
+
+ LLView* snap_view = mSnapView.get();
+ if (snap_view)
+ {
+ snap_view->localRectToOtherView(snap_view->getLocalRect(), &snap_rect, this);
+ }
return snap_rect;
}
@@ -2815,7 +2869,7 @@ void LLFloater::initFromParams(const LLFloater::Params& p)
// close callback
if (p.close_callback.isProvided())
{
- mCloseSignal.connect(initCommitCallback(p.close_callback));
+ setCloseCallback(initCommitCallback(p.close_callback));
}
}
@@ -2825,6 +2879,11 @@ boost::signals2::connection LLFloater::setMinimizeCallback( const commit_signal_
return mMinimizeSignal->connect(cb);
}
+boost::signals2::connection LLFloater::setCloseCallback( const commit_signal_t::slot_type& cb )
+{
+ return mCloseSignal.connect(cb);
+}
+
LLFastTimer::DeclareTimer POST_BUILD("Floater Post Build");
bool LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, const std::string& filename, LLXMLNodePtr output_node)
@@ -2857,7 +2916,7 @@ bool LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, const std::str
params.from_xui = true;
applyXUILayout(params, parent);
initFromParams(params);
-
+
initFloater(params);
LLMultiFloater* last_host = LLFloater::getFloaterHost();
diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h
index 32d03f9f83..5b7b020881 100644
--- a/indra/llui/llfloater.h
+++ b/indra/llui/llfloater.h
@@ -144,6 +144,7 @@ public:
bool buildFromFile(const std::string &filename, LLXMLNodePtr output_node = NULL);
boost::signals2::connection setMinimizeCallback( const commit_signal_t::slot_type& cb );
+ boost::signals2::connection setCloseCallback( const commit_signal_t::slot_type& cb );
void initFromParams(const LLFloater::Params& p);
bool initFloaterXML(LLXMLNodePtr node, LLView *parent, const std::string& filename, LLXMLNodePtr output_node = NULL);
@@ -284,6 +285,8 @@ public:
static void setFloaterHost(LLMultiFloater* hostp) {sHostp = hostp; }
static LLMultiFloater* getFloaterHost() {return sHostp; }
+
+ void updateTransparency(ETypeTransparency transparency_type);
protected:
@@ -341,6 +344,10 @@ private:
void addDragHandle();
void layoutDragHandle(); // repair layout
+ static void updateActiveFloaterTransparency();
+ static void updateInactiveFloaterTransparency();
+ void updateTransparency(LLView* view, ETypeTransparency transparency_type);
+
public:
// Called when floater is opened, passes mKey
// Public so external views or floaters can watch for this floater opening
@@ -489,10 +496,10 @@ public:
// value is not defined.
S32 getZOrder(LLFloater* child);
- void setSnapOffsetBottom(S32 offset) { mSnapOffsetBottom = offset; }
- void setSnapOffsetRight(S32 offset) { mSnapOffsetRight = offset; }
+ void setFloaterSnapView(LLHandle<LLView> snap_view) {mSnapView = snap_view; }
private:
+ LLHandle<LLView> mSnapView;
BOOL mFocusCycleMode;
S32 mSnapOffsetBottom;
S32 mSnapOffsetRight;
diff --git a/indra/llui/llfloaterreg.h b/indra/llui/llfloaterreg.h
index 94387fb41a..8414b92113 100644
--- a/indra/llui/llfloaterreg.h
+++ b/indra/llui/llfloaterreg.h
@@ -27,14 +27,9 @@
#define LLFLOATERREG_H
/// llcommon
-#include "llboost.h"
#include "llrect.h"
-#include "llstl.h"
#include "llsd.h"
-/// llui
-#include "lluictrl.h"
-
#include <boost/function.hpp>
//*******************************************************
@@ -43,6 +38,7 @@
//
class LLFloater;
+class LLUICtrl;
typedef boost::function<LLFloater* (const LLSD& key)> LLFloaterBuildFunc;
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/llfocusmgr.cpp b/indra/llui/llfocusmgr.cpp
index 43e5f6b051..724d190307 100644
--- a/indra/llui/llfocusmgr.cpp
+++ b/indra/llui/llfocusmgr.cpp
@@ -113,6 +113,16 @@ boost::signals2::connection LLFocusableElement::setTopLostCallback(const focus_s
+typedef std::list<LLHandle<LLView> > view_handle_list_t;
+typedef std::map<LLHandle<LLView>, LLHandle<LLView> > focus_history_map_t;
+struct LLFocusMgr::Impl
+{
+ // caching list of keyboard focus ancestors for calling onFocusReceived and onFocusLost
+ view_handle_list_t mCachedKeyboardFocusList;
+
+ focus_history_map_t mFocusHistory;
+};
+
LLFocusMgr gFocusMgr;
LLFocusMgr::LLFocusMgr()
@@ -123,10 +133,17 @@ LLFocusMgr::LLFocusMgr()
mDefaultKeyboardFocus( NULL ),
mKeystrokesOnly(FALSE),
mTopCtrl( NULL ),
- mAppHasFocus(TRUE) // Macs don't seem to notify us that we've gotten focus, so default to true
+ mAppHasFocus(TRUE), // Macs don't seem to notify us that we've gotten focus, so default to true
+ mImpl(new LLFocusMgr::Impl)
{
}
+LLFocusMgr::~LLFocusMgr()
+{
+ mImpl->mFocusHistory.clear();
+ delete mImpl;
+ mImpl = NULL;
+}
void LLFocusMgr::releaseFocusIfNeeded( LLView* view )
{
@@ -179,7 +196,7 @@ void LLFocusMgr::setKeyboardFocus(LLFocusableElement* new_focus, BOOL lock, BOOL
mKeyboardFocus = new_focus;
// list of the focus and it's ancestors
- view_handle_list_t old_focus_list = mCachedKeyboardFocusList;
+ view_handle_list_t old_focus_list = mImpl->mCachedKeyboardFocusList;
view_handle_list_t new_focus_list;
// walk up the tree to root and add all views to the new_focus_list
@@ -206,7 +223,7 @@ void LLFocusMgr::setKeyboardFocus(LLFocusableElement* new_focus, BOOL lock, BOOL
LLView* old_focus_view = old_focus_iter->get();
if (old_focus_view)
{
- mCachedKeyboardFocusList.pop_front();
+ mImpl->mCachedKeyboardFocusList.pop_front();
old_focus_view->onFocusLost();
}
}
@@ -219,7 +236,7 @@ void LLFocusMgr::setKeyboardFocus(LLFocusableElement* new_focus, BOOL lock, BOOL
LLView* new_focus_view = new_focus_riter->get();
if (new_focus_view)
{
- mCachedKeyboardFocusList.push_front(new_focus_view->getHandle());
+ mImpl->mCachedKeyboardFocusList.push_front(new_focus_view->getHandle());
new_focus_view->onFocusReceived();
}
}
@@ -254,7 +271,7 @@ void LLFocusMgr::setKeyboardFocus(LLFocusableElement* new_focus, BOOL lock, BOOL
if (focus_subtree)
{
LLView* focused_view = dynamic_cast<LLView*>(mKeyboardFocus);
- mFocusHistory[focus_subtree->getHandle()] = focused_view ? focused_view->getHandle() : LLHandle<LLView>();
+ mImpl->mFocusHistory[focus_subtree->getHandle()] = focused_view ? focused_view->getHandle() : LLHandle<LLView>();
}
}
@@ -456,8 +473,8 @@ LLUICtrl* LLFocusMgr::getLastFocusForGroup(LLView* subtree_root) const
{
if (subtree_root)
{
- focus_history_map_t::const_iterator found_it = mFocusHistory.find(subtree_root->getHandle());
- if (found_it != mFocusHistory.end())
+ focus_history_map_t::const_iterator found_it = mImpl->mFocusHistory.find(subtree_root->getHandle());
+ if (found_it != mImpl->mFocusHistory.end())
{
// found last focus for this subtree
return static_cast<LLUICtrl*>(found_it->second.get());
@@ -470,6 +487,6 @@ void LLFocusMgr::clearLastFocusForGroup(LLView* subtree_root)
{
if (subtree_root)
{
- mFocusHistory.erase(subtree_root->getHandle());
+ mImpl->mFocusHistory.erase(subtree_root->getHandle());
}
}
diff --git a/indra/llui/llfocusmgr.h b/indra/llui/llfocusmgr.h
index 22c1895075..25ae1d2579 100644
--- a/indra/llui/llfocusmgr.h
+++ b/indra/llui/llfocusmgr.h
@@ -74,7 +74,7 @@ class LLFocusMgr
{
public:
LLFocusMgr();
- ~LLFocusMgr() { mFocusHistory.clear(); }
+ ~LLFocusMgr();
// Mouse Captor
void setMouseCapture(LLMouseHandler* new_captor); // new_captor = NULL to release the mouse.
@@ -120,6 +120,8 @@ public:
bool keyboardFocusHasAccelerators() const;
+ struct Impl;
+
private:
LLUICtrl* mLockedView;
@@ -132,10 +134,6 @@ private:
LLFocusableElement* mDefaultKeyboardFocus;
BOOL mKeystrokesOnly;
- // caching list of keyboard focus ancestors for calling onFocusReceived and onFocusLost
- typedef std::list<LLHandle<LLView> > view_handle_list_t;
- view_handle_list_t mCachedKeyboardFocusList;
-
// Top View
LLUICtrl* mTopCtrl;
@@ -143,8 +141,7 @@ private:
BOOL mAppHasFocus;
- typedef std::map<LLHandle<LLView>, LLHandle<LLView> > focus_history_map_t;
- focus_history_map_t mFocusHistory;
+ Impl * mImpl;
};
extern LLFocusMgr gFocusMgr;
diff --git a/indra/llui/llhandle.h b/indra/llui/llhandle.h
index a43f095d67..8c000eee48 100644
--- a/indra/llui/llhandle.h
+++ b/indra/llui/llhandle.h
@@ -61,13 +61,6 @@ public:
return *this;
}
- template<typename Subclass>
- LLHandle<T>& operator =(const LLHandle<Subclass>& other)
- {
- mTombStone = other.mTombStone;
- return *this;
- }
-
bool isDead() const
{
return mTombStone->getTarget() == NULL;
@@ -99,7 +92,6 @@ public:
{
return lhs.mTombStone > rhs.mTombStone;
}
-protected:
protected:
LLPointer<LLTombStone<T> > mTombStone;
diff --git a/indra/llui/lliconctrl.cpp b/indra/llui/lliconctrl.cpp
index 627957061d..47f2cfaf89 100644
--- a/indra/llui/lliconctrl.cpp
+++ b/indra/llui/lliconctrl.cpp
@@ -41,6 +41,7 @@ static LLDefaultChildRegistry::Register<LLIconCtrl> r("icon");
LLIconCtrl::Params::Params()
: image("image_name"),
color("color"),
+ use_draw_context_alpha("use_draw_context_alpha", true),
scale_image("scale_image")
{
tab_stop = false;
@@ -51,6 +52,7 @@ LLIconCtrl::LLIconCtrl(const LLIconCtrl::Params& p)
: LLUICtrl(p),
mColor(p.color()),
mImagep(p.image),
+ mUseDrawContextAlpha(p.use_draw_context_alpha),
mPriority(0),
mDrawWidth(0),
mDrawHeight(0)
@@ -71,7 +73,8 @@ void LLIconCtrl::draw()
{
if( mImagep.notNull() )
{
- mImagep->draw(getLocalRect(), mColor.get() % getDrawContext().mAlpha );
+ const F32 alpha = mUseDrawContextAlpha ? getDrawContext().mAlpha : getCurrentTransparency();
+ mImagep->draw(getLocalRect(), mColor.get() % alpha );
}
LLUICtrl::draw();
diff --git a/indra/llui/lliconctrl.h b/indra/llui/lliconctrl.h
index 79a8b0fb28..efa0925a4a 100644
--- a/indra/llui/lliconctrl.h
+++ b/indra/llui/lliconctrl.h
@@ -30,6 +30,7 @@
#include "lluuid.h"
#include "v4color.h"
#include "lluictrl.h"
+#include "lluiimage.h"
#include "stdenums.h"
class LLTextBox;
@@ -48,6 +49,7 @@ public:
{
Optional<LLUIImage*> image;
Optional<LLUIColor> color;
+ Optional<bool> use_draw_context_alpha;
Ignored scale_image;
Params();
};
@@ -68,6 +70,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() ;
@@ -79,6 +82,10 @@ protected:
S32 mDrawWidth ;
S32 mDrawHeight ;
+ // If set to true (default), use the draw context transparency.
+ // If false, will use transparency returned by getCurrentTransparency(). See STORM-698.
+ bool mUseDrawContextAlpha;
+
private:
LLUIColor mColor;
LLPointer<LLUIImage> mImagep;
diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp
index 940c7e7e18..9b6830a816 100644
--- a/indra/llui/lllayoutstack.cpp
+++ b/indra/llui/lllayoutstack.cpp
@@ -38,6 +38,12 @@
static LLDefaultChildRegistry::Register<LLLayoutStack> register_layout_stack("layout_stack");
static LLLayoutStack::LayoutStackRegistry::Register<LLLayoutPanel> register_layout_panel("layout_panel");
+void LLLayoutStack::OrientationNames::declareValues()
+{
+ declare("horizontal", HORIZONTAL);
+ declare("vertical", VERTICAL);
+}
+
//
// LLLayoutPanel
//
@@ -47,47 +53,47 @@ LLLayoutPanel::LLLayoutPanel(const Params& p)
mMaxDim(p.max_dim),
mAutoResize(p.auto_resize),
mUserResize(p.user_resize),
- mCollapsed(FALSE),
- mCollapseAmt(0.f),
- mVisibleAmt(1.f), // default to fully visible
- mResizeBar(NULL)
- {
+ mCollapsed(FALSE),
+ mCollapseAmt(0.f),
+ mVisibleAmt(1.f), // default to fully visible
+ mResizeBar(NULL)
+{
// panels initialized as hidden should not start out partially visible
if (!getVisible())
- {
+ {
mVisibleAmt = 0.f;
- }
- }
+ }
+}
void LLLayoutPanel::initFromParams(const Params& p)
- {
+{
LLPanel::initFromParams(p);
setFollowsNone();
- }
+}
LLLayoutPanel::~LLLayoutPanel()
- {
- // probably not necessary, but...
- delete mResizeBar;
- mResizeBar = NULL;
- }
+{
+ // probably not necessary, but...
+ delete mResizeBar;
+ mResizeBar = NULL;
+}
F32 LLLayoutPanel::getCollapseFactor(LLLayoutStack::ELayoutOrientation orientation)
- {
+{
if (orientation == LLLayoutStack::HORIZONTAL)
- {
- F32 collapse_amt =
- clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, (F32)mMinDim / (F32)llmax(1, getRect().getWidth()));
- return mVisibleAmt * collapse_amt;
- }
- else
+ {
+ F32 collapse_amt =
+ clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, (F32)mMinDim / (F32)llmax(1, getRect().getWidth()));
+ return mVisibleAmt * collapse_amt;
+ }
+ else
{
F32 collapse_amt =
clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, llmin(1.f, (F32)mMinDim / (F32)llmax(1, getRect().getHeight())));
return mVisibleAmt * collapse_amt;
- }
}
+}
//
// LLLayoutStack
@@ -97,6 +103,8 @@ LLLayoutStack::Params::Params()
: orientation("orientation"),
animate("animate", true),
clip("clip", true),
+ open_time_constant("open_time_constant", 0.02f),
+ close_time_constant("close_time_constant", 0.03f),
border_size("border_size", LLCachedControl<S32>(*LLUI::sSettingGroups["config"], "UIResizeBarHeight", 0))
{
name="stack";
@@ -107,10 +115,12 @@ LLLayoutStack::LLLayoutStack(const LLLayoutStack::Params& p)
mMinWidth(0),
mMinHeight(0),
mPanelSpacing(p.border_size),
- mOrientation((p.orientation() == "vertical") ? VERTICAL : HORIZONTAL),
+ mOrientation(p.orientation),
mAnimate(p.animate),
mAnimatedThisFrame(false),
- mClip(p.clip)
+ mClip(p.clip),
+ mOpenTimeConstant(p.open_time_constant),
+ mCloseTimeConstant(p.close_time_constant)
{}
LLLayoutStack::~LLLayoutStack()
@@ -303,9 +313,6 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
S32 total_width = 0;
S32 total_height = 0;
- const F32 ANIM_OPEN_TIME = 0.02f;
- const F32 ANIM_CLOSE_TIME = 0.03f;
-
e_panel_list_t::iterator panel_it;
for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
{
@@ -316,7 +323,7 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
{
if (!mAnimatedThisFrame)
{
- (*panel_it)->mVisibleAmt = lerp((*panel_it)->mVisibleAmt, 1.f, LLCriticalDamp::getInterpolant(ANIM_OPEN_TIME));
+ (*panel_it)->mVisibleAmt = lerp((*panel_it)->mVisibleAmt, 1.f, LLCriticalDamp::getInterpolant(mOpenTimeConstant));
if ((*panel_it)->mVisibleAmt > 0.99f)
{
(*panel_it)->mVisibleAmt = 1.f;
@@ -334,7 +341,7 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
{
if (!mAnimatedThisFrame)
{
- (*panel_it)->mVisibleAmt = lerp((*panel_it)->mVisibleAmt, 0.f, LLCriticalDamp::getInterpolant(ANIM_CLOSE_TIME));
+ (*panel_it)->mVisibleAmt = lerp((*panel_it)->mVisibleAmt, 0.f, LLCriticalDamp::getInterpolant(mCloseTimeConstant));
if ((*panel_it)->mVisibleAmt < 0.001f)
{
(*panel_it)->mVisibleAmt = 0.f;
@@ -349,11 +356,11 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
if ((*panel_it)->mCollapsed)
{
- (*panel_it)->mCollapseAmt = lerp((*panel_it)->mCollapseAmt, 1.f, LLCriticalDamp::getInterpolant(ANIM_CLOSE_TIME));
+ (*panel_it)->mCollapseAmt = lerp((*panel_it)->mCollapseAmt, 1.f, LLCriticalDamp::getInterpolant(mCloseTimeConstant));
}
else
{
- (*panel_it)->mCollapseAmt = lerp((*panel_it)->mCollapseAmt, 0.f, LLCriticalDamp::getInterpolant(ANIM_CLOSE_TIME));
+ (*panel_it)->mCollapseAmt = lerp((*panel_it)->mCollapseAmt, 0.f, LLCriticalDamp::getInterpolant(mCloseTimeConstant));
}
if (mOrientation == HORIZONTAL)
@@ -556,7 +563,7 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
}
// update resize bars with new limits
- LLResizeBar* last_resize_bar = NULL;
+ LLLayoutPanel* last_resizeable_panel = NULL;
for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
{
LLPanel* panelp = (*panel_it);
@@ -578,17 +585,17 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
BOOL resize_bar_enabled = panelp->getVisible() && (*panel_it)->mUserResize;
(*panel_it)->mResizeBar->setVisible(resize_bar_enabled);
- if (resize_bar_enabled)
+ if ((*panel_it)->mUserResize || (*panel_it)->mAutoResize)
{
- last_resize_bar = (*panel_it)->mResizeBar;
+ last_resizeable_panel = (*panel_it);
}
}
// hide last resize bar as there is nothing past it
// resize bars need to be in between two resizable panels
- if (last_resize_bar)
+ if (last_resizeable_panel)
{
- last_resize_bar->setVisible(FALSE);
+ last_resizeable_panel->mResizeBar->setVisible(FALSE);
}
// not enough room to fit existing contents
diff --git a/indra/llui/lllayoutstack.h b/indra/llui/lllayoutstack.h
index e19ef403ef..4ac8ef0ee9 100644
--- a/indra/llui/lllayoutstack.h
+++ b/indra/llui/lllayoutstack.h
@@ -37,27 +37,35 @@ class LLLayoutPanel;
class LLLayoutStack : public LLView, public LLInstanceTracker<LLLayoutStack>
{
public:
+ typedef enum e_layout_orientation
+ {
+ HORIZONTAL,
+ VERTICAL
+ } ELayoutOrientation;
+
+ struct OrientationNames
+ : public LLInitParam::TypeValuesHelper<ELayoutOrientation, OrientationNames>
+ {
+ static void declareValues();
+ };
+
struct LayoutStackRegistry : public LLChildRegistry<LayoutStackRegistry>
{};
struct Params : public LLInitParam::Block<Params, LLView::Params>
{
- Mandatory<std::string> orientation;
+ Mandatory<ELayoutOrientation, OrientationNames> orientation;
Optional<S32> border_size;
Optional<bool> animate,
clip;
+ Optional<F32> open_time_constant,
+ close_time_constant;
Params();
};
typedef LayoutStackRegistry child_registry_t;
- typedef enum e_layout_orientation
- {
- HORIZONTAL,
- VERTICAL
- } ELayoutOrientation;
-
virtual ~LLLayoutStack();
/*virtual*/ void draw();
@@ -137,6 +145,8 @@ private:
bool mAnimatedThisFrame;
bool mAnimate;
bool mClip;
+ F32 mOpenTimeConstant;
+ F32 mCloseTimeConstant;
}; // end class LLLayoutStack
class LLLayoutPanel : public LLPanel
@@ -167,6 +177,9 @@ public:
~LLLayoutPanel();
void initFromParams(const Params& p);
+ void setMinDim(S32 value) { mMinDim = value; }
+ void setMaxDim(S32 value) { mMaxDim = value; }
+
protected:
LLLayoutPanel(const Params& p) ;
diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp
index 5f5fe851bb..0196080d90 100644
--- a/indra/llui/lllineeditor.cpp
+++ b/indra/llui/lllineeditor.cpp
@@ -88,6 +88,7 @@ LLLineEditor::Params::Params()
revert_on_esc("revert_on_esc", true),
commit_on_focus_lost("commit_on_focus_lost", true),
ignore_tab("ignore_tab", true),
+ is_password("is_password", false),
cursor_color("cursor_color"),
text_color("text_color"),
text_readonly_color("text_readonly_color"),
@@ -129,7 +130,7 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p)
mBorderThickness( 0 ),
mIgnoreArrowKeys( FALSE ),
mIgnoreTab( p.ignore_tab ),
- mDrawAsterixes( FALSE ),
+ mDrawAsterixes( p.is_password ),
mSelectAllonFocusReceived( p.select_on_focus ),
mPassDelete(FALSE),
mReadOnly(FALSE),
@@ -388,7 +389,11 @@ void LLLineEditor::setText(const LLStringExplicit &new_text)
setCursor(llmin((S32)mText.length(), getCursor()));
// Set current history line to end of history.
- if(mLineHistory.end() != mLineHistory.begin())
+ if (mLineHistory.empty())
+ {
+ mCurrentHistoryLine = mLineHistory.end();
+ }
+ else
{
mCurrentHistoryLine = mLineHistory.end() - 1;
}
@@ -1304,7 +1309,7 @@ BOOL LLLineEditor::handleSpecialKey(KEY key, MASK mask)
// handle ctrl-uparrow if we have a history enabled line editor.
case KEY_UP:
- if( mHaveHistory && ( MASK_CONTROL == mask ) )
+ if( mHaveHistory && ((mIgnoreArrowKeys == false) || ( MASK_CONTROL == mask )) )
{
if( mCurrentHistoryLine > mLineHistory.begin() )
{
@@ -1319,9 +1324,9 @@ BOOL LLLineEditor::handleSpecialKey(KEY key, MASK mask)
}
break;
- // handle ctrl-downarrow if we have a history enabled line editor
+ // handle [ctrl]-downarrow if we have a history enabled line editor
case KEY_DOWN:
- if( mHaveHistory && ( MASK_CONTROL == mask ) )
+ if( mHaveHistory && ((mIgnoreArrowKeys == false) || ( MASK_CONTROL == mask )) )
{
if( !mLineHistory.empty() && mCurrentHistoryLine < mLineHistory.end() - 1 )
{
@@ -1529,8 +1534,11 @@ void LLLineEditor::drawBackground()
{
image = mBgImage;
}
+
+ if (!image) return;
- F32 alpha = getDrawContext().mAlpha;
+ F32 alpha = getCurrentTransparency();
+
// optionally draw programmatic border
if (has_focus)
{
@@ -2286,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 a1aa6b71c6..fe191e5971 100644
--- a/indra/llui/lllineeditor.h
+++ b/indra/llui/lllineeditor.h
@@ -41,6 +41,7 @@
#include "lleditmenuhandler.h"
#include "lluictrl.h"
+#include "lluiimage.h"
#include "lluistring.h"
#include "llviewborder.h"
@@ -85,7 +86,8 @@ public:
Optional<bool> select_on_focus,
revert_on_esc,
commit_on_focus_lost,
- ignore_tab;
+ ignore_tab,
+ is_password;
// colors
Optional<LLUIColor> cursor_color,
@@ -200,6 +202,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; }
@@ -336,7 +339,7 @@ protected:
std::vector<S32> mPreeditPositions;
LLPreeditor::standouts_t mPreeditStandouts;
- LLHandle<LLView> mContextMenuHandle;
+ LLHandle<LLContextMenu> mContextMenuHandle;
private:
// Instances that by default point to the statics but can be overidden in XML.
diff --git a/indra/llui/llloadingindicator.cpp b/indra/llui/llloadingindicator.cpp
index 7b29d92ea0..c4eec1835c 100644
--- a/indra/llui/llloadingindicator.cpp
+++ b/indra/llui/llloadingindicator.cpp
@@ -39,56 +39,24 @@
//static LLDefaultChildRegistry::Register<LLLoadingIndicator> r("loading_indicator");
///////////////////////////////////////////////////////////////////////////////
-// LLLoadingIndicator::Data class
+// LLLoadingIndicator class
///////////////////////////////////////////////////////////////////////////////
-/**
- * Pre-loaded images shared by all instances of the widget
- */
-class LLLoadingIndicator::Data: public LLSingleton<LLLoadingIndicator::Data>
+LLLoadingIndicator::LLLoadingIndicator(const Params& p)
+: LLUICtrl(p),
+ mImagesPerSec(p.images_per_sec > 0 ? p.images_per_sec : 1.0f),
+ mCurImageIdx(0)
{
-public:
- /*virtual*/ void initSingleton(); // from LLSingleton
-
- LLPointer<LLUIImage> getNextImage(S8& idx) const;
- U8 getImagesCount() const { return NIMAGES; }
-private:
-
- static const U8 NIMAGES = 12;
- LLPointer<LLUIImage> mImages[NIMAGES];
-};
+}
-// virtual
-// Called right after the instance gets constructed.
-void LLLoadingIndicator::Data::initSingleton()
+void LLLoadingIndicator::initFromParams(const Params& p)
{
- // Load images.
- for (U8 i = 0; i < NIMAGES; ++i)
+ for (LLInitParam::ParamIterator<LLUIImage*>::const_iterator it = p.images().image.begin(), end_it = p.images().image.end();
+ it != end_it;
+ ++it)
{
- std::string img_name = llformat("Progress_%d", i+1);
- mImages[i] = LLUI::getUIImage(img_name, 0);
- llassert(mImages[i]);
+ mImages.push_back(it->getValue());
}
-}
-
-LLPointer<LLUIImage> LLLoadingIndicator::Data::getNextImage(S8& idx) const
-{
- // Calculate next index, performing array bounds checking.
- idx = (idx >= NIMAGES || idx < 0) ? 0 : (idx + 1) % NIMAGES;
- return mImages[idx];
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// LLLoadingIndicator class
-///////////////////////////////////////////////////////////////////////////////
-
-LLLoadingIndicator::LLLoadingIndicator(const Params& p)
-: LLUICtrl(p)
- , mRotationsPerSec(p.rotations_per_sec > 0 ? p.rotations_per_sec : 1.0f)
- , mCurImageIdx(-1)
-{
- // Select initial image.
- mCurImagep = Data::instance().getNextImage(mCurImageIdx);
// Start timer for switching images.
start();
@@ -100,16 +68,21 @@ void LLLoadingIndicator::draw()
if (mImageSwitchTimer.getStarted() && mImageSwitchTimer.hasExpired())
{
// Switch to the next image.
- mCurImagep = Data::instance().getNextImage(mCurImageIdx);
+ if (!mImages.empty())
+ {
+ mCurImageIdx = (mCurImageIdx + 1) % mImages.size();
+ }
// Restart timer.
start();
}
+ LLUIImagePtr cur_image = mImages.empty() ? LLUIImagePtr(NULL) : mImages[mCurImageIdx];
+
// Draw current image.
- if( mCurImagep.notNull() )
+ if( cur_image.notNull() )
{
- mCurImagep->draw(getLocalRect(), LLColor4::white % getDrawContext().mAlpha);
+ cur_image->draw(getLocalRect(), LLColor4::white % getDrawContext().mAlpha);
}
LLUICtrl::draw();
@@ -123,6 +96,6 @@ void LLLoadingIndicator::stop()
void LLLoadingIndicator::start()
{
mImageSwitchTimer.start();
- F32 period = 1.0f / (Data::instance().getImagesCount() * mRotationsPerSec);
+ F32 period = 1.0f / (mImages.size() * mImagesPerSec);
mImageSwitchTimer.setTimerExpirySec(period);
}
diff --git a/indra/llui/llloadingindicator.h b/indra/llui/llloadingindicator.h
index 4e4a224ef6..4c47cc267c 100644
--- a/indra/llui/llloadingindicator.h
+++ b/indra/llui/llloadingindicator.h
@@ -28,6 +28,7 @@
#define LL_LLLOADINGINDICATOR_H
#include "lluictrl.h"
+#include "lluiimage.h"
///////////////////////////////////////////////////////////////////////////////
// class LLLoadingIndicator
@@ -36,8 +37,8 @@
/**
* Perpetual loading indicator (a la MacOSX or YouTube)
*
- * Number of rotations per second can be overriden
- * with the "roations_per_sec" parameter.
+ * Number of rotations per second can be overridden
+ * with the "images_per_sec" parameter.
*
* Can start/stop spinning.
*
@@ -49,11 +50,24 @@ class LLLoadingIndicator
{
LOG_CLASS(LLLoadingIndicator);
public:
+
+ struct Images : public LLInitParam::Block<Images>
+ {
+ Multiple<LLUIImage*> image;
+
+ Images()
+ : image("image")
+ {}
+ };
+
struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
{
- Optional<F32> rotations_per_sec;
+ Optional<F32> images_per_sec;
+ Batch<Images> images;
+
Params()
- : rotations_per_sec("rotations_per_sec", 1.0f)
+ : images_per_sec("images_per_sec", 1.0f),
+ images("images")
{}
};
@@ -74,14 +88,15 @@ public:
private:
LLLoadingIndicator(const Params&);
- friend class LLUICtrlFactory;
+ void initFromParams(const Params&);
- class Data;
+ friend class LLUICtrlFactory;
- F32 mRotationsPerSec;
+ F32 mImagesPerSec;
S8 mCurImageIdx;
- LLPointer<LLUIImage> mCurImagep;
LLFrameTimer mImageSwitchTimer;
+
+ std::vector<LLUIImagePtr> mImages;
};
#endif // LL_LLLOADINGINDICATOR_H
diff --git a/indra/llui/llmenubutton.cpp b/indra/llui/llmenubutton.cpp
index 3df05f4d3f..eed0085273 100644
--- a/indra/llui/llmenubutton.cpp
+++ b/indra/llui/llmenubutton.cpp
@@ -29,7 +29,7 @@
#include "llmenubutton.h"
// Linden library includes
-#include "llmenugl.h"
+#include "lltoggleablemenu.h"
#include "llstring.h"
#include "v4color.h"
@@ -44,58 +44,77 @@ LLMenuButton::Params::Params()
LLMenuButton::LLMenuButton(const LLMenuButton::Params& p)
: LLButton(p),
- mMenu(NULL),
- mMenuVisibleLastFrame(false)
+ mIsMenuShown(false),
+ mMenuPosition(MP_BOTTOM_LEFT)
{
std::string menu_filename = p.menu_filename;
if (!menu_filename.empty())
{
- mMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>(menu_filename, LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance());
- if (!mMenu)
+ LLToggleableMenu* menu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>(menu_filename, LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance());
+ if (!menu)
{
llwarns << "Error loading menu_button menu" << llendl;
+ return;
}
+
+ menu->setVisibilityChangeCallback(boost::bind(&LLMenuButton::onMenuVisibilityChange, this, _2));
+
+ mMenuHandle = menu->getHandle();
+
+ updateMenuOrigin();
}
}
-void LLMenuButton::toggleMenu()
+boost::signals2::connection LLMenuButton::setMouseDownCallback( const mouse_signal_t::slot_type& cb )
{
- if(!mMenu)
- return;
+ return LLUICtrl::setMouseDownCallback(cb);
+}
- if (mMenu->getVisible() || mMenuVisibleLastFrame)
- {
- mMenu->setVisible(FALSE);
- }
- else
+void LLMenuButton::hideMenu()
+{
+ if(mMenuHandle.isDead()) return;
+
+ LLToggleableMenu* menu = dynamic_cast<LLToggleableMenu*>(mMenuHandle.get());
+ if (menu)
{
- LLRect rect = getRect();
- //mMenu->needsArrange(); //so it recalculates the visible elements
- LLMenuGL::showPopup(getParent(), mMenu, rect.mLeft, rect.mBottom);
+ menu->setVisible(FALSE);
}
}
-
-void LLMenuButton::hideMenu()
-{
- if(!mMenu)
- return;
- mMenu->setVisible(FALSE);
+LLToggleableMenu* LLMenuButton::getMenu()
+{
+ return dynamic_cast<LLToggleableMenu*>(mMenuHandle.get());
}
+void LLMenuButton::setMenu(LLToggleableMenu* menu, EMenuPosition position /*MP_TOP_LEFT*/)
+{
+ if (!menu) return;
+
+ mMenuHandle = menu->getHandle();
+ mMenuPosition = position;
+
+ menu->setVisibilityChangeCallback(boost::bind(&LLMenuButton::onMenuVisibilityChange, this, _2));
+}
BOOL LLMenuButton::handleKeyHere(KEY key, MASK mask )
{
+ if (mMenuHandle.isDead()) return FALSE;
+
if( KEY_RETURN == key && mask == MASK_NONE && !gKeyboard->getKeyRepeated(key))
{
+ // *HACK: We emit the mouse down signal to fire the callback bound to the
+ // menu emerging event before actually displaying the menu. See STORM-263.
+ LLUICtrl::handleMouseDown(-1, -1, MASK_NONE);
+
toggleMenu();
return TRUE;
}
- if (mMenu && mMenu->getVisible() && key == KEY_ESCAPE && mask == MASK_NONE)
+ LLToggleableMenu* menu = dynamic_cast<LLToggleableMenu*>(mMenuHandle.get());
+ if (menu && menu->getVisible() && key == KEY_ESCAPE && mask == MASK_NONE)
{
- mMenu->setVisible(FALSE);
+ menu->setVisible(FALSE);
return TRUE;
}
@@ -104,34 +123,84 @@ BOOL LLMenuButton::handleKeyHere(KEY key, MASK mask )
BOOL LLMenuButton::handleMouseDown(S32 x, S32 y, MASK mask)
{
- if (hasTabStop() && !getIsChrome())
- {
- setFocus(TRUE);
- }
+ LLButton::handleMouseDown(x, y, mask);
toggleMenu();
- if (getSoundFlags() & MOUSE_DOWN)
- {
- make_ui_sound("UISndClick");
- }
-
return TRUE;
}
-void LLMenuButton::draw()
+void LLMenuButton::toggleMenu()
{
- //we save this off so next frame when we try to close it by
- //button click, and it hides menus before we get to it, we know
- mMenuVisibleLastFrame = mMenu && mMenu->getVisible();
-
- if (mMenuVisibleLastFrame)
+ if(mMenuHandle.isDead()) return;
+
+ LLToggleableMenu* menu = dynamic_cast<LLToggleableMenu*>(mMenuHandle.get());
+ if (!menu) return;
+
+ // Store the button rectangle to toggle menu visibility if a mouse event
+ // occurred inside or outside the button rect.
+ menu->setButtonRect(this);
+
+ if (!menu->toggleVisibility() && mIsMenuShown)
{
+ setForcePressedState(false);
+ mIsMenuShown = false;
+ }
+ else
+ {
+ menu->buildDrawLabels();
+ menu->arrangeAndClear();
+ menu->updateParent(LLMenuGL::sMenuContainer);
+
+ updateMenuOrigin();
+
+ LLMenuGL::showPopup(getParent(), menu, mX, mY);
+
setForcePressedState(true);
+ mIsMenuShown = true;
}
+}
- LLButton::draw();
+void LLMenuButton::updateMenuOrigin()
+{
+ if (mMenuHandle.isDead()) return;
+
+ LLRect rect = getRect();
- setForcePressedState(false);
+ switch (mMenuPosition)
+ {
+ case MP_TOP_LEFT:
+ {
+ mX = rect.mLeft;
+ mY = rect.mTop + mMenuHandle.get()->getRect().getHeight();
+ break;
+ }
+ case MP_TOP_RIGHT:
+ {
+ const LLRect& menu_rect = mMenuHandle.get()->getRect();
+ mX = rect.mRight - menu_rect.getWidth();
+ mY = rect.mTop + menu_rect.getHeight();
+ break;
+ }
+ case MP_BOTTOM_LEFT:
+ {
+ mX = rect.mLeft;
+ mY = rect.mBottom;
+ break;
+ }
+ }
}
+void LLMenuButton::onMenuVisibilityChange(const LLSD& param)
+{
+ bool new_visibility = param["visibility"].asBoolean();
+ bool is_closed_by_button_click = param["closed_by_button_click"].asBoolean();
+
+ // Reset the button "pressed" state only if the menu is shown by this particular
+ // menu button (not any other control) and is not being closed by a click on the button.
+ if (!new_visibility && !is_closed_by_button_click && mIsMenuShown)
+ {
+ setForcePressedState(false);
+ mIsMenuShown = false;
+ }
+}
diff --git a/indra/llui/llmenubutton.h b/indra/llui/llmenubutton.h
index 81ca0e047c..7b657595da 100644
--- a/indra/llui/llmenubutton.h
+++ b/indra/llui/llmenubutton.h
@@ -29,7 +29,7 @@
#include "llbutton.h"
-class LLMenuGL;
+class LLToggleableMenu;
class LLMenuButton
: public LLButton
@@ -42,22 +42,42 @@ public:
Optional<std::string> menu_filename;
Params();
- };
+ };
+
+ typedef enum e_menu_position
+ {
+ MP_TOP_LEFT,
+ MP_TOP_RIGHT,
+ MP_BOTTOM_LEFT
+ } EMenuPosition;
- void toggleMenu();
- /*virtual*/ void draw();
+ boost::signals2::connection setMouseDownCallback( const mouse_signal_t::slot_type& cb );
+
/*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask);
/*virtual*/ BOOL handleKeyHere(KEY key, MASK mask );
+
void hideMenu();
- LLMenuGL* getMenu() { return mMenu; }
+
+ LLToggleableMenu* getMenu();
+ void setMenu(LLToggleableMenu* menu, EMenuPosition position = MP_TOP_LEFT);
+
+ void setMenuPosition(EMenuPosition position) { mMenuPosition = position; }
protected:
friend class LLUICtrlFactory;
LLMenuButton(const Params&);
+ void toggleMenu();
+ void updateMenuOrigin();
+
+ void onMenuVisibilityChange(const LLSD& param);
+
private:
- LLMenuGL* mMenu;
- bool mMenuVisibleLastFrame;
+ LLHandle<LLView> mMenuHandle;
+ bool mIsMenuShown;
+ EMenuPosition mMenuPosition;
+ S32 mX;
+ S32 mY;
};
diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index 6d590cf54e..8de9c769e2 100644
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -1462,7 +1462,7 @@ BOOL LLMenuItemBranchDownGL::handleAcceleratorKey(KEY key, MASK mask)
{
BOOL branch_visible = getBranch()->getVisible();
BOOL handled = getBranch()->handleAcceleratorKey(key, mask);
- if (handled && !branch_visible && getVisible())
+ if (handled && !branch_visible && isInVisibleChain())
{
// flash this menu entry because we triggered an invisible menu item
LLMenuHolderGL::setActivatedItem(this);
@@ -1637,6 +1637,10 @@ LLMenuScrollItem::LLMenuScrollItem(const Params& p)
}
LLButton::Params bparams;
+
+ // Disabled the Return key handling by LLMenuScrollItem instead of
+ // passing the key press to the currently selected menu item. See STORM-385.
+ bparams.commit_on_return(false);
bparams.mouse_opaque(true);
bparams.scale_image(false);
bparams.click_callback(p.scroll_callback);
@@ -1848,89 +1852,110 @@ BOOL LLMenuGL::isOpen()
}
}
-void LLMenuGL::scrollItemsUp()
+
+
+bool LLMenuGL::scrollItems(EScrollingDirection direction)
{
- // Slowing down the items scrolling when arrow button is held
+ // Slowing down items scrolling when arrow button is held
if (mScrollItemsTimer.hasExpired() && NULL != mFirstVisibleItem)
{
mScrollItemsTimer.setTimerExpirySec(.033f);
}
else
{
- return;
+ return false;
}
- item_list_t::iterator cur_item_iter;
- item_list_t::iterator prev_item_iter;
- for (cur_item_iter = mItems.begin(), prev_item_iter = mItems.begin(); cur_item_iter != mItems.end(); cur_item_iter++)
+ switch (direction)
{
- if( (*cur_item_iter) == mFirstVisibleItem)
+ case SD_UP:
+ {
+ item_list_t::iterator cur_item_iter;
+ item_list_t::iterator prev_item_iter;
+ for (cur_item_iter = mItems.begin(), prev_item_iter = mItems.begin(); cur_item_iter != mItems.end(); cur_item_iter++)
{
- break;
+ if( (*cur_item_iter) == mFirstVisibleItem)
+ {
+ break;
+ }
+ if ((*cur_item_iter)->getVisible())
+ {
+ prev_item_iter = cur_item_iter;
+ }
}
- if ((*cur_item_iter)->getVisible())
+
+ if ((*prev_item_iter)->getVisible())
{
- prev_item_iter = cur_item_iter;
+ mFirstVisibleItem = *prev_item_iter;
}
+ break;
}
-
- if ((*prev_item_iter)->getVisible())
- {
- mFirstVisibleItem = *prev_item_iter;
- }
-
- mNeedsArrange = TRUE;
- arrangeAndClear();
-}
-
-void LLMenuGL::scrollItemsDown()
-{
- // Slowing down the items scrolling when arrow button is held
- if (mScrollItemsTimer.hasExpired())
- {
- mScrollItemsTimer.setTimerExpirySec(.033f);
- }
- else
+ case SD_DOWN:
{
- return;
- }
-
- if (NULL == mFirstVisibleItem)
- {
- mFirstVisibleItem = *mItems.begin();
- }
-
- item_list_t::iterator cur_item_iter;
-
- for (cur_item_iter = mItems.begin(); cur_item_iter != mItems.end(); cur_item_iter++)
- {
- if( (*cur_item_iter) == mFirstVisibleItem)
+ if (NULL == mFirstVisibleItem)
{
- break;
+ mFirstVisibleItem = *mItems.begin();
}
- }
- item_list_t::iterator next_item_iter;
+ item_list_t::iterator cur_item_iter;
- if (cur_item_iter != mItems.end())
- {
- for (next_item_iter = ++cur_item_iter; next_item_iter != mItems.end(); next_item_iter++)
+ for (cur_item_iter = mItems.begin(); cur_item_iter != mItems.end(); cur_item_iter++)
{
- if( (*next_item_iter)->getVisible())
+ if( (*cur_item_iter) == mFirstVisibleItem)
{
break;
}
}
-
- if (next_item_iter != mItems.end() &&
- (*next_item_iter)->getVisible())
+
+ item_list_t::iterator next_item_iter;
+
+ if (cur_item_iter != mItems.end())
{
- mFirstVisibleItem = *next_item_iter;
+ for (next_item_iter = ++cur_item_iter; next_item_iter != mItems.end(); next_item_iter++)
+ {
+ if( (*next_item_iter)->getVisible())
+ {
+ break;
+ }
+ }
+
+ if (next_item_iter != mItems.end() &&
+ (*next_item_iter)->getVisible())
+ {
+ mFirstVisibleItem = *next_item_iter;
+ }
}
+ break;
}
-
+ case SD_BEGIN:
+ {
+ mFirstVisibleItem = *mItems.begin();
+ break;
+ }
+ case SD_END:
+ {
+ item_list_t::reverse_iterator first_visible_item_iter = mItems.rend();
+
+ // Need to scroll through number of actual existing items in menu.
+ // Otherwise viewer will hang for a time needed to scroll U32_MAX
+ // times in std::advance(). STORM-659.
+ size_t nitems = mItems.size();
+ U32 scrollable_items = nitems < mMaxScrollableItems ? nitems : mMaxScrollableItems;
+
+ // Advance by mMaxScrollableItems back from the end of the list
+ // to make the last item visible.
+ std::advance(first_visible_item_iter, scrollable_items);
+ mFirstVisibleItem = *first_visible_item_iter;
+ break;
+ }
+ default:
+ llwarns << "Unknown scrolling direction: " << direction << llendl;
+ }
+
mNeedsArrange = TRUE;
arrangeAndClear();
+
+ return true;
}
// rearrange the child rects so they fit the shape of the menu.
@@ -2162,7 +2187,7 @@ void LLMenuGL::arrange( void )
LLMenuScrollItem::Params item_params;
item_params.name(ARROW_UP);
item_params.arrow_type(LLMenuScrollItem::ARROW_UP);
- item_params.scroll_callback.function(boost::bind(&LLMenuGL::scrollItemsUp, this));
+ item_params.scroll_callback.function(boost::bind(&LLMenuGL::scrollItems, this, SD_UP));
mArrowUpItem = LLUICtrlFactory::create<LLMenuScrollItem>(item_params);
LLUICtrl::addChild(mArrowUpItem);
@@ -2173,7 +2198,7 @@ void LLMenuGL::arrange( void )
LLMenuScrollItem::Params item_params;
item_params.name(ARROW_DOWN);
item_params.arrow_type(LLMenuScrollItem::ARROW_DOWN);
- item_params.scroll_callback.function(boost::bind(&LLMenuGL::scrollItemsDown, this));
+ item_params.scroll_callback.function(boost::bind(&LLMenuGL::scrollItems, this, SD_DOWN));
mArrowDownItem = LLUICtrlFactory::create<LLMenuScrollItem>(item_params);
LLUICtrl::addChild(mArrowDownItem);
@@ -2596,6 +2621,7 @@ LLMenuItemGL* LLMenuGL::getHighlightedItem()
LLMenuItemGL* LLMenuGL::highlightNextItem(LLMenuItemGL* cur_item, BOOL skip_disabled)
{
+ if (mItems.empty()) return NULL;
// highlighting first item on a torn off menu is the
// same as giving focus to it
if (!cur_item && getTornOff())
@@ -2603,14 +2629,8 @@ LLMenuItemGL* LLMenuGL::highlightNextItem(LLMenuItemGL* cur_item, BOOL skip_disa
((LLFloater*)getParent())->setFocus(TRUE);
}
- item_list_t::iterator cur_item_iter;
- for (cur_item_iter = mItems.begin(); cur_item_iter != mItems.end(); ++cur_item_iter)
- {
- if( (*cur_item_iter) == cur_item)
- {
- break;
- }
- }
+ // Current item position in the items list
+ item_list_t::iterator cur_item_iter = std::find(mItems.begin(), mItems.end(), cur_item);
item_list_t::iterator next_item_iter;
if (cur_item_iter == mItems.end())
@@ -2621,9 +2641,37 @@ LLMenuItemGL* LLMenuGL::highlightNextItem(LLMenuItemGL* cur_item, BOOL skip_disa
{
next_item_iter = cur_item_iter;
next_item_iter++;
+
+ // First visible item position in the items list
+ item_list_t::iterator first_visible_item_iter = std::find(mItems.begin(), mItems.end(), mFirstVisibleItem);
+
if (next_item_iter == mItems.end())
{
next_item_iter = mItems.begin();
+
+ // If current item is the last in the list, the menu is scrolled to the beginning
+ // and the first item is highlighted.
+ if (mScrollable && !scrollItems(SD_BEGIN))
+ {
+ return NULL;
+ }
+ }
+ // If current item is the last visible, the menu is scrolled one item down
+ // and the next item is highlighted.
+ else if (mScrollable &&
+ (U32)std::abs(std::distance(first_visible_item_iter, next_item_iter)) >= mMaxScrollableItems)
+ {
+ // Call highlightNextItem() recursively only if the menu was successfully scrolled down.
+ // If scroll timer hasn't expired yet the menu won't be scrolled and calling
+ // highlightNextItem() will result in an endless recursion.
+ if (scrollItems(SD_DOWN))
+ {
+ return highlightNextItem(cur_item, skip_disabled);
+ }
+ else
+ {
+ return NULL;
+ }
}
}
@@ -2674,6 +2722,8 @@ LLMenuItemGL* LLMenuGL::highlightNextItem(LLMenuItemGL* cur_item, BOOL skip_disa
LLMenuItemGL* LLMenuGL::highlightPrevItem(LLMenuItemGL* cur_item, BOOL skip_disabled)
{
+ if (mItems.empty()) return NULL;
+
// highlighting first item on a torn off menu is the
// same as giving focus to it
if (!cur_item && getTornOff())
@@ -2681,14 +2731,8 @@ LLMenuItemGL* LLMenuGL::highlightPrevItem(LLMenuItemGL* cur_item, BOOL skip_disa
((LLFloater*)getParent())->setFocus(TRUE);
}
- item_list_t::reverse_iterator cur_item_iter;
- for (cur_item_iter = mItems.rbegin(); cur_item_iter != mItems.rend(); ++cur_item_iter)
- {
- if( (*cur_item_iter) == cur_item)
- {
- break;
- }
- }
+ // Current item reverse position from the end of the list
+ item_list_t::reverse_iterator cur_item_iter = std::find(mItems.rbegin(), mItems.rend(), cur_item);
item_list_t::reverse_iterator prev_item_iter;
if (cur_item_iter == mItems.rend())
@@ -2699,9 +2743,37 @@ LLMenuItemGL* LLMenuGL::highlightPrevItem(LLMenuItemGL* cur_item, BOOL skip_disa
{
prev_item_iter = cur_item_iter;
prev_item_iter++;
+
+ // First visible item reverse position in the items list
+ item_list_t::reverse_iterator first_visible_item_iter = std::find(mItems.rbegin(), mItems.rend(), mFirstVisibleItem);
+
if (prev_item_iter == mItems.rend())
{
prev_item_iter = mItems.rbegin();
+
+ // If current item is the first in the list, the menu is scrolled to the end
+ // and the last item is highlighted.
+ if (mScrollable && !scrollItems(SD_END))
+ {
+ return NULL;
+ }
+ }
+ // If current item is the first visible, the menu is scrolled one item up
+ // and the previous item is highlighted.
+ else if (mScrollable &&
+ std::distance(first_visible_item_iter, cur_item_iter) <= 0)
+ {
+ // Call highlightNextItem() only if the menu was successfully scrolled up.
+ // If scroll timer hasn't expired yet the menu won't be scrolled and calling
+ // highlightNextItem() will result in an endless recursion.
+ if (scrollItems(SD_UP))
+ {
+ return highlightPrevItem(cur_item, skip_disabled);
+ }
+ else
+ {
+ return NULL;
+ }
}
}
@@ -2872,12 +2944,12 @@ BOOL LLMenuGL::handleScrollWheel( S32 x, S32 y, S32 clicks )
if( clicks > 0 )
{
while( clicks-- )
- scrollItemsDown();
+ scrollItems(SD_DOWN);
}
else
{
while( clicks++ )
- scrollItemsUp();
+ scrollItems(SD_UP);
}
return TRUE;
@@ -2986,6 +3058,11 @@ void LLMenuGL::showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y)
const S32 CURSOR_HEIGHT = 22; // Approximate "normal" cursor size
const S32 CURSOR_WIDTH = 12;
+ if(menu->getChildList()->empty())
+ {
+ return;
+ }
+
// Save click point for detecting cursor moves before mouse-up.
// Must be in local coords to compare with mouseUp events.
// If the mouse doesn't move, the menu will stay open ala the Mac.
@@ -3028,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);
-
-
-
}
///============================================================================
@@ -3066,7 +3140,10 @@ BOOL LLMenuBarGL::handleAcceleratorKey(KEY key, MASK mask)
mAltKeyTrigger = FALSE;
}
- if(!result && (key == KEY_F10 && mask == MASK_CONTROL) && !gKeyboard->getKeyRepeated(key))
+ if(!result
+ && (key == KEY_F10 && mask == MASK_CONTROL)
+ && !gKeyboard->getKeyRepeated(key)
+ && isInVisibleChain())
{
if (getHighlightedItem())
{
@@ -3449,8 +3526,10 @@ BOOL LLMenuHolderGL::handleKey(KEY key, MASK mask, BOOL called_from_parent)
else
{
//highlight first enabled one
- pMenu->highlightNextItem(NULL);
- handled = true;
+ if(pMenu->highlightNextItem(NULL))
+ {
+ handled = true;
+ }
}
}
}
@@ -3683,9 +3762,7 @@ public:
LLContextMenuBranch(const Params&);
virtual ~LLContextMenuBranch()
- {
- delete mBranch;
- }
+ {}
// called to rebuild the draw label
virtual void buildDrawLabel( void );
@@ -3693,21 +3770,21 @@ public:
// onCommit() - do the primary funcationality of the menu item.
virtual void onCommit( void );
- LLContextMenu* getBranch() { return mBranch; }
+ LLContextMenu* getBranch() { return mBranch.get(); }
void setHighlight( BOOL highlight );
protected:
void showSubMenu();
- LLContextMenu* mBranch;
+ LLHandle<LLContextMenu> mBranch;
};
LLContextMenuBranch::LLContextMenuBranch(const LLContextMenuBranch::Params& p)
: LLMenuItemGL(p),
- mBranch( p.branch )
+ mBranch( p.branch()->getHandle() )
{
- mBranch->hide();
- mBranch->setParentMenuItem(this);
+ mBranch.get()->hide();
+ mBranch.get()->setParentMenuItem(this);
}
// called to rebuild the draw label
@@ -3716,12 +3793,12 @@ void LLContextMenuBranch::buildDrawLabel( void )
{
// default enablement is this -- if any of the subitems are
// enabled, this item is enabled. JC
- U32 sub_count = mBranch->getItemCount();
+ U32 sub_count = mBranch.get()->getItemCount();
U32 i;
BOOL any_enabled = FALSE;
for (i = 0; i < sub_count; i++)
{
- LLMenuItemGL* item = mBranch->getItem(i);
+ LLMenuItemGL* item = mBranch.get()->getItem(i);
item->buildDrawLabel();
if (item->getEnabled() && !item->getDrawTextDisabled() )
{
@@ -3743,13 +3820,13 @@ void LLContextMenuBranch::buildDrawLabel( void )
void LLContextMenuBranch::showSubMenu()
{
- LLMenuItemGL* menu_item = mBranch->getParentMenuItem();
+ LLMenuItemGL* menu_item = mBranch.get()->getParentMenuItem();
if (menu_item != NULL && menu_item->getVisible())
{
S32 center_x;
S32 center_y;
localPointToScreen(getRect().getWidth(), getRect().getHeight() , &center_x, &center_y);
- mBranch->show(center_x, center_y);
+ mBranch.get()->show(center_x, center_y);
}
}
@@ -3769,7 +3846,7 @@ void LLContextMenuBranch::setHighlight( BOOL highlight )
}
else
{
- mBranch->hide();
+ mBranch.get()->hide();
}
}
@@ -3800,6 +3877,11 @@ void LLContextMenu::setVisible(BOOL visible)
// Takes cursor position in screen space?
void LLContextMenu::show(S32 x, S32 y)
{
+ if (getChildList()->empty())
+ {
+ // nothing to show, so abort
+ return;
+ }
// Save click point for detecting cursor moves before mouse-up.
// Must be in local coords to compare with mouseUp events.
// If the mouse doesn't move, the menu will stay open ala the Mac.
diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h
index 19b738312e..7bde8e83ec 100644
--- a/indra/llui/llmenugl.h
+++ b/indra/llui/llmenugl.h
@@ -397,6 +397,15 @@ public:
static const std::string ARROW_UP;
static const std::string ARROW_DOWN;
+ // for scrollable menus
+ typedef enum e_scrolling_direction
+ {
+ SD_UP = 0,
+ SD_DOWN = 1,
+ SD_BEGIN = 2,
+ SD_END = 3
+ } EScrollingDirection;
+
protected:
LLMenuGL(const LLMenuGL::Params& p);
friend class LLUICtrlFactory;
@@ -503,8 +512,7 @@ public:
S32 getShortcutPad() { return mShortcutPad; }
- void scrollItemsUp();
- void scrollItemsDown();
+ bool scrollItems(EScrollingDirection direction);
BOOL isScrollable() const { return mScrollable; }
static class LLMenuHolderGL* sMenuContainer;
@@ -670,9 +678,12 @@ public:
BOOL appendContextSubMenu(LLContextMenu *menu);
+ LLHandle<LLContextMenu> getHandle() { mHandle.bind(this); return mHandle; }
+
protected:
- BOOL mHoveredAnyItem;
- LLMenuItemGL* mHoverItem;
+ BOOL mHoveredAnyItem;
+ LLMenuItemGL* mHoverItem;
+ LLRootHandle<LLContextMenu> mHandle;
};
diff --git a/indra/llui/llmultislider.cpp b/indra/llui/llmultislider.cpp
index d4e6091ee0..f744e9db41 100644
--- a/indra/llui/llmultislider.cpp
+++ b/indra/llui/llmultislider.cpp
@@ -35,6 +35,7 @@
#include "llkeyboard.h" // for the MASK constants
#include "llcontrol.h"
#include "lluictrlfactory.h"
+#include "lluiimage.h"
#include <sstream>
diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp
index dd6c632d10..6085c61f9a 100644
--- a/indra/llui/llnotifications.cpp
+++ b/indra/llui/llnotifications.cpp
@@ -28,6 +28,7 @@
#include "llnotifications.h"
#include "llnotificationtemplate.h"
+#include "llnotificationvisibilityrule.h"
#include "llavatarnamecache.h"
#include "llinstantmessage.h"
@@ -64,7 +65,7 @@ LLNotificationForm::FormElementBase::FormElementBase()
LLNotificationForm::FormIgnore::FormIgnore()
: text("text"),
control("control"),
- invert_control("invert_control", true),
+ invert_control("invert_control", false),
save_option("save_option", false)
{}
@@ -81,6 +82,7 @@ LLNotificationForm::FormButton::FormButton()
LLNotificationForm::FormInput::FormInput()
: type("type"),
+ text("text"),
max_length_chars("max_length_chars"),
width("width", 0),
value("value")
@@ -137,12 +139,6 @@ private:
bool filterIgnoredNotifications(LLNotificationPtr notification)
{
- // filter everything if we are to ignore ALL
- if(LLNotifications::instance().getIgnoreAllNotifications())
- {
- return false;
- }
-
LLNotificationFormPtr form = notification->getForm();
// Check to see if the user wants to ignore this alert
return !notification->getForm()->getIgnored();
@@ -177,6 +173,28 @@ bool handleIgnoredNotification(const LLSD& payload)
return false;
}
+bool defaultResponse(const LLSD& payload)
+{
+ if (payload["sigtype"].asString() == "add")
+ {
+ LLNotificationPtr pNotif = LLNotifications::instance().find(payload["id"].asUUID());
+ if (pNotif)
+ {
+ // supply default response
+ pNotif->respond(pNotif->getResponseTemplate(LLNotification::WITH_DEFAULT_BUTTON));
+ }
+ }
+ return false;
+}
+
+bool visibilityRuleMached(const LLSD& payload)
+{
+ // This is needed because LLNotifications::isVisibleByRules may have cancelled the notification.
+ // Returning true here makes LLNotificationChannelBase::updateItem do an early out, which prevents things from happening in the wrong order.
+ return true;
+}
+
+
namespace LLNotificationFilters
{
// a sample filter
@@ -194,7 +212,7 @@ LLNotificationForm::LLNotificationForm()
LLNotificationForm::LLNotificationForm(const std::string& name, const LLNotificationForm::Params& p)
: mIgnore(IGNORE_NO),
- mInvertSetting(true) // ignore settings by default mean true=show, false=ignore
+ mInvertSetting(false) // ignore settings by default mean true=show, false=ignore
{
if (p.ignore.isProvided())
{
@@ -219,7 +237,7 @@ LLNotificationForm::LLNotificationForm(const std::string& name, const LLNotifica
}
else
{
- LLUI::sSettingGroups["ignores"]->declareBOOL(name, show_notification, "Ignore notification with this name", TRUE);
+ LLUI::sSettingGroups["ignores"]->declareBOOL(name, show_notification, "Show notification with this name", TRUE);
mIgnoreSetting = LLUI::sSettingGroups["ignores"]->getControl(name);
}
}
@@ -357,15 +375,15 @@ LLControlVariablePtr LLNotificationForm::getIgnoreSetting()
bool LLNotificationForm::getIgnored()
{
- bool ignored = false;
+ bool show = true;
if (mIgnore != LLNotificationForm::IGNORE_NO
&& mIgnoreSetting)
{
- ignored = mIgnoreSetting->getValue().asBoolean();
- if (mInvertSetting) ignored = !ignored;
+ show = mIgnoreSetting->getValue().asBoolean();
+ if (mInvertSetting) show = !show;
}
- return ignored;
+ return !show;
}
void LLNotificationForm::setIgnored(bool ignored)
@@ -373,7 +391,7 @@ void LLNotificationForm::setIgnored(bool ignored)
if (mIgnoreSetting)
{
if (mInvertSetting) ignored = !ignored;
- mIgnoreSetting->setValue(ignored);
+ mIgnoreSetting->setValue(!ignored);
}
}
@@ -404,12 +422,49 @@ LLNotificationTemplate::LLNotificationTemplate(const LLNotificationTemplate::Par
it != end_it;
++it)
{
- mUniqueContext.push_back(it->key);
+ mUniqueContext.push_back(it->value);
+ }
+
+ lldebugs << "notification \"" << mName << "\": tag count is " << p.tags.size() << llendl;
+
+ for(LLInitParam::ParamIterator<LLNotificationTemplate::Tag>::const_iterator it = p.tags.begin(),
+ end_it = p.tags.end();
+ it != end_it;
+ ++it)
+ {
+ lldebugs << " tag \"" << std::string(it->value) << "\"" << llendl;
+ mTags.push_back(it->value);
}
mForm = LLNotificationFormPtr(new LLNotificationForm(p.name, p.form_ref.form));
}
+LLNotificationVisibilityRule::LLNotificationVisibilityRule(const LLNotificationVisibilityRule::Rule &p)
+{
+ if (p.show.isChosen())
+ {
+ mType = p.show.type;
+ mTag = p.show.tag;
+ mName = p.show.name;
+ mVisible = true;
+ }
+ else if (p.hide.isChosen())
+ {
+ mType = p.hide.type;
+ mTag = p.hide.tag;
+ mName = p.hide.name;
+ mVisible = false;
+ }
+ else if (p.respond.isChosen())
+ {
+ mType = p.respond.type;
+ mTag = p.respond.tag;
+ mName = p.respond.name;
+ mVisible = false;
+ mResponse = p.respond.response;
+ }
+}
+
LLNotification::LLNotification(const LLNotification::Params& p) :
mTimestamp(p.time_stamp),
mSubstitutions(p.substitutions),
@@ -679,6 +734,25 @@ bool LLNotification::hasUniquenessConstraints() const
return (mTemplatep ? mTemplatep->mUnique : false);
}
+bool LLNotification::matchesTag(const std::string& tag)
+{
+ bool result = false;
+
+ if(mTemplatep)
+ {
+ std::list<std::string>::iterator it;
+ for(it = mTemplatep->mTags.begin(); it != mTemplatep->mTags.end(); it++)
+ {
+ if((*it) == tag)
+ {
+ result = true;
+ break;
+ }
+ }
+ }
+
+ return result;
+}
void LLNotification::setIgnored(bool ignore)
{
@@ -719,13 +793,19 @@ bool LLNotification::isEquivalentTo(LLNotificationPtr that) const
{
const LLSD& these_substitutions = this->getSubstitutions();
const LLSD& those_substitutions = that->getSubstitutions();
+ const LLSD& this_payload = this->getPayload();
+ const LLSD& that_payload = that->getPayload();
// highlander bit sez there can only be one of these
for (std::vector<std::string>::const_iterator it = mTemplatep->mUniqueContext.begin(), end_it = mTemplatep->mUniqueContext.end();
it != end_it;
++it)
{
- if (these_substitutions.get(*it).asString() != those_substitutions.get(*it).asString())
+ // if templates differ in either substitution strings or payload with the given field name
+ // then they are considered inequivalent
+ // use of get() avoids converting the LLSD value to a map as the [] operator would
+ if (these_substitutions.get(*it).asString() != those_substitutions.get(*it).asString()
+ || this_payload.get(*it).asString() != that_payload.get(*it).asString())
{
return false;
}
@@ -1064,12 +1144,12 @@ std::string LLNotificationChannel::summarize()
// LLNotifications implementation
// ---
LLNotifications::LLNotifications() : LLNotificationChannelBase(LLNotificationFilters::includeEverything,
- LLNotificationComparators::orderByUUID()),
- mIgnoreAllNotifications(false)
+ LLNotificationComparators::orderByUUID()),
+ mIgnoreAllNotifications(false)
{
LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Notification.Show", boost::bind(&LLNotifications::addFromCallback, this, _2));
-
- mListener.reset(new LLNotificationsListener(*this));
+
+ mListener.reset(new LLNotificationsListener(*this));
}
@@ -1115,16 +1195,18 @@ bool LLNotifications::uniqueFilter(LLNotificationPtr pNotif)
bool LLNotifications::uniqueHandler(const LLSD& payload)
{
+ std::string cmd = payload["sigtype"];
+
LLNotificationPtr pNotif = LLNotifications::instance().find(payload["id"].asUUID());
if (pNotif && pNotif->hasUniquenessConstraints())
{
- if (payload["sigtype"].asString() == "add")
+ if (cmd == "add")
{
// not a duplicate according to uniqueness criteria, so we keep it
// and store it for future uniqueness checks
mUniqueNotifications.insert(std::make_pair(pNotif->getName(), pNotif));
}
- else if (payload["sigtype"].asString() == "delete")
+ else if (cmd == "delete")
{
mUniqueNotifications.erase(pNotif->getName());
}
@@ -1137,12 +1219,16 @@ bool LLNotifications::failedUniquenessTest(const LLSD& payload)
{
LLNotificationPtr pNotif = LLNotifications::instance().find(payload["id"].asUUID());
- if (!pNotif || !pNotif->hasUniquenessConstraints())
+ std::string cmd = payload["sigtype"];
+
+ if (!pNotif || cmd != "add")
{
return false;
}
- // checks against existing unique notifications
+ // Update the existing unique notification with the data from this particular instance...
+ // This guarantees that duplicate notifications will be collapsed to the one
+ // most recently triggered
for (LLNotificationMap::iterator existing_it = mUniqueNotifications.find(pNotif->getName());
existing_it != mUniqueNotifications.end();
++existing_it)
@@ -1155,7 +1241,7 @@ bool LLNotifications::failedUniquenessTest(const LLSD& payload)
// of this unique notification and update it
existing_notification->updateFrom(pNotif);
// then delete the new one
- pNotif->cancel();
+ cancel(pNotif);
}
}
@@ -1184,6 +1270,7 @@ LLNotificationChannelPtr LLNotifications::getChannel(const std::string& channelN
void LLNotifications::initSingleton()
{
loadTemplates();
+ loadVisibilityRules();
createDefaultChannels();
}
@@ -1191,15 +1278,19 @@ void LLNotifications::createDefaultChannels()
{
// now construct the various channels AFTER loading the notifications,
// because the history channel is going to rewrite the stored notifications file
- LLNotificationChannel::buildChannel("Expiration", "",
+ LLNotificationChannel::buildChannel("Enabled", "",
+ !boost::bind(&LLNotifications::getIgnoreAllNotifications, this));
+ LLNotificationChannel::buildChannel("Expiration", "Enabled",
boost::bind(&LLNotifications::expirationFilter, this, _1));
- LLNotificationChannel::buildChannel("Unexpired", "",
+ LLNotificationChannel::buildChannel("Unexpired", "Enabled",
!boost::bind(&LLNotifications::expirationFilter, this, _1)); // use negated bind
LLNotificationChannel::buildChannel("Unique", "Unexpired",
boost::bind(&LLNotifications::uniqueFilter, this, _1));
LLNotificationChannel::buildChannel("Ignore", "Unique",
filterIgnoredNotifications);
- LLNotificationChannel::buildChannel("Visible", "Ignore",
+ LLNotificationChannel::buildChannel("VisibilityRules", "Ignore",
+ boost::bind(&LLNotifications::isVisibleByRules, this, _1));
+ LLNotificationChannel::buildChannel("Visible", "VisibilityRules",
&LLNotificationFilters::includeEverything);
// create special persistent notification channel
@@ -1207,30 +1298,22 @@ void LLNotifications::createDefaultChannels()
new LLPersistentNotificationChannel();
// connect action methods to these channels
+ LLNotifications::instance().getChannel("Enabled")->
+ connectFailedFilter(&defaultResponse);
LLNotifications::instance().getChannel("Expiration")->
connectChanged(boost::bind(&LLNotifications::expirationHandler, this, _1));
// uniqueHandler slot should be added as first slot of the signal due to
// usage LLStopWhenHandled combiner in LLStandardSignal
LLNotifications::instance().getChannel("Unique")->
connectAtFrontChanged(boost::bind(&LLNotifications::uniqueHandler, this, _1));
-// failedUniquenessTest slot isn't necessary
-// LLNotifications::instance().getChannel("Unique")->
-// connectFailedFilter(boost::bind(&LLNotifications::failedUniquenessTest, this, _1));
+ LLNotifications::instance().getChannel("Unique")->
+ connectFailedFilter(boost::bind(&LLNotifications::failedUniquenessTest, this, _1));
LLNotifications::instance().getChannel("Ignore")->
connectFailedFilter(&handleIgnoredNotification);
+ LLNotifications::instance().getChannel("VisibilityRules")->
+ connectFailedFilter(&visibilityRuleMached);
}
-bool LLNotifications::addTemplate(const std::string &name,
- LLNotificationTemplatePtr theTemplate)
-{
- if (mTemplates.count(name))
- {
- llwarns << "LLNotifications -- attempted to add template '" << name << "' twice." << llendl;
- return false;
- }
- mTemplates[name] = theTemplate;
- return true;
-}
LLNotificationTemplatePtr LLNotifications::getTemplate(const std::string& name)
{
@@ -1278,7 +1361,6 @@ LLNotifications::TemplateNames LLNotifications::getTemplateNames() const
typedef std::map<std::string, std::string> StringMap;
void replaceSubstitutionStrings(LLXMLNodePtr node, StringMap& replacements)
{
- //llwarns << "replaceSubstitutionStrings" << llendl;
// walk the list of attributes looking for replacements
for (LLXMLAttribList::iterator it=node->mAttributes.begin();
it != node->mAttributes.end(); ++it)
@@ -1292,13 +1374,12 @@ void replaceSubstitutionStrings(LLXMLNodePtr node, StringMap& replacements)
if (found != replacements.end())
{
replacement = found->second;
- //llwarns << "replaceSubstituionStrings: value: " << value << " repl: " << replacement << llendl;
-
+ lldebugs << "replaceSubstitutionStrings: value: \"" << value << "\" repl: \"" << replacement << "\"." << llendl;
it->second->setValue(replacement);
}
else
{
- llwarns << "replaceSubstituionStrings FAILURE: value: " << value << " repl: " << replacement << llendl;
+ llwarns << "replaceSubstitutionStrings FAILURE: could not find replacement \"" << value << "\"." << llendl;
}
}
}
@@ -1329,23 +1410,47 @@ void replaceFormText(LLNotificationForm::Params& form, const std::string& patter
}
}
+void addPathIfExists(const std::string& new_path, std::vector<std::string>& paths)
+{
+ if (gDirUtilp->fileExists(new_path))
+ {
+ paths.push_back(new_path);
+ }
+}
+
bool LLNotifications::loadTemplates()
{
- const std::string xml_filename = "notifications.xml";
- std::string full_filename = gDirUtilp->findSkinnedFilename(LLUI::getXUIPaths().front(), xml_filename);
+ std::vector<std::string> search_paths;
+
+ std::string skin_relative_path = gDirUtilp->getDirDelimiter() + LLUI::getSkinPath() + gDirUtilp->getDirDelimiter() + "notifications.xml";
+ std::string localized_skin_relative_path = gDirUtilp->getDirDelimiter() + LLUI::getLocalizedSkinPath() + gDirUtilp->getDirDelimiter() + "notifications.xml";
+
+ addPathIfExists(gDirUtilp->getDefaultSkinDir() + skin_relative_path, search_paths);
+ addPathIfExists(gDirUtilp->getDefaultSkinDir() + localized_skin_relative_path, search_paths);
+ addPathIfExists(gDirUtilp->getSkinDir() + skin_relative_path, search_paths);
+ addPathIfExists(gDirUtilp->getSkinDir() + localized_skin_relative_path, search_paths);
+ addPathIfExists(gDirUtilp->getUserSkinDir() + skin_relative_path, search_paths);
+ addPathIfExists(gDirUtilp->getUserSkinDir() + localized_skin_relative_path, search_paths);
+ std::string base_filename = search_paths.front();
LLXMLNodePtr root;
- BOOL success = LLUICtrlFactory::getLayeredXMLNode(xml_filename, root);
+ BOOL success = LLXMLNode::getLayeredXMLNode(root, search_paths);
if (!success || root.isNull() || !root->hasName( "notifications" ))
{
- llerrs << "Problem reading UI Notifications file: " << full_filename << llendl;
+ llerrs << "Problem reading UI Notifications file: " << base_filename << llendl;
return false;
}
LLNotificationTemplate::Notifications params;
LLXUIParser parser;
- parser.readXUI(root, params, full_filename);
+ parser.readXUI(root, params, base_filename);
+
+ if(!params.validateBlock())
+ {
+ llerrs << "Problem reading UI Notifications file: " << base_filename << llendl;
+ return false;
+ }
mTemplates.clear();
@@ -1390,7 +1495,35 @@ bool LLNotifications::loadTemplates()
replaceFormText(it->form_ref.form, "$ignoretext", it->form_ref.form_template.ignore_text);
}
}
- addTemplate(it->name, LLNotificationTemplatePtr(new LLNotificationTemplate(*it)));
+ mTemplates[it->name] = LLNotificationTemplatePtr(new LLNotificationTemplate(*it));
+ }
+
+ return true;
+}
+
+bool LLNotifications::loadVisibilityRules()
+{
+ const std::string xml_filename = "notification_visibility.xml";
+ std::string full_filename = gDirUtilp->findSkinnedFilename(LLUI::getXUIPaths().front(), xml_filename);
+
+ LLNotificationVisibilityRule::Rules params;
+ LLSimpleXUIParser parser;
+ parser.readXUI(full_filename, params);
+
+ if(!params.validateBlock())
+ {
+ llerrs << "Problem reading UI Notification Visibility Rules file: " << full_filename << llendl;
+ return false;
+ }
+
+ mVisibilityRules.clear();
+
+ for(LLInitParam::ParamIterator<LLNotificationVisibilityRule::Rule>::iterator it = params.rules.begin(),
+ end_it = params.rules.end();
+ it != end_it;
+ ++it)
+ {
+ mVisibilityRules.push_back(LLNotificationVisibilityRulePtr(new LLNotificationVisibilityRule(*it)));
}
return true;
@@ -1399,7 +1532,7 @@ bool LLNotifications::loadTemplates()
// Add a simple notification (from XUI)
void LLNotifications::addFromCallback(const LLSD& name)
{
- add(LLNotification::Params().name(name.asString()));
+ add(name.asString(), LLSD(), LLSD());
}
LLNotificationPtr LLNotifications::add(const std::string& name,
@@ -1457,7 +1590,7 @@ void LLNotifications::add(const LLNotificationPtr pNotif)
void LLNotifications::cancel(LLNotificationPtr pNotif)
{
- if (pNotif == NULL) return;
+ if (pNotif == NULL || pNotif->isCancelled()) return;
LLNotificationSet::iterator it=mItems.find(pNotif);
if (it == mItems.end())
@@ -1546,6 +1679,93 @@ bool LLNotifications::getIgnoreAllNotifications()
return mIgnoreAllNotifications;
}
+bool LLNotifications::isVisibleByRules(LLNotificationPtr n)
+{
+ if(n->isRespondedTo())
+ {
+ // This avoids infinite recursion in the case where the filter calls respond()
+ return true;
+ }
+
+ VisibilityRuleList::iterator it;
+
+ for(it = mVisibilityRules.begin(); it != mVisibilityRules.end(); it++)
+ {
+ // An empty type/tag/name string will match any notification, so only do the comparison when the string is non-empty in the rule.
+ lldebugs
+ << "notification \"" << n->getName() << "\" "
+ << "testing against " << ((*it)->mVisible?"show":"hide") << " rule, "
+ << "name = \"" << (*it)->mName << "\" "
+ << "tag = \"" << (*it)->mTag << "\" "
+ << "type = \"" << (*it)->mType << "\" "
+ << llendl;
+
+ if(!(*it)->mType.empty())
+ {
+ if((*it)->mType != n->getType())
+ {
+ // Type doesn't match, so skip this rule.
+ continue;
+ }
+ }
+
+ if(!(*it)->mTag.empty())
+ {
+ // check this notification's tag(s) against it->mTag and continue if no match is found.
+ if(!n->matchesTag((*it)->mTag))
+ {
+ // This rule's non-empty tag didn't match one of the notification's tags. Skip this rule.
+ continue;
+ }
+ }
+
+ if(!(*it)->mName.empty())
+ {
+ // check this notification's name against the notification's name and continue if no match is found.
+ if((*it)->mName != n->getName())
+ {
+ // This rule's non-empty name didn't match the notification. Skip this rule.
+ continue;
+ }
+ }
+
+ // If we got here, the rule matches. Don't evaluate subsequent rules.
+ if(!(*it)->mVisible)
+ {
+ // This notification is being hidden.
+
+ if((*it)->mResponse.empty())
+ {
+ // Response property is empty. Cancel this notification.
+ lldebugs << "cancelling notification " << n->getName() << llendl;
+
+ cancel(n);
+ }
+ else
+ {
+ // Response property is not empty. Return the specified response.
+ LLSD response = n->getResponseTemplate(LLNotification::WITHOUT_DEFAULT_BUTTON);
+ // TODO: verify that the response template has an item with the correct name
+ response[(*it)->mResponse] = true;
+
+ lldebugs << "responding to notification " << n->getName() << " with response = " << response << llendl;
+
+ n->respond(response);
+ }
+
+ return false;
+ }
+
+ // If we got here, exit the loop and return true.
+ break;
+ }
+
+ lldebugs << "allowing notification " << n->getName() << llendl;
+
+ return true;
+}
+
+
// ---
// END OF LLNotifications implementation
// =========================================================
diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h
index 524cff70e8..0c4d4fc897 100644
--- a/indra/llui/llnotifications.h
+++ b/indra/llui/llnotifications.h
@@ -195,6 +195,7 @@ public:
Mandatory<std::string> type;
Optional<S32> width;
Optional<S32> max_length_chars;
+ Optional<std::string> text;
Optional<std::string> value;
FormInput();
@@ -270,6 +271,11 @@ struct LLNotificationTemplate;
// with smart pointers
typedef boost::shared_ptr<LLNotificationTemplate> LLNotificationTemplatePtr;
+
+struct LLNotificationVisibilityRule;
+
+typedef boost::shared_ptr<LLNotificationVisibilityRule> LLNotificationVisibilityRulePtr;
+
/**
* @class LLNotification
* @brief The object that expresses the details of a notification
@@ -506,7 +512,7 @@ public:
std::string getLabel() const;
std::string getURL() const;
S32 getURLOption() const;
- S32 getURLOpenExternally() const;
+ S32 getURLOpenExternally() const;
const LLNotificationFormPtr getForm();
@@ -578,6 +584,8 @@ public:
bool hasUniquenessConstraints() const;
+ bool matchesTag(const std::string& tag);
+
virtual ~LLNotification() {}
};
@@ -855,9 +863,14 @@ class LLNotifications :
friend class LLSingleton<LLNotifications>;
public:
- // load notification descriptions from file;
+ // load all notification descriptions from file
+ // calling more than once will overwrite existing templates
+ // but never delete a template
+ bool loadTemplates();
+
+ // load visibility rules from file;
// OK to call more than once because it will reload
- bool loadTemplates();
+ bool loadVisibilityRules();
// Add a simple notification (from XUI)
void addFromCallback(const LLSD& name);
@@ -904,6 +917,8 @@ public:
// test for existence
bool templateExists(const std::string& name);
+ typedef std::list<LLNotificationVisibilityRulePtr> VisibilityRuleList;
+
void forceResponse(const LLNotification::Params& params, S32 option);
void createDefaultChannels();
@@ -919,6 +934,8 @@ public:
void setIgnoreAllNotifications(bool ignore);
bool getIgnoreAllNotifications();
+ bool isVisibleByRules(LLNotificationPtr pNotification);
+
private:
// we're a singleton, so we don't have a public constructor
LLNotifications();
@@ -934,10 +951,10 @@ private:
LLNotificationChannelPtr pHistoryChannel;
LLNotificationChannelPtr pExpirationChannel;
- // put your template in
- bool addTemplate(const std::string& name, LLNotificationTemplatePtr theTemplate);
TemplateMap mTemplates;
+ VisibilityRuleList mVisibilityRules;
+
std::string mFileName;
LLNotificationMap mUniqueNotifications;
diff --git a/indra/llui/llnotificationtemplate.h b/indra/llui/llnotificationtemplate.h
index 6bc0d2aaff..eff572b553 100644
--- a/indra/llui/llnotificationtemplate.h
+++ b/indra/llui/llnotificationtemplate.h
@@ -74,11 +74,13 @@ struct LLNotificationTemplate
struct UniquenessContext : public LLInitParam::Block<UniquenessContext>
{
- Mandatory<std::string> key;
+ Mandatory<std::string> value;
UniquenessContext()
- : key("key")
- {}
+ : value("value")
+ {
+ addSynonym(value, "key");
+ }
};
@@ -88,7 +90,7 @@ struct LLNotificationTemplate
// this idiom allows
// <notification unique="true">
// as well as
- // <notification> <unique> <context key=""/> </unique>...
+ // <notification> <unique> <context></context> </unique>...
Optional<bool> dummy_val;
public:
Multiple<UniquenessContext> contexts;
@@ -156,6 +158,15 @@ struct LLNotificationTemplate
{}
};
+ struct Tag : public LLInitParam::Block<Tag>
+ {
+ Mandatory<std::string> value;
+
+ Tag()
+ : value("value")
+ {}
+ };
+
struct Params : public LLInitParam::Block<Params>
{
Mandatory<std::string> name;
@@ -173,6 +184,7 @@ struct LLNotificationTemplate
Optional<FormRef> form_ref;
Optional<ENotificationPriority,
NotificationPriorityValues> priority;
+ Multiple<Tag> tags;
Params()
@@ -189,7 +201,8 @@ struct LLNotificationTemplate
expire_option("expireOption", -1),
url("url"),
unique("unique"),
- form_ref("")
+ form_ref(""),
+ tags("tag")
{}
};
@@ -232,8 +245,8 @@ struct LLNotificationTemplate
// (used for things like progress indications, or repeating warnings
// like "the grid is going down in N minutes")
bool mUnique;
- // if we want to be unique only if a certain part of the payload is constant
- // specify the field names for the payload. The notification will only be
+ // if we want to be unique only if a certain part of the payload or substitutions args
+ // are constant specify the field names for the payload. The notification will only be
// combined if all of the fields named in the context are identical in the
// new and the old notification; otherwise, the notification will be
// duplicated. This is to support suppressing duplicate offers from the same
@@ -276,6 +289,8 @@ struct LLNotificationTemplate
// this is loaded as a name, but looked up to get the UUID upon template load.
// If null, it wasn't specified.
LLUUID mSoundEffect;
+ // List of tags that rules can match against.
+ std::list<std::string> mTags;
};
#endif //LL_LLNOTIFICATION_TEMPLATE_H
diff --git a/indra/llui/llnotificationvisibilityrule.h b/indra/llui/llnotificationvisibilityrule.h
new file mode 100644
index 0000000000..78bdec2a8f
--- /dev/null
+++ b/indra/llui/llnotificationvisibilityrule.h
@@ -0,0 +1,104 @@
+/**
+* @file llnotificationvisibility.h
+* @brief Rules for
+* @author Monroe
+*
+* $LicenseInfo:firstyear=2010&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_LLNOTIFICATION_VISIBILITY_RULE_H
+#define LL_LLNOTIFICATION_VISIBILITY_RULE_H
+
+#include "llinitparam.h"
+//#include "llnotifications.h"
+
+
+
+// This is the class of object read from the XML file (notification_visibility.xml,
+// from the appropriate local language directory).
+struct LLNotificationVisibilityRule
+{
+ struct Filter : public LLInitParam::Block<Filter>
+ {
+ Optional<std::string> type,
+ tag,
+ name;
+
+ Filter()
+ : type("type"),
+ tag("tag"),
+ name("name")
+ {}
+ };
+
+ struct Respond : public LLInitParam::Block<Respond, Filter>
+ {
+ Mandatory<std::string> response;
+
+ Respond()
+ : response("response")
+ {}
+ };
+
+ struct Rule : public LLInitParam::Choice<Rule>
+ {
+ Alternative<Filter> show;
+ Alternative<Filter> hide;
+ Alternative<Respond> respond;
+
+ Rule()
+ : show("show"),
+ hide("hide"),
+ respond("respond")
+ {}
+ };
+
+ struct Rules : public LLInitParam::Block<Rules>
+ {
+ Multiple<Rule> rules;
+
+ Rules()
+ : rules("")
+ {}
+ };
+
+ LLNotificationVisibilityRule(const Rule& p);
+
+ // If true, this rule makes matching notifications visible. Otherwise, it makes them invisible.
+ bool mVisible;
+
+ // Which response to give when making a notification invisible. An empty string means the notification should be cancelled instead of responded to.
+ std::string mResponse;
+
+ // String to match against the notification's "type". An empty string matches all notifications.
+ std::string mType;
+
+ // String to match against the notification's tag(s). An empty string matches all notifications.
+ std::string mTag;
+
+ // String to match against the notification's name. An empty string matches all notifications.
+ std::string mName;
+
+};
+
+#endif //LL_LLNOTIFICATION_VISIBILITY_RULE_H
+
diff --git a/indra/llui/llpanel.cpp b/indra/llui/llpanel.cpp
index c8e56630f1..b2383106a8 100644
--- a/indra/llui/llpanel.cpp
+++ b/indra/llui/llpanel.cpp
@@ -194,6 +194,8 @@ void LLPanel::draw()
// draw background
if( mBgVisible )
{
+ alpha = getCurrentTransparency();
+
LLRect local_rect = getLocalRect();
if (mBgOpaque )
{
@@ -434,7 +436,7 @@ void LLPanel::initFromParams(const LLPanel::Params& p)
//and LLView::initFromParams will use them to set visible and enabled
setVisible(p.visible);
setEnabled(p.enabled);
-
+ setFocusRoot(p.focus_root);
setSoundFlags(p.sound_flags);
// control_name, tab_stop, focus_lost_callback, initial_value, rect, enabled, visible
@@ -904,7 +906,7 @@ LLPanel *LLPanel::childGetVisiblePanelWithHelp()
child = *it;
// do we have a panel with a help topic?
LLPanel *panel = dynamic_cast<LLPanel *>(child);
- if (panel && panel->getVisible() && !panel->getHelpTopic().empty())
+ if (panel && panel->isInVisibleChain() && !panel->getHelpTopic().empty())
{
return panel;
}
diff --git a/indra/llui/llpanel.h b/indra/llui/llpanel.h
index c1a1a06f39..7bbbeaf709 100644
--- a/indra/llui/llpanel.h
+++ b/indra/llui/llpanel.h
@@ -32,6 +32,7 @@
#include "llcallbackmap.h"
#include "lluictrl.h"
#include "llviewborder.h"
+#include "lluiimage.h"
#include "lluistring.h"
#include "v4color.h"
#include <list>
diff --git a/indra/llui/llprogressbar.cpp b/indra/llui/llprogressbar.cpp
index aaa328754d..84a890edfa 100644
--- a/indra/llui/llprogressbar.cpp
+++ b/indra/llui/llprogressbar.cpp
@@ -38,6 +38,7 @@
#include "llfocusmgr.h"
#include "lluictrlfactory.h"
+#include "lluiimage.h"
static LLDefaultChildRegistry::Register<LLProgressBar> r("progress_bar");
@@ -50,7 +51,7 @@ LLProgressBar::Params::Params()
LLProgressBar::LLProgressBar(const LLProgressBar::Params& p)
-: LLView(p),
+: LLUICtrl(p),
mImageBar(p.image_bar),
mImageFill(p.image_fill),
mColorBackground(p.color_bg()),
@@ -80,7 +81,7 @@ void LLProgressBar::draw()
mImageFill->draw(progress_rect, bar_color);
}
-void LLProgressBar::setPercent(const F32 percent)
+void LLProgressBar::setValue(const LLSD& value)
{
- mPercentDone = llclamp(percent, 0.f, 100.f);
+ mPercentDone = llclamp((F32)value.asReal(), 0.f, 100.f);
}
diff --git a/indra/llui/llprogressbar.h b/indra/llui/llprogressbar.h
index 13297f7493..a8ec83ea00 100644
--- a/indra/llui/llprogressbar.h
+++ b/indra/llui/llprogressbar.h
@@ -27,14 +27,15 @@
#ifndef LL_LLPROGRESSBAR_H
#define LL_LLPROGRESSBAR_H
-#include "llview.h"
#include "llframetimer.h"
+#include "lluictrl.h"
+#include "lluiimage.h"
class LLProgressBar
- : public LLView
+ : public LLUICtrl
{
public:
- struct Params : public LLInitParam::Block<Params, LLView::Params>
+ struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
{
Optional<LLUIImage*> image_bar,
image_fill;
@@ -47,7 +48,7 @@ public:
LLProgressBar(const Params&);
virtual ~LLProgressBar();
- void setPercent(const F32 percent);
+ void setValue(const LLSD& value);
/*virtual*/ void draw();
diff --git a/indra/llui/llradiogroup.cpp b/indra/llui/llradiogroup.cpp
index cc348fdc63..3a12debf7e 100644
--- a/indra/llui/llradiogroup.cpp
+++ b/indra/llui/llradiogroup.cpp
@@ -69,7 +69,7 @@ protected:
static LLWidgetNameRegistry::StaticRegistrar register_radio_item(&typeid(LLRadioGroup::ItemParams), "radio_item");
LLRadioGroup::Params::Params()
-: has_border("draw_border"),
+: allow_deselect("allow_deselect"),
items("item")
{
addSynonym(items, "radio_item");
@@ -85,18 +85,8 @@ LLRadioGroup::LLRadioGroup(const LLRadioGroup::Params& p)
: LLUICtrl(p),
mFont(p.font.isProvided() ? p.font() : LLFontGL::getFontSansSerifSmall()),
mSelectedIndex(-1),
- mHasBorder(p.has_border)
-{
- if (mHasBorder)
- {
- LLViewBorder::Params params;
- params.name("radio group border");
- params.rect(LLRect(0, getRect().getHeight(), getRect().getWidth(), 0));
- params.bevel_style(LLViewBorder::BEVEL_NONE);
- LLViewBorder * vb = LLUICtrlFactory::create<LLViewBorder> (params);
- addChild (vb);
- }
-}
+ mAllowDeselect(p.allow_deselect)
+{}
void LLRadioGroup::initFromParams(const Params& p)
{
@@ -184,7 +174,7 @@ void LLRadioGroup::setIndexEnabled(S32 index, BOOL enabled)
BOOL LLRadioGroup::setSelectedIndex(S32 index, BOOL from_event)
{
- if (index < 0 || (S32)mRadioButtons.size() <= index )
+ if ((S32)mRadioButtons.size() <= index )
{
return FALSE;
}
@@ -202,13 +192,16 @@ BOOL LLRadioGroup::setSelectedIndex(S32 index, BOOL from_event)
mSelectedIndex = index;
- LLRadioCtrl* radio_item = mRadioButtons[mSelectedIndex];
- radio_item->setTabStop(true);
- radio_item->setValue( TRUE );
-
- if (hasFocus())
+ if (mSelectedIndex >= 0)
{
- mRadioButtons[mSelectedIndex]->focusFirstItem(FALSE, FALSE);
+ LLRadioCtrl* radio_item = mRadioButtons[mSelectedIndex];
+ radio_item->setTabStop(true);
+ radio_item->setValue( TRUE );
+
+ if (hasFocus())
+ {
+ radio_item->focusFirstItem(FALSE, FALSE);
+ }
}
if (!from_event)
@@ -307,8 +300,15 @@ void LLRadioGroup::onClickButton(LLUICtrl* ctrl)
LLRadioCtrl* radio = *iter;
if (radio == clicked_radio)
{
- // llinfos << "clicked button " << index << llendl;
- setSelectedIndex(index);
+ if (index == mSelectedIndex && mAllowDeselect)
+ {
+ // don't select anything
+ setSelectedIndex(-1);
+ }
+ else
+ {
+ setSelectedIndex(index);
+ }
// BUG: Calls click callback even if button didn't actually change
onCommit();
@@ -346,7 +346,7 @@ void LLRadioGroup::setValue( const LLSD& value )
}
else
{
- llwarns << "LLRadioGroup::setValue: value not found: " << value.asString() << llendl;
+ setSelectedIndex(-1, TRUE);
}
}
}
diff --git a/indra/llui/llradiogroup.h b/indra/llui/llradiogroup.h
index 0588900600..8bd5698538 100644
--- a/indra/llui/llradiogroup.h
+++ b/indra/llui/llradiogroup.h
@@ -49,7 +49,7 @@ public:
struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
{
- Optional<bool> has_border;
+ Optional<bool> allow_deselect;
Multiple<ItemParams, AtLeast<1> > items;
Params();
};
@@ -73,7 +73,6 @@ public:
void setIndexEnabled(S32 index, BOOL enabled);
// return the index value of the selected item
S32 getSelectedIndex() const { return mSelectedIndex; }
-
// set the index value programatically
BOOL setSelectedIndex(S32 index, BOOL from_event = FALSE);
@@ -103,12 +102,13 @@ public:
/*virtual*/ BOOL operateOnAll(EOperation op);
private:
- const LLFontGL* mFont;
- S32 mSelectedIndex;
+ const LLFontGL* mFont;
+ S32 mSelectedIndex;
+
typedef std::vector<class LLRadioCtrl*> button_list_t;
- button_list_t mRadioButtons;
+ button_list_t mRadioButtons;
- BOOL mHasBorder;
+ bool mAllowDeselect; // user can click on an already selected option to deselect it
};
#endif
diff --git a/indra/llui/llscrollcontainer.cpp b/indra/llui/llscrollcontainer.cpp
index 3146418a7d..380c477eb2 100644
--- a/indra/llui/llscrollcontainer.cpp
+++ b/indra/llui/llscrollcontainer.cpp
@@ -422,9 +422,10 @@ void LLScrollContainer::draw()
// Draw background
if( mIsOpaque )
{
+ F32 alpha = getCurrentTransparency();
+
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- gGL.color4fv( mBackgroundColor.get().mV );
- gl_rect_2d( mInnerRect );
+ gl_rect_2d(mInnerRect, mBackgroundColor.get() % alpha);
}
// Draw mScrolledViews and update scroll bars.
diff --git a/indra/llui/llscrolllistcolumn.cpp b/indra/llui/llscrolllistcolumn.cpp
index 2a4c1ca44c..696e4a2bb1 100644
--- a/indra/llui/llscrolllistcolumn.cpp
+++ b/indra/llui/llscrolllistcolumn.cpp
@@ -83,7 +83,14 @@ void LLScrollColumnHeader::draw()
&& (sort_column == mColumn->mSortingColumn || sort_column == mColumn->mName);
BOOL is_ascending = mColumn->mParentCtrl->getSortAscending();
- setImageOverlay(is_ascending ? "up_arrow.tga" : "down_arrow.tga", LLFontGL::RIGHT, draw_arrow ? LLColor4::white : LLColor4::transparent);
+ if (draw_arrow)
+ {
+ setImageOverlay(is_ascending ? "up_arrow.tga" : "down_arrow.tga", LLFontGL::RIGHT, LLColor4::white);
+ }
+ else
+ {
+ setImageOverlay(LLUUID::null);
+ }
// Draw children
LLButton::draw();
diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp
index 7df7c13dc0..b7848ec37c 100644
--- a/indra/llui/llscrolllistctrl.cpp
+++ b/indra/llui/llscrolllistctrl.cpp
@@ -322,6 +322,7 @@ LLScrollListCtrl::~LLScrollListCtrl()
delete mSortCallback;
std::for_each(mItemList.begin(), mItemList.end(), DeletePointer());
+ std::for_each(mColumns.begin(), mColumns.end(), DeletePairedPointer());
}
@@ -1482,8 +1483,9 @@ void LLScrollListCtrl::draw()
// Draw background
if (mBackgroundVisible)
{
+ F32 alpha = getCurrentTransparency();
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- gl_rect_2d(background, getEnabled() ? mBgWriteableColor.get() : mBgReadOnlyColor.get() );
+ gl_rect_2d(background, getEnabled() ? mBgWriteableColor.get() % alpha : mBgReadOnlyColor.get() % alpha );
}
if (mColumnsDirty)
@@ -2370,10 +2372,10 @@ void LLScrollListCtrl::onScrollChange( S32 new_pos, LLScrollbar* scrollbar )
void LLScrollListCtrl::sortByColumn(const std::string& name, BOOL ascending)
{
- std::map<std::string, LLScrollListColumn>::iterator itor = mColumns.find(name);
+ column_map_t::iterator itor = mColumns.find(name);
if (itor != mColumns.end())
{
- sortByColumnIndex((*itor).second.mIndex, ascending);
+ sortByColumnIndex((*itor).second->mIndex, ascending);
}
}
@@ -2419,11 +2421,11 @@ void LLScrollListCtrl::dirtyColumns()
// just in case someone indexes into it immediately
mColumnsIndexed.resize(mColumns.size());
- std::map<std::string, LLScrollListColumn>::iterator column_itor;
+ column_map_t::iterator column_itor;
for (column_itor = mColumns.begin(); column_itor != mColumns.end(); ++column_itor)
{
- LLScrollListColumn *column = &column_itor->second;
- mColumnsIndexed[column_itor->second.mIndex] = column;
+ LLScrollListColumn *column = column_itor->second;
+ mColumnsIndexed[column_itor->second->mIndex] = column;
}
}
@@ -2581,8 +2583,8 @@ void LLScrollListCtrl::addColumn(const LLScrollListColumn::Params& column_params
if (mColumns.find(name) == mColumns.end())
{
// Add column
- mColumns[name] = LLScrollListColumn(column_params, this);
- LLScrollListColumn* new_column = &mColumns[name];
+ mColumns[name] = new LLScrollListColumn(column_params, this);
+ LLScrollListColumn* new_column = mColumns[name];
new_column->mIndex = mColumns.size()-1;
// Add button
@@ -2604,14 +2606,14 @@ void LLScrollListCtrl::addColumn(const LLScrollListColumn::Params& column_params
S32 top = mItemListRect.mTop;
S32 left = mItemListRect.mLeft;
- for (std::map<std::string, LLScrollListColumn>::iterator itor = mColumns.begin();
+ for (column_map_t::iterator itor = mColumns.begin();
itor != mColumns.end();
++itor)
{
- if (itor->second.mIndex < new_column->mIndex &&
- itor->second.getWidth() > 0)
+ if (itor->second->mIndex < new_column->mIndex &&
+ itor->second->getWidth() > 0)
{
- left += itor->second.getWidth() + mColumnPadding;
+ left += itor->second->getWidth() + mColumnPadding;
}
}
@@ -2667,8 +2669,8 @@ void LLScrollListCtrl::onClickColumn(void *userdata)
if (column->mSortingColumn != column->mName
&& parent->mColumns.find(column->mSortingColumn) != parent->mColumns.end())
{
- LLScrollListColumn& info_redir = parent->mColumns[column->mSortingColumn];
- column_index = info_redir.mIndex;
+ LLScrollListColumn* info_redir = parent->mColumns[column->mSortingColumn];
+ column_index = info_redir->mIndex;
}
// if this column is the primary sort key, reverse the direction
@@ -2701,16 +2703,17 @@ BOOL LLScrollListCtrl::hasSortOrder() const
void LLScrollListCtrl::clearColumns()
{
- std::map<std::string, LLScrollListColumn>::iterator itor;
+ column_map_t::iterator itor;
for (itor = mColumns.begin(); itor != mColumns.end(); ++itor)
{
- LLScrollColumnHeader *header = itor->second.mHeader;
+ LLScrollColumnHeader *header = itor->second->mHeader;
if (header)
{
removeChild(header);
delete header;
}
}
+ std::for_each(mColumns.begin(), mColumns.end(), DeletePairedPointer());
mColumns.clear();
mSortColumns.clear();
mTotalStaticColumnWidth = 0;
@@ -2744,7 +2747,7 @@ LLScrollListColumn* LLScrollListCtrl::getColumn(const std::string& name)
column_map_t::iterator column_itor = mColumns.find(name);
if (column_itor != mColumns.end())
{
- return &column_itor->second;
+ return column_itor->second;
}
return NULL;
}
@@ -2805,7 +2808,7 @@ LLScrollListItem* LLScrollListCtrl::addRow(LLScrollListItem *new_item, const LLS
new_column.width.pixel_width = cell_p.width;
}
addColumn(new_column);
- columnp = &mColumns[column];
+ columnp = mColumns[column];
new_item->setNumColumns(mColumns.size());
}
@@ -2842,7 +2845,7 @@ LLScrollListItem* LLScrollListCtrl::addRow(LLScrollListItem *new_item, const LLS
LLScrollListCell* cell = LLScrollListCell::create(LLScrollListCell::Params().value(item_p.value));
if (cell)
{
- LLScrollListColumn* columnp = &(mColumns.begin()->second);
+ LLScrollListColumn* columnp = mColumns.begin()->second;
new_item->setColumn(0, cell);
if (columnp->mHeader
@@ -2857,10 +2860,10 @@ LLScrollListItem* LLScrollListCtrl::addRow(LLScrollListItem *new_item, const LLS
// add dummy cells for missing columns
for (column_map_t::iterator column_it = mColumns.begin(); column_it != mColumns.end(); ++column_it)
{
- S32 column_idx = column_it->second.mIndex;
+ S32 column_idx = column_it->second->mIndex;
if (new_item->getColumn(column_idx) == NULL)
{
- LLScrollListColumn* column_ptr = &column_it->second;
+ LLScrollListColumn* column_ptr = column_it->second;
LLScrollListCell::Params cell_p;
cell_p.width = column_ptr->getWidth();
diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h
index 8a2f893ba2..09ab89960d 100644
--- a/indra/llui/llscrolllistctrl.h
+++ b/indra/llui/llscrolllistctrl.h
@@ -491,7 +491,7 @@ private:
mutable bool mSorted;
- typedef std::map<std::string, LLScrollListColumn> column_map_t;
+ typedef std::map<std::string, LLScrollListColumn*> column_map_t;
column_map_t mColumns;
BOOL mDirty;
diff --git a/indra/llui/llsdparam.cpp b/indra/llui/llsdparam.cpp
index f97f80ab6c..9ad13054cb 100644
--- a/indra/llui/llsdparam.cpp
+++ b/indra/llui/llsdparam.cpp
@@ -45,6 +45,7 @@ LLParamSDParser::LLParamSDParser()
if (sReadFuncs.empty())
{
+ registerParserFuncs<LLInitParam::NoParamValue>(readNoValue, &LLParamSDParser::writeNoValue);
registerParserFuncs<S32>(readS32, &LLParamSDParser::writeTypedValue<S32>);
registerParserFuncs<U32>(readU32, &LLParamSDParser::writeU32Param);
registerParserFuncs<F32>(readF32, &LLParamSDParser::writeTypedValue<F32>);
@@ -71,6 +72,18 @@ bool LLParamSDParser::writeU32Param(LLParamSDParser::parser_t& parser, const voi
return true;
}
+bool LLParamSDParser::writeNoValue(LLParamSDParser::parser_t& parser, const void* val_ptr, const parser_t::name_stack_t& name_stack)
+{
+ LLParamSDParser& sdparser = static_cast<LLParamSDParser&>(parser);
+ if (!sdparser.mWriteRootSD) return false;
+
+ LLSD* sd_to_write = sdparser.getSDWriteNode(name_stack);
+ if (!sd_to_write) return false;
+
+ return true;
+}
+
+
void LLParamSDParser::readSD(const LLSD& sd, LLInitParam::BaseBlock& block, bool silent)
{
mCurReadSD = NULL;
@@ -87,6 +100,8 @@ void LLParamSDParser::writeSD(LLSD& sd, const LLInitParam::BaseBlock& block)
block.serializeBlock(*this);
}
+const LLSD NO_VALUE_MARKER;
+
void LLParamSDParser::readSDValues(const LLSD& sd, LLInitParam::BaseBlock& block)
{
if (sd.isMap())
@@ -110,6 +125,11 @@ void LLParamSDParser::readSDValues(const LLSD& sd, LLInitParam::BaseBlock& block
readSDValues(*it, block);
}
}
+ else if (sd.isUndefined())
+ {
+ mCurReadSD = &NO_VALUE_MARKER;
+ block.submitValue(mNameStack, *this);
+ }
else
{
mCurReadSD = &sd;
@@ -206,6 +226,13 @@ LLSD* LLParamSDParser::getSDWriteNode(const parser_t::name_stack_t& name_stack)
return sd_to_write;
}
+bool LLParamSDParser::readNoValue(Parser& parser, void* val_ptr)
+{
+ LLParamSDParser& self = static_cast<LLParamSDParser&>(parser);
+ return self.mCurReadSD == &NO_VALUE_MARKER;
+}
+
+
bool LLParamSDParser::readS32(Parser& parser, void* val_ptr)
{
LLParamSDParser& self = static_cast<LLParamSDParser&>(parser);
diff --git a/indra/llui/llsdparam.h b/indra/llui/llsdparam.h
index 97e8b58e49..69dab2b411 100644
--- a/indra/llui/llsdparam.h
+++ b/indra/llui/llsdparam.h
@@ -63,7 +63,9 @@ private:
LLSD* getSDWriteNode(const parser_t::name_stack_t& name_stack);
static bool writeU32Param(Parser& parser, const void* value_ptr, const parser_t::name_stack_t& name_stack);
+ static bool writeNoValue(Parser& parser, const void* value_ptr, const parser_t::name_stack_t& name_stack);
+ static bool readNoValue(Parser& parser, void* val_ptr);
static bool readS32(Parser& parser, void* val_ptr);
static bool readU32(Parser& parser, void* val_ptr);
static bool readF32(Parser& parser, void* val_ptr);
diff --git a/indra/llui/llslider.h b/indra/llui/llslider.h
index 68823ed68e..700c17ea3e 100644
--- a/indra/llui/llslider.h
+++ b/indra/llui/llslider.h
@@ -29,6 +29,7 @@
#include "llf32uictrl.h"
#include "v4color.h"
+#include "lluiimage.h"
class LLSlider : public LLF32UICtrl
{
diff --git a/indra/llui/llstyle.cpp b/indra/llui/llstyle.cpp
index 28a064e6b6..bb731f4f7e 100644
--- a/indra/llui/llstyle.cpp
+++ b/indra/llui/llstyle.cpp
@@ -88,7 +88,7 @@ void LLStyle::setVisible(BOOL is_visible)
mVisible = is_visible;
}
-LLUIImagePtr LLStyle::getImage() const
+LLPointer<LLUIImage> LLStyle::getImage() const
{
return mImagep;
}
diff --git a/indra/llui/llstyle.h b/indra/llui/llstyle.h
index 322edc343c..9f1eba79d8 100644
--- a/indra/llui/llstyle.h
+++ b/indra/llui/llstyle.h
@@ -30,6 +30,7 @@
#include "v4color.h"
#include "llui.h"
#include "llinitparam.h"
+#include "lluiimage.h"
class LLFontGL;
@@ -72,7 +73,7 @@ public:
void setLinkHREF(const std::string& href);
BOOL isLink() const;
- LLUIImagePtr getImage() const;
+ LLPointer<LLUIImage> getImage() const;
void setImage(const LLUUID& src);
void setImage(const std::string& name);
@@ -108,7 +109,7 @@ private:
const LLFontGL* mFont;
std::string mLink;
bool mIsLink;
- LLUIImagePtr mImagep;
+ LLPointer<LLUIImage> mImagep;
};
typedef LLPointer<LLStyle> LLStyleSP;
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index 9adeddca99..1cc3cc04d6 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,44 +994,68 @@ 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)
{
+ F32 alpha = getCurrentTransparency();
// clip background rect against extents, if we support scrolling
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, 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);
}
@@ -1139,7 +1164,7 @@ void LLTextBase::reflow()
S32 first_line = getFirstVisibleLine();
// if scroll anchor not on first line, update it to first character of first line
- if (!mLineInfoList.empty()
+ if ((first_line < mLineInfoList.size())
&& (mScrollIndex < mLineInfoList[first_line].mDocIndexStart
|| mScrollIndex >= mLineInfoList[first_line].mDocIndexEnd))
{
@@ -1414,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;
@@ -1423,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());
@@ -1591,7 +1616,10 @@ void LLTextBase::setText(const LLStringExplicit &utf8str, const LLStyle::Params&
// appendText modifies mCursorPos...
appendText(text, false, input_params);
// ...so move cursor to top after appending text
- startOfDoc();
+ if (!mTrackEnd)
+ {
+ startOfDoc();
+ }
onValueChange(0, getLength());
}
@@ -1622,7 +1650,7 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para
style_params.fillFrom(getDefaultStyleParams());
S32 part = (S32)LLTextParser::WHOLE;
- if(mParseHTML)
+ if (mParseHTML && !style_params.is_link) // Don't search for URLs inside a link segment (STORM-358).
{
S32 start=0,end=0;
LLUrlMatch match;
@@ -1630,6 +1658,9 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para
while ( LLUrlRegistry::instance().findUrl(text, match,
boost::bind(&LLTextBase::replaceUrl, this, _1, _2, _3)) )
{
+
+ LLTextUtil::processUrlMatch(&match,this);
+
start = match.getStart();
end = match.getEnd()+1;
@@ -1651,10 +1682,6 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para
std::string subtext=text.substr(0,start);
appendAndHighlightText(subtext, part, style_params);
}
-
- // inserts an avatar icon preceding the Url if appropriate
- LLTextUtil::processUrlMatch(&match,this);
-
// output the styled Url
appendAndHighlightTextImpl(match.getLabel(), part, link_params, match.underlineOnHoverOnly());
@@ -1994,11 +2021,10 @@ S32 LLTextBase::getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round,
pos = segment_line_start + offset;
break;
}
- else if (hit_past_end_of_line && segmentp->getEnd() > line_iter->mDocIndexEnd - 1)
+ else if (hit_past_end_of_line && segmentp->getEnd() >= line_iter->mDocIndexEnd)
{
// segment wraps to next line, so just set doc pos to the end of the line
- // segment wraps to next line, so just set doc pos to start of next line (represented by mDocIndexEnd)
- pos = llmin(getLength(), line_iter->mDocIndexEnd);
+ pos = llclamp(line_iter->mDocIndexEnd - 1, 0, getLength());
break;
}
start_x += text_width;
@@ -2214,19 +2240,39 @@ bool LLTextBase::scrolledToEnd()
return mScroller->isAtBottom();
}
-
bool LLTextBase::setCursor(S32 row, S32 column)
{
- if (0 <= row && row < (S32)mLineInfoList.size())
+ if (row < 0 || column < 0) return false;
+
+ S32 n_lines = mLineInfoList.size();
+ for (S32 line = row; line < n_lines; ++line)
{
- S32 doc_pos = mLineInfoList[row].mDocIndexStart;
- column = llclamp(column, 0, mLineInfoList[row].mDocIndexEnd - mLineInfoList[row].mDocIndexStart - 1);
- doc_pos += column;
- updateCursorXPos();
+ const line_info& li = mLineInfoList[line];
+
+ if (li.mLineNum < row)
+ {
+ continue;
+ }
+ else if (li.mLineNum > row)
+ {
+ break; // invalid column specified
+ }
+
+ // Found the given row.
+ S32 line_length = li.mDocIndexEnd - li.mDocIndexStart;;
+ if (column >= line_length)
+ {
+ column -= line_length;
+ continue;
+ }
+ // Found the given column.
+ updateCursorXPos();
+ S32 doc_pos = li.mDocIndexStart + column;
return setCursorPos(doc_pos);
}
- return false;
+
+ return false; // invalid row or column specified
}
@@ -2381,14 +2427,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;
}
}
@@ -2890,11 +2963,18 @@ bool LLImageTextSegment::getDimensions(S32 first_char, S32 num_chars, S32& width
S32 LLImageTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const
{
LLUIImagePtr image = mStyle->getImage();
+
+ if (image.isNull())
+ {
+ return 1;
+ }
+
S32 image_width = image->getWidth();
if(line_offset == 0 || num_pixels>image_width + IMAGE_HPAD)
{
return 1;
}
+
return 0;
}
@@ -2904,18 +2984,21 @@ F32 LLImageTextSegment::draw(S32 start, S32 end, S32 selection_start, S32 select
{
LLColor4 color = LLColor4::white % mEditor.getDrawContext().mAlpha;
LLUIImagePtr image = mStyle->getImage();
- S32 style_image_height = image->getHeight();
- S32 style_image_width = image->getWidth();
- // Text is drawn from the top of the draw_rect downward
-
- S32 text_center = draw_rect.mTop - (draw_rect.getHeight() / 2);
- // Align image to center of draw rect
- S32 image_bottom = text_center - (style_image_height / 2);
- image->draw(draw_rect.mLeft, image_bottom,
- style_image_width, style_image_height, color);
-
- const S32 IMAGE_HPAD = 3;
- return draw_rect.mLeft + style_image_width + IMAGE_HPAD;
+ if (image.notNull())
+ {
+ S32 style_image_height = image->getHeight();
+ S32 style_image_width = image->getWidth();
+ // Text is drawn from the top of the draw_rect downward
+
+ S32 text_center = draw_rect.mTop - (draw_rect.getHeight() / 2);
+ // Align image to center of draw rect
+ S32 image_bottom = text_center - (style_image_height / 2);
+ image->draw(draw_rect.mLeft, image_bottom,
+ style_image_width, style_image_height, color);
+
+ const S32 IMAGE_HPAD = 3;
+ return draw_rect.mLeft + style_image_width + IMAGE_HPAD;
+ }
}
return 0.0;
}
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/lltexteditor.cpp b/indra/llui/lltexteditor.cpp
index 94bf716e7d..9bd445988d 100644
--- a/indra/llui/lltexteditor.cpp
+++ b/indra/llui/lltexteditor.cpp
@@ -277,6 +277,8 @@ LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) :
mHPad += UI_TEXTEDITOR_LINE_NUMBER_MARGIN;
updateRects();
}
+
+ mParseOnTheFly = TRUE;
}
void LLTextEditor::initFromParams( const LLTextEditor::Params& p)
@@ -324,8 +326,10 @@ void LLTextEditor::setText(const LLStringExplicit &utf8str, const LLStyle::Param
blockUndo();
deselect();
-
+
+ mParseOnTheFly = FALSE;
LLTextBase::setText(utf8str, input_params);
+ mParseOnTheFly = TRUE;
resetDirty();
}
@@ -588,6 +592,10 @@ void LLTextEditor::indentSelectedLines( S32 spaces )
}
}
+ // Disabling parsing on the fly to avoid updating text segments
+ // until all indentation commands are executed.
+ mParseOnTheFly = FALSE;
+
// Find each start-of-line and indent it
do
{
@@ -613,6 +621,8 @@ void LLTextEditor::indentSelectedLines( S32 spaces )
}
while( cur < right );
+ mParseOnTheFly = TRUE;
+
if( (right < getLength()) && (text[right] == '\n') )
{
right++;
@@ -1367,6 +1377,7 @@ void LLTextEditor::pastePrimary()
// paste from primary (itsprimary==true) or clipboard (itsprimary==false)
void LLTextEditor::pasteHelper(bool is_primary)
{
+ mParseOnTheFly = FALSE;
bool can_paste_it;
if (is_primary)
{
@@ -1450,6 +1461,7 @@ void LLTextEditor::pasteHelper(bool is_primary)
deselect();
onKeyStroke();
+ mParseOnTheFly = TRUE;
}
@@ -2385,7 +2397,7 @@ void LLTextEditor::loadKeywords(const std::string& filename,
void LLTextEditor::updateSegments()
{
- if (mReflowIndex < S32_MAX && mKeywords.isLoaded())
+ if (mReflowIndex < S32_MAX && mKeywords.isLoaded() && mParseOnTheFly)
{
LLFastTimer ft(FTM_SYNTAX_HIGHLIGHTING);
// HACK: No non-ascii keywords for now
diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h
index 58ecefdccb..9e4b95003b 100644
--- a/indra/llui/lltexteditor.h
+++ b/indra/llui/lltexteditor.h
@@ -315,6 +315,7 @@ private:
BOOL mAllowEmbeddedItems;
bool mShowContextMenu;
+ bool mParseOnTheFly;
LLUUID mSourceID;
diff --git a/indra/llui/lltoggleablemenu.cpp b/indra/llui/lltoggleablemenu.cpp
index 0eb2dc1387..d29260750f 100644
--- a/indra/llui/lltoggleablemenu.cpp
+++ b/indra/llui/lltoggleablemenu.cpp
@@ -35,10 +35,22 @@ static LLDefaultChildRegistry::Register<LLToggleableMenu> r("toggleable_menu");
LLToggleableMenu::LLToggleableMenu(const LLToggleableMenu::Params& p)
: LLMenuGL(p),
mButtonRect(),
+ mVisibilityChangeSignal(NULL),
mClosedByButtonClick(false)
{
}
+LLToggleableMenu::~LLToggleableMenu()
+{
+ delete mVisibilityChangeSignal;
+}
+
+boost::signals2::connection LLToggleableMenu::setVisibilityChangeCallback(const commit_signal_t::slot_type& cb)
+{
+ if (!mVisibilityChangeSignal) mVisibilityChangeSignal = new commit_signal_t();
+ return mVisibilityChangeSignal->connect(cb);
+}
+
// virtual
void LLToggleableMenu::handleVisibilityChange (BOOL curVisibilityIn)
{
@@ -49,6 +61,12 @@ void LLToggleableMenu::handleVisibilityChange (BOOL curVisibilityIn)
{
mClosedByButtonClick = true;
}
+
+ if (mVisibilityChangeSignal)
+ {
+ (*mVisibilityChangeSignal)(this,
+ LLSD().with("visibility", curVisibilityIn).with("closed_by_button_click", mClosedByButtonClick));
+ }
}
void LLToggleableMenu::setButtonRect(const LLRect& rect, LLView* current_view)
diff --git a/indra/llui/lltoggleablemenu.h b/indra/llui/lltoggleablemenu.h
index f036cdfffb..2094bd776f 100644
--- a/indra/llui/lltoggleablemenu.h
+++ b/indra/llui/lltoggleablemenu.h
@@ -41,6 +41,10 @@ protected:
LLToggleableMenu(const Params&);
friend class LLUICtrlFactory;
public:
+ ~LLToggleableMenu();
+
+ boost::signals2::connection setVisibilityChangeCallback( const commit_signal_t::slot_type& cb );
+
virtual void handleVisibilityChange (BOOL curVisibilityIn);
const LLRect& getButtonRect() const { return mButtonRect; }
@@ -57,6 +61,7 @@ public:
protected:
bool mClosedByButtonClick;
LLRect mButtonRect;
+ commit_signal_t* mVisibilityChangeSignal;
};
#endif // LL_LLTOGGLEABLEMENU_H
diff --git a/indra/llui/lltransutil.cpp b/indra/llui/lltransutil.cpp
index 9d0ff9d5cb..58fa8a0828 100644
--- a/indra/llui/lltransutil.cpp
+++ b/indra/llui/lltransutil.cpp
@@ -26,10 +26,11 @@
#include "linden_common.h"
+#include "lltransutil.h"
+
#include "lltrans.h"
#include "lluictrlfactory.h"
-
-#include "lltransutil.h"
+#include "llxmlnode.h"
bool LLTransUtil::parseStrings(const std::string& xml_filename, const std::set<std::string>& default_args)
diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp
index ff9af21e54..8020ca802b 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
@@ -950,7 +952,7 @@ void gl_ring( F32 radius, F32 width, const LLColor4& center_color, const LLColor
}
// Draw gray and white checkerboard with black border
-void gl_rect_2d_checkerboard(const LLRect& rect)
+void gl_rect_2d_checkerboard(const LLRect& rect, GLfloat alpha)
{
// Initialize the first time this is called.
const S32 PIXELS = 32;
@@ -971,11 +973,11 @@ void gl_rect_2d_checkerboard(const LLRect& rect)
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
// ...white squares
- gGL.color3f( 1.f, 1.f, 1.f );
+ gGL.color4f( 1.f, 1.f, 1.f, alpha );
gl_rect_2d(rect);
// ...gray squares
- gGL.color3f( .7f, .7f, .7f );
+ gGL.color4f( .7f, .7f, .7f, alpha );
gGL.flush();
glPolygonStipple( checkerboard );
@@ -1596,23 +1598,25 @@ void LLUI::initClass(const settings_map_t& settings,
sWindow = NULL; // set later in startup
LLFontGL::sShadowColor = LLUIColorTable::instance().getColor("ColorDropShadow");
+ LLUICtrl::CommitCallbackRegistry::Registrar& reg = LLUICtrl::CommitCallbackRegistry::defaultRegistrar();
+
// Callbacks for associating controls with floater visibilty:
- LLUICtrl::CommitCallbackRegistry::defaultRegistrar().add("Floater.Toggle", boost::bind(&LLFloaterReg::toggleFloaterInstance, _2));
- LLUICtrl::CommitCallbackRegistry::defaultRegistrar().add("Floater.Show", boost::bind(&LLFloaterReg::showFloaterInstance, _2));
- LLUICtrl::CommitCallbackRegistry::defaultRegistrar().add("Floater.Hide", boost::bind(&LLFloaterReg::hideFloaterInstance, _2));
- LLUICtrl::CommitCallbackRegistry::defaultRegistrar().add("Floater.InitToVisibilityControl", boost::bind(&LLFloaterReg::initUICtrlToFloaterVisibilityControl, _1, _2));
+ reg.add("Floater.Toggle", boost::bind(&LLFloaterReg::toggleFloaterInstance, _2));
+ reg.add("Floater.Show", boost::bind(&LLFloaterReg::showFloaterInstance, _2));
+ reg.add("Floater.Hide", boost::bind(&LLFloaterReg::hideFloaterInstance, _2));
+ reg.add("Floater.InitToVisibilityControl", boost::bind(&LLFloaterReg::initUICtrlToFloaterVisibilityControl, _1, _2));
// Button initialization callback for toggle buttons
- LLUICtrl::CommitCallbackRegistry::defaultRegistrar().add("Button.SetFloaterToggle", boost::bind(&LLButton::setFloaterToggle, _1, _2));
+ reg.add("Button.SetFloaterToggle", boost::bind(&LLButton::setFloaterToggle, _1, _2));
// Button initialization callback for toggle buttons on dockale floaters
- LLUICtrl::CommitCallbackRegistry::defaultRegistrar().add("Button.SetDockableFloaterToggle", boost::bind(&LLButton::setDockableFloaterToggle, _1, _2));
+ reg.add("Button.SetDockableFloaterToggle", boost::bind(&LLButton::setDockableFloaterToggle, _1, _2));
// Display the help topic for the current context
- LLUICtrl::CommitCallbackRegistry::defaultRegistrar().add("Button.ShowHelp", boost::bind(&LLButton::showHelp, _1, _2));
+ reg.add("Button.ShowHelp", boost::bind(&LLButton::showHelp, _1, _2));
// Currently unused, but kept for reference:
- LLUICtrl::CommitCallbackRegistry::defaultRegistrar().add("Button.ToggleFloater", boost::bind(&LLButton::toggleFloaterAndSetToggleState, _1, _2));
+ reg.add("Button.ToggleFloater", boost::bind(&LLButton::toggleFloaterAndSetToggleState, _1, _2));
// Used by menus along with Floater.Toggle to display visibility as a checkmark
LLUICtrl::EnableCallbackRegistry::defaultRegistrar().add("Floater.Visible", boost::bind(&LLFloaterReg::floaterInstanceVisible, _2));
@@ -1620,8 +1624,11 @@ void LLUI::initClass(const settings_map_t& settings,
void LLUI::cleanupClass()
{
+ if(sImageProvider)
+ {
sImageProvider->cleanUp();
}
+}
void LLUI::setPopupFuncs(const add_popup_t& add_popup, const remove_popup_t& remove_popup, const clear_popups_t& clear_popups)
{
@@ -2015,37 +2022,84 @@ 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
namespace LLInitParam
{
- TypedParam<LLUIColor >::TypedParam(BlockDescriptor& descriptor, const char* name, const LLUIColor& value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count)
- : super_t(descriptor, name, value, func, min_count, max_count),
+ ParamValue<LLUIColor, TypeValues<LLUIColor> >::ParamValue(const LLUIColor& color)
+ : super_t(color),
red("red"),
green("green"),
blue("blue"),
alpha("alpha"),
control("")
{
- setBlockFromValue();
+ updateBlockFromValue();
}
- void TypedParam<LLUIColor>::setValueFromBlock() const
+ void ParamValue<LLUIColor, TypeValues<LLUIColor> >::updateValueFromBlock()
{
if (control.isProvided())
{
- mData.mValue = LLUIColorTable::instance().getColor(control);
+ updateValue(LLUIColorTable::instance().getColor(control));
}
else
{
- mData.mValue = LLColor4(red, green, blue, alpha);
+ updateValue(LLColor4(red, green, blue, alpha));
}
}
- void TypedParam<LLUIColor>::setBlockFromValue()
+ void ParamValue<LLUIColor, TypeValues<LLUIColor> >::updateBlockFromValue()
{
- LLColor4 color = mData.mValue.get();
+ LLColor4 color = getValue();
red.set(color.mV[VRED], false);
green.set(color.mV[VGREEN], false);
blue.set(color.mV[VBLUE], false);
@@ -2053,38 +2107,32 @@ namespace LLInitParam
control.set("", false);
}
- void TypeValues<LLUIColor>::declareValues()
- {
- declare("white", LLColor4::white);
- declare("black", LLColor4::black);
- declare("red", LLColor4::red);
- declare("green", LLColor4::green);
- declare("blue", LLColor4::blue);
- }
-
bool ParamCompare<const LLFontGL*, false>::equals(const LLFontGL* a, const LLFontGL* b)
{
return !(a->getFontDesc() < b->getFontDesc())
&& !(b->getFontDesc() < a->getFontDesc());
}
- TypedParam<const LLFontGL*>::TypedParam(BlockDescriptor& descriptor, const char* _name, const LLFontGL*const value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count)
- : super_t(descriptor, _name, value, func, min_count, max_count),
+ ParamValue<const LLFontGL*, TypeValues<const LLFontGL*> >::ParamValue(const LLFontGL* fontp)
+ : super_t(fontp),
name("name"),
size("size"),
style("style")
{
- setBlockFromValue();
+ if (!fontp)
+ {
+ updateValue(LLFontGL::getFontDefault());
+ }
addSynonym(name, "");
- setBlockFromValue();
+ updateBlockFromValue();
}
- void TypedParam<const LLFontGL*>::setValueFromBlock() const
+ void ParamValue<const LLFontGL*, TypeValues<const LLFontGL*> >::updateValueFromBlock()
{
const LLFontGL* res_fontp = LLFontGL::getFontByName(name);
if (res_fontp)
{
- mData.mValue = res_fontp;
+ updateValue(res_fontp);
return;
}
@@ -2094,22 +2142,26 @@ namespace LLInitParam
const LLFontGL* fontp = LLFontGL::getFont(desc);
if (fontp)
{
- mData.mValue = fontp;
- }
+ updateValue(fontp);
+ }
+ else
+ {
+ updateValue(LLFontGL::getFontDefault());
+ }
}
- void TypedParam<const LLFontGL*>::setBlockFromValue()
+ void ParamValue<const LLFontGL*, TypeValues<const LLFontGL*> >::updateBlockFromValue()
{
- if (mData.mValue)
+ if (getValue())
{
- name.set(LLFontGL::nameFromFont(mData.mValue), false);
- size.set(LLFontGL::sizeFromFont(mData.mValue), false);
- style.set(LLFontGL::getStringFromStyle(mData.mValue->getFontDesc().getStyle()), false);
+ name.set(LLFontGL::nameFromFont(getValue()), false);
+ size.set(LLFontGL::sizeFromFont(getValue()), false);
+ style.set(LLFontGL::getStringFromStyle(getValue()->getFontDesc().getStyle()), false);
}
}
- TypedParam<LLRect>::TypedParam(BlockDescriptor& descriptor, const char* name, const LLRect& value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count)
- : super_t(descriptor, name, value, func, min_count, max_count),
+ ParamValue<LLRect, TypeValues<LLRect> >::ParamValue(const LLRect& rect)
+ : super_t(rect),
left("left"),
top("top"),
right("right"),
@@ -2117,10 +2169,10 @@ namespace LLInitParam
width("width"),
height("height")
{
- setBlockFromValue();
+ updateBlockFromValue();
}
- void TypedParam<LLRect>::setValueFromBlock() const
+ void ParamValue<LLRect, TypeValues<LLRect> >::updateValueFromBlock()
{
LLRect rect;
@@ -2181,40 +2233,41 @@ namespace LLInitParam
rect.mBottom = bottom;
rect.mTop = top;
}
- mData.mValue = rect;
+ updateValue(rect);
}
- void TypedParam<LLRect>::setBlockFromValue()
+ void ParamValue<LLRect, TypeValues<LLRect> >::updateBlockFromValue()
{
// because of the ambiguity in specifying a rect by position and/or dimensions
// we clear the "provided" flag so that values from xui/etc have priority
// over those calculated from the rect object
- left.set(mData.mValue.mLeft, false);
- right.set(mData.mValue.mRight, false);
- bottom.set(mData.mValue.mBottom, false);
- top.set(mData.mValue.mTop, false);
- width.set(mData.mValue.getWidth(), false);
- height.set(mData.mValue.getHeight(), false);
+ LLRect& value = getValue();
+ left.set(value.mLeft, false);
+ right.set(value.mRight, false);
+ bottom.set(value.mBottom, false);
+ top.set(value.mTop, false);
+ width.set(value.getWidth(), false);
+ height.set(value.getHeight(), false);
}
- TypedParam<LLCoordGL>::TypedParam(BlockDescriptor& descriptor, const char* name, LLCoordGL value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count)
- : super_t(descriptor, name, value, func, min_count, max_count),
+ ParamValue<LLCoordGL, TypeValues<LLCoordGL> >::ParamValue(const LLCoordGL& coord)
+ : super_t(coord),
x("x"),
y("y")
{
- setBlockFromValue();
+ updateBlockFromValue();
}
- void TypedParam<LLCoordGL>::setValueFromBlock() const
+ void ParamValue<LLCoordGL, TypeValues<LLCoordGL> >::updateValueFromBlock()
{
- mData.mValue.set(x, y);
+ updateValue(LLCoordGL(x, y));
}
- void TypedParam<LLCoordGL>::setBlockFromValue()
+ void ParamValue<LLCoordGL, TypeValues<LLCoordGL> >::updateBlockFromValue()
{
- x.set(mData.mValue.mX, false);
- y.set(mData.mValue.mY, false);
+ x.set(getValue().mX, false);
+ y.set(getValue().mY, false);
}
diff --git a/indra/llui/llui.h b/indra/llui/llui.h
index fc545c85d5..c583d58d5a 100644
--- a/indra/llui/llui.h
+++ b/indra/llui/llui.h
@@ -33,15 +33,12 @@
#include "llrect.h"
#include "llcontrol.h"
#include "llcoord.h"
-#include "lluiimage.h" // *TODO: break this dependency, need to add #include "lluiimage.h" to all widgets that hold an Optional<LLUIImage*> in their paramblocks
#include "llinitparam.h"
#include "llregistry.h"
#include "lluicolor.h"
#include "lluicolortable.h"
#include <boost/signals2.hpp>
#include "lllazyvalue.h"
-#include "llhandle.h" // *TODO: remove this dependency, added as a
- // convenience when LLHandle moved to llhandle.h
#include "llframetimer.h"
// LLUIFactory
@@ -79,7 +76,7 @@ void gl_rect_2d_offset_local( S32 left, S32 top, S32 right, S32 bottom, const LL
void gl_rect_2d_offset_local( S32 left, S32 top, S32 right, S32 bottom, S32 pixel_offset = 0, BOOL filled = TRUE );
void gl_rect_2d(const LLRect& rect, BOOL filled = TRUE );
void gl_rect_2d(const LLRect& rect, const LLColor4& color, BOOL filled = TRUE );
-void gl_rect_2d_checkerboard(const LLRect& rect);
+void gl_rect_2d_checkerboard(const LLRect& rect, GLfloat alpha = 1.0f);
void gl_drop_shadow(S32 left, S32 top, S32 right, S32 bottom, const LLColor4 &start_color, S32 lines);
@@ -185,6 +182,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);
@@ -238,8 +262,6 @@ private:
// Moved LLLocalClipRect to lllocalcliprect.h
-// Moved all LLHandle-related code to llhandle.h
-
//RN: maybe this needs to moved elsewhere?
class LLImageProviderInterface
{
@@ -371,10 +393,10 @@ public:
namespace LLInitParam
{
template<>
- class TypedParam<LLRect>
- : public BlockValue<LLRect>
+ class ParamValue<LLRect, TypeValues<LLRect> >
+ : public CustomParamValue<LLRect>
{
- typedef BlockValue<LLRect> super_t;
+ typedef CustomParamValue<LLRect> super_t;
public:
Optional<S32> left,
top,
@@ -383,62 +405,43 @@ namespace LLInitParam
width,
height;
- TypedParam(BlockDescriptor& descriptor, const char* name, const LLRect& value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count);
+ ParamValue(const LLRect& value);
- void setValueFromBlock() const;
- void setBlockFromValue();
+ void updateValueFromBlock();
+ void updateBlockFromValue();
};
template<>
- struct TypeValues<LLUIColor> : public TypeValuesHelper<LLUIColor>
+ class ParamValue<LLUIColor, TypeValues<LLUIColor> >
+ : public CustomParamValue<LLUIColor>
{
- static void declareValues();
- };
+ typedef CustomParamValue<LLUIColor> super_t;
- template<>
- class TypedParam<LLUIColor>
- : public BlockValue<LLUIColor>
- {
- typedef BlockValue<LLUIColor> super_t;
public:
- Optional<F32> red,
- green,
- blue,
- alpha;
- Optional<std::string> control;
-
- TypedParam(BlockDescriptor& descriptor, const char* name, const LLUIColor& value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count);
- void setValueFromBlock() const;
- void setBlockFromValue();
+ Optional<F32> red,
+ green,
+ blue,
+ alpha;
+ Optional<std::string> control;
+
+ ParamValue(const LLUIColor& color);
+ void updateValueFromBlock();
+ void updateBlockFromValue();
};
- // provide a better default for Optional<const LLFontGL*> than NULL
- template <>
- struct DefaultInitializer<const LLFontGL*>
- {
- // return reference to a single default instance of T
- // built-in types will be initialized to zero, default constructor otherwise
- static const LLFontGL* get()
- {
- static const LLFontGL* sDefaultFont = LLFontGL::getFontDefault();
- return sDefaultFont;
- }
- };
-
-
template<>
- class TypedParam<const LLFontGL*>
- : public BlockValue<const LLFontGL*>
+ class ParamValue<const LLFontGL*, TypeValues<const LLFontGL*> >
+ : public CustomParamValue<const LLFontGL* >
{
- typedef BlockValue<const LLFontGL*> super_t;
+ typedef CustomParamValue<const LLFontGL*> super_t;
public:
Optional<std::string> name,
size,
style;
- TypedParam(BlockDescriptor& descriptor, const char* name, const LLFontGL* const value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count);
- void setValueFromBlock() const;
- void setBlockFromValue();
+ ParamValue(const LLFontGL* value);
+ void updateValueFromBlock();
+ void updateBlockFromValue();
};
template<>
@@ -467,17 +470,17 @@ namespace LLInitParam
template<>
- class TypedParam<LLCoordGL>
- : public BlockValue<LLCoordGL>
+ class ParamValue<LLCoordGL, TypeValues<LLCoordGL> >
+ : public CustomParamValue<LLCoordGL>
{
- typedef BlockValue<LLCoordGL> super_t;
+ typedef CustomParamValue<LLCoordGL> super_t;
public:
Optional<S32> x,
y;
- TypedParam(BlockDescriptor& descriptor, const char* name, LLCoordGL value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count);
- void setValueFromBlock() const;
- void setBlockFromValue();
+ ParamValue(const LLCoordGL& val);
+ void updateValueFromBlock();
+ void updateBlockFromValue();
};
}
diff --git a/indra/llui/lluicolortable.cpp b/indra/llui/lluicolortable.cpp
index 0641f6d175..9455d09cc0 100644
--- a/indra/llui/lluicolortable.cpp
+++ b/indra/llui/lluicolortable.cpp
@@ -215,6 +215,12 @@ bool LLUIColorTable::loadFromSettings()
result |= loadFromFilename(current_filename, mLoadedColors);
}
+ current_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SKIN, "colors.xml");
+ if(current_filename != default_filename)
+ {
+ result |= loadFromFilename(current_filename, mLoadedColors);
+ }
+
std::string user_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "colors.xml");
loadFromFilename(user_filename, mUserSetColors);
diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp
index 3ac3bf8c41..0a06b5e74f 100644
--- a/indra/llui/lluictrl.cpp
+++ b/indra/llui/lluictrl.cpp
@@ -36,6 +36,9 @@
static LLDefaultChildRegistry::Register<LLUICtrl> r("ui_ctrl");
+F32 LLUICtrl::sActiveControlTransparency = 1.0f;
+F32 LLUICtrl::sInactiveControlTransparency = 1.0f;
+
// Compiler optimization, generate extern template
template class LLUICtrl* LLView::getChild<class LLUICtrl>(
const std::string& name, BOOL recurse) const;
@@ -110,7 +113,8 @@ LLUICtrl::LLUICtrl(const LLUICtrl::Params& p, const LLViewModelPtr& viewmodel)
mMouseUpSignal(NULL),
mRightMouseDownSignal(NULL),
mRightMouseUpSignal(NULL),
- mDoubleClickSignal(NULL)
+ mDoubleClickSignal(NULL),
+ mTransparencyType(TT_DEFAULT)
{
mUICtrlHandle.bind(this);
}
@@ -823,7 +827,7 @@ LLUICtrl* LLUICtrl::findRootMostFocusRoot()
{
LLUICtrl* focus_root = NULL;
LLUICtrl* next_view = this;
- while(next_view)
+ while(next_view && next_view->hasTabStop())
{
if (next_view->isFocusRoot())
{
@@ -923,6 +927,37 @@ BOOL LLUICtrl::getTentative() const
void LLUICtrl::setColor(const LLColor4& color)
{ }
+F32 LLUICtrl::getCurrentTransparency()
+{
+ F32 alpha = 0;
+
+ switch(mTransparencyType)
+ {
+ case TT_DEFAULT:
+ alpha = getDrawContext().mAlpha;
+ break;
+
+ case TT_ACTIVE:
+ alpha = sActiveControlTransparency;
+ break;
+
+ case TT_INACTIVE:
+ alpha = sInactiveControlTransparency;
+ break;
+
+ case TT_FADING:
+ alpha = sInactiveControlTransparency / 2;
+ break;
+ }
+
+ return alpha;
+}
+
+void LLUICtrl::setTransparencyType(ETypeTransparency type)
+{
+ mTransparencyType = type;
+}
+
boost::signals2::connection LLUICtrl::setCommitCallback( const commit_signal_t::slot_type& cb )
{
if (!mCommitSignal) mCommitSignal = new commit_signal_t();
diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h
index 76dfdf754c..b37e9f6b1b 100644
--- a/indra/llui/lluictrl.h
+++ b/indra/llui/lluictrl.h
@@ -120,6 +120,13 @@ public:
Params();
};
+ enum ETypeTransparency
+ {
+ TT_DEFAULT,
+ TT_ACTIVE, // focused floater
+ TT_INACTIVE, // other floaters
+ TT_FADING, // fading toast
+ };
/*virtual*/ ~LLUICtrl();
void initFromParams(const Params& p);
@@ -202,6 +209,11 @@ public:
virtual void setColor(const LLColor4& color);
+ F32 getCurrentTransparency();
+
+ void setTransparencyType(ETypeTransparency type);
+ ETypeTransparency getTransparencyType() const {return mTransparencyType;}
+
BOOL focusNextItem(BOOL text_entry_only);
BOOL focusPrevItem(BOOL text_entry_only);
BOOL focusFirstItem(BOOL prefer_text_fields = FALSE, BOOL focus_flash = TRUE );
@@ -283,6 +295,10 @@ protected:
boost::signals2::connection mMakeVisibleControlConnection;
LLControlVariable* mMakeInvisibleControlVariable;
boost::signals2::connection mMakeInvisibleControlConnection;
+
+ static F32 sActiveControlTransparency;
+ static F32 sInactiveControlTransparency;
+
private:
BOOL mTabStop;
@@ -290,6 +306,8 @@ private:
BOOL mTentative;
LLRootHandle<LLUICtrl> mUICtrlHandle;
+ ETypeTransparency mTransparencyType;
+
class DefaultTabGroupFirstSorter;
};
diff --git a/indra/llui/lluictrlfactory.cpp b/indra/llui/lluictrlfactory.cpp
index 5de96f9d48..25e7a31e90 100644
--- a/indra/llui/lluictrlfactory.cpp
+++ b/indra/llui/lluictrlfactory.cpp
@@ -152,7 +152,27 @@ static LLFastTimer::DeclareTimer FTM_XML_PARSE("XML Reading/Parsing");
bool LLUICtrlFactory::getLayeredXMLNode(const std::string &xui_filename, LLXMLNodePtr& root)
{
LLFastTimer timer(FTM_XML_PARSE);
- return LLXMLNode::getLayeredXMLNode(xui_filename, root, LLUI::getXUIPaths());
+
+ std::vector<std::string> paths;
+ std::string path = gDirUtilp->findSkinnedFilename(LLUI::getSkinPath(), xui_filename);
+ if (!path.empty())
+ {
+ paths.push_back(path);
+ }
+
+ std::string localize_path = gDirUtilp->findSkinnedFilename(LLUI::getLocalizedSkinPath(), xui_filename);
+ if (!localize_path.empty() && localize_path != path)
+ {
+ paths.push_back(localize_path);
+ }
+
+ if (paths.empty())
+ {
+ // sometimes whole path is passed in as filename
+ paths.push_back(xui_filename);
+ }
+
+ return LLXMLNode::getLayeredXMLNode(root, paths);
}
@@ -214,7 +234,7 @@ LLView *LLUICtrlFactory::createFromXML(LLXMLNodePtr node, LLView* parent, const
std::string LLUICtrlFactory::getCurFileName()
{
- return mFileNames.empty() ? "" : gDirUtilp->getWorkingDir() + gDirUtilp->getDirDelimiter() + mFileNames.back();
+ return mFileNames.empty() ? "" : mFileNames.back();
}
diff --git a/indra/llui/lluiimage.cpp b/indra/llui/lluiimage.cpp
index 1ffad4806e..f37947a50b 100644
--- a/indra/llui/lluiimage.cpp
+++ b/indra/llui/lluiimage.cpp
@@ -155,32 +155,32 @@ void LLUIImage::onImageLoaded()
namespace LLInitParam
{
- void TypedParam<LLUIImage*>::setValueFromBlock() const
+ void ParamValue<LLUIImage*, TypeValues<LLUIImage*> >::updateValueFromBlock()
{
// The keyword "none" is specifically requesting a null image
// do not default to current value. Used to overwrite template images.
if (name() == "none")
{
- mData.mValue = NULL;
+ updateValue(NULL);
return;
}
LLUIImage* imagep = LLUI::getUIImage(name());
if (imagep)
{
- mData.mValue = imagep;
+ updateValue(imagep);
}
}
- void TypedParam<LLUIImage*>::setBlockFromValue()
+ void ParamValue<LLUIImage*, TypeValues<LLUIImage*> >::updateBlockFromValue()
{
- if (mData.mValue == NULL)
+ if (getValue() == NULL)
{
name.set("none", false);
}
else
{
- name.set(mData.mValue->getName(), false);
+ name.set(getValue()->getName(), false);
}
}
diff --git a/indra/llui/lluiimage.h b/indra/llui/lluiimage.h
index 38107c112d..139d88e0ac 100644
--- a/indra/llui/lluiimage.h
+++ b/indra/llui/lluiimage.h
@@ -92,22 +92,23 @@ protected:
namespace LLInitParam
{
template<>
- class TypedParam<LLUIImage*, TypeValues<LLUIImage*>, false>
- : public BlockValue<LLUIImage*>
+ class ParamValue<LLUIImage*, TypeValues<LLUIImage*> >
+ : public CustomParamValue<LLUIImage*>
{
typedef boost::add_reference<boost::add_const<LLUIImage*>::type>::type T_const_ref;
- typedef BlockValue<LLUIImage*> super_t;
+ typedef CustomParamValue<LLUIImage*> super_t;
public:
Optional<std::string> name;
- TypedParam(BlockDescriptor& descriptor, const char* name, super_t::value_assignment_t value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count)
- : super_t(descriptor, name, value, func, min_count, max_count)
+ ParamValue(LLUIImage* const& image)
+ : super_t(image)
{
- setBlockFromValue();
+ updateBlockFromValue();
+ addSynonym(name, "name");
}
- void setValueFromBlock() const;
- void setBlockFromValue();
+ void updateValueFromBlock();
+ void updateBlockFromValue();
};
// Need custom comparison function for our test app, which only loads
diff --git a/indra/llui/lluistring.h b/indra/llui/lluistring.h
index eff2467bf0..cb40c85582 100644
--- a/indra/llui/lluistring.h
+++ b/indra/llui/lluistring.h
@@ -58,9 +58,10 @@ class LLUIString
public:
// These methods all perform appropriate argument substitution
// and modify mOrig where appropriate
- LLUIString() : mArgs(NULL), mNeedsResult(false), mNeedsWResult(false) {}
+ LLUIString() : mArgs(NULL), mNeedsResult(false), mNeedsWResult(false) {}
LLUIString(const std::string& instring, const LLStringUtil::format_map_t& args);
LLUIString(const std::string& instring) : mArgs(NULL) { assign(instring); }
+ ~LLUIString() { delete mArgs; }
void assign(const std::string& instring);
LLUIString& operator=(const std::string& s) { assign(s); return *this; }
@@ -81,14 +82,14 @@ public:
void clear();
void clearArgs() { if (mArgs) mArgs->clear(); }
-
+
// These utility functions are included for text editing.
// They do not affect mOrig and do not perform argument substitution
void truncate(S32 maxchars);
void erase(S32 charidx, S32 len);
void insert(S32 charidx, const LLWString& wchars);
void replace(S32 charidx, llwchar wc);
-
+
private:
// something changed, requiring reformatting of strings
void dirty();
@@ -100,7 +101,7 @@ private:
void updateResult() const;
void updateWResult() const;
LLStringUtil::format_map_t& getArgs();
-
+
std::string mOrig;
mutable std::string mResult;
mutable LLWString mWResult; // for displaying
diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp
index efb3f1a8be..9db1feafd1 100644
--- a/indra/llui/llurlentry.cpp
+++ b/indra/llui/llurlentry.cpp
@@ -27,6 +27,7 @@
#include "linden_common.h"
#include "llurlentry.h"
+#include "lluictrl.h"
#include "lluri.h"
#include "llurlmatch.h"
#include "llurlregistry.h"
@@ -35,6 +36,7 @@
#include "llcachename.h"
#include "lltrans.h"
#include "lluicolortable.h"
+#include "message.h"
#define APP_HEADER_REGEX "((x-grid-location-info://[-\\w\\.]+/app)|(secondlife:///app))"
@@ -167,6 +169,15 @@ void LLUrlEntryBase::callObservers(const std::string &id,
}
}
+/// is this a match for a URL that should not be hyperlinked?
+bool LLUrlEntryBase::isLinkDisabled() const
+{
+ // this allows us to have a global setting to turn off text hyperlink highlighting/action
+ bool globally_disabled = LLUI::sSettingGroups["config"]->getBOOL("DisableTextHyperlinkActions");
+
+ return globally_disabled;
+}
+
static std::string getStringAfterToken(const std::string str, const std::string token)
{
size_t pos = str.find(token);
@@ -456,8 +467,8 @@ std::string LLUrlEntryAgent::getLabel(const std::string &url, const LLUrlLabelCa
LLStyle::Params LLUrlEntryAgent::getStyle() const
{
LLStyle::Params style_params = LLUrlEntryBase::getStyle();
- style_params.color = LLUIColorTable::instance().getColor("AgentLinkColor");
- style_params.readonly_color = LLUIColorTable::instance().getColor("AgentLinkColor");
+ style_params.color = LLUIColorTable::instance().getColor("HTMLLinkColor");
+ style_params.readonly_color = LLUIColorTable::instance().getColor("HTMLLinkColor");
return style_params;
}
@@ -674,8 +685,8 @@ std::string LLUrlEntryGroup::getLabel(const std::string &url, const LLUrlLabelCa
LLStyle::Params LLUrlEntryGroup::getStyle() const
{
LLStyle::Params style_params = LLUrlEntryBase::getStyle();
- style_params.color = LLUIColorTable::instance().getColor("GroupLinkColor");
- style_params.readonly_color = LLUIColorTable::instance().getColor("GroupLinkColor");
+ style_params.color = LLUIColorTable::instance().getColor("HTMLLinkColor");
+ style_params.readonly_color = LLUIColorTable::instance().getColor("HTMLLinkColor");
return style_params;
}
@@ -730,6 +741,13 @@ std::string LLUrlEntryObjectIM::getLocation(const std::string &url) const
return LLUrlEntryBase::getLocation(url);
}
+// LLUrlEntryParcel statics.
+LLUUID LLUrlEntryParcel::sAgentID(LLUUID::null);
+LLUUID LLUrlEntryParcel::sSessionID(LLUUID::null);
+LLHost LLUrlEntryParcel::sRegionHost(LLHost::invalid);
+bool LLUrlEntryParcel::sDisconnected(false);
+std::set<LLUrlEntryParcel*> LLUrlEntryParcel::sParcelInfoObservers;
+
///
/// LLUrlEntryParcel Describes a Second Life parcel Url, e.g.,
/// secondlife:///app/parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/about
@@ -741,13 +759,88 @@ LLUrlEntryParcel::LLUrlEntryParcel()
boost::regex::perl|boost::regex::icase);
mMenuName = "menu_url_parcel.xml";
mTooltip = LLTrans::getString("TooltipParcelUrl");
+
+ sParcelInfoObservers.insert(this);
+}
+
+LLUrlEntryParcel::~LLUrlEntryParcel()
+{
+ sParcelInfoObservers.erase(this);
}
std::string LLUrlEntryParcel::getLabel(const std::string &url, const LLUrlLabelCallback &cb)
{
+ LLSD path_array = LLURI(url).pathArray();
+ S32 path_parts = path_array.size();
+
+ if (path_parts < 3) // no parcel id
+ {
+ llwarns << "Failed to parse url [" << url << "]" << llendl;
+ return url;
+ }
+
+ std::string parcel_id_string = unescapeUrl(path_array[2]); // parcel id
+
+ // Add an observer to call LLUrlLabelCallback when we have parcel name.
+ addObserver(parcel_id_string, url, cb);
+
+ LLUUID parcel_id(parcel_id_string);
+
+ sendParcelInfoRequest(parcel_id);
+
return unescapeUrl(url);
}
+void LLUrlEntryParcel::sendParcelInfoRequest(const LLUUID& parcel_id)
+{
+ if (sRegionHost == LLHost::invalid || sDisconnected) return;
+
+ LLMessageSystem *msg = gMessageSystem;
+ msg->newMessage("ParcelInfoRequest");
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, sAgentID );
+ msg->addUUID("SessionID", sSessionID);
+ msg->nextBlock("Data");
+ msg->addUUID("ParcelID", parcel_id);
+ msg->sendReliable(sRegionHost);
+}
+
+void LLUrlEntryParcel::onParcelInfoReceived(const std::string &id, const std::string &label)
+{
+ callObservers(id, label.empty() ? LLTrans::getString("RegionInfoError") : label, mIcon);
+}
+
+// static
+void LLUrlEntryParcel::processParcelInfo(const LLParcelData& parcel_data)
+{
+ std::string label(LLStringUtil::null);
+ if (!parcel_data.name.empty())
+ {
+ label = parcel_data.name;
+ }
+ // If parcel name is empty use Sim_name (x, y, z) for parcel label.
+ else if (!parcel_data.sim_name.empty())
+ {
+ S32 region_x = llround(parcel_data.global_x) % REGION_WIDTH_UNITS;
+ S32 region_y = llround(parcel_data.global_y) % REGION_WIDTH_UNITS;
+ S32 region_z = llround(parcel_data.global_z);
+
+ label = llformat("%s (%d, %d, %d)",
+ parcel_data.sim_name.c_str(), region_x, region_y, region_z);
+ }
+
+ for (std::set<LLUrlEntryParcel*>::iterator iter = sParcelInfoObservers.begin();
+ iter != sParcelInfoObservers.end();
+ ++iter)
+ {
+ LLUrlEntryParcel* url_entry = *iter;
+ if (url_entry)
+ {
+ url_entry->onParcelInfoReceived(parcel_data.parcel_id.asString(), label);
+ }
+ }
+}
+
//
// LLUrlEntryPlace Describes secondlife://<location> URLs
//
@@ -796,6 +889,69 @@ std::string LLUrlEntryPlace::getLocation(const std::string &url) const
}
//
+// LLUrlEntryRegion Describes secondlife:///app/region/REGION_NAME/X/Y/Z URLs, e.g.
+// secondlife:///app/region/Ahern/128/128/0
+//
+LLUrlEntryRegion::LLUrlEntryRegion()
+{
+ mPattern = boost::regex("secondlife:///app/region/[^/\\s]+(/\\d+)?(/\\d+)?(/\\d+)?/?",
+ boost::regex::perl|boost::regex::icase);
+ mMenuName = "menu_url_slurl.xml";
+ mTooltip = LLTrans::getString("TooltipSLURL");
+}
+
+std::string LLUrlEntryRegion::getLabel(const std::string &url, const LLUrlLabelCallback &cb)
+{
+ //
+ // we handle SLURLs in the following formats:
+ // - secondlife:///app/region/Place/X/Y/Z
+ // - secondlife:///app/region/Place/X/Y
+ // - secondlife:///app/region/Place/X
+ // - secondlife:///app/region/Place
+ //
+
+ LLSD path_array = LLURI(url).pathArray();
+ S32 path_parts = path_array.size();
+
+ if (path_parts < 3) // no region name
+ {
+ llwarns << "Failed to parse url [" << url << "]" << llendl;
+ return url;
+ }
+
+ std::string label = unescapeUrl(path_array[2]); // region name
+
+ if (path_parts > 3) // secondlife:///app/region/Place/X
+ {
+ std::string x = path_array[3];
+ label += " (" + x;
+
+ if (path_parts > 4) // secondlife:///app/region/Place/X/Y
+ {
+ std::string y = path_array[4];
+ label += "," + y;
+
+ if (path_parts > 5) // secondlife:///app/region/Place/X/Y/Z
+ {
+ std::string z = path_array[5];
+ label = label + "," + z;
+ }
+ }
+
+ label += ")";
+ }
+
+ return label;
+}
+
+std::string LLUrlEntryRegion::getLocation(const std::string &url) const
+{
+ LLSD path_array = LLURI(url).pathArray();
+ std::string region_name = unescapeUrl(path_array[2]);
+ return region_name;
+}
+
+//
// LLUrlEntryTeleport Describes a Second Life teleport Url, e.g.,
// secondlife:///app/teleport/Ahern/50/50/50/
// x-grid-location-info://lincoln.lindenlab.com/app/teleport/Ahern/50/50/50/
@@ -978,7 +1134,7 @@ std::string LLUrlEntryWorldMap::getLocation(const std::string &url) const
//
LLUrlEntryNoLink::LLUrlEntryNoLink()
{
- mPattern = boost::regex("<nolink>[^<]*</nolink>",
+ mPattern = boost::regex("<nolink>.*</nolink>",
boost::regex::perl|boost::regex::icase);
}
@@ -995,7 +1151,8 @@ std::string LLUrlEntryNoLink::getLabel(const std::string &url, const LLUrlLabelC
LLStyle::Params LLUrlEntryNoLink::getStyle() const
{
- return LLStyle::Params();
+ // Don't render as URL (i.e. no context menu or hand cursor).
+ return LLStyle::Params().is_link(false);
}
diff --git a/indra/llui/llurlentry.h b/indra/llui/llurlentry.h
index 9b91c103ef..5f82721c0f 100644
--- a/indra/llui/llurlentry.h
+++ b/indra/llui/llurlentry.h
@@ -31,6 +31,9 @@
#include "lluuid.h"
#include "lluicolor.h"
#include "llstyle.h"
+
+#include "llhost.h" // for resolving parcel name by parcel id
+
#include <boost/signals2.hpp>
#include <boost/regex.hpp>
#include <string>
@@ -94,6 +97,8 @@ public:
virtual LLUUID getID(const std::string &string) const { return LLUUID::null; }
+ bool isLinkDisabled() const;
+
protected:
std::string getIDStringFromUrl(const std::string &url) const;
std::string escapeUrl(const std::string &url) const;
@@ -183,7 +188,7 @@ private:
/// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/(completename|displayname|username)
/// that displays various forms of user name
/// This is a base class for the various implementations of name display
-class LLUrlEntryAgentName : public LLUrlEntryBase
+class LLUrlEntryAgentName : public LLUrlEntryBase, public boost::signals2::trackable
{
public:
LLUrlEntryAgentName();
@@ -283,8 +288,44 @@ private:
class LLUrlEntryParcel : public LLUrlEntryBase
{
public:
+ struct LLParcelData
+ {
+ LLUUID parcel_id;
+ std::string name;
+ std::string sim_name;
+ F32 global_x;
+ F32 global_y;
+ F32 global_z;
+ };
+
LLUrlEntryParcel();
+ ~LLUrlEntryParcel();
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
+
+ // Sends a parcel info request to sim.
+ void sendParcelInfoRequest(const LLUUID& parcel_id);
+
+ // Calls observers of certain parcel id providing them with parcel label.
+ void onParcelInfoReceived(const std::string &id, const std::string &label);
+
+ // Processes parcel label and triggers notifying observers.
+ static void processParcelInfo(const LLParcelData& parcel_data);
+
+ // Next 4 setters are used to update agent and viewer connection information
+ // upon events like user login, viewer disconnect and user changing region host.
+ // These setters are made public to be accessible from newview and should not be
+ // used in other cases.
+ static void setAgentID(const LLUUID& id) { sAgentID = id; }
+ static void setSessionID(const LLUUID& id) { sSessionID = id; }
+ static void setRegionHost(const LLHost& host) { sRegionHost = host; }
+ static void setDisconnected(bool disconnected) { sDisconnected = disconnected; }
+
+private:
+ static LLUUID sAgentID;
+ static LLUUID sSessionID;
+ static LLHost sRegionHost;
+ static bool sDisconnected;
+ static std::set<LLUrlEntryParcel*> sParcelInfoObservers;
};
///
@@ -300,6 +341,18 @@ public:
};
///
+/// LLUrlEntryRegion Describes a Second Life location Url, e.g.,
+/// secondlife:///app/region/Ahern/128/128/0
+///
+class LLUrlEntryRegion : public LLUrlEntryBase
+{
+public:
+ LLUrlEntryRegion();
+ /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
+ /*virtual*/ std::string getLocation(const std::string &url) const;
+};
+
+///
/// LLUrlEntryTeleport Describes a Second Life teleport Url, e.g.,
/// secondlife:///app/teleport/Ahern/50/50/50/
///
diff --git a/indra/llui/llurlregistry.cpp b/indra/llui/llurlregistry.cpp
index 478b412d5e..523ee5d78c 100644
--- a/indra/llui/llurlregistry.cpp
+++ b/indra/llui/llurlregistry.cpp
@@ -54,6 +54,7 @@ LLUrlRegistry::LLUrlRegistry()
registerUrl(new LLUrlEntryGroup());
registerUrl(new LLUrlEntryParcel());
registerUrl(new LLUrlEntryTeleport());
+ registerUrl(new LLUrlEntryRegion());
registerUrl(new LLUrlEntryWorldMap());
registerUrl(new LLUrlEntryObjectIM());
registerUrl(new LLUrlEntryPlace());
diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp
index 3fa86bf0ca..245126d178 100644
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -102,6 +102,7 @@ LLView::Params::Params()
left_pad("left_pad"),
left_delta("left_delta", S32_MAX),
from_xui("from_xui", false),
+ focus_root("focus_root", false),
needs_translate("translate"),
xmlns("xmlns"),
xmlns_xsi("xmlns:xsi"),
@@ -113,16 +114,16 @@ LLView::Params::Params()
}
LLView::LLView(const LLView::Params& p)
-: mName(p.name),
+: mVisible(p.visible),
+ mName(p.name),
mParentView(NULL),
mReshapeFlags(FOLLOWS_NONE),
mFromXUI(p.from_xui),
- mIsFocusRoot(FALSE),
+ mIsFocusRoot(p.focus_root),
mLastVisible(FALSE),
mNextInsertionOrdinal(0),
mHoverCursor(getCursorFromString(p.hover_cursor)),
mEnabled(p.enabled),
- mVisible(p.visible),
mMouseOpaque(p.mouse_opaque),
mSoundFlags(p.sound_flags),
mUseBoundingRect(p.use_bounding_rect),
@@ -163,8 +164,6 @@ LLView::~LLView()
if (mDefaultWidgets)
{
- std::for_each(mDefaultWidgets->begin(), mDefaultWidgets->end(),
- DeletePairedPointer());
delete mDefaultWidgets;
mDefaultWidgets = NULL;
}
@@ -339,7 +338,7 @@ void LLView::removeChild(LLView* child)
}
else
{
- llerrs << "LLView::removeChild called with non-child" << llendl;
+ llwarns << child->getName() << "is not a child of " << getName() << llendl;
}
updateBoundingRect();
}
@@ -1300,7 +1299,13 @@ void LLView::drawChildren()
{
if (!mChildList.empty())
{
- LLRect rootRect = getRootView()->getRect();
+ static const LLRect* rootRect = NULL;
+
+ if (!mParentView)
+ {
+ rootRect = &mRect;
+ }
+
LLRect screenRect;
++sDepth;
@@ -1314,7 +1319,7 @@ void LLView::drawChildren()
{
// Only draw views that are within the root view
localRectToScreen(viewp->getRect(),&screenRect);
- if ( rootRect.overlaps(screenRect) && LLUI::sDirtyRect.overlaps(screenRect))
+ if ( rootRect->overlaps(screenRect) && LLUI::sDirtyRect.overlaps(screenRect))
{
LLUI::pushMatrix();
{
@@ -1682,18 +1687,7 @@ BOOL LLView::hasChild(const std::string& childname, BOOL recurse) const
//-----------------------------------------------------------------------------
LLView* LLView::getChildView(const std::string& name, BOOL recurse) const
{
- LLView* child = findChildView(name, recurse);
- if (!child)
- {
- child = getDefaultWidget<LLView>(name);
- if (!child)
- {
- LLView::Params view_params;
- view_params.name = name;
- child = LLUICtrlFactory::create<LLView>(view_params);
- }
- }
- return child;
+ return getChild<LLView>(name, recurse);
}
static LLFastTimer::DeclareTimer FTM_FIND_VIEWS("Find Widgets");
@@ -1970,7 +1964,7 @@ void LLView::centerWithin(const LLRect& bounds)
translate( left - getRect().mLeft, bottom - getRect().mBottom );
}
-BOOL LLView::localPointToOtherView( S32 x, S32 y, S32 *other_x, S32 *other_y, LLView* other_view) const
+BOOL LLView::localPointToOtherView( S32 x, S32 y, S32 *other_x, S32 *other_y, const LLView* other_view) const
{
const LLView* cur_view = this;
const LLView* root_view = NULL;
@@ -2013,7 +2007,7 @@ BOOL LLView::localPointToOtherView( S32 x, S32 y, S32 *other_x, S32 *other_y, LL
return FALSE;
}
-BOOL LLView::localRectToOtherView( const LLRect& local, LLRect* other, LLView* other_view ) const
+BOOL LLView::localRectToOtherView( const LLRect& local, LLRect* other, const LLView* other_view ) const
{
LLRect cur_rect = local;
const LLView* cur_view = this;
@@ -2804,11 +2798,14 @@ LLView::root_to_view_iterator_t LLView::endRootToView()
// only create maps on demand, as they incur heap allocation/deallocation cost
// when a view is constructed/deconstructed
-LLView::default_widget_map_t& LLView::getDefaultWidgetMap() const
+LLView& LLView::getDefaultWidgetContainer() const
{
if (!mDefaultWidgets)
{
- mDefaultWidgets = new default_widget_map_t();
+ LLView::Params p;
+ p.name = "default widget container";
+ p.visible = false; // ensures default widgets can't steal focus, etc.
+ mDefaultWidgets = new LLView(p);
}
return *mDefaultWidgets;
}
diff --git a/indra/llui/llview.h b/indra/llui/llview.h
index 33d345beff..594a5eec6b 100644
--- a/indra/llui/llview.h
+++ b/indra/llui/llview.h
@@ -34,6 +34,7 @@
#include "stdtypes.h"
#include "llcoord.h"
#include "llfontgl.h"
+#include "llhandle.h"
#include "llmortician.h"
#include "llmousehandler.h"
#include "llstring.h"
@@ -116,7 +117,8 @@ public:
visible,
mouse_opaque,
use_bounding_rect,
- from_xui;
+ from_xui,
+ focus_root;
Optional<S32> tab_group,
default_tab_group;
@@ -286,7 +288,7 @@ public:
void setAllChildrenEnabled(BOOL b);
virtual void setVisible(BOOL visible);
- BOOL getVisible() const { return mVisible; }
+ const BOOL& getVisible() const { return mVisible; }
virtual void setEnabled(BOOL enabled);
BOOL getEnabled() const { return mEnabled; }
/// 'available' in this context means 'visible and enabled': in other
@@ -405,21 +407,16 @@ public:
BOOL blockMouseEvent(S32 x, S32 y) const;
// See LLMouseHandler virtuals for screenPointToLocal and localPointToScreen
- BOOL localPointToOtherView( S32 x, S32 y, S32 *other_x, S32 *other_y, LLView* other_view) const;
- BOOL localRectToOtherView( const LLRect& local, LLRect* other, LLView* other_view ) const;
+ BOOL localPointToOtherView( S32 x, S32 y, S32 *other_x, S32 *other_y, const LLView* other_view) const;
+ BOOL localRectToOtherView( const LLRect& local, LLRect* other, const LLView* other_view ) const;
void screenRectToLocal( const LLRect& screen, LLRect* local ) const;
void localRectToScreen( const LLRect& local, LLRect* screen ) const;
LLControlVariable *findControl(const std::string& name);
- // Moved setValue(), getValue(), setControlValue(), setControlName(),
- // controlListener() to LLUICtrl because an LLView is NOT assumed to
- // contain a value. If that's what you want, use LLUICtrl instead.
-// virtual bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata);
-
const child_list_t* getChildList() const { return &mChildList; }
- const child_list_const_iter_t beginChild() { return mChildList.begin(); }
- const child_list_const_iter_t endChild() { return mChildList.end(); }
+ child_list_const_iter_t beginChild() const { return mChildList.begin(); }
+ child_list_const_iter_t endChild() const { return mChildList.end(); }
// LLMouseHandler functions
// Default behavior is to pass events to children
@@ -466,12 +463,8 @@ public:
template <class T> T* getDefaultWidget(const std::string& name) const
{
- default_widget_map_t::const_iterator found_it = getDefaultWidgetMap().find(name);
- if (found_it == getDefaultWidgetMap().end())
- {
- return NULL;
- }
- return dynamic_cast<T*>(found_it->second);
+ LLView* widgetp = getDefaultWidgetContainer().findChildView(name);
+ return dynamic_cast<T*>(widgetp);
}
//////////////////////////////////////////////
@@ -551,11 +544,13 @@ private:
LLView* mParentView;
child_list_t mChildList;
- std::string mName;
// location in pixels, relative to surrounding structure, bottom,left=0,0
+ BOOL mVisible;
LLRect mRect;
LLRect mBoundingRect;
+
std::string mLayout;
+ std::string mName;
U32 mReshapeFlags;
@@ -577,17 +572,15 @@ private:
LLRootHandle<LLView> mHandle;
BOOL mLastVisible;
- BOOL mVisible;
-
S32 mNextInsertionOrdinal;
static LLWindow* sWindow; // All root views must know about their window.
typedef std::map<std::string, LLView*> default_widget_map_t;
// allocate this map no demand, as it is rarely needed
- mutable default_widget_map_t* mDefaultWidgets;
+ mutable LLView* mDefaultWidgets;
- default_widget_map_t& getDefaultWidgetMap() const;
+ LLView& getDefaultWidgetContainer() const;
public:
// Depth in view hierarchy during rendering
@@ -654,7 +647,7 @@ template <class T> T* LLView::getChild(const std::string& name, BOOL recurse) co
return NULL;
}
- getDefaultWidgetMap()[name] = result;
+ getDefaultWidgetContainer().addChild(result);
}
}
return result;
diff --git a/indra/llui/llviewborder.cpp b/indra/llui/llviewborder.cpp
index 89cd34c37c..32d7ea7c25 100644
--- a/indra/llui/llviewborder.cpp
+++ b/indra/llui/llviewborder.cpp
@@ -28,6 +28,7 @@
#include "llrender.h"
#include "llfocusmgr.h"
#include "lluictrlfactory.h"
+#include "lluiimage.h"
static LLDefaultChildRegistry::Register<LLViewBorder> r("view_border");
diff --git a/indra/llui/llwindowshade.cpp b/indra/llui/llwindowshade.cpp
new file mode 100644
index 0000000000..77e94385d4
--- /dev/null
+++ b/indra/llui/llwindowshade.cpp
@@ -0,0 +1,328 @@
+/**
+ * @file LLWindowShade.cpp
+ * @brief Notification dialog that slides down and optionally disabled a piece of UI
+ *
+ * $LicenseInfo:firstyear=2006&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 "llwindowshade.h"
+
+#include "lllayoutstack.h"
+#include "lltextbox.h"
+#include "lliconctrl.h"
+#include "llbutton.h"
+#include "llcheckboxctrl.h"
+#include "lllineeditor.h"
+
+const S32 MIN_NOTIFICATION_AREA_HEIGHT = 30;
+const S32 MAX_NOTIFICATION_AREA_HEIGHT = 100;
+
+LLWindowShade::Params::Params()
+: bg_image("bg_image"),
+ modal("modal", false),
+ text_color("text_color"),
+ can_close("can_close", true)
+{
+ mouse_opaque = false;
+}
+
+LLWindowShade::LLWindowShade(const LLWindowShade::Params& params)
+: LLUICtrl(params),
+ mNotification(params.notification),
+ mModal(params.modal),
+ mFormHeight(0),
+ mTextColor(params.text_color)
+{
+ setFocusRoot(true);
+}
+
+void LLWindowShade::initFromParams(const LLWindowShade::Params& params)
+{
+ LLUICtrl::initFromParams(params);
+
+ LLLayoutStack::Params layout_p;
+ layout_p.name = "notification_stack";
+ layout_p.rect = params.rect;
+ layout_p.follows.flags = FOLLOWS_ALL;
+ layout_p.mouse_opaque = false;
+ layout_p.orientation = LLLayoutStack::VERTICAL;
+ layout_p.border_size = 0;
+
+ LLLayoutStack* stackp = LLUICtrlFactory::create<LLLayoutStack>(layout_p);
+ addChild(stackp);
+
+ LLLayoutPanel::Params panel_p;
+ panel_p.rect = LLRect(0, 30, 800, 0);
+ panel_p.name = "notification_area";
+ panel_p.visible = false;
+ panel_p.user_resize = false;
+ panel_p.background_visible = true;
+ panel_p.bg_alpha_image = params.bg_image;
+ panel_p.auto_resize = false;
+ LLLayoutPanel* notification_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p);
+ stackp->addChild(notification_panel);
+
+ panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>();
+ panel_p.auto_resize = true;
+ panel_p.user_resize = false;
+ panel_p.rect = params.rect;
+ panel_p.name = "background_area";
+ panel_p.mouse_opaque = false;
+ panel_p.background_visible = false;
+ panel_p.bg_alpha_color = LLColor4(0.f, 0.f, 0.f, 0.2f);
+ LLLayoutPanel* dummy_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p);
+ stackp->addChild(dummy_panel);
+
+ layout_p = LLUICtrlFactory::getDefaultParams<LLLayoutStack>();
+ layout_p.rect = LLRect(0, 30, 800, 0);
+ layout_p.follows.flags = FOLLOWS_ALL;
+ layout_p.orientation = LLLayoutStack::HORIZONTAL;
+ stackp = LLUICtrlFactory::create<LLLayoutStack>(layout_p);
+ notification_panel->addChild(stackp);
+
+ panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>();
+ panel_p.rect.height = 30;
+ LLLayoutPanel* panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p);
+ stackp->addChild(panel);
+
+ LLIconCtrl::Params icon_p;
+ icon_p.name = "notification_icon";
+ icon_p.rect = LLRect(5, 23, 21, 8);
+ panel->addChild(LLUICtrlFactory::create<LLIconCtrl>(icon_p));
+
+ LLTextBox::Params text_p;
+ text_p.rect = LLRect(31, 20, panel->getRect().getWidth() - 5, 0);
+ text_p.follows.flags = FOLLOWS_ALL;
+ text_p.text_color = mTextColor;
+ text_p.font = LLFontGL::getFontSansSerifSmall();
+ text_p.font.style = "BOLD";
+ text_p.name = "notification_text";
+ text_p.use_ellipses = true;
+ text_p.wrap = true;
+ panel->addChild(LLUICtrlFactory::create<LLTextBox>(text_p));
+
+ panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>();
+ panel_p.auto_resize = false;
+ panel_p.user_resize = false;
+ panel_p.name="form_elements";
+ panel_p.rect = LLRect(0, 30, 130, 0);
+ LLLayoutPanel* form_elements_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p);
+ stackp->addChild(form_elements_panel);
+
+ if (params.can_close)
+ {
+ panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>();
+ panel_p.auto_resize = false;
+ panel_p.user_resize = false;
+ panel_p.rect = LLRect(0, 30, 25, 0);
+ LLLayoutPanel* close_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p);
+ stackp->addChild(close_panel);
+
+ LLButton::Params button_p;
+ button_p.name = "close_notification";
+ button_p.rect = LLRect(5, 23, 21, 7);
+ button_p.image_color.control="DkGray_66";
+ button_p.image_unselected.name="Icon_Close_Foreground";
+ button_p.image_selected.name="Icon_Close_Press";
+ button_p.click_callback.function = boost::bind(&LLWindowShade::onCloseNotification, this);
+
+ close_panel->addChild(LLUICtrlFactory::create<LLButton>(button_p));
+ }
+
+ LLSD payload = mNotification->getPayload();
+
+ LLNotificationFormPtr formp = mNotification->getForm();
+ LLLayoutPanel& notification_area = getChildRef<LLLayoutPanel>("notification_area");
+ notification_area.getChild<LLUICtrl>("notification_icon")->setValue(mNotification->getIcon());
+ notification_area.getChild<LLUICtrl>("notification_text")->setValue(mNotification->getMessage());
+ notification_area.getChild<LLUICtrl>("notification_text")->setToolTip(mNotification->getMessage());
+
+ LLNotificationForm::EIgnoreType ignore_type = formp->getIgnoreType();
+ LLLayoutPanel& form_elements = notification_area.getChildRef<LLLayoutPanel>("form_elements");
+ form_elements.deleteAllChildren();
+
+ const S32 FORM_PADDING_HORIZONTAL = 10;
+ const S32 FORM_PADDING_VERTICAL = 3;
+ const S32 WIDGET_HEIGHT = 24;
+ const S32 LINE_EDITOR_WIDTH = 120;
+ S32 cur_x = FORM_PADDING_HORIZONTAL;
+ S32 cur_y = FORM_PADDING_VERTICAL + WIDGET_HEIGHT;
+ S32 form_width = cur_x;
+
+ if (ignore_type != LLNotificationForm::IGNORE_NO)
+ {
+ LLCheckBoxCtrl::Params checkbox_p;
+ checkbox_p.name = "ignore_check";
+ checkbox_p.rect = LLRect(cur_x, cur_y, cur_x, cur_y - WIDGET_HEIGHT);
+ checkbox_p.label = formp->getIgnoreMessage();
+ checkbox_p.label_text.text_color = LLColor4::black;
+ checkbox_p.commit_callback.function = boost::bind(&LLWindowShade::onClickIgnore, this, _1);
+ checkbox_p.initial_value = formp->getIgnored();
+
+ LLCheckBoxCtrl* check = LLUICtrlFactory::create<LLCheckBoxCtrl>(checkbox_p);
+ check->setRect(check->getBoundingRect());
+ form_elements.addChild(check);
+ cur_x = check->getRect().mRight + FORM_PADDING_HORIZONTAL;
+ form_width = llmax(form_width, cur_x);
+ }
+
+ for (S32 i = 0; i < formp->getNumElements(); i++)
+ {
+ LLSD form_element = formp->getElement(i);
+ std::string type = form_element["type"].asString();
+ if (type == "button")
+ {
+ LLButton::Params button_p;
+ button_p.name = form_element["name"];
+ button_p.label = form_element["text"];
+ button_p.rect = LLRect(cur_x, cur_y, cur_x, cur_y - WIDGET_HEIGHT);
+ button_p.click_callback.function = boost::bind(&LLWindowShade::onClickNotificationButton, this, form_element["name"].asString());
+ button_p.auto_resize = true;
+
+ LLButton* button = LLUICtrlFactory::create<LLButton>(button_p);
+ button->autoResize();
+ form_elements.addChild(button);
+
+ if (form_element["default"].asBoolean())
+ {
+ form_elements.setDefaultBtn(button);
+ }
+
+ cur_x = button->getRect().mRight + FORM_PADDING_HORIZONTAL;
+ form_width = llmax(form_width, cur_x);
+ }
+ else if (type == "text" || type == "password")
+ {
+ // if not at beginning of line...
+ if (cur_x != FORM_PADDING_HORIZONTAL)
+ {
+ // start new line
+ cur_x = FORM_PADDING_HORIZONTAL;
+ cur_y -= WIDGET_HEIGHT + FORM_PADDING_VERTICAL;
+ }
+ LLTextBox::Params label_p;
+ label_p.name = form_element["name"].asString() + "_label";
+ label_p.rect = LLRect(cur_x, cur_y, cur_x + LINE_EDITOR_WIDTH, cur_y - WIDGET_HEIGHT);
+ label_p.initial_value = form_element["text"];
+ label_p.text_color = mTextColor;
+ label_p.font_valign = LLFontGL::VCENTER;
+ label_p.v_pad = 5;
+ LLTextBox* textbox = LLUICtrlFactory::create<LLTextBox>(label_p);
+ textbox->reshapeToFitText();
+ textbox->reshape(textbox->getRect().getWidth(), form_elements.getRect().getHeight() - 2 * FORM_PADDING_VERTICAL);
+ form_elements.addChild(textbox);
+ cur_x = textbox->getRect().mRight + FORM_PADDING_HORIZONTAL;
+
+ LLLineEditor::Params line_p;
+ line_p.name = form_element["name"];
+ line_p.keystroke_callback = boost::bind(&LLWindowShade::onEnterNotificationText, this, _1, form_element["name"].asString());
+ line_p.is_password = type == "password";
+ line_p.rect = LLRect(cur_x, cur_y, cur_x + LINE_EDITOR_WIDTH, cur_y - WIDGET_HEIGHT);
+
+ LLLineEditor* line_editor = LLUICtrlFactory::create<LLLineEditor>(line_p);
+ form_elements.addChild(line_editor);
+ form_width = llmax(form_width, cur_x + LINE_EDITOR_WIDTH + FORM_PADDING_HORIZONTAL);
+
+ // reset to start of next line
+ cur_x = FORM_PADDING_HORIZONTAL;
+ cur_y -= WIDGET_HEIGHT + FORM_PADDING_VERTICAL;
+ }
+ }
+
+ mFormHeight = form_elements.getRect().getHeight() - (cur_y - FORM_PADDING_VERTICAL) + WIDGET_HEIGHT;
+ form_elements.reshape(form_width, mFormHeight);
+ form_elements.setMinDim(form_width);
+
+ // move all form elements back onto form surface
+ S32 delta_y = WIDGET_HEIGHT + FORM_PADDING_VERTICAL - cur_y;
+ for (child_list_const_iter_t it = form_elements.getChildList()->begin(), end_it = form_elements.getChildList()->end();
+ it != end_it;
+ ++it)
+ {
+ (*it)->translate(0, delta_y);
+ }
+}
+
+void LLWindowShade::show()
+{
+ getChildRef<LLLayoutPanel>("notification_area").setVisible(true);
+ getChildRef<LLLayoutPanel>("background_area").setBackgroundVisible(mModal);
+
+ setMouseOpaque(mModal);
+}
+
+void LLWindowShade::draw()
+{
+ LLRect message_rect = getChild<LLTextBox>("notification_text")->getTextBoundingRect();
+
+ LLLayoutPanel* notification_area = getChild<LLLayoutPanel>("notification_area");
+
+ notification_area->reshape(notification_area->getRect().getWidth(),
+ llclamp(message_rect.getHeight() + 10,
+ llmin(mFormHeight, MAX_NOTIFICATION_AREA_HEIGHT),
+ MAX_NOTIFICATION_AREA_HEIGHT));
+
+ LLUICtrl::draw();
+ if (mNotification && !mNotification->isActive())
+ {
+ hide();
+ }
+}
+
+void LLWindowShade::hide()
+{
+ getChildRef<LLLayoutPanel>("notification_area").setVisible(false);
+ getChildRef<LLLayoutPanel>("background_area").setBackgroundVisible(false);
+
+ setMouseOpaque(false);
+}
+
+void LLWindowShade::onCloseNotification()
+{
+ LLNotifications::instance().cancel(mNotification);
+}
+
+void LLWindowShade::onClickIgnore(LLUICtrl* ctrl)
+{
+ bool check = ctrl->getValue().asBoolean();
+ if (mNotification && mNotification->getForm()->getIgnoreType() == LLNotificationForm::IGNORE_SHOW_AGAIN)
+ {
+ // question was "show again" so invert value to get "ignore"
+ check = !check;
+ }
+ mNotification->setIgnored(check);
+}
+
+void LLWindowShade::onClickNotificationButton(const std::string& name)
+{
+ if (!mNotification) return;
+
+ mNotificationResponse[name] = true;
+
+ mNotification->respond(mNotificationResponse);
+}
+
+void LLWindowShade::onEnterNotificationText(LLUICtrl* ctrl, const std::string& name)
+{
+ mNotificationResponse[name] = ctrl->getValue().asString();
+}
diff --git a/indra/llui/llwindowshade.h b/indra/llui/llwindowshade.h
new file mode 100644
index 0000000000..09ffc2cd54
--- /dev/null
+++ b/indra/llui/llwindowshade.h
@@ -0,0 +1,70 @@
+/**
+ * @file llwindowshade.h
+ * @brief Notification dialog that slides down and optionally disabled a piece of UI
+ *
+ * $LicenseInfo:firstyear=2006&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_LLWINDOWSHADE_H
+#define LL_LLWINDOWSHADE_H
+
+#include "lluictrl.h"
+#include "llnotifications.h"
+#include "lluiimage.h"
+
+class LLWindowShade : public LLUICtrl
+{
+public:
+ struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
+ {
+ Mandatory<LLNotificationPtr> notification;
+ Optional<LLUIImage*> bg_image;
+ Optional<LLUIColor> text_color;
+ Optional<bool> modal,
+ can_close;
+
+ Params();
+ };
+
+ void show();
+ /*virtual*/ void draw();
+ void hide();
+
+private:
+ friend class LLUICtrlFactory;
+
+ LLWindowShade(const Params& p);
+ void initFromParams(const Params& params);
+
+ void onCloseNotification();
+ void onClickNotificationButton(const std::string& name);
+ void onEnterNotificationText(LLUICtrl* ctrl, const std::string& name);
+ void onClickIgnore(LLUICtrl* ctrl);
+
+ LLNotificationPtr mNotification;
+ LLSD mNotificationResponse;
+ bool mModal;
+ S32 mFormHeight;
+ LLUIColor mTextColor;
+};
+
+#endif // LL_LLWINDOWSHADE_H
diff --git a/indra/llui/tests/llurlentry_stub.cpp b/indra/llui/tests/llurlentry_stub.cpp
index f30704cb22..26b3b17577 100644
--- a/indra/llui/tests/llurlentry_stub.cpp
+++ b/indra/llui/tests/llurlentry_stub.cpp
@@ -30,6 +30,7 @@
#include "llavatarnamecache.h"
#include "llcachename.h"
#include "lluuid.h"
+#include "message.h"
#include <string>
@@ -113,32 +114,30 @@ namespace LLInitParam
const U8* block_addr = reinterpret_cast<const U8*>(enclosing_block);
mEnclosingBlockOffset = (U16)(my_addr - block_addr);
}
- void BaseBlock::setLastChangedParam(const Param& last_param, bool user_provided) {}
+ void BaseBlock::paramChanged(const Param& last_param, bool user_provided) {}
- void BaseBlock::addParam(BlockDescriptor& block_data, const ParamDescriptor& in_param, const char* char_name){}
+ void BaseBlock::addParam(BlockDescriptor& block_data, const ParamDescriptorPtr in_param, const char* char_name){}
+ void BaseBlock::addSynonym(Param& param, const std::string& synonym) {}
param_handle_t BaseBlock::getHandleFromParam(const Param* param) const {return 0;}
void BaseBlock::init(BlockDescriptor& descriptor, BlockDescriptor& base_descriptor, size_t block_size)
{
descriptor.mCurrentBlockPtr = this;
}
- bool BaseBlock::deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack){ return true; }
- bool BaseBlock::serializeBlock(Parser& parser, Parser::name_stack_t name_stack, const LLInitParam::BaseBlock* diff_block) const { return true; }
- bool BaseBlock::inspectBlock(Parser& parser, Parser::name_stack_t name_stack) const { return true; }
- bool BaseBlock::merge(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite) { return true; }
+ bool BaseBlock::deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack, S32 generation){ return true; }
+ void BaseBlock::serializeBlock(Parser& parser, Parser::name_stack_t name_stack, const LLInitParam::BaseBlock* diff_block) const {}
+ bool BaseBlock::inspectBlock(Parser& parser, Parser::name_stack_t name_stack, S32 min_value, S32 max_value) const { return true; }
+ bool BaseBlock::mergeBlock(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite) { return true; }
bool BaseBlock::validateBlock(bool emit_errors) const { return true; }
- TypedParam<LLUIColor >::TypedParam(BlockDescriptor& descriptor, const char* name, const LLUIColor& value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count)
- : super_t(descriptor, name, value, func, min_count, max_count)
+ ParamValue<LLUIColor, TypeValues<LLUIColor> >::ParamValue(const LLUIColor& color)
+ : super_t(color)
{}
- void TypedParam<LLUIColor>::setValueFromBlock() const
+ void ParamValue<LLUIColor, TypeValues<LLUIColor> >::updateValueFromBlock()
{}
- void TypedParam<LLUIColor>::setBlockFromValue()
- {}
-
- void TypeValues<LLUIColor>::declareValues()
+ void ParamValue<LLUIColor, TypeValues<LLUIColor> >::updateBlockFromValue()
{}
bool ParamCompare<const LLFontGL*, false>::equals(const LLFontGL* a, const LLFontGL* b)
@@ -146,14 +145,14 @@ namespace LLInitParam
return false;
}
- TypedParam<const LLFontGL*>::TypedParam(BlockDescriptor& descriptor, const char* _name, const LLFontGL*const value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count)
- : super_t(descriptor, _name, value, func, min_count, max_count)
+ ParamValue<const LLFontGL*, TypeValues<const LLFontGL*> >::ParamValue(const LLFontGL* fontp)
+ : super_t(fontp)
{}
- void TypedParam<const LLFontGL*>::setValueFromBlock() const
+ void ParamValue<const LLFontGL*, TypeValues<const LLFontGL*> >::updateValueFromBlock()
{}
- void TypedParam<const LLFontGL*>::setBlockFromValue()
+ void ParamValue<const LLFontGL*, TypeValues<const LLFontGL*> >::updateBlockFromValue()
{}
void TypeValues<LLFontGL::HAlign>::declareValues()
@@ -165,10 +164,10 @@ namespace LLInitParam
void TypeValues<LLFontGL::ShadowType>::declareValues()
{}
- void TypedParam<LLUIImage*>::setValueFromBlock() const
+ void ParamValue<LLUIImage*, TypeValues<LLUIImage*> >::updateValueFromBlock()
{}
- void TypedParam<LLUIImage*>::setBlockFromValue()
+ void ParamValue<LLUIImage*, TypeValues<LLUIImage*> >::updateBlockFromValue()
{}
@@ -191,3 +190,20 @@ LLFontGL* LLFontGL::getFontDefault()
{
return NULL;
}
+
+char const* const _PREHASH_AgentData = (char *)"AgentData";
+char const* const _PREHASH_AgentID = (char *)"AgentID";
+
+LLHost LLHost::invalid(INVALID_PORT,INVALID_HOST_IP_ADDRESS);
+
+LLMessageSystem* gMessageSystem = NULL;
+
+//
+// Stub implementation for LLMessageSystem
+//
+void LLMessageSystem::newMessage(const char *name) { }
+void LLMessageSystem::nextBlockFast(const char *blockname) { }
+void LLMessageSystem::nextBlock(const char *blockname) { }
+void LLMessageSystem::addUUIDFast( const char *varname, const LLUUID& uuid) { }
+void LLMessageSystem::addUUID( const char *varname, const LLUUID& uuid) { }
+S32 LLMessageSystem::sendReliable(const LLHost &host) { return 0; }
diff --git a/indra/llui/tests/llurlentry_test.cpp b/indra/llui/tests/llurlentry_test.cpp
index 5c6623da61..2f814f4200 100644
--- a/indra/llui/tests/llurlentry_test.cpp
+++ b/indra/llui/tests/llurlentry_test.cpp
@@ -27,6 +27,7 @@
#include "linden_common.h"
#include "../llurlentry.h"
+#include "../lluictrl.h"
#include "llurlentry_stub.cpp"
#include "lltut.h"
#include "../lluicolortable.h"
@@ -34,6 +35,14 @@
#include <boost/regex.hpp>
+typedef std::map<std::string, LLControlGroup*> settings_map_t;
+settings_map_t LLUI::sSettingGroups;
+
+BOOL LLControlGroup::getBOOL(const std::string& name)
+{
+ return false;
+}
+
LLUIColor LLUIColorTable::getColor(const std::string& name, const LLColor4& default_color) const
{
return LLUIColor();
@@ -61,6 +70,22 @@ S32 LLUIImage::getHeight() const
return 0;
}
+namespace LLInitParam
+{
+ S32 Parser::sNextParseGeneration = 0;
+ BlockDescriptor::BlockDescriptor() {}
+ ParamDescriptor::ParamDescriptor(param_handle_t p,
+ merge_func_t merge_func,
+ deserialize_func_t deserialize_func,
+ serialize_func_t serialize_func,
+ validation_func_t validation_func,
+ inspect_func_t inspect_func,
+ S32 min_count,
+ S32 max_count){}
+ ParamDescriptor::~ParamDescriptor() {}
+
+}
+
namespace tut
{
struct LLUrlEntryData
@@ -94,6 +119,45 @@ namespace tut
ensure_equals(testname, url, expected);
}
+ void dummyCallback(const std::string &url, const std::string &label, const std::string& icon)
+ {
+ }
+
+ void testLabel(const std::string &testname, LLUrlEntryBase &entry,
+ const char *text, const std::string &expected)
+ {
+ boost::regex regex = entry.getPattern();
+ std::string label = "";
+ boost::cmatch result;
+ bool found = boost::regex_search(text, result, regex);
+ if (found)
+ {
+ S32 start = static_cast<U32>(result[0].first - text);
+ S32 end = static_cast<U32>(result[0].second - text);
+ std::string url = std::string(text+start, end-start);
+ label = entry.getLabel(url, boost::bind(dummyCallback, _1, _2, _3));
+ }
+ ensure_equals(testname, label, expected);
+ }
+
+ void testLocation(const std::string &testname, LLUrlEntryBase &entry,
+ const char *text, const std::string &expected)
+ {
+ boost::regex regex = entry.getPattern();
+ std::string location = "";
+ boost::cmatch result;
+ bool found = boost::regex_search(text, result, regex);
+ if (found)
+ {
+ S32 start = static_cast<U32>(result[0].first - text);
+ S32 end = static_cast<U32>(result[0].second - text);
+ std::string url = std::string(text+start, end-start);
+ location = entry.getLocation(url);
+ }
+ ensure_equals(testname, location, expected);
+ }
+
+
template<> template<>
void object::test<1>()
{
@@ -688,4 +752,114 @@ namespace tut
"<nolink>My Object</nolink>",
"My Object");
}
+
+ template<> template<>
+ void object::test<13>()
+ {
+ //
+ // test LLUrlEntryRegion - secondlife:///app/region/<location> URLs
+ //
+ LLUrlEntryRegion url;
+
+ // Regex tests.
+ testRegex("no valid region", url,
+ "secondlife:///app/region/",
+ "");
+
+ testRegex("invalid coords", url,
+ "secondlife:///app/region/Korea2/a/b/c",
+ "secondlife:///app/region/Korea2/"); // don't count invalid coords
+
+ testRegex("Ahern (50,50,50) [1]", url,
+ "secondlife:///app/region/Ahern/50/50/50/",
+ "secondlife:///app/region/Ahern/50/50/50/");
+
+ testRegex("Ahern (50,50,50) [2]", url,
+ "XXX secondlife:///app/region/Ahern/50/50/50/ XXX",
+ "secondlife:///app/region/Ahern/50/50/50/");
+
+ testRegex("Ahern (50,50,50) [3]", url,
+ "XXX secondlife:///app/region/Ahern/50/50/50 XXX",
+ "secondlife:///app/region/Ahern/50/50/50");
+
+ testRegex("Ahern (50,50,50) multicase", url,
+ "XXX secondlife:///app/region/Ahern/50/50/50/ XXX",
+ "secondlife:///app/region/Ahern/50/50/50/");
+
+ testRegex("Ahern (50,50) [1]", url,
+ "XXX secondlife:///app/region/Ahern/50/50/ XXX",
+ "secondlife:///app/region/Ahern/50/50/");
+
+ testRegex("Ahern (50,50) [2]", url,
+ "XXX secondlife:///app/region/Ahern/50/50 XXX",
+ "secondlife:///app/region/Ahern/50/50");
+
+ // DEV-21577: In-world SLURLs containing "(" or ")" are not treated as a hyperlink in chat
+ testRegex("Region with brackets", url,
+ "XXX secondlife:///app/region/Burning%20Life%20(Hyper)/27/210/30 XXX",
+ "secondlife:///app/region/Burning%20Life%20(Hyper)/27/210/30");
+
+ // DEV-35459: SLURLs and teleport Links not parsed properly
+ testRegex("Region with quote", url,
+ "XXX secondlife:///app/region/A'ksha%20Oasis/41/166/701 XXX",
+ "secondlife:///app/region/A%27ksha%20Oasis/41/166/701");
+
+ // Rendering tests.
+ testLabel("Render /app/region/Ahern/50/50/50/", url,
+ "secondlife:///app/region/Ahern/50/50/50/",
+ "Ahern (50,50,50)");
+
+ testLabel("Render /app/region/Ahern/50/50/50", url,
+ "secondlife:///app/region/Ahern/50/50/50",
+ "Ahern (50,50,50)");
+
+ testLabel("Render /app/region/Ahern/50/50/", url,
+ "secondlife:///app/region/Ahern/50/50/",
+ "Ahern (50,50)");
+
+ testLabel("Render /app/region/Ahern/50/50", url,
+ "secondlife:///app/region/Ahern/50/50",
+ "Ahern (50,50)");
+
+ testLabel("Render /app/region/Ahern/50/", url,
+ "secondlife:///app/region/Ahern/50/",
+ "Ahern (50)");
+
+ testLabel("Render /app/region/Ahern/50", url,
+ "secondlife:///app/region/Ahern/50",
+ "Ahern (50)");
+
+ testLabel("Render /app/region/Ahern/", url,
+ "secondlife:///app/region/Ahern/",
+ "Ahern");
+
+ testLabel("Render /app/region/Ahern/ within context", url,
+ "XXX secondlife:///app/region/Ahern/ XXX",
+ "Ahern");
+
+ testLabel("Render /app/region/Ahern", url,
+ "secondlife:///app/region/Ahern",
+ "Ahern");
+
+ testLabel("Render /app/region/Ahern within context", url,
+ "XXX secondlife:///app/region/Ahern XXX",
+ "Ahern");
+
+ testLabel("Render /app/region/Product%20Engine/", url,
+ "secondlife:///app/region/Product%20Engine/",
+ "Product Engine");
+
+ testLabel("Render /app/region/Product%20Engine", url,
+ "secondlife:///app/region/Product%20Engine",
+ "Product Engine");
+
+ // Location parsing texts.
+ testLocation("Location /app/region/Ahern/50/50/50/", url,
+ "secondlife:///app/region/Ahern/50/50/50/",
+ "Ahern");
+
+ testLocation("Location /app/region/Product%20Engine", url,
+ "secondlife:///app/region/Product%20Engine",
+ "Product Engine");
+ }
}
diff --git a/indra/llui/tests/llurlmatch_test.cpp b/indra/llui/tests/llurlmatch_test.cpp
index fdaab00f18..e09ef33d49 100644
--- a/indra/llui/tests/llurlmatch_test.cpp
+++ b/indra/llui/tests/llurlmatch_test.cpp
@@ -66,11 +66,25 @@ namespace LLInitParam
BaseBlock::BaseBlock() {}
BaseBlock::~BaseBlock() {}
- void BaseBlock::setLastChangedParam(const Param& last_param, bool user_provided) {}
-
- void BaseBlock::addParam(BlockDescriptor& block_data, const ParamDescriptor& in_param, const char* char_name){}
+ S32 Parser::sNextParseGeneration = 0;
+
+ BlockDescriptor::BlockDescriptor() {}
+ ParamDescriptor::ParamDescriptor(param_handle_t p,
+ merge_func_t merge_func,
+ deserialize_func_t deserialize_func,
+ serialize_func_t serialize_func,
+ validation_func_t validation_func,
+ inspect_func_t inspect_func,
+ S32 min_count,
+ S32 max_count){}
+ ParamDescriptor::~ParamDescriptor() {}
+
+ void BaseBlock::paramChanged(const Param& last_param, bool user_provided) {}
+
+ void BaseBlock::addParam(BlockDescriptor& block_data, const ParamDescriptorPtr in_param, const char* char_name){}
param_handle_t BaseBlock::getHandleFromParam(const Param* param) const {return 0;}
-
+ void BaseBlock::addSynonym(Param& param, const std::string& synonym) {}
+
void BaseBlock::init(BlockDescriptor& descriptor, BlockDescriptor& base_descriptor, size_t block_size)
{
descriptor.mCurrentBlockPtr = this;
@@ -84,23 +98,20 @@ namespace LLInitParam
mEnclosingBlockOffset = (U16)(my_addr - block_addr);
}
- bool BaseBlock::deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack){ return true; }
- bool BaseBlock::serializeBlock(Parser& parser, Parser::name_stack_t name_stack, const LLInitParam::BaseBlock* diff_block) const { return true; }
- bool BaseBlock::inspectBlock(Parser& parser, Parser::name_stack_t name_stack) const { return true; }
- bool BaseBlock::merge(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite) { return true; }
+ bool BaseBlock::deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack, S32 generation){ return true; }
+ void BaseBlock::serializeBlock(Parser& parser, Parser::name_stack_t name_stack, const LLInitParam::BaseBlock* diff_block) const {}
+ bool BaseBlock::inspectBlock(Parser& parser, Parser::name_stack_t name_stack, S32 min_count, S32 max_count) const { return true; }
+ bool BaseBlock::mergeBlock(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite) { return true; }
bool BaseBlock::validateBlock(bool emit_errors) const { return true; }
- TypedParam<LLUIColor >::TypedParam(BlockDescriptor& descriptor, const char* name, const LLUIColor& value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count)
- : super_t(descriptor, name, value, func, min_count, max_count)
+ ParamValue<LLUIColor, TypeValues<LLUIColor> >::ParamValue(const LLUIColor& color)
+ : super_t(color)
{}
- void TypedParam<LLUIColor>::setValueFromBlock() const
+ void ParamValue<LLUIColor, TypeValues<LLUIColor> >::updateValueFromBlock()
{}
- void TypedParam<LLUIColor>::setBlockFromValue()
- {}
-
- void TypeValues<LLUIColor>::declareValues()
+ void ParamValue<LLUIColor, TypeValues<LLUIColor> >::updateBlockFromValue()
{}
bool ParamCompare<const LLFontGL*, false>::equals(const LLFontGL* a, const LLFontGL* b)
@@ -108,14 +119,15 @@ namespace LLInitParam
return false;
}
- TypedParam<const LLFontGL*>::TypedParam(BlockDescriptor& descriptor, const char* _name, const LLFontGL*const value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count)
- : super_t(descriptor, _name, value, func, min_count, max_count)
+
+ ParamValue<const LLFontGL*, TypeValues<const LLFontGL*> >::ParamValue(const LLFontGL* fontp)
+ : super_t(fontp)
{}
- void TypedParam<const LLFontGL*>::setValueFromBlock() const
+ void ParamValue<const LLFontGL*, TypeValues<const LLFontGL*> >::updateValueFromBlock()
{}
- void TypedParam<const LLFontGL*>::setBlockFromValue()
+ void ParamValue<const LLFontGL*, TypeValues<const LLFontGL*> >::updateBlockFromValue()
{}
void TypeValues<LLFontGL::HAlign>::declareValues()
@@ -127,10 +139,10 @@ namespace LLInitParam
void TypeValues<LLFontGL::ShadowType>::declareValues()
{}
- void TypedParam<LLUIImage*>::setValueFromBlock() const
+ void ParamValue<LLUIImage*, TypeValues<LLUIImage*> >::updateValueFromBlock()
{}
- void TypedParam<LLUIImage*>::setBlockFromValue()
+ void ParamValue<LLUIImage*, TypeValues<LLUIImage*> >::updateBlockFromValue()
{}
bool ParamCompare<LLUIImage*, false>::equals(
diff --git a/indra/llvfs/CMakeLists.txt b/indra/llvfs/CMakeLists.txt
index 722f4e2bfd..b6d1ce61e5 100644
--- a/indra/llvfs/CMakeLists.txt
+++ b/indra/llvfs/CMakeLists.txt
@@ -12,6 +12,7 @@ include_directories(
set(llvfs_SOURCE_FILES
lldir.cpp
+ lldiriterator.cpp
lllfsthread.cpp
llpidlock.cpp
llvfile.cpp
@@ -24,6 +25,7 @@ set(llvfs_HEADER_FILES
lldir.h
lldirguard.h
+ lldiriterator.h
lllfsthread.h
llpidlock.h
llvfile.h
@@ -60,6 +62,11 @@ list(APPEND llvfs_SOURCE_FILES ${llvfs_HEADER_FILES})
add_library (llvfs ${llvfs_SOURCE_FILES})
+target_link_libraries(llvfs
+ ${BOOST_FILESYSTEM_LIBRARY}
+ ${BOOST_SYSTEM_LIBRARY}
+ )
+
if (DARWIN)
include(CMakeFindFrameworks)
find_library(CARBON_LIBRARY Carbon)
@@ -67,17 +74,17 @@ if (DARWIN)
endif (DARWIN)
-if(LL_TESTS)
- # Add tests
- include(LLAddBuildTest)
- # UNIT TESTS
- SET(llvfs_TEST_SOURCE_FILES
- # none so far
- )
- LL_ADD_PROJECT_UNIT_TESTS(llvfs "${llvfs_TEST_SOURCE_FILES}")
-
- # INTEGRATION TESTS
- set(test_libs llmath llcommon llvfs ${LLCOMMON_LIBRARIES} ${WINDOWS_LIBRARIES})
- # TODO: Some of these need refactoring to be proper Unit tests rather than Integration tests.
- LL_ADD_INTEGRATION_TEST(lldir "" "${test_libs}")
-endif(LL_TESTS)
+# Add tests
+if (LL_TESTS)
+ include(LLAddBuildTest)
+ # UNIT TESTS
+ SET(llvfs_TEST_SOURCE_FILES
+ # none so far
+ )
+ LL_ADD_PROJECT_UNIT_TESTS(llvfs "${llvfs_TEST_SOURCE_FILES}")
+
+ # INTEGRATION TESTS
+ set(test_libs llmath llcommon llvfs ${LLCOMMON_LIBRARIES} ${WINDOWS_LIBRARIES})
+ # TODO: Some of these need refactoring to be proper Unit tests rather than Integration tests.
+ LL_ADD_INTEGRATION_TEST(lldir "" "${test_libs}")
+endif (LL_TESTS)
diff --git a/indra/llvfs/lldir.cpp b/indra/llvfs/lldir.cpp
index 938fb008c9..f3ac17d612 100644
--- a/indra/llvfs/lldir.cpp
+++ b/indra/llvfs/lldir.cpp
@@ -40,6 +40,8 @@
#include "lltimer.h" // ms_sleep()
#include "lluuid.h"
+#include "lldiriterator.h"
+
#if LL_WINDOWS
#include "lldir_win32.h"
LLDir_Win32 gDirUtil;
@@ -83,7 +85,9 @@ S32 LLDir::deleteFilesInDir(const std::string &dirname, const std::string &mask)
std::string filename;
std::string fullpath;
S32 result;
- while (getNextFileInDir(dirname, mask, filename, FALSE))
+
+ LLDirIterator iter(dirname, mask);
+ while (iter.next(filename))
{
fullpath = dirname;
fullpath += getDirDelimiter();
@@ -101,10 +105,18 @@ S32 LLDir::deleteFilesInDir(const std::string &dirname, const std::string &mask)
{
if (0 != LLFile::remove(fullpath))
{
+ retry_count++;
result = errno;
llwarns << "Problem removing " << fullpath << " - errorcode: "
<< result << " attempt " << retry_count << llendl;
- ms_sleep(1000);
+
+ if(retry_count >= 5)
+ {
+ llwarns << "Failed to remove " << fullpath << llendl ;
+ return count ;
+ }
+
+ ms_sleep(100);
}
else
{
@@ -113,8 +125,7 @@ S32 LLDir::deleteFilesInDir(const std::string &dirname, const std::string &mask)
llwarns << "Successfully removed " << fullpath << llendl;
}
break;
- }
- retry_count++;
+ }
}
count++;
}
@@ -142,7 +153,11 @@ const std::string LLDir::findFile(const std::string& filename, const std::vector
{
if (!search_path_iter->empty())
{
- std::string filename_and_path = (*search_path_iter) + getDirDelimiter() + filename;
+ std::string filename_and_path = (*search_path_iter);
+ if (!filename.empty())
+ {
+ filename_and_path += getDirDelimiter() + filename;
+ }
if (fileExists(filename_and_path))
{
return filename_and_path;
@@ -382,11 +397,7 @@ std::string LLDir::getExpandedFilename(ELLPath location, const std::string& subd
break;
case LL_PATH_USER_SKIN:
- prefix = getOSUserAppDir();
- prefix += mDirDelimiter;
- prefix += "user_settings";
- prefix += mDirDelimiter;
- prefix += "skins";
+ prefix = getUserSkinDir();
break;
case LL_PATH_SKINS:
diff --git a/indra/llvfs/lldir.h b/indra/llvfs/lldir.h
index 4f63c04aab..5ee8bdb542 100644
--- a/indra/llvfs/lldir.h
+++ b/indra/llvfs/lldir.h
@@ -74,8 +74,7 @@ class LLDir
// pure virtual functions
virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask) = 0;
- virtual BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname, BOOL wrap) = 0;
- virtual void getRandomFileInDir(const std::string &dirname, const std::string &mask, std::string &fname) = 0;
+
virtual std::string getCurPath() = 0;
virtual BOOL fileExists(const std::string &filename) const = 0;
diff --git a/indra/llvfs/lldir_linux.cpp b/indra/llvfs/lldir_linux.cpp
index a1c6669b97..407f3b93fb 100644
--- a/indra/llvfs/lldir_linux.cpp
+++ b/indra/llvfs/lldir_linux.cpp
@@ -93,11 +93,11 @@ LLDir_Linux::LLDir_Linux()
#else
mAppRODataDir = tmp_str;
#endif
- std::string::size_type indra_pos = mExecutableDir.find("/indra");
- if (indra_pos != std::string::npos)
+ std::string::size_type build_dir_pos = mExecutableDir.rfind("/build-linux-");
+ if (build_dir_pos != std::string::npos)
{
// ...we're in a dev checkout
- mSkinBaseDir = mExecutableDir.substr(0, indra_pos) + "/indra/newview/skins";
+ mSkinBaseDir = mExecutableDir.substr(0, build_dir_pos) + "/indra/newview/skins";
llinfos << "Running in dev checkout with mSkinBaseDir "
<< mSkinBaseDir << llendl;
}
@@ -242,114 +242,6 @@ U32 LLDir_Linux::countFilesInDir(const std::string &dirname, const std::string &
return (file_count);
}
-// get the next file in the directory
-// automatically wrap if we've hit the end
-BOOL LLDir_Linux::getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname, BOOL wrap)
-{
- glob_t g;
- BOOL result = FALSE;
- fname = "";
-
- if(!(dirname == mCurrentDir))
- {
- // different dir specified, close old search
- mCurrentDirIndex = -1;
- mCurrentDirCount = -1;
- mCurrentDir = dirname;
- }
-
- std::string tmp_str;
- tmp_str = dirname;
- tmp_str += mask;
-
- if(glob(tmp_str.c_str(), GLOB_NOSORT, NULL, &g) == 0)
- {
- if(g.gl_pathc > 0)
- {
- if((int)g.gl_pathc != mCurrentDirCount)
- {
- // Number of matches has changed since the last search, meaning a file has been added or deleted.
- // Reset the index.
- mCurrentDirIndex = -1;
- mCurrentDirCount = g.gl_pathc;
- }
-
- mCurrentDirIndex++;
-
- if((mCurrentDirIndex >= (int)g.gl_pathc) && wrap)
- {
- mCurrentDirIndex = 0;
- }
-
- if(mCurrentDirIndex < (int)g.gl_pathc)
- {
-// llinfos << "getNextFileInDir: returning number " << mCurrentDirIndex << ", path is " << g.gl_pathv[mCurrentDirIndex] << llendl;
-
- // The API wants just the filename, not the full path.
- //fname = g.gl_pathv[mCurrentDirIndex];
-
- char *s = strrchr(g.gl_pathv[mCurrentDirIndex], '/');
-
- if(s == NULL)
- s = g.gl_pathv[mCurrentDirIndex];
- else if(s[0] == '/')
- s++;
-
- fname = s;
-
- result = TRUE;
- }
- }
-
- globfree(&g);
- }
-
- return(result);
-}
-
-
-// get a random file in the directory
-// automatically wrap if we've hit the end
-void LLDir_Linux::getRandomFileInDir(const std::string &dirname, const std::string &mask, std::string &fname)
-{
- S32 num_files;
- S32 which_file;
- DIR *dirp;
- dirent *entryp = NULL;
-
- fname = "";
-
- num_files = countFilesInDir(dirname,mask);
- if (!num_files)
- {
- return;
- }
-
- which_file = ll_rand(num_files);
-
-// llinfos << "Random select file #" << which_file << llendl;
-
- // which_file now indicates the (zero-based) index to which file to play
-
- if (!((dirp = opendir(dirname.c_str()))))
- {
- while (which_file--)
- {
- if (!((entryp = readdir(dirp))))
- {
- return;
- }
- }
-
- if ((!which_file) && entryp)
- {
- fname = entryp->d_name;
- }
-
- closedir(dirp);
- }
-}
-
std::string LLDir_Linux::getCurPath()
{
char tmp_str[LL_MAX_PATH]; /* Flawfinder: ignore */
diff --git a/indra/llvfs/lldir_linux.h b/indra/llvfs/lldir_linux.h
index 809959e873..7603239867 100644
--- a/indra/llvfs/lldir_linux.h
+++ b/indra/llvfs/lldir_linux.h
@@ -1,6 +1,6 @@
/**
* @file lldir_linux.h
- * @brief Definition of directory utilities class for linux
+ * @brief Definition of directory utilities class for linux
*
* $LicenseInfo:firstyear=2000&license=viewerlgpl$
* Second Life Viewer Source Code
@@ -24,6 +24,10 @@
* $/LicenseInfo$
*/
+#if !LL_LINUX
+#error This header must not be included when compiling for any target other than Linux. Consider including lldir.h instead.
+#endif // !LL_LINUX
+
#ifndef LL_LLDIR_LINUX_H
#define LL_LLDIR_LINUX_H
@@ -40,11 +44,9 @@ public:
/*virtual*/ void initAppDirs(const std::string &app_name,
const std::string& app_read_only_data_dir);
-public:
+
virtual std::string getCurPath();
virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask);
- virtual BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname, BOOL wrap);
- virtual void getRandomFileInDir(const std::string &dirname, const std::string &mask, std::string &fname);
/*virtual*/ BOOL fileExists(const std::string &filename) const;
/*virtual*/ std::string getLLPluginLauncher();
@@ -54,7 +56,7 @@ private:
DIR *mDirp;
int mCurrentDirIndex;
int mCurrentDirCount;
- std::string mCurrentDir;
+ std::string mCurrentDir;
};
#endif // LL_LLDIR_LINUX_H
diff --git a/indra/llvfs/lldir_mac.cpp b/indra/llvfs/lldir_mac.cpp
index b41b0ec5dd..8f48f92e2a 100644
--- a/indra/llvfs/lldir_mac.cpp
+++ b/indra/llvfs/lldir_mac.cpp
@@ -150,11 +150,11 @@ LLDir_Mac::LLDir_Mac()
CFURLRef resourcesURLRef = CFBundleCopyResourcesDirectoryURL(mainBundleRef);
CFURLRefToLLString(resourcesURLRef, mAppRODataDir, true);
- U32 indra_pos = mExecutableDir.find("/indra");
- if (indra_pos != std::string::npos)
+ U32 build_dir_pos = mExecutableDir.rfind("/build-darwin-");
+ if (build_dir_pos != std::string::npos)
{
// ...we're in a dev checkout
- mSkinBaseDir = mExecutableDir.substr(0, indra_pos)
+ mSkinBaseDir = mExecutableDir.substr(0, build_dir_pos)
+ "/indra/newview/skins";
llinfos << "Running in dev checkout with mSkinBaseDir "
<< mSkinBaseDir << llendl;
@@ -258,107 +258,6 @@ U32 LLDir_Mac::countFilesInDir(const std::string &dirname, const std::string &ma
return (file_count);
}
-// get the next file in the directory
-// automatically wrap if we've hit the end
-BOOL LLDir_Mac::getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname, BOOL wrap)
-{
- glob_t g;
- BOOL result = FALSE;
- fname = "";
-
- if(!(dirname == mCurrentDir))
- {
- // different dir specified, close old search
- mCurrentDirIndex = -1;
- mCurrentDirCount = -1;
- mCurrentDir = dirname;
- }
-
- std::string tmp_str;
- tmp_str = dirname;
- tmp_str += mask;
-
- if(glob(tmp_str.c_str(), GLOB_NOSORT, NULL, &g) == 0)
- {
- if(g.gl_pathc > 0)
- {
- if(g.gl_pathc != mCurrentDirCount)
- {
- // Number of matches has changed since the last search, meaning a file has been added or deleted.
- // Reset the index.
- mCurrentDirIndex = -1;
- mCurrentDirCount = g.gl_pathc;
- }
-
- mCurrentDirIndex++;
-
- if((mCurrentDirIndex >= g.gl_pathc) && wrap)
- {
- mCurrentDirIndex = 0;
- }
-
- if(mCurrentDirIndex < g.gl_pathc)
- {
-// llinfos << "getNextFileInDir: returning number " << mCurrentDirIndex << ", path is " << g.gl_pathv[mCurrentDirIndex] << llendl;
-
- // The API wants just the filename, not the full path.
- //fname = g.gl_pathv[mCurrentDirIndex];
-
- char *s = strrchr(g.gl_pathv[mCurrentDirIndex], '/');
-
- if(s == NULL)
- s = g.gl_pathv[mCurrentDirIndex];
- else if(s[0] == '/')
- s++;
-
- fname = s;
-
- result = TRUE;
- }
- }
-
- globfree(&g);
- }
-
- return(result);
-}
-
-// get a random file in the directory
-void LLDir_Mac::getRandomFileInDir(const std::string &dirname, const std::string &mask, std::string &fname)
-{
- S32 which_file;
- glob_t g;
- fname = "";
-
- std::string tmp_str;
- tmp_str = dirname;
- tmp_str += mask;
-
- if(glob(tmp_str.c_str(), GLOB_NOSORT, NULL, &g) == 0)
- {
- if(g.gl_pathc > 0)
- {
-
- which_file = ll_rand(g.gl_pathc);
-
-// llinfos << "getRandomFileInDir: returning number " << which_file << ", path is " << g.gl_pathv[which_file] << llendl;
- // The API wants just the filename, not the full path.
- //fname = g.gl_pathv[which_file];
-
- char *s = strrchr(g.gl_pathv[which_file], '/');
-
- if(s == NULL)
- s = g.gl_pathv[which_file];
- else if(s[0] == '/')
- s++;
-
- fname = s;
- }
-
- globfree(&g);
- }
-}
-
S32 LLDir_Mac::deleteFilesInDir(const std::string &dirname, const std::string &mask)
{
glob_t g;
diff --git a/indra/llvfs/lldir_mac.h b/indra/llvfs/lldir_mac.h
index 04c52dc940..bc3f0fac00 100644
--- a/indra/llvfs/lldir_mac.h
+++ b/indra/llvfs/lldir_mac.h
@@ -24,6 +24,10 @@
* $/LicenseInfo$
*/
+#if !LL_DARWIN
+#error This header must not be included when compiling for any target other than Mac OS. Consider including lldir.h instead.
+#endif // !LL_DARWIN
+
#ifndef LL_LLDIR_MAC_H
#define LL_LLDIR_MAC_H
@@ -39,12 +43,10 @@ public:
/*virtual*/ void initAppDirs(const std::string &app_name,
const std::string& app_read_only_data_dir);
-public:
+
virtual S32 deleteFilesInDir(const std::string &dirname, const std::string &mask);
virtual std::string getCurPath();
virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask);
- virtual BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname, BOOL wrap);
- virtual void getRandomFileInDir(const std::string &dirname, const std::string &ask, std::string &fname);
virtual BOOL fileExists(const std::string &filename) const;
/*virtual*/ std::string getLLPluginLauncher();
diff --git a/indra/llvfs/lldir_solaris.cpp b/indra/llvfs/lldir_solaris.cpp
index 4323dfd44a..21f8c3acdb 100644
--- a/indra/llvfs/lldir_solaris.cpp
+++ b/indra/llvfs/lldir_solaris.cpp
@@ -260,114 +260,6 @@ U32 LLDir_Solaris::countFilesInDir(const std::string &dirname, const std::string
return (file_count);
}
-// get the next file in the directory
-// automatically wrap if we've hit the end
-BOOL LLDir_Solaris::getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname, BOOL wrap)
-{
- glob_t g;
- BOOL result = FALSE;
- fname = "";
-
- if(!(dirname == mCurrentDir))
- {
- // different dir specified, close old search
- mCurrentDirIndex = -1;
- mCurrentDirCount = -1;
- mCurrentDir = dirname;
- }
-
- std::string tmp_str;
- tmp_str = dirname;
- tmp_str += mask;
-
- if(glob(tmp_str.c_str(), GLOB_NOSORT, NULL, &g) == 0)
- {
- if(g.gl_pathc > 0)
- {
- if((int)g.gl_pathc != mCurrentDirCount)
- {
- // Number of matches has changed since the last search, meaning a file has been added or deleted.
- // Reset the index.
- mCurrentDirIndex = -1;
- mCurrentDirCount = g.gl_pathc;
- }
-
- mCurrentDirIndex++;
-
- if((mCurrentDirIndex >= (int)g.gl_pathc) && wrap)
- {
- mCurrentDirIndex = 0;
- }
-
- if(mCurrentDirIndex < (int)g.gl_pathc)
- {
-// llinfos << "getNextFileInDir: returning number " << mCurrentDirIndex << ", path is " << g.gl_pathv[mCurrentDirIndex] << llendl;
-
- // The API wants just the filename, not the full path.
- //fname = g.gl_pathv[mCurrentDirIndex];
-
- char *s = strrchr(g.gl_pathv[mCurrentDirIndex], '/');
-
- if(s == NULL)
- s = g.gl_pathv[mCurrentDirIndex];
- else if(s[0] == '/')
- s++;
-
- fname = s;
-
- result = TRUE;
- }
- }
-
- globfree(&g);
- }
-
- return(result);
-}
-
-
-// get a random file in the directory
-// automatically wrap if we've hit the end
-void LLDir_Solaris::getRandomFileInDir(const std::string &dirname, const std::string &mask, std::string &fname)
-{
- S32 num_files;
- S32 which_file;
- DIR *dirp;
- dirent *entryp = NULL;
-
- fname = "";
-
- num_files = countFilesInDir(dirname,mask);
- if (!num_files)
- {
- return;
- }
-
- which_file = ll_rand(num_files);
-
-// llinfos << "Random select file #" << which_file << llendl;
-
- // which_file now indicates the (zero-based) index to which file to play
-
- if (!((dirp = opendir(dirname.c_str()))))
- {
- while (which_file--)
- {
- if (!((entryp = readdir(dirp))))
- {
- return;
- }
- }
-
- if ((!which_file) && entryp)
- {
- fname = entryp->d_name;
- }
-
- closedir(dirp);
- }
-}
-
std::string LLDir_Solaris::getCurPath()
{
char tmp_str[LL_MAX_PATH]; /* Flawfinder: ignore */
diff --git a/indra/llvfs/lldir_solaris.h b/indra/llvfs/lldir_solaris.h
index 6e0c5cfc69..0b58a45b15 100644
--- a/indra/llvfs/lldir_solaris.h
+++ b/indra/llvfs/lldir_solaris.h
@@ -24,6 +24,10 @@
* $/LicenseInfo$
*/
+#if !LL_SOLARIS
+#error This header must not be included when compiling for any target other than Solaris. Consider including lldir.h instead.
+#endif // !LL_SOLARIS
+
#ifndef LL_LLDIR_SOLARIS_H
#define LL_LLDIR_SOLARIS_H
@@ -40,18 +44,16 @@ public:
/*virtual*/ void initAppDirs(const std::string &app_name,
const std::string& app_read_only_data_dir);
-public:
+
virtual std::string getCurPath();
virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask);
- virtual BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname, BOOL wrap);
- virtual void getRandomFileInDir(const std::string &dirname, const std::string &mask, std::string &fname);
/*virtual*/ BOOL fileExists(const std::string &filename) const;
private:
DIR *mDirp;
int mCurrentDirIndex;
int mCurrentDirCount;
- std::string mCurrentDir;
+ std::string mCurrentDir;
};
#endif // LL_LLDIR_SOLARIS_H
diff --git a/indra/llvfs/lldir_win32.cpp b/indra/llvfs/lldir_win32.cpp
index 52d864e26f..7709945123 100644
--- a/indra/llvfs/lldir_win32.cpp
+++ b/indra/llvfs/lldir_win32.cpp
@@ -81,10 +81,11 @@ LLDir_Win32::LLDir_Win32()
// fprintf(stderr, "mTempDir = <%s>",mTempDir);
-#if 1
- // Don't use the real app path for now, as we'll have to add parsing to detect if
- // we're in a developer tree, which has a different structure from the installed product.
+ // Set working directory, for LLDir::getWorkingDir()
+ GetCurrentDirectory(MAX_PATH, w_str);
+ mWorkingDir = utf16str_to_utf8str(llutf16string(w_str));
+ // Set the executable directory
S32 size = GetModuleFileName(NULL, w_str, MAX_PATH);
if (size)
{
@@ -100,32 +101,35 @@ LLDir_Win32::LLDir_Win32()
{
mExecutableFilename = mExecutablePathAndName;
}
- GetCurrentDirectory(MAX_PATH, w_str);
- mWorkingDir = utf16str_to_utf8str(llutf16string(w_str));
}
else
{
fprintf(stderr, "Couldn't get APP path, assuming current directory!");
- GetCurrentDirectory(MAX_PATH, w_str);
- mExecutableDir = utf16str_to_utf8str(llutf16string(w_str));
+ mExecutableDir = mWorkingDir;
// Assume it's the current directory
}
-#else
- GetCurrentDirectory(MAX_PATH, w_str);
- mExecutableDir = utf16str_to_utf8str(llutf16string(w_str));
-#endif
- if (mExecutableDir.find("indra") == std::string::npos)
+ // mAppRODataDir = ".";
+
+ // Determine the location of the App-Read-Only-Data
+ // Try the working directory then the exe's dir.
+ mAppRODataDir = mWorkingDir;
+
+
+// if (mExecutableDir.find("indra") == std::string::npos)
+
+ // *NOTE:Mani - It is a mistake to put viewer specific code in
+ // the LLDir implementation. The references to 'skins' and
+ // 'llplugin' need to go somewhere else.
+ // alas... this also gets called during static initialization
+ // time due to the construction of gDirUtil in lldir.cpp.
+ if(! LLFile::isdir(mAppRODataDir + mDirDelimiter + "skins"))
{
- // Running from installed directory. Make sure current
- // directory isn't something crazy (e.g. if invoking from
- // command line).
- SetCurrentDirectory(utf8str_to_utf16str(mExecutableDir).c_str());
- GetCurrentDirectory(MAX_PATH, w_str);
- mWorkingDir = utf16str_to_utf8str(llutf16string(w_str));
+ // What? No skins in the working dir?
+ // Try the executable's directory.
+ mAppRODataDir = mExecutableDir;
}
- mAppRODataDir = mWorkingDir;
llinfos << "mAppRODataDir = " << mAppRODataDir << llendl;
@@ -206,14 +210,6 @@ void LLDir_Win32::initAppDirs(const std::string &app_name,
}
}
- res = LLFile::mkdir(getExpandedFilename(LL_PATH_USER_SKIN,""));
- if (res == -1)
- {
- if (errno != EEXIST)
- {
- llwarns << "Couldn't create LL_PATH_SKINS dir " << getExpandedFilename(LL_PATH_USER_SKIN,"") << llendl;
- }
- }
mCAFile = getExpandedFilename(LL_PATH_APP_SETTINGS, "CA.pem");
}
@@ -244,122 +240,6 @@ U32 LLDir_Win32::countFilesInDir(const std::string &dirname, const std::string &
return (file_count);
}
-
-// get the next file in the directory
-// automatically wrap if we've hit the end
-BOOL LLDir_Win32::getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname, BOOL wrap)
-{
- llutf16string dirnamew = utf8str_to_utf16str(dirname);
- return getNextFileInDir(dirnamew, mask, fname, wrap);
-
-}
-
-BOOL LLDir_Win32::getNextFileInDir(const llutf16string &dirname, const std::string &mask, std::string &fname, BOOL wrap)
-{
- WIN32_FIND_DATAW FileData;
-
- fname = "";
- llutf16string pathname = dirname;
- pathname += utf8str_to_utf16str(mask);
-
- if (pathname != mCurrentDir)
- {
- // different dir specified, close old search
- if (mCurrentDir[0])
- {
- FindClose(mDirSearch_h);
- }
- mCurrentDir = pathname;
-
- // and open new one
- // Check error opening Directory structure
- if ((mDirSearch_h = FindFirstFile(pathname.c_str(), &FileData)) == INVALID_HANDLE_VALUE)
- {
-// llinfos << "Unable to locate first file" << llendl;
- return(FALSE);
- }
- }
- else // get next file in list
- {
- // Find next entry
- if (!FindNextFile(mDirSearch_h, &FileData))
- {
- if (GetLastError() == ERROR_NO_MORE_FILES)
- {
- // No more files, so reset to beginning of directory
- FindClose(mDirSearch_h);
- mCurrentDir[0] = NULL;
-
- if (wrap)
- {
- return(getNextFileInDir(pathname,"",fname,TRUE));
- }
- else
- {
- fname[0] = 0;
- return(FALSE);
- }
- }
- else
- {
- // Error
-// llinfos << "Unable to locate next file" << llendl;
- return(FALSE);
- }
- }
- }
-
- // convert from TCHAR to char
- fname = utf16str_to_utf8str(FileData.cFileName);
-
- // fname now first name in list
- return(TRUE);
-}
-
-
-// get a random file in the directory
-// automatically wrap if we've hit the end
-void LLDir_Win32::getRandomFileInDir(const std::string &dirname, const std::string &mask, std::string &fname)
-{
- S32 num_files;
- S32 which_file;
- HANDLE random_search_h;
-
- fname = "";
-
- llutf16string pathname = utf8str_to_utf16str(dirname);
- pathname += utf8str_to_utf16str(mask);
-
- WIN32_FIND_DATA FileData;
- fname[0] = NULL;
-
- num_files = countFilesInDir(dirname,mask);
- if (!num_files)
- {
- return;
- }
-
- which_file = ll_rand(num_files);
-
-// llinfos << "Random select mp3 #" << which_file << llendl;
-
- // which_file now indicates the (zero-based) index to which file to play
-
- if ((random_search_h = FindFirstFile(pathname.c_str(), &FileData)) != INVALID_HANDLE_VALUE)
- {
- while (which_file--)
- {
- if (!FindNextFile(random_search_h, &FileData))
- {
- return;
- }
- }
- FindClose(random_search_h);
-
- fname = utf16str_to_utf8str(llutf16string(FileData.cFileName));
- }
-}
-
std::string LLDir_Win32::getCurPath()
{
WCHAR w_str[MAX_PATH];
diff --git a/indra/llvfs/lldir_win32.h b/indra/llvfs/lldir_win32.h
index d3e45dc1f3..62fb4713ab 100644
--- a/indra/llvfs/lldir_win32.h
+++ b/indra/llvfs/lldir_win32.h
@@ -24,6 +24,10 @@
* $/LicenseInfo$
*/
+#if !LL_WINDOWS
+#error This header must not be included when compiling for any target other than Windows. Consider including lldir.h instead.
+#endif // !LL_WINDOWS
+
#ifndef LL_LLDIR_WIN32_H
#define LL_LLDIR_WIN32_H
@@ -40,16 +44,12 @@ public:
/*virtual*/ std::string getCurPath();
/*virtual*/ U32 countFilesInDir(const std::string &dirname, const std::string &mask);
- /*virtual*/ BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname, BOOL wrap);
- /*virtual*/ void getRandomFileInDir(const std::string &dirname, const std::string &mask, std::string &fname);
/*virtual*/ BOOL fileExists(const std::string &filename) const;
/*virtual*/ std::string getLLPluginLauncher();
/*virtual*/ std::string getLLPluginFilename(std::string base_name);
private:
- BOOL LLDir_Win32::getNextFileInDir(const llutf16string &dirname, const std::string &mask, std::string &fname, BOOL wrap);
-
void* mDirSearch_h;
llutf16string mCurrentDir;
};
diff --git a/indra/llvfs/lldiriterator.cpp b/indra/llvfs/lldiriterator.cpp
new file mode 100644
index 0000000000..041436ed92
--- /dev/null
+++ b/indra/llvfs/lldiriterator.cpp
@@ -0,0 +1,203 @@
+/**
+ * @file lldiriterator.cpp
+ * @brief Iterator through directory entries matching the search pattern.
+ *
+ * $LicenseInfo:firstyear=2010&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 "lldiriterator.h"
+
+#include <boost/filesystem.hpp>
+#include <boost/regex.hpp>
+
+namespace fs = boost::filesystem;
+
+static std::string glob_to_regex(const std::string& glob);
+
+class LLDirIterator::Impl
+{
+public:
+ Impl(const std::string &dirname, const std::string &mask);
+ ~Impl();
+
+ bool next(std::string &fname);
+
+private:
+ boost::regex mFilterExp;
+ fs::directory_iterator mIter;
+ bool mIsValid;
+};
+
+LLDirIterator::Impl::Impl(const std::string &dirname, const std::string &mask)
+ : mIsValid(false)
+{
+ fs::path dir_path(dirname);
+
+ // Check if path exists.
+ if (!fs::exists(dir_path))
+ {
+ llwarns << "Invalid path: \"" << dir_path.string() << "\"" << llendl;
+ return;
+ }
+
+ // Initialize the directory iterator for the given path.
+ try
+ {
+ mIter = fs::directory_iterator(dir_path);
+ }
+ catch (fs::basic_filesystem_error<fs::path>& e)
+ {
+ llerrs << e.what() << llendl;
+ return;
+ }
+
+ // Convert the glob mask to a regular expression
+ std::string exp = glob_to_regex(mask);
+
+ // Initialize boost::regex with the expression converted from
+ // the glob mask.
+ // An exception is thrown if the expression is not valid.
+ try
+ {
+ mFilterExp.assign(exp);
+ }
+ catch (boost::regex_error& e)
+ {
+ llerrs << "\"" << exp << "\" is not a valid regular expression: "
+ << e.what() << llendl;
+ return;
+ }
+
+ mIsValid = true;
+}
+
+LLDirIterator::Impl::~Impl()
+{
+}
+
+bool LLDirIterator::Impl::next(std::string &fname)
+{
+ fname = "";
+
+ if (!mIsValid)
+ {
+ llwarns << "The iterator is not correctly initialized." << llendl;
+ return false;
+ }
+
+ fs::directory_iterator end_itr; // default construction yields past-the-end
+ bool found = false;
+ while (mIter != end_itr && !found)
+ {
+ boost::smatch match;
+ std::string name = mIter->path().filename();
+ if (found = boost::regex_match(name, match, mFilterExp))
+ {
+ fname = name;
+ }
+
+ ++mIter;
+ }
+
+ return found;
+}
+
+std::string glob_to_regex(const std::string& glob)
+{
+ std::string regex;
+ regex.reserve(glob.size()<<1);
+ S32 braces = 0;
+ bool escaped = false;
+ bool square_brace_open = false;
+
+ for (std::string::const_iterator i = glob.begin(); i != glob.end(); ++i)
+ {
+ char c = *i;
+
+ switch (c)
+ {
+ case '.':
+ regex+="\\.";
+ break;
+ case '*':
+ if (glob.begin() == i)
+ {
+ regex+="[^.].*";
+ }
+ else
+ {
+ regex+= escaped ? "*" : ".*";
+ }
+ break;
+ case '?':
+ regex+= escaped ? '?' : '.';
+ break;
+ case '{':
+ braces++;
+ regex+='(';
+ break;
+ case '}':
+ if (!braces)
+ {
+ llerrs << "glob_to_regex: Closing brace without an equivalent opening brace: " << glob << llendl;
+ }
+
+ regex+=')';
+ braces--;
+ break;
+ case ',':
+ regex+= braces ? '|' : c;
+ break;
+ case '!':
+ regex+= square_brace_open ? '^' : c;
+ break;
+ default:
+ regex+=c;
+ break;
+ }
+
+ escaped = ('\\' == c);
+ square_brace_open = ('[' == c);
+ }
+
+ if (braces)
+ {
+ llerrs << "glob_to_regex: Unterminated brace expression: " << glob << llendl;
+ }
+
+ return regex;
+}
+
+LLDirIterator::LLDirIterator(const std::string &dirname, const std::string &mask)
+{
+ mImpl = new Impl(dirname, mask);
+}
+
+LLDirIterator::~LLDirIterator()
+{
+ delete mImpl;
+}
+
+bool LLDirIterator::next(std::string &fname)
+{
+ return mImpl->next(fname);
+}
diff --git a/indra/llvfs/lldiriterator.h b/indra/llvfs/lldiriterator.h
new file mode 100644
index 0000000000..0b48be41b3
--- /dev/null
+++ b/indra/llvfs/lldiriterator.h
@@ -0,0 +1,87 @@
+/**
+ * @file lldiriterator.h
+ * @brief Iterator through directory entries matching the search pattern.
+ *
+ * $LicenseInfo:firstyear=2010&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_LLDIRITERATOR_H
+#define LL_LLDIRITERATOR_H
+
+#include "linden_common.h"
+
+/**
+ * Class LLDirIterator
+ *
+ * Iterates through directory entries matching the search pattern.
+ */
+class LLDirIterator
+{
+public:
+ /**
+ * Constructs LLDirIterator object to search for glob pattern
+ * matches in a directory.
+ *
+ * @param dirname - name of a directory to search in.
+ * @param mask - search pattern, a glob expression
+ *
+ * Wildcards supported in glob expressions:
+ * --------------------------------------------------------------
+ * | Wildcard | Matches |
+ * --------------------------------------------------------------
+ * | * |zero or more characters |
+ * | ? |exactly one character |
+ * | [abcde] |exactly one character listed |
+ * | [a-e] |exactly one character in the given range |
+ * | [!abcde] |any character that is not listed |
+ * | [!a-e] |any character that is not in the given range |
+ * | {abc,xyz} |exactly one entire word in the options given |
+ * --------------------------------------------------------------
+ */
+ LLDirIterator(const std::string &dirname, const std::string &mask);
+
+ ~LLDirIterator();
+
+ /**
+ * Searches for the next directory entry matching the glob mask
+ * specified upon iterator construction.
+ * Returns true if a match is found, sets fname
+ * parameter to the name of the matched directory entry and
+ * increments the iterator position.
+ *
+ * Typical usage:
+ * <code>
+ * LLDirIterator iter(directory, pattern);
+ * if ( iter.next(scanResult) )
+ * </code>
+ *
+ * @param fname - name of the matched directory entry.
+ * @return true if a match is found, false otherwise.
+ */
+ bool next(std::string &fname);
+
+protected:
+ class Impl;
+ Impl* mImpl;
+};
+
+#endif //LL_LLDIRITERATOR_H
diff --git a/indra/llvfs/llvfile.cpp b/indra/llvfs/llvfile.cpp
index a8db7b235e..ca749c5eaf 100644
--- a/indra/llvfs/llvfile.cpp
+++ b/indra/llvfs/llvfile.cpp
@@ -314,7 +314,7 @@ BOOL LLVFile::setMaxSize(S32 size)
if (!mVFS->checkAvailable(size))
{
- LLFastTimer t(FTM_VFILE_WAIT);
+ //LLFastTimer t(FTM_VFILE_WAIT);
S32 count = 0;
while (sVFSThread->getPending() > 1000)
{
@@ -422,7 +422,7 @@ bool LLVFile::isLocked(EVFSLock lock)
void LLVFile::waitForLock(EVFSLock lock)
{
- LLFastTimer t(FTM_VFILE_WAIT);
+ //LLFastTimer t(FTM_VFILE_WAIT);
// spin until the lock clears
while (isLocked(lock))
{
diff --git a/indra/llvfs/llvfs.cpp b/indra/llvfs/llvfs.cpp
index c1fe21c57d..82c926620a 100644
--- a/indra/llvfs/llvfs.cpp
+++ b/indra/llvfs/llvfs.cpp
@@ -26,6 +26,8 @@
#include "linden_common.h"
+#include "llvfs.h"
+
#include <sys/stat.h>
#include <set>
#include <map>
@@ -39,8 +41,6 @@
#include <sys/file.h>
#endif
-#include "llvfs.h"
-
#include "llstl.h"
#include "lltimer.h"
@@ -1711,7 +1711,8 @@ void LLVFS::audit()
BOOL vfs_corrupt = FALSE;
- std::vector<U8> buffer(index_size);
+ // since we take the address of element 0, we need to have at least one element.
+ std::vector<U8> buffer(llmax<size_t>(index_size,1U));
if (fread(&buffer[0], 1, index_size, mIndexFP) != index_size)
{
@@ -2035,6 +2036,9 @@ std::string get_extension(LLAssetType::EType type)
case LLAssetType::AT_ANIMATION:
extension = ".lla";
break;
+ case LLAssetType::AT_MESH:
+ extension = ".slm";
+ break;
default:
// Just use the asset server filename extension in most cases
extension += ".";
diff --git a/indra/llvfs/tests/lldir_test.cpp b/indra/llvfs/tests/lldir_test.cpp
index bcffa449c8..ea321c5ae9 100644
--- a/indra/llvfs/tests/lldir_test.cpp
+++ b/indra/llvfs/tests/lldir_test.cpp
@@ -28,6 +28,7 @@
#include "linden_common.h"
#include "../lldir.h"
+#include "../lldiriterator.h"
#include "../test/lltut.h"
@@ -256,5 +257,167 @@ namespace tut
gDirUtilp->getExtension(dottedPathExt),
"ext");
}
+
+ std::string makeTestFile( const std::string& dir, const std::string& file )
+ {
+ std::string path = dir + file;
+ LLFILE* handle = LLFile::fopen( path, "w" );
+ ensure("failed to open test file '"+path+"'", handle != NULL );
+ // Harbison & Steele, 4th ed., p. 366: "If an error occurs, fputs
+ // returns EOF; otherwise, it returns some other, nonnegative value."
+ ensure("failed to write to test file '"+path+"'", EOF != fputs("test file", handle) );
+ fclose(handle);
+ return path;
+ }
+
+ std::string makeTestDir( const std::string& dirbase )
+ {
+ int counter;
+ std::string uniqueDir;
+ bool foundUnused;
+ std::string delim = gDirUtilp->getDirDelimiter();
+
+ for (counter=0, foundUnused=false; !foundUnused; counter++ )
+ {
+ char counterStr[3];
+ sprintf(counterStr, "%02d", counter);
+ uniqueDir = dirbase + counterStr;
+ foundUnused = ! ( LLFile::isdir(uniqueDir) || LLFile::isfile(uniqueDir) );
+ }
+ ensure("test directory '" + uniqueDir + "' creation failed", !LLFile::mkdir(uniqueDir));
+
+ return uniqueDir + delim; // HACK - apparently, the trailing delimiter is needed...
+ }
+
+ static const char* DirScanFilename[5] = { "file1.abc", "file2.abc", "file1.xyz", "file2.xyz", "file1.mno" };
+
+ void scanTest(const std::string& directory, const std::string& pattern, bool correctResult[5])
+ {
+
+ // Scan directory and see if any file1.* files are found
+ std::string scanResult;
+ int found = 0;
+ bool filesFound[5] = { false, false, false, false, false };
+ //std::cerr << "searching '"+directory+"' for '"+pattern+"'\n";
+
+ LLDirIterator iter(directory, pattern);
+ while ( found <= 5 && iter.next(scanResult) )
+ {
+ found++;
+ //std::cerr << " found '"+scanResult+"'\n";
+ int check;
+ for (check=0; check < 5 && ! ( scanResult == DirScanFilename[check] ); check++)
+ {
+ }
+ // check is now either 5 (not found) or the index of the matching name
+ if (check < 5)
+ {
+ ensure( "found file '"+(std::string)DirScanFilename[check]+"' twice", ! filesFound[check] );
+ filesFound[check] = true;
+ }
+ else // check is 5 - should not happen
+ {
+ fail( "found unknown file '"+scanResult+"'");
+ }
+ }
+ for (int i=0; i<5; i++)
+ {
+ if (correctResult[i])
+ {
+ ensure("scan of '"+directory+"' using '"+pattern+"' did not return '"+DirScanFilename[i]+"'", filesFound[i]);
+ }
+ else
+ {
+ ensure("scan of '"+directory+"' using '"+pattern+"' incorrectly returned '"+DirScanFilename[i]+"'", !filesFound[i]);
+ }
+ }
+ }
+
+ template<> template<>
+ void LLDirTest_object_t::test<5>()
+ // LLDirIterator::next
+ {
+ std::string delim = gDirUtilp->getDirDelimiter();
+ std::string dirTemp = LLFile::tmpdir();
+
+ // Create the same 5 file names of the two directories
+
+ std::string dir1 = makeTestDir(dirTemp + "LLDirIterator");
+ std::string dir2 = makeTestDir(dirTemp + "LLDirIterator");
+ std::string dir1files[5];
+ std::string dir2files[5];
+ for (int i=0; i<5; i++)
+ {
+ dir1files[i] = makeTestFile(dir1, DirScanFilename[i]);
+ dir2files[i] = makeTestFile(dir2, DirScanFilename[i]);
+ }
+
+ // Scan dir1 and see if each of the 5 files is found exactly once
+ bool expected1[5] = { true, true, true, true, true };
+ scanTest(dir1, "*", expected1);
+
+ // Scan dir2 and see if only the 2 *.xyz files are found
+ bool expected2[5] = { false, false, true, true, false };
+ scanTest(dir1, "*.xyz", expected2);
+
+ // Scan dir2 and see if only the 1 *.mno file is found
+ bool expected3[5] = { false, false, false, false, true };
+ scanTest(dir2, "*.mno", expected3);
+
+ // Scan dir1 and see if any *.foo files are found
+ bool expected4[5] = { false, false, false, false, false };
+ scanTest(dir1, "*.foo", expected4);
+
+ // Scan dir1 and see if any file1.* files are found
+ bool expected5[5] = { true, false, true, false, true };
+ scanTest(dir1, "file1.*", expected5);
+
+ // Scan dir1 and see if any file1.* files are found
+ bool expected6[5] = { true, true, false, false, false };
+ scanTest(dir1, "file?.abc", expected6);
+
+ // Scan dir2 and see if any file?.x?z files are found
+ bool expected7[5] = { false, false, true, true, false };
+ scanTest(dir2, "file?.x?z", expected7);
+
+ // Scan dir2 and see if any file?.??c files are found
+ bool expected8[5] = { true, true, false, false, false };
+ scanTest(dir2, "file?.??c", expected8);
+ scanTest(dir2, "*.??c", expected8);
+
+ // Scan dir1 and see if any *.?n? files are found
+ bool expected9[5] = { false, false, false, false, true };
+ scanTest(dir1, "*.?n?", expected9);
+
+ // Scan dir1 and see if any *.???? files are found
+ bool expected10[5] = { false, false, false, false, false };
+ scanTest(dir1, "*.????", expected10);
+
+ // Scan dir1 and see if any ?????.* files are found
+ bool expected11[5] = { true, true, true, true, true };
+ scanTest(dir1, "?????.*", expected11);
+
+ // Scan dir1 and see if any ??l??.xyz files are found
+ bool expected12[5] = { false, false, true, true, false };
+ scanTest(dir1, "??l??.xyz", expected12);
+
+ bool expected13[5] = { true, false, true, false, false };
+ scanTest(dir1, "file1.{abc,xyz}", expected13);
+
+ bool expected14[5] = { true, true, false, false, false };
+ scanTest(dir1, "file[0-9].abc", expected14);
+
+ bool expected15[5] = { true, true, false, false, false };
+ scanTest(dir1, "file[!a-z].abc", expected15);
+
+ // clean up all test files and directories
+ for (int i=0; i<5; i++)
+ {
+ LLFile::remove(dir1files[i]);
+ LLFile::remove(dir2files[i]);
+ }
+ LLFile::rmdir(dir1);
+ LLFile::rmdir(dir2);
+ }
}
diff --git a/indra/llwindow/CMakeLists.txt b/indra/llwindow/CMakeLists.txt
index bf3233f386..3d89867bc1 100644
--- a/indra/llwindow/CMakeLists.txt
+++ b/indra/llwindow/CMakeLists.txt
@@ -30,20 +30,25 @@ include_directories(
${LLVFS_INCLUDE_DIRS}
${LLWINDOW_INCLUDE_DIRS}
${LLXML_INCLUDE_DIRS}
+ ${DIRECTX_INCLUDE_DIR}
)
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
@@ -59,12 +64,13 @@ set(viewer_HEADER_FILES
# Libraries on which this library depends, needed for Linux builds
# Sort by high-level to low-level
-if (NOT LINUX OR VIEWER)
+if (LINUX AND VIEWER)
set(llwindow_LINK_LIBRARIES
${UI_LIBRARIES} # for GTK
${SDL_LIBRARY}
+ fontconfig # For FCInit and other FC* functions.
)
-endif (NOT LINUX OR VIEWER)
+endif (LINUX AND VIEWER)
if (DARWIN)
list(APPEND llwindow_SOURCE_FILES
diff --git a/indra/llwindow/llkeyboard.h b/indra/llwindow/llkeyboard.h
index be16f31abc..ba472cfde5 100644
--- a/indra/llwindow/llkeyboard.h
+++ b/indra/llwindow/llkeyboard.h
@@ -40,7 +40,7 @@ enum EKeystate
KEYSTATE_UP
};
-typedef void (*LLKeyFunc)(EKeystate keystate);
+typedef boost::function<void(EKeystate keystate)> LLKeyFunc;
typedef std::string (LLKeyStringTranslatorFunc)(const char *label);
enum EKeyboardInsertMode
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/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp
index affd7276cc..cb2abc5bc0 100644
--- a/indra/llwindow/llwindowmacosx.cpp
+++ b/indra/llwindow/llwindowmacosx.cpp
@@ -108,9 +108,6 @@ static long getDictLong (CFDictionaryRef refDict, CFStringRef key);
static EventTypeSpec WindowHandlerEventList[] =
{
// Window-related events
- // { kEventClassWindow, kEventWindowCollapsing },
- // { kEventClassWindow, kEventWindowCollapsed },
- // { kEventClassWindow, kEventWindowShown },
{ kEventClassWindow, kEventWindowActivated },
{ kEventClassWindow, kEventWindowDeactivated },
{ kEventClassWindow, kEventWindowShown },
@@ -121,8 +118,7 @@ static EventTypeSpec WindowHandlerEventList[] =
{ kEventClassWindow, kEventWindowClose },
{ kEventClassWindow, kEventWindowBoundsChanging },
{ kEventClassWindow, kEventWindowBoundsChanged },
- // { kEventClassWindow, kEventWindowZoomed },
- // { kEventClassWindow, kEventWindowDrawContent },
+ { kEventClassWindow, kEventWindowGetIdealSize },
// Mouse events
{ kEventClassMouse, kEventMouseDown },
@@ -248,6 +244,7 @@ LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks,
mCursorIgnoreNextDelta = FALSE;
mNeedsResize = FALSE;
mOverrideAspectRatio = 0.f;
+ mMaximized = FALSE;
mMinimized = FALSE;
mTSMDocument = NULL; // Just in case.
mLanguageTextInputAllowed = FALSE;
@@ -455,24 +452,23 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits
if(!mFullscreen && (mWindow == NULL))
{
- Rect window_rect;
//int displayWidth = CGDisplayPixelsWide(mDisplay);
//int displayHeight = CGDisplayPixelsHigh(mDisplay);
//const int menuBarPlusTitleBar = 44; // Ugly magic number.
LL_DEBUGS("Window") << "createContext: creating window" << LL_ENDL;
- window_rect.left = (long) x;
- window_rect.right = (long) x + width;
- window_rect.top = (long) y;
- window_rect.bottom = (long) y + height;
+ mPreviousWindowRect.left = (long) x;
+ mPreviousWindowRect.right = (long) x + width;
+ mPreviousWindowRect.top = (long) y;
+ mPreviousWindowRect.bottom = (long) y + height;
//-----------------------------------------------------------------------
// Create the window
//-----------------------------------------------------------------------
mWindow = NewCWindow(
NULL,
- &window_rect,
+ &mPreviousWindowRect,
mWindowTitle,
false, // Create the window invisible. Whoever calls createContext() should show it after any moving/resizing.
// noGrowDocProc, // Window with no grow box and no zoom box
@@ -481,8 +477,7 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits
kFirstWindowOfClass,
true,
(long)this);
-
-
+
if (!mWindow)
{
setupFailure("Window creation error", "Error", OSMB_OK);
@@ -541,20 +536,20 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits
GLint fullscreenAttrib[] =
{
AGL_RGBA,
- AGL_FULLSCREEN,
- // AGL_NO_RECOVERY, // MBW -- XXX -- Not sure if we want this attribute
- AGL_SAMPLE_BUFFERS_ARB, mFSAASamples > 0 ? 1 : 0,
- AGL_SAMPLES_ARB, mFSAASamples,
- AGL_DOUBLEBUFFER,
- AGL_CLOSEST_POLICY,
- AGL_ACCELERATED,
- AGL_RED_SIZE, 8,
- AGL_GREEN_SIZE, 8,
- AGL_BLUE_SIZE, 8,
- AGL_ALPHA_SIZE, 8,
- AGL_DEPTH_SIZE, 24,
- AGL_STENCIL_SIZE, 8,
- AGL_NONE
+ AGL_FULLSCREEN,
+ AGL_NO_RECOVERY,
+ AGL_SAMPLE_BUFFERS_ARB, mFSAASamples > 0 ? 1 : 0,
+ AGL_SAMPLES_ARB, mFSAASamples,
+ AGL_DOUBLEBUFFER,
+ AGL_CLOSEST_POLICY,
+ AGL_ACCELERATED,
+ AGL_RED_SIZE, 8,
+ AGL_GREEN_SIZE, 8,
+ AGL_BLUE_SIZE, 8,
+ AGL_ALPHA_SIZE, 8,
+ AGL_DEPTH_SIZE, 24,
+ AGL_STENCIL_SIZE, 8,
+ AGL_NONE
};
LL_DEBUGS("Window") << "createContext: creating fullscreen pixelformat" << LL_ENDL;
@@ -567,21 +562,28 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits
}
else
{
+ // NOTE from Leslie:
+ //
+ // AGL_NO_RECOVERY, when combined with AGL_ACCELERATED prevents software rendering
+ // fallback which means we won't hvae shaders that compile and link but then don't
+ // work. The drawback is that our shader compilation will be a bit more finicky though.
+
GLint windowedAttrib[] =
{
AGL_RGBA,
- AGL_DOUBLEBUFFER,
- AGL_CLOSEST_POLICY,
- AGL_ACCELERATED,
- AGL_SAMPLE_BUFFERS_ARB, mFSAASamples > 0 ? 1 : 0,
- AGL_SAMPLES_ARB, mFSAASamples,
- AGL_RED_SIZE, 8,
- AGL_GREEN_SIZE, 8,
- AGL_BLUE_SIZE, 8,
- AGL_ALPHA_SIZE, 8,
- AGL_DEPTH_SIZE, 24,
- AGL_STENCIL_SIZE, 8,
- AGL_NONE
+ AGL_NO_RECOVERY,
+ AGL_DOUBLEBUFFER,
+ AGL_CLOSEST_POLICY,
+ AGL_ACCELERATED,
+ AGL_SAMPLE_BUFFERS_ARB, mFSAASamples > 0 ? 1 : 0,
+ AGL_SAMPLES_ARB, mFSAASamples,
+ AGL_RED_SIZE, 8,
+ AGL_GREEN_SIZE, 8,
+ AGL_BLUE_SIZE, 8,
+ AGL_ALPHA_SIZE, 8,
+ AGL_DEPTH_SIZE, 24,
+ AGL_STENCIL_SIZE, 8,
+ AGL_NONE
};
LL_DEBUGS("Window") << "createContext: creating windowed pixelformat" << LL_ENDL;
@@ -1093,31 +1095,22 @@ BOOL LLWindowMacOSX::getVisible()
BOOL LLWindowMacOSX::getMinimized()
{
- BOOL result = FALSE;
-
- // Since the set of states where we want to act "minimized" is non-trivial, it's easier to
- // track things locally than to try and retrieve the state from the window manager.
- result = mMinimized;
-
- return(result);
+ return mMinimized;
}
BOOL LLWindowMacOSX::getMaximized()
{
- BOOL result = FALSE;
-
- if (mWindow)
- {
- // TODO
- }
-
- return(result);
+ return mMaximized;
}
BOOL LLWindowMacOSX::maximize()
{
- // TODO
- return FALSE;
+ if (mWindow && !mMaximized)
+ {
+ ZoomWindow(mWindow, inContent, true);
+ }
+
+ return mMaximized;
}
BOOL LLWindowMacOSX::getFullscreen()
@@ -2559,7 +2552,24 @@ OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef e
GetEventParameter(event, kEventParamCurrentBounds, typeQDRectangle, NULL, sizeof(Rect), NULL, &currentBounds);
GetEventParameter(event, kEventParamPreviousBounds, typeQDRectangle, NULL, sizeof(Rect), NULL, &previousBounds);
-
+
+ // Put an offset into window un-maximize operation since the kEventWindowGetIdealSize
+ // event only allows the specification of size and not position.
+ if (mMaximized)
+ {
+ short leftOffset = mPreviousWindowRect.left - currentBounds.left;
+ currentBounds.left += leftOffset;
+ currentBounds.right += leftOffset;
+
+ short topOffset = mPreviousWindowRect.top - currentBounds.top;
+ currentBounds.top += topOffset;
+ currentBounds.bottom += topOffset;
+ }
+ else
+ {
+ // Store off the size for future un-maximize operations
+ mPreviousWindowRect = previousBounds;
+ }
if ((currentBounds.right - currentBounds.left) < MIN_WIDTH)
{
@@ -2578,13 +2588,43 @@ OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef e
case kEventWindowBoundsChanged:
{
+ // Get new window bounds
Rect newBounds;
-
GetEventParameter(event, kEventParamCurrentBounds, typeQDRectangle, NULL, sizeof(Rect), NULL, &newBounds);
+
+ // Get previous window bounds
+ Rect oldBounds;
+ GetEventParameter(event, kEventParamPreviousBounds, typeQDRectangle, NULL, sizeof(Rect), NULL, &oldBounds);
+
+ // Determine if the new size is larger than the old
+ bool newBoundsLarger = ((newBounds.right - newBounds.left) >= (oldBounds.right - oldBounds.left));
+ newBoundsLarger &= ((newBounds.bottom - newBounds.top) >= (oldBounds.bottom - oldBounds.top));
+
+ // Check to see if this is a zoom event (+ button on window pane)
+ unsigned int eventParams;
+ GetEventParameter(event, kEventParamAttributes, typeUInt32, NULL, sizeof(int), NULL, &eventParams);
+ bool isZoomEvent = ((eventParams & kWindowBoundsChangeZoom) != 0);
+
+ // Maximized flag is if zoom event and increasing window size
+ mMaximized = (isZoomEvent && newBoundsLarger);
+
aglUpdateContext(mContext);
+
mCallbacks->handleResize(this, newBounds.right - newBounds.left, newBounds.bottom - newBounds.top);
-
-
+ }
+ break;
+
+ case kEventWindowGetIdealSize:
+ // Only recommend a new ideal size when un-maximizing
+ if (mMaximized == TRUE)
+ {
+ Point nonMaximizedSize;
+
+ nonMaximizedSize.v = mPreviousWindowRect.bottom - mPreviousWindowRect.top;
+ nonMaximizedSize.h = mPreviousWindowRect.right - mPreviousWindowRect.left;
+
+ SetEventParameter(event, kEventParamDimensions, typeQDPoint, sizeof(Point), &nonMaximizedSize);
+ result = noErr;
}
break;
diff --git a/indra/llwindow/llwindowmacosx.h b/indra/llwindow/llwindowmacosx.h
index 6dc093b4be..6c9e075a21 100644
--- a/indra/llwindow/llwindowmacosx.h
+++ b/indra/llwindow/llwindowmacosx.h
@@ -156,7 +156,6 @@ protected:
static pascal Boolean staticMoveEventComparator( EventRef event, void* data);
OSStatus eventHandler (EventHandlerCallRef myHandler, EventRef event);
void adjustCursorDecouple(bool warpingMouse = false);
- void fixWindowSize(void);
void stopDockTileBounce();
static MASK modifiersToMask(SInt16 modifiers);
@@ -182,6 +181,7 @@ protected:
EventComparatorUPP mMoveEventCampartorUPP;
Rect mOldMouseClip; // Screen rect to which the mouse cursor was globally constrained before we changed it in clipMouse()
+ Rect mPreviousWindowRect; // Save previous window for un-maximize event
Str255 mWindowTitle;
double mOriginalAspectRatio;
BOOL mSimulatedRightClick;
@@ -195,6 +195,7 @@ protected:
BOOL mNeedsResize; // Constructor figured out the window is too big, it needs a resize.
LLCoordScreen mNeedsResizeSize;
F32 mOverrideAspectRatio;
+ BOOL mMaximized;
BOOL mMinimized;
U32 mFSAASamples;
BOOL mForceRebuild;
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index 87075c7318..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))
{
@@ -544,7 +546,27 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
if (closest_refresh == 0)
{
LL_WARNS("Window") << "Couldn't find display mode " << width << " by " << height << " at " << BITS_PER_PIXEL << " bits per pixel" << LL_ENDL;
- success = FALSE;
+ //success = FALSE;
+
+ if (!EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode))
+ {
+ success = FALSE;
+ }
+ else
+ {
+ if (dev_mode.dmBitsPerPel == BITS_PER_PIXEL)
+ {
+ LL_WARNS("Window") << "Current BBP is OK falling back to that" << LL_ENDL;
+ window_rect.right=width=dev_mode.dmPelsWidth;
+ window_rect.bottom=height=dev_mode.dmPelsHeight;
+ success = TRUE;
+ }
+ else
+ {
+ LL_WARNS("Window") << "Current BBP is BAD" << LL_ENDL;
+ success = FALSE;
+ }
+ }
}
// If we found a good resolution, use it.
@@ -858,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;
@@ -2691,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++)
@@ -2766,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/llxml/CMakeLists.txt b/indra/llxml/CMakeLists.txt
index eb5166ee71..21cdf5f926 100644
--- a/indra/llxml/CMakeLists.txt
+++ b/indra/llxml/CMakeLists.txt
@@ -45,27 +45,25 @@ target_link_libraries( llxml
${EXPAT_LIBRARIES}
)
+# tests
-if(LL_TESTS)
- # tests
+if (LL_TESTS)
+ # unit tests
- # unit tests
+ SET(llxml_TEST_SOURCE_FILES
+ # none yet!
+ )
+ LL_ADD_PROJECT_UNIT_TESTS(llxml "${llxml_TEST_SOURCE_FILES}")
- SET(llxml_TEST_SOURCE_FILES
- # none yet!
- )
- LL_ADD_PROJECT_UNIT_TESTS(llxml "${llxml_TEST_SOURCE_FILES}")
+ # integration tests
- # integration tests
+ # set(TEST_DEBUG on)
+ set(test_libs
+ ${LLXML_LIBRARIES}
+ ${WINDOWS_LIBRARIES}
+ ${LLMATH_LIBRARIES}
+ ${LLCOMMON_LIBRARIES}
+ )
- # set(TEST_DEBUG on)
- set(test_libs
- ${LLXML_LIBRARIES}
- ${WINDOWS_LIBRARIES}
- ${LLMATH_LIBRARIES}
- ${LLCOMMON_LIBRARIES}
- )
-
- LL_ADD_INTEGRATION_TEST(llcontrol "" "${test_libs}")
-
-endif(LL_TESTS)
+ LL_ADD_INTEGRATION_TEST(llcontrol "" "${test_libs}")
+endif (LL_TESTS)
diff --git a/indra/llxml/llcontrol.cpp b/indra/llxml/llcontrol.cpp
index f9a39826f5..0809d95628 100644
--- a/indra/llxml/llcontrol.cpp
+++ b/indra/llxml/llcontrol.cpp
@@ -170,6 +170,20 @@ LLSD LLControlVariable::getComparableValue(const LLSD& value)
storable_value = false;
}
}
+ else if (TYPE_LLSD == type() && value.isString())
+ {
+ LLPointer<LLSDNotationParser> parser = new LLSDNotationParser;
+ LLSD result;
+ std::stringstream value_stream(value.asString());
+ if (parser->parse(value_stream, result, LLSDSerialize::SIZE_UNLIMITED) != LLSDParser::PARSE_FAILURE)
+ {
+ storable_value = result;
+ }
+ else
+ {
+ storable_value = value;
+ }
+ }
else
{
storable_value = value;
@@ -821,11 +835,9 @@ U32 LLControlGroup::saveToFile(const std::string& filename, BOOL nondefault_only
return num_saved;
}
-U32 LLControlGroup::loadFromFile(const std::string& filename, bool set_default_values)
+U32 LLControlGroup::loadFromFile(const std::string& filename, bool set_default_values, bool save_values)
{
- std::string name;
LLSD settings;
- LLSD control_map;
llifstream infile;
infile.open(filename);
if(!infile.is_open())
@@ -849,8 +861,8 @@ U32 LLControlGroup::loadFromFile(const std::string& filename, bool set_default_v
for(LLSD::map_const_iterator itr = settings.beginMap(); itr != settings.endMap(); ++itr)
{
bool persist = true;
- name = (*itr).first;
- control_map = (*itr).second;
+ std::string const & name = itr->first;
+ LLSD const & control_map = itr->second;
if(control_map.has("Persist"))
{
@@ -894,8 +906,7 @@ U32 LLControlGroup::loadFromFile(const std::string& filename, bool set_default_v
}
else if(existing_control->isPersisted())
{
-
- existing_control->setValue(control_map["Value"]);
+ existing_control->setValue(control_map["Value"], save_values);
}
// *NOTE: If not persisted and not setting defaults,
// the value should not get loaded.
@@ -1107,7 +1118,7 @@ bool convert_from_llsd<bool>(const LLSD& sd, eControlType type, const std::strin
return sd.asBoolean();
else
{
- CONTROL_ERRS << "Invalid BOOL value" << llendl;
+ CONTROL_ERRS << "Invalid BOOL value for " << control_name << ": " << sd << llendl;
return FALSE;
}
}
@@ -1119,7 +1130,7 @@ S32 convert_from_llsd<S32>(const LLSD& sd, eControlType type, const std::string&
return sd.asInteger();
else
{
- CONTROL_ERRS << "Invalid S32 value" << llendl;
+ CONTROL_ERRS << "Invalid S32 value for " << control_name << ": " << sd << llendl;
return 0;
}
}
@@ -1131,7 +1142,7 @@ U32 convert_from_llsd<U32>(const LLSD& sd, eControlType type, const std::string&
return sd.asInteger();
else
{
- CONTROL_ERRS << "Invalid U32 value" << llendl;
+ CONTROL_ERRS << "Invalid U32 value for " << control_name << ": " << sd << llendl;
return 0;
}
}
@@ -1143,7 +1154,7 @@ F32 convert_from_llsd<F32>(const LLSD& sd, eControlType type, const std::string&
return (F32) sd.asReal();
else
{
- CONTROL_ERRS << "Invalid F32 value" << llendl;
+ CONTROL_ERRS << "Invalid F32 value for " << control_name << ": " << sd << llendl;
return 0.0f;
}
}
@@ -1155,7 +1166,7 @@ std::string convert_from_llsd<std::string>(const LLSD& sd, eControlType type, co
return sd.asString();
else
{
- CONTROL_ERRS << "Invalid string value" << llendl;
+ CONTROL_ERRS << "Invalid string value for " << control_name << ": " << sd << llendl;
return LLStringUtil::null;
}
}
@@ -1173,7 +1184,7 @@ LLVector3 convert_from_llsd<LLVector3>(const LLSD& sd, eControlType type, const
return (LLVector3)sd;
else
{
- CONTROL_ERRS << "Invalid LLVector3 value" << llendl;
+ CONTROL_ERRS << "Invalid LLVector3 value for " << control_name << ": " << sd << llendl;
return LLVector3::zero;
}
}
@@ -1185,7 +1196,7 @@ LLVector3d convert_from_llsd<LLVector3d>(const LLSD& sd, eControlType type, cons
return (LLVector3d)sd;
else
{
- CONTROL_ERRS << "Invalid LLVector3d value" << llendl;
+ CONTROL_ERRS << "Invalid LLVector3d value for " << control_name << ": " << sd << llendl;
return LLVector3d::zero;
}
}
@@ -1197,7 +1208,7 @@ LLRect convert_from_llsd<LLRect>(const LLSD& sd, eControlType type, const std::s
return LLRect(sd);
else
{
- CONTROL_ERRS << "Invalid rect value" << llendl;
+ CONTROL_ERRS << "Invalid rect value for " << control_name << ": " << sd << llendl;
return LLRect::null;
}
}
@@ -1211,19 +1222,19 @@ LLColor4 convert_from_llsd<LLColor4>(const LLSD& sd, eControlType type, const st
LLColor4 color(sd);
if (color.mV[VRED] < 0.f || color.mV[VRED] > 1.f)
{
- llwarns << "Color " << control_name << " value out of range " << llendl;
+ llwarns << "Color " << control_name << " red value out of range: " << color << llendl;
}
else if (color.mV[VGREEN] < 0.f || color.mV[VGREEN] > 1.f)
{
- llwarns << "Color " << control_name << " value out of range " << llendl;
+ llwarns << "Color " << control_name << " green value out of range: " << color << llendl;
}
else if (color.mV[VBLUE] < 0.f || color.mV[VBLUE] > 1.f)
{
- llwarns << "Color " << control_name << " value out of range " << llendl;
+ llwarns << "Color " << control_name << " blue value out of range: " << color << llendl;
}
else if (color.mV[VALPHA] < 0.f || color.mV[VALPHA] > 1.f)
{
- llwarns << "Color " << control_name << " value out of range " << llendl;
+ llwarns << "Color " << control_name << " alpha value out of range: " << color << llendl;
}
return LLColor4(sd);
@@ -1242,7 +1253,7 @@ LLColor3 convert_from_llsd<LLColor3>(const LLSD& sd, eControlType type, const st
return sd;
else
{
- CONTROL_ERRS << "Invalid LLColor3 value" << llendl;
+ CONTROL_ERRS << "Invalid LLColor3 value for " << control_name << ": " << sd << llendl;
return LLColor3::white;
}
}
diff --git a/indra/llxml/llcontrol.h b/indra/llxml/llcontrol.h
index 93975579cc..e402061e1f 100644
--- a/indra/llxml/llcontrol.h
+++ b/indra/llxml/llcontrol.h
@@ -289,7 +289,7 @@ public:
// as the given type.
U32 loadFromFileLegacy(const std::string& filename, BOOL require_declaration = TRUE, eControlType declare_as = TYPE_STRING);
U32 saveToFile(const std::string& filename, BOOL nondefault_only);
- U32 loadFromFile(const std::string& filename, bool default_values = false);
+ U32 loadFromFile(const std::string& filename, bool default_values = false, bool save_values = true);
void resetToDefaults();
};
diff --git a/indra/llxml/llxmlnode.cpp b/indra/llxml/llxmlnode.cpp
index 8168f968cd..9f1e249ddd 100644
--- a/indra/llxml/llxmlnode.cpp
+++ b/indra/llxml/llxmlnode.cpp
@@ -859,23 +859,21 @@ BOOL LLXMLNode::isFullyDefault()
}
// static
-bool LLXMLNode::getLayeredXMLNode(const std::string &xui_filename, LLXMLNodePtr& root,
+bool LLXMLNode::getLayeredXMLNode(LLXMLNodePtr& root,
const std::vector<std::string>& paths)
{
- std::string full_filename = gDirUtilp->findSkinnedFilename(paths.front(), xui_filename);
- if (full_filename.empty())
+ if (paths.empty()) return false;
+
+ std::string filename = paths.front();
+ if (filename.empty())
{
return false;
}
-
- if (!LLXMLNode::parseFile(full_filename, root, NULL))
+
+ if (!LLXMLNode::parseFile(filename, root, NULL))
{
- // try filename as passed in since sometimes we load an xml file from a user-supplied path
- if (!LLXMLNode::parseFile(xui_filename, root, NULL))
- {
- llwarns << "Problem reading UI description file: " << xui_filename << llendl;
- return false;
- }
+ llwarns << "Problem reading UI description file: " << filename << llendl;
+ return false;
}
LLXMLNodePtr updateRoot;
@@ -887,7 +885,7 @@ bool LLXMLNode::getLayeredXMLNode(const std::string &xui_filename, LLXMLNodePtr&
std::string nodeName;
std::string updateName;
- std::string layer_filename = gDirUtilp->findSkinnedFilename((*itor), xui_filename);
+ std::string layer_filename = *itor;
if(layer_filename.empty())
{
// no localized version of this file, that's ok, keep looking
@@ -896,7 +894,7 @@ bool LLXMLNode::getLayeredXMLNode(const std::string &xui_filename, LLXMLNodePtr&
if (!LLXMLNode::parseFile(layer_filename, updateRoot, NULL))
{
- llwarns << "Problem reading localized UI description file: " << (*itor) + gDirUtilp->getDirDelimiter() + xui_filename << llendl;
+ llwarns << "Problem reading localized UI description file: " << layer_filename << llendl;
return false;
}
diff --git a/indra/llxml/llxmlnode.h b/indra/llxml/llxmlnode.h
index 9df37ccb6f..e3da7169e7 100644
--- a/indra/llxml/llxmlnode.h
+++ b/indra/llxml/llxmlnode.h
@@ -149,8 +149,7 @@ public:
LLXMLNodePtr& update_node);
static LLXMLNodePtr replaceNode(LLXMLNodePtr node, LLXMLNodePtr replacement_node);
- static bool getLayeredXMLNode(const std::string &xui_filename, LLXMLNodePtr& root,
- const std::vector<std::string>& paths);
+ static bool getLayeredXMLNode(LLXMLNodePtr& root, const std::vector<std::string>& paths);
// Write standard XML file header:
diff --git a/indra/llxuixml/llinitparam.cpp b/indra/llxuixml/llinitparam.cpp
index 2c92539387..b3312798dd 100644
--- a/indra/llxuixml/llinitparam.cpp
+++ b/indra/llxuixml/llinitparam.cpp
@@ -44,8 +44,51 @@ namespace LLInitParam
}
//
+ // ParamDescriptor
+ //
+ ParamDescriptor::ParamDescriptor(param_handle_t p,
+ merge_func_t merge_func,
+ deserialize_func_t deserialize_func,
+ serialize_func_t serialize_func,
+ validation_func_t validation_func,
+ inspect_func_t inspect_func,
+ S32 min_count,
+ S32 max_count)
+ : mParamHandle(p),
+ mMergeFunc(merge_func),
+ mDeserializeFunc(deserialize_func),
+ mSerializeFunc(serialize_func),
+ mValidationFunc(validation_func),
+ mInspectFunc(inspect_func),
+ mMinCount(min_count),
+ mMaxCount(max_count),
+ mGeneration(0),
+ mUserData(NULL)
+ {}
+
+ ParamDescriptor::ParamDescriptor()
+ : mParamHandle(0),
+ mMergeFunc(NULL),
+ mDeserializeFunc(NULL),
+ mSerializeFunc(NULL),
+ mValidationFunc(NULL),
+ mInspectFunc(NULL),
+ mMinCount(0),
+ mMaxCount(0),
+ mGeneration(0),
+ mUserData(NULL)
+ {}
+
+ ParamDescriptor::~ParamDescriptor()
+ {
+ delete mUserData;
+ }
+
+ //
// Parser
//
+ S32 Parser::sNextParseGeneration = 0;
+
Parser::~Parser()
{}
@@ -73,6 +116,12 @@ namespace LLInitParam
std::copy(src_block_data.mAllParams.begin(), src_block_data.mAllParams.end(), std::back_inserter(mAllParams));
}
+ BlockDescriptor::BlockDescriptor()
+ : mMaxParamOffset(0),
+ mInitializationState(UNINITIALIZED),
+ mCurrentBlockPtr(NULL)
+ {}
+
//
// BaseBlock
//
@@ -115,7 +164,7 @@ namespace LLInitParam
bool BaseBlock::submitValue(const Parser::name_stack_t& name_stack, Parser& p, bool silent)
{
- if (!deserializeBlock(p, std::make_pair(name_stack.begin(), name_stack.end())))
+ if (!deserializeBlock(p, std::make_pair(name_stack.begin(), name_stack.end()), -1))
{
if (!silent)
{
@@ -145,7 +194,7 @@ namespace LLInitParam
return true;
}
- bool BaseBlock::serializeBlock(Parser& parser, Parser::name_stack_t name_stack, const LLInitParam::BaseBlock* diff_block) const
+ void BaseBlock::serializeBlock(Parser& parser, Parser::name_stack_t name_stack, const LLInitParam::BaseBlock* diff_block) const
{
// named param is one like LLView::Params::follows
// unnamed param is like LLView::Params::rect - implicit
@@ -212,11 +261,9 @@ namespace LLInitParam
name_stack.pop_back();
}
}
-
- return true;
}
- bool BaseBlock::inspectBlock(Parser& parser, Parser::name_stack_t name_stack) const
+ bool BaseBlock::inspectBlock(Parser& parser, Parser::name_stack_t name_stack, S32 min_count, S32 max_count) const
{
// named param is one like LLView::Params::follows
// unnamed param is like LLView::Params::rect - implicit
@@ -273,11 +320,13 @@ namespace LLInitParam
return true;
}
- bool BaseBlock::deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack)
+ bool BaseBlock::deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack, S32 parent_generation)
{
BlockDescriptor& block_data = mostDerivedBlockDescriptor();
bool names_left = name_stack.first != name_stack.second;
+ S32 parse_generation = name_stack.first == name_stack.second ? -1 : name_stack.first->second;
+
if (names_left)
{
const std::string& top_name = name_stack.first->first;
@@ -294,7 +343,7 @@ namespace LLInitParam
Parser::name_stack_range_t new_name_stack(name_stack.first, name_stack.second);
++new_name_stack.first;
- return deserialize_func(*paramp, p, new_name_stack, name_stack.first == name_stack.second ? -1 : name_stack.first->second);
+ return deserialize_func(*paramp, p, new_name_stack, parse_generation);
}
}
@@ -306,42 +355,50 @@ namespace LLInitParam
Param* paramp = getParamFromHandle((*it)->mParamHandle);
ParamDescriptor::deserialize_func_t deserialize_func = (*it)->mDeserializeFunc;
- if (deserialize_func && deserialize_func(*paramp, p, name_stack, name_stack.first == name_stack.second ? -1 : name_stack.first->second))
+ if (deserialize_func && deserialize_func(*paramp, p, name_stack, parse_generation))
{
return true;
}
}
+ // if no match, and no names left on stack, this is just an existence assertion of this block
+ // verify by calling readValue with NoParamValue type, an inherently unparseable type
+ if (!names_left)
+ {
+ NoParamValue no_value;
+ return p.readValue(no_value);
+ }
+
return false;
}
//static
- void BaseBlock::addParam(BlockDescriptor& block_data, const ParamDescriptor& in_param, const char* char_name)
+ void BaseBlock::addParam(BlockDescriptor& block_data, const ParamDescriptorPtr in_param, const char* char_name)
{
- // create a copy of the paramdescriptor in allparams
+ // create a copy of the param descriptor in mAllParams
// so other data structures can store a pointer to it
block_data.mAllParams.push_back(in_param);
- ParamDescriptor& param(block_data.mAllParams.back());
+ ParamDescriptorPtr param(block_data.mAllParams.back());
std::string name(char_name);
- if ((size_t)param.mParamHandle > block_data.mMaxParamOffset)
+ if ((size_t)param->mParamHandle > block_data.mMaxParamOffset)
{
llerrs << "Attempted to register param with block defined for parent class, make sure to derive from LLInitParam::Block<YOUR_CLASS, PARAM_BLOCK_BASE_CLASS>" << llendl;
}
if (name.empty())
{
- block_data.mUnnamedParams.push_back(&param);
+ block_data.mUnnamedParams.push_back(param);
}
else
{
// don't use insert, since we want to overwrite existing entries
- block_data.mNamedParams[name] = &param;
+ block_data.mNamedParams[name] = param;
}
- if (param.mValidationFunc)
+ if (param->mValidationFunc)
{
- block_data.mValidationList.push_back(std::make_pair(param.mParamHandle, param.mValidationFunc));
+ block_data.mValidationList.push_back(std::make_pair(param->mParamHandle, param->mValidationFunc));
}
}
@@ -359,7 +416,7 @@ namespace LLInitParam
llerrs << "Attempted to register param with block defined for parent class, make sure to derive from LLInitParam::Block<YOUR_CLASS, PARAM_BLOCK_BASE_CLASS>" << llendl;
}
- ParamDescriptor* param_descriptor = findParamDescriptor(handle);
+ ParamDescriptorPtr param_descriptor = findParamDescriptor(param);
if (param_descriptor)
{
if (synonym.empty())
@@ -374,7 +431,7 @@ namespace LLInitParam
}
}
- void BaseBlock::setLastChangedParam(const Param& last_param, bool user_provided)
+ void BaseBlock::paramChanged(const Param& changed_param, bool user_provided)
{
if (user_provided)
{
@@ -396,22 +453,23 @@ namespace LLInitParam
return LLStringUtil::null;
}
- ParamDescriptor* BaseBlock::findParamDescriptor(param_handle_t handle)
+ ParamDescriptorPtr BaseBlock::findParamDescriptor(const Param& param)
{
+ param_handle_t handle = getHandleFromParam(&param);
BlockDescriptor& descriptor = mostDerivedBlockDescriptor();
BlockDescriptor::all_params_list_t::iterator end_it = descriptor.mAllParams.end();
for (BlockDescriptor::all_params_list_t::iterator it = descriptor.mAllParams.begin();
it != end_it;
++it)
{
- if (it->mParamHandle == handle) return &(*it);
+ if ((*it)->mParamHandle == handle) return *it;
}
- return NULL;
+ return ParamDescriptorPtr();
}
// take all provided params from other and apply to self
// NOTE: this requires that "other" is of the same derived type as this
- bool BaseBlock::merge(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite)
+ bool BaseBlock::mergeBlock(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite)
{
bool some_param_changed = false;
BlockDescriptor::all_params_list_t::const_iterator end_it = block_data.mAllParams.end();
@@ -419,19 +477,14 @@ namespace LLInitParam
it != end_it;
++it)
{
- const Param* other_paramp = other.getParamFromHandle(it->mParamHandle);
- ParamDescriptor::merge_func_t merge_func = it->mMergeFunc;
+ const Param* other_paramp = other.getParamFromHandle((*it)->mParamHandle);
+ ParamDescriptor::merge_func_t merge_func = (*it)->mMergeFunc;
if (merge_func)
{
- Param* paramp = getParamFromHandle(it->mParamHandle);
+ Param* paramp = getParamFromHandle((*it)->mParamHandle);
some_param_changed |= merge_func(*paramp, *other_paramp, overwrite);
}
}
return some_param_changed;
}
-
- bool ParamCompare<LLSD, false>::equals(const LLSD &a, const LLSD &b)
- {
- return false;
- }
}
diff --git a/indra/llxuixml/llinitparam.h b/indra/llxuixml/llinitparam.h
index 8cb5bd80fc..a853999e94 100644
--- a/indra/llxuixml/llinitparam.h
+++ b/indra/llxuixml/llinitparam.h
@@ -1,5 +1,5 @@
/**
-f * @file llinitparam.h
+ * @file llinitparam.h
* @brief parameter block abstraction for creating complex objects and
* parsing construction parameters from xml and LLSD
*
@@ -29,18 +29,14 @@ f * @file llinitparam.h
#define LL_LLPARAM_H
#include <vector>
-
-#include <stddef.h>
#include <boost/function.hpp>
-#include <boost/bind.hpp>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/unordered_map.hpp>
-#include "llregistry.h"
-#include "llmemory.h"
-
+#include <boost/shared_ptr.hpp>
namespace LLInitParam
{
+ template<typename T> const T& defaultValue() { static T value; return value; }
template <typename T, bool IS_BOOST_FUNCTION = boost::is_convertible<T, boost::function_base>::value >
struct ParamCompare
@@ -61,122 +57,119 @@ namespace LLInitParam
}
};
- // default constructor adaptor for InitParam Values
- // constructs default instances of the given type, returned by const reference
- template <typename T>
- struct DefaultInitializer
+ template<>
+ struct ParamCompare<LLSD, false>
{
- typedef const T& T_const_ref;
- // return reference to a single default instance of T
- // built-in types will be initialized to zero, default constructor otherwise
- static T_const_ref get() { static T t = T(); return t; }
+ static bool equals(const LLSD &a, const LLSD &b) { return false; }
};
// helper functions and classes
typedef ptrdiff_t param_handle_t;
+ // empty default implementation of key cache
+ // leverages empty base class optimization
template <typename T>
class TypeValues
{
public:
- // empty default implemenation of key cache
- class KeyCache
+ typedef std::map<std::string, T> value_name_map_t;
+
+ void setValueName(const std::string& key) {}
+ std::string getValueName() const { return ""; }
+ void clearValueName() const {}
+
+ static bool getValueFromName(const std::string& name, T& value)
{
- public:
- void setKey(const std::string& key) {}
- std::string getKey() const { return ""; }
- void clearKey(){}
- };
+ return false;
+ }
- static bool get(const std::string& name, T& value)
+ static bool valueNamesExist()
{
return false;
}
- static bool empty()
+ static std::vector<std::string>* getPossibleValues()
{
- return true;
+ return NULL;
}
- static std::vector<std::string>* getPossibleValues() { return NULL; }
+ static value_name_map_t* getValueNames() {return NULL;}
};
template <typename T, typename DERIVED_TYPE = TypeValues<T> >
class TypeValuesHelper
- : public LLRegistrySingleton<std::string, T, DERIVED_TYPE >
{
- typedef LLRegistrySingleton<std::string, T, DERIVED_TYPE> super_t;
- typedef LLSingleton<DERIVED_TYPE> singleton_t;
public:
+ typedef typename std::map<std::string, T> value_name_map_t;
//TODO: cache key by index to save on param block size
- class KeyCache
+ void setValueName(const std::string& value_name)
{
- public:
- void setKey(const std::string& key)
- {
- mKey = key;
- }
-
- void clearKey()
- {
- mKey = "";
- }
+ mValueName = value_name;
+ }
- std::string getKey() const
- {
- return mKey;
- }
+ std::string getValueName() const
+ {
+ return mValueName;
+ }
- private:
- std::string mKey;
- };
+ void clearValueName() const
+ {
+ mValueName.clear();
+ }
- static bool get(const std::string& name, T& value)
+ static bool getValueFromName(const std::string& name, T& value)
{
- if (!singleton_t::instance().exists(name)) return false;
+ value_name_map_t* map = getValueNames();
+ typename value_name_map_t::iterator found_it = map->find(name);
+ if (found_it == map->end()) return false;
- value = *singleton_t::instance().getValue(name);
+ value = found_it->second;
return true;
}
- static bool empty()
+ static bool valueNamesExist()
{
- return singleton_t::instance().LLRegistry<std::string, T>::empty();
+ return !getValueNames()->empty();
}
- //override this to add name value pairs
- static void declareValues() {}
-
- void initSingleton()
+ static value_name_map_t* getValueNames()
{
- DERIVED_TYPE::declareValues();
- }
+ static value_name_map_t sMap;
+ static bool sInitialized = false;
- static const std::vector<std::string>* getPossibleValues()
- {
- // in order to return a pointer to a member, we lazily
- // evaluate the result and store it in mValues here
- if (singleton_t::instance().mValues.empty())
+ if (!sInitialized)
{
- typename super_t::Registrar::registry_map_t::const_iterator it;
- for (it = super_t::defaultRegistrar().beginItems(); it != super_t::defaultRegistrar().endItems(); ++it)
- {
- singleton_t::instance().mValues.push_back(it->first);
- }
+ sInitialized = true;
+ DERIVED_TYPE::declareValues();
}
- return &singleton_t::instance().mValues;
+ return &sMap;
}
+ static std::vector<std::string>* getPossibleValues()
+ {
+ static std::vector<std::string> sValues;
+
+ value_name_map_t* map = getValueNames();
+ for (typename value_name_map_t::iterator it = map->begin(), end_it = map->end();
+ it != end_it;
+ ++it)
+ {
+ sValues.push_back(it->first);
+ }
+ return &sValues;
+ }
- protected:
static void declare(const std::string& name, const T& value)
{
- super_t::defaultRegistrar().add(name, value);
+ (*getValueNames())[name] = value;
}
- private:
- std::vector<std::string> mValues;
+ protected:
+ static void getName(const std::string& name, const T& value)
+ {}
+
+ mutable std::string mValueName;
};
class Parser
@@ -193,9 +186,9 @@ namespace LLInitParam
}
};
- typedef std::vector<std::pair<std::string, S32> > name_stack_t;
+ typedef std::vector<std::pair<std::string, S32> > name_stack_t;
typedef std::pair<name_stack_t::const_iterator, name_stack_t::const_iterator> name_stack_range_t;
- typedef std::vector<std::string> possible_values_t;
+ typedef std::vector<std::string> possible_values_t;
typedef bool (*parser_read_func_t)(Parser& parser, void* output);
typedef bool (*parser_write_func_t)(Parser& parser, const void*, const name_stack_t&);
@@ -207,7 +200,7 @@ namespace LLInitParam
Parser(parser_read_func_map_t& read_map, parser_write_func_map_t& write_map, parser_inspect_func_map_t& inspect_map)
: mParseSilently(false),
- mParseGeneration(0),
+ mParseGeneration(sNextParseGeneration),
mParserReadFuncs(&read_map),
mParserWriteFuncs(&write_map),
mParserInspectFuncs(&inspect_map)
@@ -252,7 +245,7 @@ namespace LLInitParam
void setParseSilently(bool silent) { mParseSilently = silent; }
S32 getParseGeneration() { return mParseGeneration; }
- S32 newParseGeneration() { return ++mParseGeneration; }
+ S32 newParseGeneration() { return mParseGeneration = ++sNextParseGeneration; }
protected:
@@ -276,8 +269,13 @@ namespace LLInitParam
parser_write_func_map_t* mParserWriteFuncs;
parser_inspect_func_map_t* mParserInspectFuncs;
S32 mParseGeneration;
+
+ static S32 sNextParseGeneration;
};
+ // used to indicate no matching value to a given name when parsing
+ struct NoParamValue{};
+
class BaseBlock;
class Param
@@ -292,25 +290,30 @@ namespace LLInitParam
Param(class BaseBlock* enclosing_block);
// store pointer to enclosing block as offset to reduce space and allow for quick copying
- BaseBlock& enclosingBlock() const
+ class BaseBlock& enclosingBlock() const
{
const U8* my_addr = reinterpret_cast<const U8*>(this);
// get address of enclosing BLOCK class using stored offset to enclosing BaseBlock class
- return *const_cast<BaseBlock*>(
- reinterpret_cast<const BaseBlock*>(my_addr - (ptrdiff_t)(S32)mEnclosingBlockOffset));
+ return *const_cast<class BaseBlock*>
+ (reinterpret_cast<const class BaseBlock*>
+ (my_addr - (ptrdiff_t)(S32)mEnclosingBlockOffset));
}
private:
friend class BaseBlock;
- bool mIsProvided;
U16 mEnclosingBlockOffset;
+ bool mIsProvided;
};
// various callbacks and constraints associated with an individual param
struct ParamDescriptor
{
- public:
+ struct UserData
+ {
+ virtual ~UserData() {}
+ };
+
typedef bool(*merge_func_t)(Param&, const Param&, bool);
typedef bool(*deserialize_func_t)(Param&, Parser&, const Parser::name_stack_range_t&, S32);
typedef void(*serialize_func_t)(const Param&, Parser&, Parser::name_stack_t&, const Param* diff_param);
@@ -318,40 +321,18 @@ namespace LLInitParam
typedef bool(*validation_func_t)(const Param*);
ParamDescriptor(param_handle_t p,
- merge_func_t merge_func,
- deserialize_func_t deserialize_func,
- serialize_func_t serialize_func,
- validation_func_t validation_func,
- inspect_func_t inspect_func,
- S32 min_count,
- S32 max_count)
- : mParamHandle(p),
- mMergeFunc(merge_func),
- mDeserializeFunc(deserialize_func),
- mSerializeFunc(serialize_func),
- mValidationFunc(validation_func),
- mInspectFunc(inspect_func),
- mMinCount(min_count),
- mMaxCount(max_count),
- mGeneration(0),
- mNumRefs(0)
- {}
+ merge_func_t merge_func,
+ deserialize_func_t deserialize_func,
+ serialize_func_t serialize_func,
+ validation_func_t validation_func,
+ inspect_func_t inspect_func,
+ S32 min_count,
+ S32 max_count);
- ParamDescriptor()
- : mParamHandle(0),
- mMergeFunc(NULL),
- mDeserializeFunc(NULL),
- mSerializeFunc(NULL),
- mValidationFunc(NULL),
- mInspectFunc(NULL),
- mMinCount(0),
- mMaxCount(0),
- mGeneration(0),
- mNumRefs(0)
- {}
+ ParamDescriptor();
+ ~ParamDescriptor();
param_handle_t mParamHandle;
-
merge_func_t mMergeFunc;
deserialize_func_t mDeserializeFunc;
serialize_func_t mSerializeFunc;
@@ -361,17 +342,16 @@ namespace LLInitParam
S32 mMaxCount;
S32 mGeneration;
S32 mNumRefs;
+ UserData* mUserData;
};
+ typedef boost::shared_ptr<ParamDescriptor> ParamDescriptorPtr;
+
// each derived Block class keeps a static data structure maintaining offsets to various params
class BlockDescriptor
{
public:
- BlockDescriptor()
- : mMaxParamOffset(0),
- mInitializationState(UNINITIALIZED),
- mCurrentBlockPtr(NULL)
- {}
+ BlockDescriptor();
typedef enum e_initialization_state
{
@@ -382,12 +362,10 @@ namespace LLInitParam
void aggregateBlockData(BlockDescriptor& src_block_data);
- public:
- typedef boost::unordered_map<const std::string, ParamDescriptor*> param_map_t; // references param descriptors stored in mAllParams
- typedef std::vector<ParamDescriptor*> param_list_t;
-
- typedef std::list<ParamDescriptor> all_params_list_t;// references param descriptors stored in mAllParams
- typedef std::vector<std::pair<param_handle_t, ParamDescriptor::validation_func_t> > param_validation_list_t;
+ typedef boost::unordered_map<const std::string, ParamDescriptorPtr> param_map_t;
+ typedef std::vector<ParamDescriptorPtr> param_list_t;
+ typedef std::list<ParamDescriptorPtr> all_params_list_t;
+ typedef std::vector<std::pair<param_handle_t, ParamDescriptor::validation_func_t> > param_validation_list_t;
param_map_t mNamedParams; // parameters with associated names
param_list_t mUnnamedParams; // parameters with_out_ associated names
@@ -453,6 +431,7 @@ namespace LLInitParam
Param* getParamFromHandle(const param_handle_t param_handle)
{
if (param_handle == 0) return NULL;
+
U8* baseblock_address = reinterpret_cast<U8*>(this);
return reinterpret_cast<Param*>(baseblock_address + param_handle);
}
@@ -466,14 +445,13 @@ namespace LLInitParam
void addSynonym(Param& param, const std::string& synonym);
// Blocks can override this to do custom tracking of changes
- virtual void setLastChangedParam(const Param& last_param, bool user_provided);
+ virtual void paramChanged(const Param& changed_param, bool user_provided);
S32 getLastChangeVersion() const { return mChangeVersion; }
- bool isDefault() const { return mChangeVersion == 0; }
- bool deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack);
- bool serializeBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), const BaseBlock* diff_block = NULL) const;
- bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t()) const;
+ bool deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack, S32 generation);
+ void serializeBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), const BaseBlock* diff_block = NULL) const;
+ bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const;
virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return selfBlockDescriptor(); }
virtual BlockDescriptor& mostDerivedBlockDescriptor() { return selfBlockDescriptor(); }
@@ -490,13 +468,20 @@ namespace LLInitParam
return false;
}
- static void addParam(BlockDescriptor& block_data, const ParamDescriptor& param, const char* name);
+ static void addParam(BlockDescriptor& block_data, ParamDescriptorPtr param, const char* name);
+
+ ParamDescriptorPtr findParamDescriptor(const Param& param);
+
protected:
void init(BlockDescriptor& descriptor, BlockDescriptor& base_descriptor, size_t block_size);
+ bool mergeBlockParam(bool param_provided, BlockDescriptor& block_data, const BaseBlock& other, bool overwrite)
+ {
+ return mergeBlock(block_data, other, overwrite);
+ }
// take all provided params from other and apply to self
- bool merge(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite);
+ bool mergeBlock(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite);
// can be updated in getters
mutable S32 mChangeVersion;
@@ -509,63 +494,133 @@ namespace LLInitParam
private:
const std::string& getParamName(const BlockDescriptor& block_data, const Param* paramp) const;
- ParamDescriptor* findParamDescriptor(param_handle_t handle);
- };
-
-
- template<typename T>
- struct ParamIterator
- {
- typedef typename std::vector<T>::const_iterator const_iterator;
- typedef typename std::vector<T>::iterator iterator;
};
// these templates allow us to distinguish between template parameters
// that derive from BaseBlock and those that don't
- // this is supposedly faster than boost::is_convertible and its ilk
template<typename T, typename Void = void>
- struct IsBaseBlock
+ struct IsBlock
{
static const bool value = false;
};
template<typename T>
- struct IsBaseBlock<T, typename T::baseblock_base_class_t>
+ struct IsBlock<T, typename T::baseblock_base_class_t>
{
static const bool value = true;
};
+ template<typename T, typename NAME_VALUE_LOOKUP, bool VALUE_IS_BLOCK = IsBlock<T>::value>
+ class ParamValue : public NAME_VALUE_LOOKUP
+ {
+ public:
+ typedef const T& value_assignment_t;
+
+ ParamValue(): mValue() {}
+ ParamValue(const T& other) : mValue(other) {}
+
+ void setValue(value_assignment_t val)
+ {
+ mValue = val;
+ }
+
+ value_assignment_t getValue() const
+ {
+ return mValue;
+ }
+
+ T& getValue()
+ {
+ return mValue;
+ }
+
+ private:
+ T mValue;
+ };
+
+ template<typename T, typename NAME_VALUE_LOOKUP>
+ class ParamValue<T, NAME_VALUE_LOOKUP, true>
+ : public T,
+ public NAME_VALUE_LOOKUP
+ {
+ public:
+ typedef const T& value_assignment_t;
+
+ S32 mKeyVersion;
+ mutable S32 mValidatedVersion;
+ mutable bool mValidated; // lazy validation flag
+
+ ParamValue()
+ : T(),
+ mKeyVersion(0),
+ mValidatedVersion(-1),
+ mValidated(false)
+ {}
+
+ ParamValue(const T& other)
+ : T(other),
+ mKeyVersion(0),
+ mValidatedVersion(-1),
+ mValidated(false)
+ {
+ }
+
+ void setValue(value_assignment_t val)
+ {
+ *this = val;
+ }
+
+ value_assignment_t getValue() const
+ {
+ return *this;
+ }
+
+ T& getValue()
+ {
+ return *this;
+ }
+ };
+
+ template<typename T, typename NAME_VALUE_LOOKUP = TypeValues<T> >
+ struct ParamIterator
+ {
+ typedef typename std::vector<ParamValue<T, NAME_VALUE_LOOKUP> >::const_iterator const_iterator;
+ typedef typename std::vector<ParamValue<T, NAME_VALUE_LOOKUP> >::iterator iterator;
+ };
+
// specialize for custom parsing/decomposition of specific classes
// e.g. TypedParam<LLRect> has left, top, right, bottom, etc...
template<typename T,
typename NAME_VALUE_LOOKUP = TypeValues<T>,
bool HAS_MULTIPLE_VALUES = false,
- bool VALUE_IS_BLOCK = IsBaseBlock<T>::value>
+ bool VALUE_IS_BLOCK = IsBlock<ParamValue<T, NAME_VALUE_LOOKUP> >::value>
class TypedParam
- : public Param
+ : public Param,
+ public ParamValue<T, NAME_VALUE_LOOKUP>
{
public:
- typedef const T& value_const_ref_t;
- typedef value_const_ref_t value_assignment_t;
- typedef typename NAME_VALUE_LOOKUP::KeyCache key_cache_t;
+ typedef const T& value_assignment_t;
typedef TypedParam<T, NAME_VALUE_LOOKUP, HAS_MULTIPLE_VALUES, VALUE_IS_BLOCK> self_t;
+ typedef NAME_VALUE_LOOKUP name_value_lookup_t;
+ typedef ParamValue<T, NAME_VALUE_LOOKUP> param_value_t;
TypedParam(BlockDescriptor& block_descriptor, const char* name, value_assignment_t value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count)
: Param(block_descriptor.mCurrentBlockPtr)
{
if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING))
{
- ParamDescriptor param_descriptor(block_descriptor.mCurrentBlockPtr->getHandleFromParam(this),
+ ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor(
+ block_descriptor.mCurrentBlockPtr->getHandleFromParam(this),
&mergeWith,
&deserializeParam,
&serializeParam,
validate_func,
&inspectParam,
- min_count, max_count);
+ min_count, max_count));
BaseBlock::addParam(block_descriptor, param_descriptor, name);
}
- mData.mValue = value;
+ setValue(value);
}
bool isProvided() const { return Param::anyProvided(); }
@@ -576,27 +631,27 @@ namespace LLInitParam
// no further names in stack, attempt to parse value now
if (name_stack.first == name_stack.second)
{
- if (parser.readValue(typed_param.mData.mValue))
+ if (parser.readValue(typed_param.getValue()))
{
- typed_param.mData.clearKey();
+ typed_param.clearValueName();
typed_param.setProvided(true);
- typed_param.enclosingBlock().setLastChangedParam(param, true);
+ typed_param.enclosingBlock().paramChanged(param, true);
return true;
}
// try to parse a known named value
- if(!NAME_VALUE_LOOKUP::empty())
+ if(name_value_lookup_t::valueNamesExist())
{
// try to parse a known named value
std::string name;
if (parser.readValue(name))
{
// try to parse a per type named value
- if (NAME_VALUE_LOOKUP::get(name, typed_param.mData.mValue))
+ if (name_value_lookup_t::getValueFromName(name, typed_param.getValue()))
{
- typed_param.mData.setKey(name);
+ typed_param.setValueName(name);
typed_param.setProvided(true);
- typed_param.enclosingBlock().setLastChangedParam(param, true);
+ typed_param.enclosingBlock().paramChanged(param, true);
return true;
}
@@ -616,13 +671,13 @@ namespace LLInitParam
name_stack.back().second = parser.newParseGeneration();
}
- std::string key = typed_param.mData.getKey();
+ std::string key = typed_param.getValueName();
// first try to write out name of name/value pair
if (!key.empty())
{
- if (!diff_param || !ParamCompare<std::string>::equals(static_cast<const self_t*>(diff_param)->mData.getKey(), key))
+ if (!diff_param || !ParamCompare<std::string>::equals(static_cast<const self_t*>(diff_param)->getValueName(), key))
{
if (!parser.writeValue(key, name_stack))
{
@@ -631,8 +686,9 @@ namespace LLInitParam
}
}
// then try to serialize value directly
- else if (!diff_param || !ParamCompare<T>::equals(typed_param.get(), static_cast<const self_t*>(diff_param)->get())) {
- if (!parser.writeValue(typed_param.mData.mValue, name_stack))
+ else if (!diff_param || !ParamCompare<T>::equals(typed_param.getValue(), static_cast<const self_t*>(diff_param)->getValue()))
+ {
+ if (!parser.writeValue(typed_param.getValue(), name_stack))
{
return;
}
@@ -644,18 +700,18 @@ namespace LLInitParam
// tell parser about our actual type
parser.inspectValue<T>(name_stack, min_count, max_count, NULL);
// then tell it about string-based alternatives ("red", "blue", etc. for LLColor4)
- if (NAME_VALUE_LOOKUP::getPossibleValues())
+ if (name_value_lookup_t::getPossibleValues())
{
- parser.inspectValue<std::string>(name_stack, min_count, max_count, NAME_VALUE_LOOKUP::getPossibleValues());
+ parser.inspectValue<std::string>(name_stack, min_count, max_count, name_value_lookup_t::getPossibleValues());
}
}
void set(value_assignment_t val, bool flag_as_provided = true)
{
- mData.mValue = val;
- mData.clearKey();
+ setValue(val);
+ param_value_t::clearValueName();
setProvided(flag_as_provided);
- Param::enclosingBlock().setLastChangedParam(*this, flag_as_provided);
+ Param::enclosingBlock().paramChanged(*this, flag_as_provided);
}
void setIfNotProvided(value_assignment_t val, bool flag_as_provided = true)
@@ -667,65 +723,56 @@ namespace LLInitParam
}
// implicit conversion
- operator value_assignment_t() const { return get(); }
+ operator value_assignment_t() const { return param_value_t::getValue(); }
// explicit conversion
- value_assignment_t operator()() const { return get(); }
+ value_assignment_t operator()() const { return param_value_t::getValue(); }
protected:
- value_assignment_t get() const
- {
- return mData.mValue;
- }
static bool mergeWith(Param& dst, const Param& src, bool overwrite)
{
const self_t& src_typed_param = static_cast<const self_t&>(src);
self_t& dst_typed_param = static_cast<self_t&>(dst);
+
if (src_typed_param.isProvided()
&& (overwrite || !dst_typed_param.isProvided()))
{
- dst_typed_param.mData.clearKey();
- dst_typed_param.set(src_typed_param.get());
+ dst_typed_param.clearValueName();
+ dst_typed_param.set(src_typed_param.getValue());
return true;
}
return false;
}
-
- struct Data : public key_cache_t
- {
- T mValue;
- };
-
- Data mData;
};
// parameter that is a block
template <typename T, typename NAME_VALUE_LOOKUP>
class TypedParam<T, NAME_VALUE_LOOKUP, false, true>
- : public T,
- public Param
+ : public Param,
+ public ParamValue<T, NAME_VALUE_LOOKUP>
{
public:
typedef const T value_const_t;
typedef T value_t;
- typedef value_const_t& value_const_ref_t;
- typedef value_const_ref_t value_assignment_t;
- typedef typename NAME_VALUE_LOOKUP::KeyCache key_cache_t;
+ typedef value_const_t& value_assignment_t;
typedef TypedParam<T, NAME_VALUE_LOOKUP, false, true> self_t;
+ typedef NAME_VALUE_LOOKUP name_value_lookup_t;
+ typedef ParamValue<T, NAME_VALUE_LOOKUP> param_value_t;
TypedParam(BlockDescriptor& block_descriptor, const char* name, value_assignment_t value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count)
: Param(block_descriptor.mCurrentBlockPtr),
- T(value)
+ param_value_t(value)
{
if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING))
{
- ParamDescriptor param_descriptor(block_descriptor.mCurrentBlockPtr->getHandleFromParam(this),
+ ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor(
+ block_descriptor.mCurrentBlockPtr->getHandleFromParam(this),
&mergeWith,
&deserializeParam,
&serializeParam,
validate_func,
&inspectParam,
- min_count, max_count);
+ min_count, max_count));
BaseBlock::addParam(block_descriptor, param_descriptor, name);
}
}
@@ -734,25 +781,27 @@ namespace LLInitParam
{
self_t& typed_param = static_cast<self_t&>(param);
// attempt to parse block...
- if(typed_param.deserializeBlock(parser, name_stack))
+ if(typed_param.deserializeBlock(parser, name_stack, generation))
{
- typed_param.mData.clearKey();
- typed_param.enclosingBlock().setLastChangedParam(param, true);
+ typed_param.clearValueName();
+ typed_param.enclosingBlock().paramChanged(param, true);
+ typed_param.setProvided(true);
return true;
}
- if(!NAME_VALUE_LOOKUP::empty())
+ if(name_value_lookup_t::valueNamesExist())
{
// try to parse a known named value
std::string name;
if (parser.readValue(name))
{
// try to parse a per type named value
- if (NAME_VALUE_LOOKUP::get(name, typed_param))
+ if (name_value_lookup_t::getValueFromName(name, typed_param.getValue()))
{
- typed_param.enclosingBlock().setLastChangedParam(param, true);
- typed_param.mData.setKey(name);
- typed_param.mData.mKeyVersion = typed_param.getLastChangeVersion();
+ typed_param.enclosingBlock().paramChanged(param, true);
+ typed_param.setValueName(name);
+ typed_param.setProvided(true);
+ typed_param.mKeyVersion = typed_param.getLastChangeVersion();
return true;
}
@@ -764,13 +813,15 @@ namespace LLInitParam
static void serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const Param* diff_param)
{
const self_t& typed_param = static_cast<const self_t&>(param);
+ if (!typed_param.isProvided()) return;
+
if (!name_stack.empty())
{
name_stack.back().second = parser.newParseGeneration();
}
- std::string key = typed_param.mData.getKey();
- if (!key.empty() && typed_param.mData.mKeyVersion == typed_param.getLastChangeVersion())
+ std::string key = typed_param.getValueName();
+ if (!key.empty() && typed_param.mKeyVersion == typed_param.getLastChangeVersion())
{
if (!parser.writeValue(key, name_stack))
{
@@ -787,33 +838,33 @@ namespace LLInitParam
{
// I am a param that is also a block, so just recurse into my contents
const self_t& typed_param = static_cast<const self_t&>(param);
- typed_param.inspectBlock(parser, name_stack);
+ typed_param.inspectBlock(parser, name_stack, min_count, max_count);
}
// a param-that-is-a-block is provided when the user has set one of its child params
// *and* the block as a whole validates
bool isProvided() const
{
- // only validate block when it hasn't already passed validation and user has supplied *some* value
- if (Param::anyProvided() && mData.mValidatedVersion < T::getLastChangeVersion())
+ // only validate block when it hasn't already passed validation with current data
+ if (Param::anyProvided() && param_value_t::mValidatedVersion < param_value_t::getLastChangeVersion())
{
// a sub-block is "provided" when it has been filled in enough to be valid
- mData.mValidated = T::validateBlock(false);
- mData.mValidatedVersion = T::getLastChangeVersion();
+ param_value_t::mValidated = param_value_t::validateBlock(false);
+ param_value_t::mValidatedVersion = param_value_t::getLastChangeVersion();
}
- return Param::anyProvided() && mData.mValidated;
+ return Param::anyProvided() && param_value_t::mValidated;
}
// assign block contents to this param-that-is-a-block
void set(value_assignment_t val, bool flag_as_provided = true)
{
- value_t::operator=(val);
- mData.clearKey();
+ setValue(val);
+ param_value_t::clearValueName();
// force revalidation of block by clearing known provided version
// next call to isProvided() will update provision status based on validity
- mData.mValidatedVersion = 0;
+ param_value_t::mValidatedVersion = -1;
setProvided(flag_as_provided);
- Param::enclosingBlock().setLastChangedParam(*this, flag_as_provided);
+ Param::enclosingBlock().paramChanged(*this, flag_as_provided);
}
void setIfNotProvided(value_assignment_t val, bool flag_as_provided = true)
@@ -825,10 +876,10 @@ namespace LLInitParam
}
// propagate changed status up to enclosing block
- /*virtual*/ void setLastChangedParam(const Param& last_param, bool user_provided)
+ /*virtual*/ void paramChanged(const Param& changed_param, bool user_provided)
{
- T::setLastChangedParam(last_param, user_provided);
- Param::enclosingBlock().setLastChangedParam(*this, user_provided);
+ ParamValue<T, NAME_VALUE_LOOKUP>::paramChanged(changed_param, user_provided);
+ Param::enclosingBlock().paramChanged(*this, user_provided);
if (user_provided)
{
// a child param has been explicitly changed
@@ -838,41 +889,30 @@ namespace LLInitParam
}
// implicit conversion
- operator value_assignment_t() const { return get(); }
+ operator value_assignment_t() const { return param_value_t::getValue(); }
// explicit conversion
- value_assignment_t operator()() const { return get(); }
+ value_assignment_t operator()() const { return param_value_t::getValue(); }
protected:
- value_assignment_t get() const
- {
- return *this;
- }
static bool mergeWith(Param& dst, const Param& src, bool overwrite)
{
const self_t& src_typed_param = static_cast<const self_t&>(src);
self_t& dst_typed_param = static_cast<self_t&>(dst);
- if (dst_typed_param.T::merge(T::selfBlockDescriptor(), src_typed_param, overwrite))
+
+ if (src_typed_param.anyProvided())
{
- dst_typed_param.mData.clearKey();
- return true;
+ bool param_provided = src_typed_param.isProvided() && (overwrite || !dst_typed_param.isProvided());
+ if (dst_typed_param.mergeBlockParam(param_provided, param_value_t::selfBlockDescriptor(), src_typed_param, overwrite))
+ {
+ dst_typed_param.clearValueName();
+ dst_typed_param.setProvided(true);
+ dst_typed_param.enclosingBlock().paramChanged(dst_typed_param, true);
+ return true;
+ }
}
return false;
}
-
- struct Data : public key_cache_t
- {
- S32 mKeyVersion;
- mutable S32 mValidatedVersion;
- mutable bool mValidated; // lazy validation flag
-
- Data()
- : mKeyVersion(0),
- mValidatedVersion(0),
- mValidated(false)
- {}
- };
- Data mData;
};
// container of non-block parameters
@@ -882,29 +922,28 @@ namespace LLInitParam
{
public:
typedef TypedParam<VALUE_TYPE, NAME_VALUE_LOOKUP, true, false> self_t;
- typedef typename std::vector<VALUE_TYPE> container_t;
+ typedef ParamValue<VALUE_TYPE, NAME_VALUE_LOOKUP> param_value_t;
+ typedef typename std::vector<param_value_t> container_t;
typedef const container_t& value_assignment_t;
typedef VALUE_TYPE value_t;
- typedef value_t& value_ref_t;
- typedef const value_t& value_const_ref_t;
+ typedef NAME_VALUE_LOOKUP name_value_lookup_t;
- typedef typename NAME_VALUE_LOOKUP::KeyCache key_cache_t;
-
TypedParam(BlockDescriptor& block_descriptor, const char* name, value_assignment_t value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count)
- : Param(block_descriptor.mCurrentBlockPtr),
- mValues(value)
+ : Param(block_descriptor.mCurrentBlockPtr)
{
- mCachedKeys.resize(mValues.size());
+ std::copy(value.begin(), value.end(), std::back_inserter(mValues));
+
if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING))
{
- ParamDescriptor param_descriptor(block_descriptor.mCurrentBlockPtr->getHandleFromParam(this),
+ ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor(
+ block_descriptor.mCurrentBlockPtr->getHandleFromParam(this),
&mergeWith,
&deserializeParam,
&serializeParam,
validate_func,
&inspectParam,
- min_count, max_count);
+ min_count, max_count));
BaseBlock::addParam(block_descriptor, param_descriptor, name);
}
}
@@ -921,29 +960,22 @@ namespace LLInitParam
// attempt to read value directly
if (parser.readValue(value))
{
- typed_param.mValues.push_back(value);
- // save an empty name/value key as a placeholder
- typed_param.mCachedKeys.push_back(key_cache_t());
- typed_param.enclosingBlock().setLastChangedParam(param, true);
- typed_param.setProvided(true);
+ typed_param.add(value);
return true;
}
// try to parse a known named value
- if(!NAME_VALUE_LOOKUP::empty())
+ if(name_value_lookup_t::valueNamesExist())
{
// try to parse a known named value
std::string name;
if (parser.readValue(name))
{
// try to parse a per type named value
- if (NAME_VALUE_LOOKUP::get(name, typed_param.mValues))
+ if (name_value_lookup_t::getValueFromName(name, typed_param.mValues))
{
- typed_param.mValues.push_back(value);
- typed_param.mCachedKeys.push_back(key_cache_t());
- typed_param.mCachedKeys.back().setKey(name);
- typed_param.enclosingBlock().setLastChangedParam(param, true);
- typed_param.setProvided(true);
+ typed_param.add(value);
+ typed_param.mValues.back().setValueName(name);
return true;
}
@@ -958,25 +990,27 @@ namespace LLInitParam
const self_t& typed_param = static_cast<const self_t&>(param);
if (!typed_param.isProvided() || name_stack.empty()) return;
- const_iterator it = typed_param.mValues.begin();
- for (typename std::vector<key_cache_t>::const_iterator key_it = typed_param.mCachedKeys.begin();
- it != typed_param.mValues.end();
- ++key_it, ++it)
+ for (const_iterator it = typed_param.mValues.begin(), end_it = typed_param.mValues.end();
+ it != end_it;
+ ++it)
{
- std::string key = key_it->get();
+ std::string key = it->getValue();
name_stack.back().second = parser.newParseGeneration();
- if(!key.empty())
+ if(key.empty())
+ // not parsed via name values, write out value directly
{
- if(!parser.writeValue(key, name_stack))
+ if (!parser.writeValue(*it, name_stack))
{
- return;
+ break;
}
}
- // not parse via name values, write out value directly
- else if (!parser.writeValue(*it, name_stack))
+ else
{
- return;
+ if(!parser.writeValue(key, name_stack))
+ {
+ break;
+ }
}
}
}
@@ -984,19 +1018,17 @@ namespace LLInitParam
static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count)
{
parser.inspectValue<VALUE_TYPE>(name_stack, min_count, max_count, NULL);
- if (NAME_VALUE_LOOKUP::getPossibleValues())
+ if (name_value_lookup_t::getPossibleValues())
{
- parser.inspectValue<std::string>(name_stack, min_count, max_count, NAME_VALUE_LOOKUP::getPossibleValues());
+ parser.inspectValue<std::string>(name_stack, min_count, max_count, name_value_lookup_t::getPossibleValues());
}
}
void set(value_assignment_t val, bool flag_as_provided = true)
{
mValues = val;
- mCachedKeys.clear();
- mCachedKeys.resize(mValues.size());
setProvided(flag_as_provided);
- Param::enclosingBlock().setLastChangedParam(*this, flag_as_provided);
+ Param::enclosingBlock().paramChanged(*this, flag_as_provided);
}
@@ -1008,23 +1040,23 @@ namespace LLInitParam
}
}
- value_ref_t add()
+ value_t& add()
{
- mValues.push_back(value_t());
- mCachedKeys.push_back(key_cache_t());
+ mValues.push_back(param_value_t(value_t()));
setProvided(true);
+ Param::enclosingBlock().paramChanged(*this, true);
return mValues.back();
}
- void add(value_const_ref_t item)
+ void add(const value_t& item)
{
- mValues.push_back(item);
- mCachedKeys.push_back(key_cache_t());
+ mValues.push_back(param_value_t(item));
setProvided(true);
+ Param::enclosingBlock().paramChanged(*this, true);
}
// implicit conversion
- operator value_assignment_t() const { return self_t::get(); }
+ operator value_assignment_t() const { return mValues; }
typedef typename container_t::iterator iterator;
typedef typename container_t::const_iterator const_iterator;
@@ -1041,27 +1073,31 @@ namespace LLInitParam
}
protected:
- value_assignment_t get() const
- {
- return mValues;
- }
-
static bool mergeWith(Param& dst, const Param& src, bool overwrite)
{
const self_t& src_typed_param = static_cast<const self_t&>(src);
self_t& dst_typed_param = static_cast<self_t&>(dst);
- if (src_typed_param.isProvided()
- && (overwrite || !dst_typed_param.isProvided()))
+ if (overwrite)
{
- dst_typed_param.set(src_typed_param.get());
- return true;
+ std::copy(src_typed_param.begin(), src_typed_param.end(), std::back_inserter(dst_typed_param.mValues));
}
- return false;
+ else
+ {
+ container_t new_values(src_typed_param.mValues);
+ std::copy(dst_typed_param.begin(), dst_typed_param.end(), std::back_inserter(new_values));
+ std::swap(dst_typed_param.mValues, new_values);
+ }
+
+ if (src_typed_param.begin() != src_typed_param.end())
+ {
+ dst_typed_param.setProvided(true);
+ dst_typed_param.enclosingBlock().paramChanged(dst_typed_param, true);
+ }
+ return true;
}
container_t mValues;
- std::vector<key_cache_t> mCachedKeys;
};
// container of block parameters
@@ -1071,80 +1107,76 @@ namespace LLInitParam
{
public:
typedef TypedParam<VALUE_TYPE, NAME_VALUE_LOOKUP, true, true> self_t;
- typedef typename std::vector<VALUE_TYPE> container_t;
+ typedef ParamValue<VALUE_TYPE, NAME_VALUE_LOOKUP> param_value_t;
+ typedef typename std::vector<param_value_t> container_t;
typedef const container_t& value_assignment_t;
-
typedef VALUE_TYPE value_t;
- typedef value_t& value_ref_t;
- typedef const value_t& value_const_ref_t;
-
- typedef typename NAME_VALUE_LOOKUP::KeyCache key_cache_t;
+ typedef NAME_VALUE_LOOKUP name_value_lookup_t;
TypedParam(BlockDescriptor& block_descriptor, const char* name, value_assignment_t value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count)
: Param(block_descriptor.mCurrentBlockPtr),
- mValues(value),
- mLastParamGeneration(0)
+ mLastParseGeneration(0)
{
- mCachedKeys.resize(mValues.size());
+ std::copy(value.begin(), value.end(), back_inserter(mValues));
+
if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING))
{
- ParamDescriptor param_descriptor(block_descriptor.mCurrentBlockPtr->getHandleFromParam(this),
+ ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor(
+ block_descriptor.mCurrentBlockPtr->getHandleFromParam(this),
&mergeWith,
&deserializeParam,
&serializeParam,
validate_func,
&inspectParam,
- min_count, max_count);
+ min_count, max_count));
BaseBlock::addParam(block_descriptor, param_descriptor, name);
}
}
bool isProvided() const { return Param::anyProvided(); }
- value_ref_t operator[](S32 index) { return mValues[index]; }
- value_const_ref_t operator[](S32 index) const { return mValues[index]; }
-
static bool deserializeParam(Param& param, Parser& parser, const Parser::name_stack_range_t& name_stack, S32 generation)
{
self_t& typed_param = static_cast<self_t&>(param);
bool new_value = false;
- if (generation != typed_param.mLastParamGeneration || typed_param.mValues.empty())
+
+ if (generation != typed_param.mLastParseGeneration
+ || typed_param.mValues.empty())
{
new_value = true;
typed_param.mValues.push_back(value_t());
- typed_param.mCachedKeys.push_back(Data());
}
- value_ref_t value = typed_param.mValues.back();
+ param_value_t& value = typed_param.mValues.back();
// attempt to parse block...
- if(value.deserializeBlock(parser, name_stack))
+ if(value.deserializeBlock(parser, name_stack, generation))
{
if (new_value)
{ // successfully parsed new value, let's keep it
- typed_param.mLastParamGeneration = generation;
+ typed_param.mLastParseGeneration = generation;
}
- typed_param.enclosingBlock().setLastChangedParam(param, true);
+ typed_param.enclosingBlock().paramChanged(param, true);
typed_param.setProvided(true);
return true;
}
- else if(!NAME_VALUE_LOOKUP::empty())
+ else if(name_value_lookup_t::valueNamesExist())
{
// try to parse a known named value
std::string name;
if (parser.readValue(name))
{
// try to parse a per type named value
- if (NAME_VALUE_LOOKUP::get(name, value))
+ if (name_value_lookup_t::getValueFromName(name, value.getValue()))
{
if (new_value)
{ // successfully parsed new value, let's keep it
- typed_param.mLastParamGeneration = generation;
+ typed_param.mLastParseGeneration = generation;
}
- typed_param.mCachedKeys.back().setKey(name);
- typed_param.mCachedKeys.back().mKeyVersion = value.getLastChangeVersion();
- typed_param.enclosingBlock().setLastChangedParam(param, true);
+ typed_param.mValues.back().setValueName(name);
+ typed_param.mValues.back().mKeyVersion = value.getLastChangeVersion();
+ typed_param.enclosingBlock().paramChanged(param, true);
typed_param.setProvided(true);
return true;
}
@@ -1155,7 +1187,6 @@ namespace LLInitParam
if (new_value)
{ // failed to parse new value, pop it off
typed_param.mValues.pop_back();
- typed_param.mCachedKeys.pop_back();
}
return false;
@@ -1166,26 +1197,22 @@ namespace LLInitParam
const self_t& typed_param = static_cast<const self_t&>(param);
if (!typed_param.isProvided() || name_stack.empty()) return;
- const_iterator it = typed_param.mValues.begin();
- for (typename std::vector<Data>::const_iterator key_it = typed_param.mCachedKeys.begin();
- it != typed_param.mValues.end();
- ++key_it, ++it)
+ for (const_iterator it = typed_param.mValues.begin(), end_it = typed_param.mValues.end();
+ it != end_it;
+ ++it)
{
name_stack.back().second = parser.newParseGeneration();
- std::string key = key_it->getKey();
- if (!key.empty() && key_it->mKeyVersion == it->getLastChangeVersion())
+ std::string key = it->getValueName();
+ if (!key.empty() && it->mKeyVersion == it->getLastChangeVersion())
{
- if(!parser.writeValue(key, name_stack))
- {
- return;
- }
+ parser.writeValue(key, name_stack);
}
// Not parsed via named values, write out value directly
// NOTE: currently we don't worry about removing default values in Multiple
- else if (!it->serializeBlock(parser, name_stack, NULL))
+ else
{
- return;
+ it->serializeBlock(parser, name_stack, NULL);
}
}
}
@@ -1193,16 +1220,14 @@ namespace LLInitParam
static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count)
{
// I am a vector of blocks, so describe my contents recursively
- value_t().inspectBlock(parser, name_stack);
+ param_value_t(value_t()).inspectBlock(parser, name_stack, min_count, max_count);
}
void set(value_assignment_t val, bool flag_as_provided = true)
{
mValues = val;
- mCachedKeys.clear();
- mCachedKeys.resize(mValues.size());
setProvided(flag_as_provided);
- Param::enclosingBlock().setLastChangedParam(*this, flag_as_provided);
+ Param::enclosingBlock().paramChanged(*this, flag_as_provided);
}
void setIfNotProvided(value_assignment_t val, bool flag_as_provided = true)
@@ -1213,23 +1238,23 @@ namespace LLInitParam
}
}
- value_ref_t add()
+ value_t& add()
{
mValues.push_back(value_t());
- mCachedKeys.push_back(Data());
setProvided(true);
+ Param::enclosingBlock().paramChanged(*this, true);
return mValues.back();
}
- void add(value_const_ref_t item)
+ void add(const value_t& item)
{
mValues.push_back(item);
- mCachedKeys.push_back(Data());
setProvided(true);
+ Param::enclosingBlock().paramChanged(*this, true);
}
// implicit conversion
- operator value_assignment_t() const { return self_t::get(); }
+ operator value_assignment_t() const { return mValues; }
typedef typename container_t::iterator iterator;
typedef typename container_t::const_iterator const_iterator;
@@ -1243,8 +1268,8 @@ namespace LLInitParam
U32 numValidElements() const
{
U32 count = 0;
- for (const_iterator it = mValues.begin();
- it != mValues.end();
+ for (const_iterator it = mValues.begin(), end_it = mValues.end();
+ it != end_it;
++it)
{
if(it->validateBlock(false)) count++;
@@ -1253,74 +1278,77 @@ namespace LLInitParam
}
protected:
- value_assignment_t get() const
- {
- return mValues;
- }
static bool mergeWith(Param& dst, const Param& src, bool overwrite)
{
const self_t& src_typed_param = static_cast<const self_t&>(src);
self_t& dst_typed_param = static_cast<self_t&>(dst);
- if (src_typed_param.isProvided()
- && (overwrite || !dst_typed_param.isProvided()))
+ if (overwrite)
{
- dst_typed_param.set(src_typed_param.get());
- return true;
+ std::copy(src_typed_param.begin(), src_typed_param.end(), std::back_inserter(dst_typed_param.mValues));
+ }
+ else
+ {
+ container_t new_values(src_typed_param.mValues);
+ std::copy(dst_typed_param.begin(), dst_typed_param.end(), std::back_inserter(new_values));
+ std::swap(dst_typed_param.mValues, new_values);
}
- return false;
- }
- struct Data : public key_cache_t
- {
- S32 mKeyVersion; // version of block for which key was last valid
+ if (src_typed_param.begin() != src_typed_param.end())
+ {
+ dst_typed_param.setProvided(true);
+ dst_typed_param.enclosingBlock().paramChanged(dst_typed_param, true);
+ }
- Data() : mKeyVersion(0) {}
- };
+ return true;
+ }
container_t mValues;
- std::vector<Data> mCachedKeys;
- S32 mLastParamGeneration;
+ S32 mLastParseGeneration;
};
template <typename DERIVED_BLOCK>
class Choice : public BaseBlock
{
- typedef Choice<DERIVED_BLOCK> self_t;
- typedef Choice<DERIVED_BLOCK> enclosing_block_t;
+ typedef Choice<DERIVED_BLOCK> self_t;
+ typedef Choice<DERIVED_BLOCK> enclosing_block_t;
LOG_CLASS(self_t);
public:
// take all provided params from other and apply to self
bool overwriteFrom(const self_t& other)
{
- return merge(selfBlockDescriptor(), other, true);
+ return mergeBlock(selfBlockDescriptor(), other, true);
}
// take all provided params that are not already provided, and apply to self
bool fillFrom(const self_t& other)
{
- return merge(selfBlockDescriptor(), other, false);
+ return mergeBlock(selfBlockDescriptor(), other, false);
}
- // merge with other block
- bool merge(BlockDescriptor& block_data, const self_t& other, bool overwrite)
+ bool mergeBlockParam(bool param_provided, BlockDescriptor& block_data, const self_t& other, bool overwrite)
{
- // only merge a choice if we are overwriting with other's contents
- if (overwrite)
+ if (param_provided)
{
- mCurChoice = other.mCurChoice;
- return BaseBlock::merge(selfBlockDescriptor(), other, overwrite);
+ return mergeBlock(block_data, other, overwrite);
}
return false;
}
+ // merge with other block
+ bool mergeBlock(BlockDescriptor& block_data, const self_t& other, bool overwrite)
+ {
+ mCurChoice = other.mCurChoice;
+ return BaseBlock::mergeBlock(selfBlockDescriptor(), other, overwrite);
+ }
+
// clear out old choice when param has changed
- /*virtual*/ void setLastChangedParam(const Param& last_param, bool user_provided)
+ /*virtual*/ void paramChanged(const Param& changed_param, bool user_provided)
{
- param_handle_t changed_param_handle = BaseBlock::getHandleFromParam(&last_param);
+ param_handle_t changed_param_handle = BaseBlock::getHandleFromParam(&changed_param);
// if we have a new choice...
if (changed_param_handle != mCurChoice)
{
@@ -1332,7 +1360,7 @@ namespace LLInitParam
}
mCurChoice = changed_param_handle;
}
- BaseBlock::setLastChangedParam(last_param, user_provided);
+ BaseBlock::paramChanged(changed_param, user_provided);
}
virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return selfBlockDescriptor(); }
@@ -1355,20 +1383,21 @@ namespace LLInitParam
friend class Choice<DERIVED_BLOCK>;
typedef Alternative<T, NAME_VALUE_LOOKUP> self_t;
- typedef TypedParam<T, NAME_VALUE_LOOKUP, false, IsBaseBlock<T>::value> super_t;
+ typedef TypedParam<T, NAME_VALUE_LOOKUP, false, IsBlock<ParamValue<T, NAME_VALUE_LOOKUP> >::value> super_t;
typedef typename super_t::value_assignment_t value_assignment_t;
- explicit Alternative(const char* name, value_assignment_t val = DefaultInitializer<T>::get())
+ explicit Alternative(const char* name, value_assignment_t val = defaultValue<T>())
: super_t(DERIVED_BLOCK::selfBlockDescriptor(), name, val, NULL, 0, 1),
mOriginalValue(val)
{
// assign initial choice to first declared option
DERIVED_BLOCK* blockp = ((DERIVED_BLOCK*)DERIVED_BLOCK::selfBlockDescriptor().mCurrentBlockPtr);
- if (LL_UNLIKELY(
- DERIVED_BLOCK::selfBlockDescriptor().mInitializationState == BlockDescriptor::INITIALIZING
- && blockp->mCurChoice == 0))
+ if (LL_UNLIKELY(DERIVED_BLOCK::selfBlockDescriptor().mInitializationState == BlockDescriptor::INITIALIZING))
{
- blockp->mCurChoice = Param::enclosingBlock().getHandleFromParam(this);
+ if(blockp->mCurChoice == 0)
+ {
+ blockp->mCurChoice = Param::enclosingBlock().getHandleFromParam(this);
+ }
}
}
@@ -1387,7 +1416,7 @@ namespace LLInitParam
{
if (static_cast<enclosing_block_t&>(Param::enclosingBlock()).getCurrentChoice() == this)
{
- return super_t::get();
+ return super_t::getValue();
}
return mOriginalValue;
}
@@ -1396,7 +1425,7 @@ namespace LLInitParam
{
if (static_cast<enclosing_block_t&>(Param::enclosingBlock()).getCurrentChoice() == this)
{
- return super_t::get();
+ return super_t::getValue();
}
return mOriginalValue;
}
@@ -1430,8 +1459,8 @@ namespace LLInitParam
class Block
: public BASE_BLOCK
{
- typedef Block<DERIVED_BLOCK, BASE_BLOCK> self_t;
- typedef Block<DERIVED_BLOCK, BASE_BLOCK> block_t;
+ typedef Block<DERIVED_BLOCK, BASE_BLOCK> self_t;
+ typedef Block<DERIVED_BLOCK, BASE_BLOCK> block_t;
public:
typedef BASE_BLOCK base_block_t;
@@ -1439,13 +1468,13 @@ namespace LLInitParam
// take all provided params from other and apply to self
bool overwriteFrom(const self_t& other)
{
- return BaseBlock::merge(selfBlockDescriptor(), other, true);
+ return static_cast<DERIVED_BLOCK*>(this)->mergeBlock(selfBlockDescriptor(), other, true);
}
// take all provided params that are not already provided, and apply to self
bool fillFrom(const self_t& other)
{
- return BaseBlock::merge(selfBlockDescriptor(), other, false);
+ return static_cast<DERIVED_BLOCK*>(this)->mergeBlock(selfBlockDescriptor(), other, false);
}
virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return selfBlockDescriptor(); }
@@ -1465,10 +1494,10 @@ namespace LLInitParam
class Optional : public TypedParam<T, NAME_VALUE_LOOKUP, false>
{
public:
- typedef TypedParam<T, NAME_VALUE_LOOKUP, false, IsBaseBlock<T>::value> super_t;
+ typedef TypedParam<T, NAME_VALUE_LOOKUP, false, IsBlock<ParamValue<T, NAME_VALUE_LOOKUP> >::value> super_t;
typedef typename super_t::value_assignment_t value_assignment_t;
- explicit Optional(const char* name = "", value_assignment_t val = DefaultInitializer<T>::get())
+ explicit Optional(const char* name = "", value_assignment_t val = defaultValue<T>())
: super_t(DERIVED_BLOCK::selfBlockDescriptor(), name, val, NULL, 0, 1)
{
//#pragma message("Parsing LLInitParam::Block::Optional")
@@ -1480,7 +1509,7 @@ namespace LLInitParam
return *this;
}
- DERIVED_BLOCK& operator()(typename super_t::value_assignment_t val)
+ DERIVED_BLOCK& operator()(value_assignment_t val)
{
super_t::set(val);
return static_cast<DERIVED_BLOCK&>(Param::enclosingBlock());
@@ -1492,12 +1521,12 @@ namespace LLInitParam
class Mandatory : public TypedParam<T, NAME_VALUE_LOOKUP, false>
{
public:
- typedef TypedParam<T, NAME_VALUE_LOOKUP, false, IsBaseBlock<T>::value> super_t;
+ typedef TypedParam<T, NAME_VALUE_LOOKUP, false, IsBlock<ParamValue<T, NAME_VALUE_LOOKUP> >::value> super_t;
typedef Mandatory<T, NAME_VALUE_LOOKUP> self_t;
typedef typename super_t::value_assignment_t value_assignment_t;
// mandatory parameters require a name to be parseable
- explicit Mandatory(const char* name = "", value_assignment_t val = DefaultInitializer<T>::get())
+ explicit Mandatory(const char* name = "", value_assignment_t val = defaultValue<T>())
: super_t(DERIVED_BLOCK::selfBlockDescriptor(), name, val, &validate, 1, 1)
{}
@@ -1526,15 +1555,15 @@ namespace LLInitParam
class Multiple : public TypedParam<T, NAME_VALUE_LOOKUP, true>
{
public:
- typedef TypedParam<T, NAME_VALUE_LOOKUP, true, IsBaseBlock<T>::value> super_t;
+ typedef TypedParam<T, NAME_VALUE_LOOKUP, true, IsBlock<ParamValue<T, NAME_VALUE_LOOKUP> >::value> super_t;
typedef Multiple<T, RANGE, NAME_VALUE_LOOKUP> self_t;
typedef typename super_t::container_t container_t;
typedef typename super_t::value_assignment_t value_assignment_t;
typedef typename super_t::iterator iterator;
typedef typename super_t::const_iterator const_iterator;
- explicit Multiple(const char* name = "", value_assignment_t val = DefaultInitializer<container_t>::get())
- : super_t(DERIVED_BLOCK::selfBlockDescriptor(), name, val, &validate, RANGE::minCount(), RANGE::maxCount())
+ explicit Multiple(const char* name = "")
+ : super_t(DERIVED_BLOCK::selfBlockDescriptor(), name, container_t(), &validate, RANGE::minCount(), RANGE::maxCount())
{}
Multiple& operator=(value_assignment_t val)
@@ -1542,7 +1571,7 @@ namespace LLInitParam
set(val);
return *this;
}
-
+
DERIVED_BLOCK& operator()(typename super_t::value_assignment_t val)
{
super_t::set(val);
@@ -1556,6 +1585,96 @@ namespace LLInitParam
}
};
+ template <typename T, typename RANGE = BaseBlock::AnyAmount, typename NAME_VALUE_LOOKUP = TypeValues<T> >
+ class Batch : private TypedParam<T, NAME_VALUE_LOOKUP, false>
+ {
+ public:
+ typedef ParamValue<T, NAME_VALUE_LOOKUP> param_value_t;
+ typedef TypedParam<T, NAME_VALUE_LOOKUP, false, IsBlock<param_value_t>::value> super_t;
+ typedef Batch<T, RANGE, NAME_VALUE_LOOKUP> self_t;
+ typedef typename super_t::value_assignment_t value_assignment_t;
+ typedef typename super_t::value_t value_t;
+
+ struct BatchDefaultValue : public ParamDescriptor::UserData
+ {
+ BatchDefaultValue(const T& value)
+ : mValue(value)
+ {}
+
+ T mValue;
+ };
+
+ explicit Batch(const char* name, value_assignment_t val)
+ : super_t(DERIVED_BLOCK::selfBlockDescriptor(), name, val, NULL, 0, 1),
+ mLastParseGeneration(-1)
+ {
+ BlockDescriptor& block_descriptor = DERIVED_BLOCK::selfBlockDescriptor();
+ if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING))
+ {
+ ParamDescriptorPtr param_descriptorp = block_descriptor.mCurrentBlockPtr->findParamDescriptor(*this);
+
+ if (param_descriptorp)
+ {
+ param_descriptorp->mDeserializeFunc = &deserializeParam;
+ param_descriptorp->mUserData = new BatchDefaultValue(new param_value_t(val));
+ }
+ }
+ }
+
+ explicit Batch(const char* name = "")
+ : super_t(DERIVED_BLOCK::selfBlockDescriptor(), name, defaultValue<T>(), NULL, 0, 1),
+ mLastParseGeneration(-1)
+ {
+ BlockDescriptor& block_descriptor = DERIVED_BLOCK::selfBlockDescriptor();
+ if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING))
+ {
+ ParamDescriptorPtr param_descriptorp = block_descriptor.mCurrentBlockPtr->findParamDescriptor(*this);
+
+ if (param_descriptorp)
+ {
+ param_descriptorp->mDeserializeFunc = &deserializeParam;
+ }
+ }
+ }
+
+ Batch& operator=(value_assignment_t val)
+ {
+ set(val);
+ return *this;
+ }
+
+ DERIVED_BLOCK& operator()(value_assignment_t val)
+ {
+ super_t::set(val);
+ return static_cast<DERIVED_BLOCK&>(Param::enclosingBlock());
+ }
+
+ using super_t::operator();
+
+ private:
+ static bool deserializeParam(Param& param, Parser& parser, const Parser::name_stack_range_t& name_stack, S32 generation)
+ {
+ self_t& typed_param = static_cast<self_t&>(param);
+
+ if (generation != typed_param.mLastParseGeneration)
+ {
+ ParamDescriptorPtr descriptor = typed_param.enclosingBlock().findParamDescriptor(param);
+ if (descriptor && static_cast<BatchDefaultValue*>(descriptor->mUserData))
+ {
+ static_cast<param_value_t&>(typed_param) = (static_cast<BatchDefaultValue*>(descriptor->mUserData))->mValue;
+ }
+ else
+ {
+ static_cast<param_value_t&>(typed_param) = param_value_t(value_t());
+ }
+ typed_param.mLastParseGeneration = generation;
+ }
+ return super_t::deserializeParam(param, parser, name_stack, generation);
+ }
+
+ S32 mLastParseGeneration;
+ };
+
class Deprecated : public Param
{
public:
@@ -1565,13 +1684,14 @@ namespace LLInitParam
BlockDescriptor& block_descriptor = DERIVED_BLOCK::selfBlockDescriptor();
if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING))
{
- ParamDescriptor param_descriptor(block_descriptor.mCurrentBlockPtr->getHandleFromParam(this),
+ ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor(
+ block_descriptor.mCurrentBlockPtr->getHandleFromParam(this),
NULL,
&deserializeParam,
NULL,
NULL,
NULL,
- 0, S32_MAX);
+ 0, S32_MAX));
BaseBlock::addParam(block_descriptor, param_descriptor, name);
}
}
@@ -1599,137 +1719,91 @@ namespace LLInitParam
}
};
- template<typename T, typename DERIVED = TypedParam<T> >
- class BlockValue
- : public Block<TypedParam<T, TypeValues<T>, false> >,
- public Param
+ template<typename T>
+ class CustomParamValue
+ : public Block<ParamValue<T, TypeValues<T> > >,
+ public TypeValues<T>
{
public:
typedef enum e_value_age
{
- OLDER_THAN_BLOCK, // mData.mValue needs to be refreshed from the block parameters
- NEWER_THAN_BLOCK, // mData.mValue holds the authoritative value (which has been replicated to the block parameters via setBlockFromValue)
- SAME_AS_BLOCK // mData.mValue is derived from the block parameters, which are authoritative
+ VALUE_NEEDS_UPDATE, // mValue needs to be refreshed from the block parameters
+ VALUE_AUTHORITATIVE, // mValue holds the authoritative value (which has been replicated to the block parameters via updateBlockFromValue)
+ BLOCK_AUTHORITATIVE // mValue is derived from the block parameters, which are authoritative
} EValueAge;
- typedef BlockValue<T> self_t;
- typedef Block<TypedParam<T, TypeValues<T>, false> > block_t;
- typedef const T& value_const_ref_t;
- typedef value_const_ref_t value_assignment_t;
- typedef typename TypeValues<T>::KeyCache key_cache_t;
+ typedef ParamValue<T, TypeValues<T> > derived_t;
+ typedef CustomParamValue<T> self_t;
+ typedef Block<derived_t> block_t;
+ typedef const T& value_assignment_t;
- BlockValue(BlockDescriptor& block_descriptor, const char* name, value_assignment_t value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count)
- : Param(block_descriptor.mCurrentBlockPtr),
- mData(value, NEWER_THAN_BLOCK)
- {
- if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING))
- {
- ParamDescriptor param_descriptor(block_descriptor.mCurrentBlockPtr->getHandleFromParam(this),
- &mergeWith,
- &deserializeParam,
- &serializeParam,
- validate_func,
- &inspectParam,
- min_count, max_count);
- BaseBlock::addParam(block_descriptor, param_descriptor, name);
- }
- }
-
- // implicit conversion
- operator value_assignment_t() const { return get(); }
- // explicit conversion
- value_assignment_t operator()() const { return get(); }
+ CustomParamValue(const T& value = T())
+ : mValue(value),
+ mValueAge(VALUE_AUTHORITATIVE),
+ mKeyVersion(0),
+ mValidatedVersion(-1)
+ {}
- static bool deserializeParam(Param& param, Parser& parser, const Parser::name_stack_range_t& name_stack, S32 generation)
+ bool deserializeBlock(Parser& parser, Parser::name_stack_range_t name_stack, S32 generation)
{
- DERIVED& typed_param = static_cast<DERIVED&>(param);
+ derived_t& typed_param = static_cast<derived_t&>(*this);
// type to apply parse direct value T
if (name_stack.first == name_stack.second)
{
- if(parser.readValue(typed_param.mData.mValue))
+ if(parser.readValue(typed_param.mValue))
{
- typed_param.enclosingBlock().setLastChangedParam(param, true);
- typed_param.setProvided(true);
- typed_param.mData.clearKey();
- typed_param.mData.mValueAge = NEWER_THAN_BLOCK;
- typed_param.setBlockFromValue();
+ typed_param.clearValueName();
+ typed_param.mValueAge = VALUE_AUTHORITATIVE;
+ typed_param.updateBlockFromValue();
return true;
}
-
- if(!TypeValues<T>::empty())
- {
- // try to parse a known named value
- std::string name;
- if (parser.readValue(name))
- {
- // try to parse a per type named value
- if (TypeValues<T>::get(name, typed_param.mData.mValue))
- {
- typed_param.mData.setKey(name);
- typed_param.enclosingBlock().setLastChangedParam(param, true);
- typed_param.setProvided(true);
- typed_param.mData.mValueAge = NEWER_THAN_BLOCK;
- typed_param.setBlockFromValue();
-
- return true;
- }
- }
- }
}
// fall back on parsing block components for T
// if we deserialized at least one component...
- if (typed_param.BaseBlock::deserializeBlock(parser, name_stack))
+ if (typed_param.BaseBlock::deserializeBlock(parser, name_stack, generation))
{
- // ...our block is provided, and considered changed
- typed_param.enclosingBlock().setLastChangedParam(param, true);
- typed_param.setProvided(true);
return true;
}
+
return false;
}
- static void serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const Param* diff_param)
+ void serializeBlock(Parser& parser, Parser::name_stack_t name_stack = Parser::name_stack_t(), const BaseBlock* diff_block = NULL) const
{
- const self_t& typed_param = static_cast<const self_t&>(param);
-
- if (!typed_param.isProvided()) return;
+ const self_t& typed_param = static_cast<const self_t&>(*this);
+ const self_t* diff_param = static_cast<const self_t*>(diff_block);
- std::string key = typed_param.mData.getKey();
+ std::string key = typed_param.getValueName();
// first try to write out name of name/value pair
if (!key.empty())
{
- if (!diff_param || !ParamCompare<std::string>::equals(static_cast<const self_t*>(diff_param)->mData.getKey(), key))
+ if (!diff_param || !ParamCompare<std::string>::equals(diff_param->getValueName(), key))
{
- if (!parser.writeValue(key, name_stack))
- {
- return;
- }
+ parser.writeValue(key, name_stack);
}
}
// then try to serialize value directly
- else if (!diff_param || !ParamCompare<T>::equals(typed_param.get(), (static_cast<const self_t*>(diff_param))->get()))
+ else if (!diff_param || !ParamCompare<T>::equals(typed_param.getValue(), diff_param->getValue()))
{
- if (parser.writeValue(typed_param.mData.mValue, name_stack))
+ if (!parser.writeValue(typed_param.getValue(), name_stack))
{
- return;
+ //RN: *always* serialize provided components of BlockValue (don't pass diff_param on),
+ // since these tend to be viewed as the constructor arguments for the value T. It seems
+ // cleaner to treat the uniqueness of a BlockValue according to the generated value, and
+ // not the individual components. This way <color red="0" green="1" blue="0"/> will not
+ // be exported as <color green="1"/>, since it was probably the intent of the user to
+ // be specific about the RGB color values. This also fixes an issue where we distinguish
+ // between rect.left not being provided and rect.left being explicitly set to 0 (same as default)
+ block_t::serializeBlock(parser, name_stack, NULL);
}
-
- //RN: *always* serialize provided components of BlockValue (don't pass diff_param on),
- // since these tend to be viewed as the constructor arguments for the value T. It seems
- // cleaner to treat the uniqueness of a BlockValue according to the generated value, and
- // not the individual components. This way <color red="0" green="1" blue="0"/> will not
- // be exported as <color green="1"/>, since it was probably the intent of the user to
- // be specific about the RGB color values. This also fixes an issue where we distinguish
- // between rect.left not being provided and rect.left being explicitly set to 0 (same as default)
- typed_param.BaseBlock::serializeBlock(parser, name_stack, NULL);
}
}
- static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count)
+ bool inspectBlock(Parser& parser, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const
{
// first, inspect with actual type...
parser.inspectValue<T>(name_stack, min_count, max_count, NULL);
@@ -1739,25 +1813,19 @@ namespace LLInitParam
parser.inspectValue<std::string>(name_stack, min_count, max_count, TypeValues<T>::getPossibleValues());
}
// then recursively inspect contents...
- const self_t& typed_param = static_cast<const self_t&>(param);
- typed_param.inspectBlock(parser, name_stack);
+ return block_t::inspectBlock(parser, name_stack, min_count, max_count);
}
-
- bool isProvided() const
+ bool validateBlock(bool emit_errors = true) const
{
- if (!Param::anyProvided()) return false;
-
- // block has an updated parameter
- // if cached value is stale, regenerate from params
- if (mData.mValueAge == OLDER_THAN_BLOCK)
+ if (mValueAge == VALUE_NEEDS_UPDATE)
{
- if (block_t::validateBlock(false))
+ if (block_t::validateBlock(emit_errors))
{
- static_cast<const DERIVED*>(this)->setValueFromBlock();
// clear stale keyword associated with old value
- mData.clearKey();
- mData.mValueAge = SAME_AS_BLOCK;
+ TypeValues<T>::clearValueName();
+ mValueAge = BLOCK_AUTHORITATIVE;
+ static_cast<derived_t*>(const_cast<self_t*>(this))->updateValueFromBlock();
return true;
}
else
@@ -1774,104 +1842,84 @@ namespace LLInitParam
}
}
- void set(value_assignment_t val, bool flag_as_provided = true)
+ // propagate change status up to enclosing block
+ /*virtual*/ void paramChanged(const Param& changed_param, bool user_provided)
+ {
+ BaseBlock::paramChanged(changed_param, user_provided);
+ if (user_provided)
{
- Param::enclosingBlock().setLastChangedParam(*this, flag_as_provided);
+ // a parameter changed, so our value is out of date
+ mValueAge = VALUE_NEEDS_UPDATE;
+ }
+ }
+ void setValue(value_assignment_t val)
+ {
+ derived_t& typed_param = static_cast<derived_t&>(*this);
// set param version number to be up to date, so we ignore block contents
- mData.mValueAge = NEWER_THAN_BLOCK;
-
- mData.mValue = val;
- mData.clearKey();
- setProvided(flag_as_provided);
- static_cast<DERIVED*>(this)->setBlockFromValue();
+ mValueAge = VALUE_AUTHORITATIVE;
+ mValue = val;
+ typed_param.clearValueName();
+ static_cast<derived_t*>(const_cast<self_t*>(this))->updateBlockFromValue();
}
- void setIfNotProvided(value_assignment_t val, bool flag_as_provided = true)
+ value_assignment_t getValue() const
{
- // don't override any user provided value
- if (!isProvided())
- {
- set(val, flag_as_provided);
- }
+ validateBlock(true);
+ return mValue;
}
- // propagate change status up to enclosing block
- /*virtual*/ void setLastChangedParam(const Param& last_param, bool user_provided)
- {
- BaseBlock::setLastChangedParam(last_param, user_provided);
- Param::enclosingBlock().setLastChangedParam(*this, user_provided);
- if (user_provided)
- {
- setProvided(true); // some component provided
- // a parameter changed, so our value is out of date
- mData.mValueAge = OLDER_THAN_BLOCK;
- }
+ T& getValue()
+ {
+ validateBlock(true);
+ return mValue;
}
+ S32 mKeyVersion;
+
protected:
- value_assignment_t get() const
- {
- // if some parameters were provided, issue warnings on invalid blocks
- if (Param::anyProvided() && (mData.mValueAge == OLDER_THAN_BLOCK))
- {
- // go ahead and issue warnings at this point if any param is invalid
- if(block_t::validateBlock(true))
- {
- static_cast<const DERIVED*>(this)->setValueFromBlock();
- mData.clearKey();
- mData.mValueAge = SAME_AS_BLOCK;
- }
- }
- return mData.mValue;
+ // use this from within updateValueFromBlock() to set the value without making it authoritative
+ void updateValue(value_assignment_t value)
+ {
+ mValue = value;
}
-
- struct Data : public key_cache_t
+ bool mergeBlockParam(bool param_provided, BlockDescriptor& block_data, const BaseBlock& other, bool overwrite)
{
- Data(const T& value, EValueAge age)
- : mValue(value),
- mValueAge(age)
- {}
-
- T mValue;
- EValueAge mValueAge;
- };
-
- // mutable to allow lazy updates on get
- mutable Data mData;
+ if (param_provided)
+ {
+ return mergeBlock(block_data, other, overwrite);
+ }
+ return false;
+ }
- private:
- static bool mergeWith(Param& dst, const Param& src, bool overwrite)
+ bool mergeBlock(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite)
{
- const DERIVED& src_typed_param = static_cast<const DERIVED&>(src);
- DERIVED& dst_typed_param = static_cast<DERIVED&>(dst);
+ const derived_t& src_typed_param = static_cast<const derived_t&>(other);
- if (src_typed_param.isProvided()
- && (overwrite || !dst_typed_param.isProvided()))
+ if (src_typed_param.mValueAge == VALUE_AUTHORITATIVE)
{
- if (src_typed_param.mData.mValueAge == NEWER_THAN_BLOCK)
- {
- // copy value over
- dst_typed_param.set(src_typed_param.get());
- }
- else
- {
- // merge individual parameters into destination
- dst_typed_param.merge(block_t::selfBlockDescriptor(), src_typed_param, overwrite);
- }
+ // copy value over
+ setValue(src_typed_param.getValue());
return true;
}
- return false;
+ else
+ {
+ // merge individual parameters into destination
+ return block_t::mergeBlock(block_t::selfBlockDescriptor(), src_typed_param, overwrite);
+ }
}
- };
- template<>
- struct ParamCompare<LLSD, false>
- {
- static bool equals(const LLSD &a, const LLSD &b);
+ mutable S32 mValidatedVersion;
+ mutable bool mValidated; // lazy validation flag
+
+ private:
+
+ mutable T mValue;
+ mutable EValueAge mValueAge;
};
}
+
#endif // LL_LLPARAM_H
diff --git a/indra/llxuixml/llregistry.h b/indra/llxuixml/llregistry.h
index eee9933739..36ce6a97b7 100644
--- a/indra/llxuixml/llregistry.h
+++ b/indra/llxuixml/llregistry.h
@@ -343,4 +343,9 @@ private:
ScopedRegistrar* mStaticScope;
};
+// helper macro for doing static registration
+#define GLUED_TOKEN(x, y) x ## y
+#define GLUE_TOKENS(x, y) GLUED_TOKEN(x, y)
+#define LLREGISTER_STATIC(REGISTRY, KEY, VALUE) static REGISTRY::StaticRegistrar GLUE_TOKENS(reg, __LINE__)(KEY, VALUE);
+
#endif
diff --git a/indra/llxuixml/lltrans.cpp b/indra/llxuixml/lltrans.cpp
index 11127a53f5..5388069c24 100644
--- a/indra/llxuixml/lltrans.cpp
+++ b/indra/llxuixml/lltrans.cpp
@@ -30,6 +30,8 @@
#include "llfasttimer.h" // for call count statistics
#include "llxuiparser.h"
+#include "llsd.h"
+#include "llxmlnode.h"
#include <map>
@@ -154,13 +156,28 @@ std::string LLTrans::getString(const std::string &xml_desc, const LLStringUtil::
}
else
{
- LLSD args;
- args["STRING_NAME"] = xml_desc;
LL_WARNS_ONCE("configuration") << "Missing String in strings.xml: [" << xml_desc << "]" << LL_ENDL;
+ return "MissingString("+xml_desc+")";
+ }
+}
- //LLNotificationsUtil::add("MissingString", args); // *TODO: resurrect
- //return xml_desc;
+//static
+std::string LLTrans::getString(const std::string &xml_desc, const LLSD& msg_args)
+{
+ // Don't care about time as much as call count. Make sure we're not
+ // calling LLTrans::getString() in an inner loop. JC
+ LLFastTimer timer(FTM_GET_TRANS);
+ template_map_t::iterator iter = sStringTemplates.find(xml_desc);
+ if (iter != sStringTemplates.end())
+ {
+ std::string text = iter->second.mText;
+ LLStringUtil::format(text, msg_args);
+ return text;
+ }
+ else
+ {
+ LL_WARNS_ONCE("configuration") << "Missing String in strings.xml: [" << xml_desc << "]" << LL_ENDL;
return "MissingString("+xml_desc+")";
}
}
@@ -182,11 +199,27 @@ bool LLTrans::findString(std::string &result, const std::string &xml_desc, const
}
else
{
- LLSD args;
- args["STRING_NAME"] = xml_desc;
- LL_WARNS_ONCE("configuration") << "Missing String in strings.xml: [" << xml_desc << "]" << LL_ENDL;
- //LLNotificationsUtil::add("MissingString", args);
-
+ LL_WARNS_ONCE("configuration") << "Missing String in strings.xml: [" << xml_desc << "]" << LL_ENDL;
+ return false;
+ }
+}
+
+//static
+bool LLTrans::findString(std::string &result, const std::string &xml_desc, const LLSD& msg_args)
+{
+ LLFastTimer timer(FTM_GET_TRANS);
+
+ template_map_t::iterator iter = sStringTemplates.find(xml_desc);
+ if (iter != sStringTemplates.end())
+ {
+ std::string text = iter->second.mText;
+ LLStringUtil::format(text, msg_args);
+ result = text;
+ return true;
+ }
+ else
+ {
+ LL_WARNS_ONCE("configuration") << "Missing String in strings.xml: [" << xml_desc << "]" << LL_ENDL;
return false;
}
}
@@ -255,3 +288,8 @@ std::string LLTrans::getCountString(const std::string& language, const std::stri
std::string key = llformat("%s%s", xml_desc.c_str(), form);
return getString(key, args);
}
+
+void LLTrans::setDefaultArg(const std::string& name, const std::string& value)
+{
+ sDefaultArgs[name] = value;
+}
diff --git a/indra/llxuixml/lltrans.h b/indra/llxuixml/lltrans.h
index 42c27b6976..128b51d383 100644
--- a/indra/llxuixml/lltrans.h
+++ b/indra/llxuixml/lltrans.h
@@ -29,8 +29,12 @@
#include <map>
+#include "llpointer.h"
#include "llstring.h"
-#include "llxmlnode.h"
+
+class LLXMLNode;
+
+class LLSD;
/**
* @brief String template loaded from strings.xml
@@ -61,9 +65,9 @@ public:
* @param default_args Set of strings (expected to be in the file) to use as default replacement args, e.g. "SECOND_LIFE"
* @returns true if the file was parsed successfully, true if something went wrong
*/
- static bool parseStrings(LLXMLNodePtr& root, const std::set<std::string>& default_args);
+ static bool parseStrings(LLPointer<LLXMLNode> & root, const std::set<std::string>& default_args);
- static bool parseLanguageStrings(LLXMLNodePtr &root);
+ static bool parseLanguageStrings(LLPointer<LLXMLNode> & root);
/**
* @brief Returns a translated string
@@ -72,7 +76,9 @@ public:
* @returns Translated string
*/
static std::string getString(const std::string &xml_desc, const LLStringUtil::format_map_t& args);
+ static std::string getString(const std::string &xml_desc, const LLSD& args);
static bool findString(std::string &result, const std::string &xml_desc, const LLStringUtil::format_map_t& args);
+ static bool findString(std::string &result, const std::string &xml_desc, const LLSD& args);
// Returns translated string with [COUNT] replaced with a number, following
// special per-language logic for plural nouns. For example, some languages
@@ -110,6 +116,8 @@ public:
return sDefaultArgs;
}
+ static void setDefaultArg(const std::string& name, const std::string& value);
+
// insert default args into an arg list
static void getArgs(LLStringUtil::format_map_t& args)
{
diff --git a/indra/llxuixml/llxuiparser.cpp b/indra/llxuixml/llxuiparser.cpp
index 9942af6b37..72a7bb7af5 100644
--- a/indra/llxuixml/llxuiparser.cpp
+++ b/indra/llxuixml/llxuiparser.cpp
@@ -388,6 +388,7 @@ LLXUIParser::LLXUIParser()
{
if (sXUIReadFuncs.empty())
{
+ registerParserFuncs<LLInitParam::NoParamValue>(readNoValue, writeNoValue);
registerParserFuncs<bool>(readBoolValue, writeBoolValue);
registerParserFuncs<std::string>(readStringValue, writeStringValue);
registerParserFuncs<U8>(readU8Value, writeU8Value);
@@ -406,6 +407,7 @@ LLXUIParser::LLXUIParser()
}
static LLFastTimer::DeclareTimer FTM_PARSE_XUI("XUI Parsing");
+const LLXMLNodePtr DUMMY_NODE = new LLXMLNode();
void LLXUIParser::readXUI(LLXMLNodePtr node, LLInitParam::BaseBlock& block, const std::string& filename, bool silent)
{
@@ -432,6 +434,17 @@ bool LLXUIParser::readXUIImpl(LLXMLNodePtr nodep, LLInitParam::BaseBlock& block)
boost::char_separator<char> sep(".");
bool values_parsed = false;
+ bool silent = mCurReadDepth > 0;
+
+ if (nodep->getFirstChild().isNull()
+ && nodep->mAttributes.empty()
+ && nodep->getSanitizedValue().empty())
+ {
+ // empty node, just parse as NoValue
+ mCurReadNode = DUMMY_NODE;
+ return block.submitValue(mNameStack, *this, silent);
+ }
+
// submit attributes for current node
values_parsed |= readAttributes(nodep, block);
@@ -444,7 +457,6 @@ bool LLXUIParser::readXUIImpl(LLXMLNodePtr nodep, LLInitParam::BaseBlock& block)
mNameStack.push_back(std::make_pair(std::string("value"), newParseGeneration()));
// child nodes are not necessarily valid parameters (could be a child widget)
// so don't complain once we've recursed
- bool silent = mCurReadDepth > 0;
if (!block.submitValue(mNameStack, *this, true))
{
mNameStack.pop_back();
@@ -549,6 +561,7 @@ bool LLXUIParser::readAttributes(LLXMLNodePtr nodep, LLInitParam::BaseBlock& blo
boost::char_separator<char> sep(".");
bool any_parsed = false;
+ bool silent = mCurReadDepth > 0;
for(LLXMLAttribList::const_iterator attribute_it = nodep->mAttributes.begin();
attribute_it != nodep->mAttributes.end();
@@ -567,7 +580,6 @@ bool LLXUIParser::readAttributes(LLXMLNodePtr nodep, LLInitParam::BaseBlock& blo
}
// child nodes are not necessarily valid attributes, so don't complain once we've recursed
- bool silent = mCurReadDepth > 0;
any_parsed |= block.submitValue(mNameStack, *this, silent);
while(num_tokens_pushed-- > 0)
@@ -634,6 +646,19 @@ LLXMLNodePtr LLXUIParser::getNode(const name_stack_t& stack)
return (out_node == mWriteRootNode ? LLXMLNodePtr(NULL) : out_node);
}
+bool LLXUIParser::readNoValue(Parser& parser, void* val_ptr)
+{
+ LLXUIParser& self = static_cast<LLXUIParser&>(parser);
+ return self.mCurReadNode == DUMMY_NODE;
+}
+
+bool LLXUIParser::writeNoValue(Parser& parser, const void* val_ptr, const name_stack_t& stack)
+{
+ // just create node
+ LLXUIParser& self = static_cast<LLXUIParser&>(parser);
+ LLXMLNodePtr node = self.getNode(stack);
+ return node.notNull();
+}
bool LLXUIParser::readBoolValue(Parser& parser, void* val_ptr)
{
@@ -1049,6 +1074,8 @@ static LLInitParam::Parser::parser_read_func_map_t sSimpleXUIReadFuncs;
static LLInitParam::Parser::parser_write_func_map_t sSimpleXUIWriteFuncs;
static LLInitParam::Parser::parser_inspect_func_map_t sSimpleXUIInspectFuncs;
+const char* NO_VALUE_MARKER = "no_value";
+
LLSimpleXUIParser::LLSimpleXUIParser(LLSimpleXUIParser::element_start_callback_t element_cb)
: Parser(sSimpleXUIReadFuncs, sSimpleXUIWriteFuncs, sSimpleXUIInspectFuncs),
mLastWriteGeneration(-1),
@@ -1057,6 +1084,7 @@ LLSimpleXUIParser::LLSimpleXUIParser(LLSimpleXUIParser::element_start_callback_t
{
if (sSimpleXUIReadFuncs.empty())
{
+ registerParserFuncs<LLInitParam::NoParamValue>(readNoValue);
registerParserFuncs<bool>(readBoolValue);
registerParserFuncs<std::string>(readStringValue);
registerParserFuncs<U8>(readU8Value);
@@ -1120,6 +1148,8 @@ bool LLSimpleXUIParser::readXUI(const std::string& filename, LLInitParam::BaseBl
return false;
}
+ mEmptyLeafNode.push_back(false);
+
if( !XML_ParseBuffer(mParser, bytes_read, TRUE ) )
{
LL_WARNS("ReadXUI") << "Error while parsing file " << filename << LL_ENDL;
@@ -1127,6 +1157,8 @@ bool LLSimpleXUIParser::readXUI(const std::string& filename, LLInitParam::BaseBl
return false;
}
+ mEmptyLeafNode.pop_back();
+
XML_ParserFree( mParser );
return true;
}
@@ -1211,8 +1243,14 @@ void LLSimpleXUIParser::startElement(const char *name, const char **atts)
}
}
+ // parent node is not empty
+ mEmptyLeafNode.back() = false;
+ // we are empty if we have no attributes
+ mEmptyLeafNode.push_back(atts[0] == NULL);
+
mTokenSizeStack.push_back(num_tokens_pushed);
readAttributes(atts);
+
}
bool LLSimpleXUIParser::readAttributes(const char **atts)
@@ -1246,7 +1284,7 @@ bool LLSimpleXUIParser::readAttributes(const char **atts)
return any_parsed;
}
-void LLSimpleXUIParser::processText()
+bool LLSimpleXUIParser::processText()
{
if (!mTextContents.empty())
{
@@ -1259,12 +1297,22 @@ void LLSimpleXUIParser::processText()
mNameStack.pop_back();
}
mTextContents.clear();
+ return true;
}
+ return false;
}
void LLSimpleXUIParser::endElement(const char *name)
{
- processText();
+ bool has_text = processText();
+
+ // no text, attributes, or children
+ if (!has_text && mEmptyLeafNode.back())
+ {
+ // submit this as a valueless name (even though there might be text contents we haven't seen yet)
+ mCurAttributeValueBegin = NO_VALUE_MARKER;
+ mOutputStack.back().first->submitValue(mNameStack, *this, mParseSilently);
+ }
if (--mOutputStack.back().second == 0)
{
@@ -1282,6 +1330,7 @@ void LLSimpleXUIParser::endElement(const char *name)
mNameStack.pop_back();
}
mScope.pop_back();
+ mEmptyLeafNode.pop_back();
}
void LLSimpleXUIParser::characterData(const char *s, int len)
@@ -1328,6 +1377,12 @@ void LLSimpleXUIParser::parserError(const std::string& message)
#endif
}
+bool LLSimpleXUIParser::readNoValue(Parser& parser, void* val_ptr)
+{
+ LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser);
+ return self.mCurAttributeValueBegin == NO_VALUE_MARKER;
+}
+
bool LLSimpleXUIParser::readBoolValue(Parser& parser, void* val_ptr)
{
LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser);
diff --git a/indra/llxuixml/llxuiparser.h b/indra/llxuixml/llxuiparser.h
index 5c613b0c69..0c38c4da93 100644
--- a/indra/llxuixml/llxuiparser.h
+++ b/indra/llxuixml/llxuiparser.h
@@ -28,7 +28,6 @@
#define LLXUIPARSER_H
#include "llinitparam.h"
-#include "llfasttimer.h"
#include "llregistry.h"
#include "llpointer.h"
@@ -95,6 +94,7 @@ public:
};
+class LLXUIParserImpl;
class LLXUIParser : public LLInitParam::Parser
{
@@ -116,6 +116,7 @@ private:
bool readAttributes(LLXMLNodePtr nodep, LLInitParam::BaseBlock& block);
//reader helper functions
+ static bool readNoValue(Parser& parser, void* val_ptr);
static bool readBoolValue(Parser& parser, void* val_ptr);
static bool readStringValue(Parser& parser, void* val_ptr);
static bool readU8Value(Parser& parser, void* val_ptr);
@@ -132,6 +133,7 @@ private:
static bool readSDValue(Parser& parser, void* val_ptr);
//writer helper functions
+ static bool writeNoValue(Parser& parser, const void* val_ptr, const name_stack_t&);
static bool writeBoolValue(Parser& parser, const void* val_ptr, const name_stack_t&);
static bool writeStringValue(Parser& parser, const void* val_ptr, const name_stack_t&);
static bool writeU8Value(Parser& parser, const void* val_ptr, const name_stack_t&);
@@ -174,6 +176,7 @@ private:
// ordering of child elements from base file to localized diff file. Then we can use a pair
// of coroutines to perform matching of xml nodes during parsing. Not sure if the overhead
// of coroutines would offset the gain from SAX parsing
+class LLSimpleXUIParserImpl;
class LLSimpleXUIParser : public LLInitParam::Parser
{
@@ -194,6 +197,7 @@ public:
private:
//reader helper functions
+ static bool readNoValue(Parser&, void* val_ptr);
static bool readBoolValue(Parser&, void* val_ptr);
static bool readStringValue(Parser&, void* val_ptr);
static bool readU8Value(Parser&, void* val_ptr);
@@ -218,7 +222,7 @@ private:
void endElement(const char *name);
void characterData(const char *s, int len);
bool readAttributes(const char **atts);
- void processText();
+ bool processText();
Parser::name_stack_t mNameStack;
struct XML_ParserStruct* mParser;
@@ -230,6 +234,7 @@ private:
const char* mCurAttributeValueBegin;
std::vector<S32> mTokenSizeStack;
std::vector<std::string> mScope;
+ std::vector<bool> mEmptyLeafNode;
element_start_callback_t mElementCB;
std::vector<std::pair<LLInitParam::BaseBlock*, S32> > mOutputStack;
diff --git a/indra/lscript/lscript_compile/indra.l b/indra/lscript/lscript_compile/indra.l
index 8fe9f5ed29..188c9e1950 100644
--- a/indra/lscript/lscript_compile/indra.l
+++ b/indra/lscript/lscript_compile/indra.l
@@ -8,8 +8,11 @@ FS (f|F)
%n 4000
%p 5000
+%top {
+ #include "linden_common.h"
+}
+
%{
-#include "linden_common.h"
// Deal with the fact that lex/yacc generates unreachable code
#ifdef LL_WINDOWS
#pragma warning (disable : 4018) // warning C4018: signed/unsigned mismatch
diff --git a/indra/mac_updater/CMakeLists.txt b/indra/mac_updater/CMakeLists.txt
index 44f98e5e18..00dcedecaa 100644
--- a/indra/mac_updater/CMakeLists.txt
+++ b/indra/mac_updater/CMakeLists.txt
@@ -3,7 +3,9 @@
project(mac_updater)
include(00-Common)
+include(OpenSSL)
include(CURL)
+include(CARes)
include(LLCommon)
include(LLVFS)
include(Linking)
@@ -11,6 +13,8 @@ include(Linking)
include_directories(
${LLCOMMON_INCLUDE_DIRS}
${LLVFS_INCLUDE_DIRS}
+ ${CURL_INCLUDE_DIRS}
+ ${CARES_INCLUDE_DIRS}
)
set(mac_updater_SOURCE_FILES
@@ -49,7 +53,10 @@ set_target_properties(mac-updater
target_link_libraries(mac-updater
${LLVFS_LIBRARIES}
+ ${OPENSSL_LIBRARIES}
+ ${CRYPTO_LIBRARIES}
${CURL_LIBRARIES}
+ ${CARES_LIBRARIES}
${LLCOMMON_LIBRARIES}
)
diff --git a/indra/mac_updater/mac_updater.cpp b/indra/mac_updater/mac_updater.cpp
index e4d100d1ec..809f66cb1d 100644
--- a/indra/mac_updater/mac_updater.cpp
+++ b/indra/mac_updater/mac_updater.cpp
@@ -26,6 +26,9 @@
#include "linden_common.h"
+#include <boost/format.hpp>
+
+#include <libgen.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
@@ -61,6 +64,9 @@ Boolean gCancelled = false;
const char *gUpdateURL;
const char *gProductName;
+const char *gBundleID;
+const char *gDmgFile;
+const char *gMarkerPath;
void *updatethreadproc(void*);
@@ -329,6 +335,18 @@ int parse_args(int argc, char **argv)
{
gProductName = argv[j];
}
+ else if ((!strcmp(argv[j], "-bundleid")) && (++j < argc))
+ {
+ gBundleID = argv[j];
+ }
+ else if ((!strcmp(argv[j], "-dmg")) && (++j < argc))
+ {
+ gDmgFile = argv[j];
+ }
+ else if ((!strcmp(argv[j], "-marker")) && (++j < argc))
+ {
+ gMarkerPath = argv[j];;
+ }
}
return 0;
@@ -355,10 +373,13 @@ int main(int argc, char **argv)
//
gUpdateURL = NULL;
gProductName = NULL;
+ gBundleID = NULL;
+ gDmgFile = NULL;
+ gMarkerPath = NULL;
parse_args(argc, argv);
- if (!gUpdateURL)
+ if ((gUpdateURL == NULL) && (gDmgFile == NULL))
{
- llinfos << "Usage: mac_updater -url <url> [-name <product_name>] [-program <program_name>]" << llendl;
+ llinfos << "Usage: mac_updater -url <url> | -dmg <dmg file> [-name <product_name>] [-program <program_name>]" << llendl;
exit(1);
}
else
@@ -372,6 +393,14 @@ int main(int argc, char **argv)
{
gProductName = "Second Life";
}
+ if (gBundleID)
+ {
+ llinfos << "Bundle ID is: " << gBundleID << llendl;
+ }
+ else
+ {
+ gBundleID = "com.secondlife.indra.viewer";
+ }
}
llinfos << "Starting " << gProductName << " Updater" << llendl;
@@ -474,11 +503,18 @@ int main(int argc, char **argv)
NULL,
&retval_mac);
}
-
+
+ if(gMarkerPath != 0)
+ {
+ // Create a install fail marker that can be used by the viewer to
+ // detect install problems.
+ std::ofstream stream(gMarkerPath);
+ if(stream) stream << -1;
+ }
+ exit(-1);
+ } else {
+ exit(0);
}
-
- // Don't dispose of things, just exit. This keeps the update thread from potentially getting hosed.
- exit(0);
if(gWindow != NULL)
{
@@ -592,7 +628,8 @@ static bool isFSRefViewerBundle(FSRef *targetRef)
CFURLRef targetURL = NULL;
CFBundleRef targetBundle = NULL;
CFStringRef targetBundleID = NULL;
-
+ CFStringRef sourceBundleID = NULL;
+
targetURL = CFURLCreateFromFSRef(NULL, targetRef);
if(targetURL == NULL)
@@ -619,7 +656,8 @@ static bool isFSRefViewerBundle(FSRef *targetRef)
}
else
{
- if(CFStringCompare(targetBundleID, CFSTR("com.secondlife.indra.viewer"), 0) == kCFCompareEqualTo)
+ sourceBundleID = CFStringCreateWithCString(NULL, gBundleID, kCFStringEncodingUTF8);
+ if(CFStringCompare(sourceBundleID, targetBundleID, 0) == kCFCompareEqualTo)
{
// This is the bundle we're looking for.
result = true;
@@ -684,17 +722,26 @@ static OSErr findAppBundleOnDiskImage(FSRef *parent, FSRef *app)
// Looks promising. Check to see if it has the right bundle identifier.
if(isFSRefViewerBundle(&ref))
{
+ llinfos << name << " is the one" << llendl;
// This is the one. Return it.
*app = ref;
found = true;
+ break;
+ } else {
+ llinfos << name << " is not the bundle we are looking for; move along" << llendl;
}
+
}
}
}
}
- while(!err && !found);
+ while(!err);
+
+ llinfos << "closing the iterator" << llendl;
FSCloseIterator(iterator);
+
+ llinfos << "closed" << llendl;
}
if(!err && !found)
@@ -905,6 +952,22 @@ void *updatethreadproc(void*)
#endif // 0 *HACK for DEV-11935
+ // Skip downloading the file if the dmg was passed on the command line.
+ std::string dmgName;
+ if(gDmgFile != NULL) {
+ dmgName = basename((char *)gDmgFile);
+ char * dmgDir = dirname((char *)gDmgFile);
+ strncpy(tempDir, dmgDir, sizeof(tempDir));
+ err = FSPathMakeRef((UInt8*)tempDir, &tempDirRef, NULL);
+ if(err != noErr) throw 0;
+ chdir(tempDir);
+ goto begin_install;
+ } else {
+ // Continue on to download file.
+ dmgName = "SecondLife.dmg";
+ }
+
+
strncat(temp, "/SecondLifeUpdate_XXXXXX", (sizeof(temp) - strlen(temp)) - 1);
if(mkdtemp(temp) == NULL)
{
@@ -963,14 +1026,17 @@ void *updatethreadproc(void*)
fclose(downloadFile);
downloadFile = NULL;
}
-
+
+ begin_install:
sendProgress(0, 0, CFSTR("Mounting image..."));
LLFile::mkdir("mnt", 0700);
// NOTE: we could add -private at the end of this command line to keep the image from showing up in the Finder,
// but if our cleanup fails, this makes it much harder for the user to unmount the image.
std::string mountOutput;
- FILE* mounter = popen("hdiutil attach SecondLife.dmg -mountpoint mnt", "r"); /* Flawfinder: ignore */
+ boost::format cmdFormat("hdiutil attach %s -mountpoint mnt");
+ cmdFormat % dmgName;
+ FILE* mounter = popen(cmdFormat.str().c_str(), "r"); /* Flawfinder: ignore */
if(mounter == NULL)
{
@@ -1036,12 +1102,19 @@ void *updatethreadproc(void*)
throw 0;
}
+ sendProgress(0, 0, CFSTR("Searching for the app bundle..."));
err = findAppBundleOnDiskImage(&mountRef, &sourceRef);
if(err != noErr)
{
llinfos << "Couldn't find application bundle on mounted disk image." << llendl;
throw 0;
}
+ else
+ {
+ llinfos << "found the bundle." << llendl;
+ }
+
+ sendProgress(0, 0, CFSTR("Preparing to copy files..."));
FSRef asideRef;
char aside[MAX_PATH]; /* Flawfinder: ignore */
@@ -1061,7 +1134,11 @@ void *updatethreadproc(void*)
// Move aside old version (into work directory)
err = FSMoveObject(&targetRef, &tempDirRef, &asideRef);
if(err != noErr)
+ {
+ llwarns << "failed to move aside old version (error code " <<
+ err << ")" << llendl;
throw 0;
+ }
// Grab the path for later use.
err = FSRefMakePath(&asideRef, (UInt8*)aside, sizeof(aside));
@@ -1153,16 +1230,14 @@ void *updatethreadproc(void*)
// Move work directory to the trash
if(tempDir[0] != 0)
{
-// chdir("/");
-// FSDeleteObjects(tempDirRef);
-
llinfos << "Moving work directory to the trash." << llendl;
- err = FSMoveObject(&tempDirRef, &trashFolderRef, NULL);
-
-// snprintf(temp, sizeof(temp), "rm -rf '%s'", tempDir);
-// printf("%s\n", temp);
-// system(temp);
+ FSRef trashRef;
+ OSStatus err = FSMoveObjectToTrashSync(&tempDirRef, &trashRef, 0);
+ if(err != noErr) {
+ llwarns << "failed to move files to trash, (error code " <<
+ err << ")" << llendl;
+ }
}
if(!gCancelled && !gFailure && (target[0] != 0))
diff --git a/indra/media_plugins/example/media_plugin_example.cpp b/indra/media_plugins/example/media_plugin_example.cpp
index f8a871930e..da7de01799 100644
--- a/indra/media_plugins/example/media_plugin_example.cpp
+++ b/indra/media_plugins/example/media_plugin_example.cpp
@@ -6,21 +6,21 @@
* $LicenseInfo:firstyear=2008&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$
* @endcond
@@ -39,48 +39,48 @@
////////////////////////////////////////////////////////////////////////////////
//
class MediaPluginExample :
- public MediaPluginBase
+ public MediaPluginBase
{
- public:
- MediaPluginExample( LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data );
- ~MediaPluginExample();
-
- /*virtual*/ void receiveMessage( const char* message_string );
-
- private:
- bool init();
- void update( F64 milliseconds );
- void write_pixel( int x, int y, unsigned char r, unsigned char g, unsigned char b );
- bool mFirstTime;
-
- time_t mLastUpdateTime;
- enum Constants { ENumObjects = 10 };
- unsigned char* mBackgroundPixels;
- int mColorR[ ENumObjects ];
- int mColorG[ ENumObjects ];
- int mColorB[ ENumObjects ];
- int mXpos[ ENumObjects ];
- int mYpos[ ENumObjects ];
- int mXInc[ ENumObjects ];
- int mYInc[ ENumObjects ];
- int mBlockSize[ ENumObjects ];
- bool mMouseButtonDown;
- bool mStopAction;
+ public:
+ MediaPluginExample( LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data );
+ ~MediaPluginExample();
+
+ /*virtual*/ void receiveMessage( const char* message_string );
+
+ private:
+ bool init();
+ void update( F64 milliseconds );
+ void write_pixel( int x, int y, unsigned char r, unsigned char g, unsigned char b );
+ bool mFirstTime;
+
+ time_t mLastUpdateTime;
+ enum Constants { ENumObjects = 10 };
+ unsigned char* mBackgroundPixels;
+ int mColorR[ ENumObjects ];
+ int mColorG[ ENumObjects ];
+ int mColorB[ ENumObjects ];
+ int mXpos[ ENumObjects ];
+ int mYpos[ ENumObjects ];
+ int mXInc[ ENumObjects ];
+ int mYInc[ ENumObjects ];
+ int mBlockSize[ ENumObjects ];
+ bool mMouseButtonDown;
+ bool mStopAction;
};
////////////////////////////////////////////////////////////////////////////////
//
MediaPluginExample::MediaPluginExample( LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data ) :
- MediaPluginBase( host_send_func, host_user_data )
+ MediaPluginBase( host_send_func, host_user_data )
{
- mFirstTime = true;
- mWidth = 0;
- mHeight = 0;
- mDepth = 4;
- mPixels = 0;
- mMouseButtonDown = false;
- mStopAction = false;
- mLastUpdateTime = 0;
+ mFirstTime = true;
+ mWidth = 0;
+ mHeight = 0;
+ mDepth = 4;
+ mPixels = 0;
+ mMouseButtonDown = false;
+ mStopAction = false;
+ mLastUpdateTime = 0;
}
////////////////////////////////////////////////////////////////////////////////
@@ -93,395 +93,320 @@ MediaPluginExample::~MediaPluginExample()
//
void MediaPluginExample::receiveMessage( const char* message_string )
{
- LLPluginMessage message_in;
-
- if ( message_in.parse( message_string ) >= 0 )
- {
- std::string message_class = message_in.getClass();
- std::string message_name = message_in.getName();
-
- if ( message_class == LLPLUGIN_MESSAGE_CLASS_BASE )
- {
- if ( message_name == "init" )
- {
- LLPluginMessage message( "base", "init_response" );
- LLSD versions = LLSD::emptyMap();
- versions[ LLPLUGIN_MESSAGE_CLASS_BASE ] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION;
- versions[ LLPLUGIN_MESSAGE_CLASS_MEDIA ] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION;
- versions[ LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER ] = LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER_VERSION;
- message.setValueLLSD( "versions", versions );
-
- std::string plugin_version = "Example media plugin, Example Version 1.0.0.0";
- message.setValue( "plugin_version", plugin_version );
- sendMessage( message );
- }
- else
- if ( message_name == "idle" )
- {
- // no response is necessary here.
- F64 time = message_in.getValueReal( "time" );
-
- // Convert time to milliseconds for update()
- update( time );
- }
- else
- if ( message_name == "cleanup" )
- {
- // clean up here
- }
- else
- if ( message_name == "shm_added" )
- {
- SharedSegmentInfo info;
- info.mAddress = message_in.getValuePointer( "address" );
- info.mSize = ( size_t )message_in.getValueS32( "size" );
- std::string name = message_in.getValue( "name" );
-
- mSharedSegments.insert( SharedSegmentMap::value_type( name, info ) );
-
- }
- else
- if ( message_name == "shm_remove" )
- {
- std::string name = message_in.getValue( "name" );
-
- SharedSegmentMap::iterator iter = mSharedSegments.find( name );
- if( iter != mSharedSegments.end() )
- {
- if ( mPixels == iter->second.mAddress )
- {
- // This is the currently active pixel buffer.
- // Make sure we stop drawing to it.
- mPixels = NULL;
- mTextureSegmentName.clear();
- };
- mSharedSegments.erase( iter );
- }
- else
- {
- //std::cerr << "MediaPluginExample::receiveMessage: unknown shared memory region!" << std::endl;
- };
-
- // Send the response so it can be cleaned up.
- LLPluginMessage message( "base", "shm_remove_response" );
- message.setValue( "name", name );
- sendMessage( message );
- }
- else
- {
- //std::cerr << "MediaPluginExample::receiveMessage: unknown base message: " << message_name << std::endl;
- };
- }
- else
- if ( message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA )
- {
- if ( message_name == "init" )
- {
- // Plugin gets to decide the texture parameters to use.
- LLPluginMessage message( LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params" );
- message.setValueS32( "default_width", mWidth );
- message.setValueS32( "default_height", mHeight );
- message.setValueS32( "depth", mDepth );
- message.setValueU32( "internalformat", GL_RGBA );
- message.setValueU32( "format", GL_RGBA );
- message.setValueU32( "type", GL_UNSIGNED_BYTE );
- message.setValueBoolean( "coords_opengl", false );
- sendMessage( message );
- }
- else if ( message_name == "size_change" )
- {
- std::string name = message_in.getValue( "name" );
- S32 width = message_in.getValueS32( "width" );
- S32 height = message_in.getValueS32( "height" );
- S32 texture_width = message_in.getValueS32( "texture_width" );
- S32 texture_height = message_in.getValueS32( "texture_height" );
-
- if ( ! name.empty() )
- {
- // Find the shared memory region with this name
- SharedSegmentMap::iterator iter = mSharedSegments.find( name );
- if ( iter != mSharedSegments.end() )
- {
- mPixels = ( unsigned char* )iter->second.mAddress;
- mWidth = width;
- mHeight = height;
-
- mTextureWidth = texture_width;
- mTextureHeight = texture_height;
-
- init();
- };
- };
-
- LLPluginMessage message( LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response" );
- message.setValue( "name", name );
- message.setValueS32( "width", width );
- message.setValueS32( "height", height );
- message.setValueS32( "texture_width", texture_width );
- message.setValueS32( "texture_height", texture_height );
- sendMessage( message );
- }
- else
- if ( message_name == "load_uri" )
- {
- std::string uri = message_in.getValue( "uri" );
- if ( ! uri.empty() )
- {
- };
- }
- else
- if ( message_name == "mouse_event" )
- {
- std::string event = message_in.getValue( "event" );
- S32 button = message_in.getValueS32( "button" );
-
- // left mouse button
- if ( button == 0 )
- {
- int mouse_x = message_in.getValueS32( "x" );
- int mouse_y = message_in.getValueS32( "y" );
- std::string modifiers = message_in.getValue( "modifiers" );
-
- if ( event == "move" )
- {
- if ( mMouseButtonDown )
- write_pixel( mouse_x, mouse_y, rand() % 0x80 + 0x80, rand() % 0x80 + 0x80, rand() % 0x80 + 0x80 );
- }
- else
- if ( event == "down" )
- {
- mMouseButtonDown = true;
- }
- else
- if ( event == "up" )
- {
- mMouseButtonDown = false;
- }
- else
- if ( event == "double_click" )
- {
- };
- };
- }
- else
- if ( message_name == "key_event" )
- {
- std::string event = message_in.getValue( "event" );
- S32 key = message_in.getValueS32( "key" );
- std::string modifiers = message_in.getValue( "modifiers" );
-
- if ( event == "down" )
- {
- if ( key == ' ')
- {
- mLastUpdateTime = 0;
- update( 0.0f );
- };
- };
- }
- else
- {
- //std::cerr << "MediaPluginExample::receiveMessage: unknown media message: " << message_string << std::endl;
- };
- }
- else
- if ( message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER )
- {
- if ( message_name == "browse_reload" )
- {
- mLastUpdateTime = 0;
- mFirstTime = true;
- mStopAction = false;
- update( 0.0f );
- }
- else
- if ( message_name == "browse_stop" )
- {
- for( int n = 0; n < ENumObjects; ++n )
- mXInc[ n ] = mYInc[ n ] = 0;
-
- mStopAction = true;
- update( 0.0f );
- }
- else
- {
- //std::cerr << "MediaPluginExample::receiveMessage: unknown media_browser message: " << message_string << std::endl;
- };
- }
- else
- {
- //std::cerr << "MediaPluginExample::receiveMessage: unknown message class: " << message_class << std::endl;
- };
- };
+// std::cerr << "MediaPluginWebKit::receiveMessage: received message: \"" << message_string << "\"" << std::endl;
+ LLPluginMessage message_in;
+
+ if(message_in.parse(message_string) >= 0)
+ {
+ std::string message_class = message_in.getClass();
+ std::string message_name = message_in.getName();
+ if(message_class == LLPLUGIN_MESSAGE_CLASS_BASE)
+ {
+ if(message_name == "init")
+ {
+ LLPluginMessage message("base", "init_response");
+ LLSD versions = LLSD::emptyMap();
+ versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION;
+ versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION;
+ versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER] = LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER_VERSION;
+ message.setValueLLSD("versions", versions);
+
+ std::string plugin_version = "Example plugin 1.0..0";
+ message.setValue("plugin_version", plugin_version);
+ sendMessage(message);
+ }
+ else if(message_name == "idle")
+ {
+ // no response is necessary here.
+ F64 time = message_in.getValueReal("time");
+
+ // Convert time to milliseconds for update()
+ update((int)(time * 1000.0f));
+ }
+ else if(message_name == "cleanup")
+ {
+ }
+ else if(message_name == "shm_added")
+ {
+ SharedSegmentInfo info;
+ info.mAddress = message_in.getValuePointer("address");
+ info.mSize = (size_t)message_in.getValueS32("size");
+ std::string name = message_in.getValue("name");
+
+ mSharedSegments.insert(SharedSegmentMap::value_type(name, info));
+
+ }
+ else if(message_name == "shm_remove")
+ {
+ std::string name = message_in.getValue("name");
+
+ SharedSegmentMap::iterator iter = mSharedSegments.find(name);
+ if(iter != mSharedSegments.end())
+ {
+ if(mPixels == iter->second.mAddress)
+ {
+ // This is the currently active pixel buffer. Make sure we stop drawing to it.
+ mPixels = NULL;
+ mTextureSegmentName.clear();
+ }
+ mSharedSegments.erase(iter);
+ }
+ else
+ {
+// std::cerr << "MediaPluginWebKit::receiveMessage: unknown shared memory region!" << std::endl;
+ }
+
+ // Send the response so it can be cleaned up.
+ LLPluginMessage message("base", "shm_remove_response");
+ message.setValue("name", name);
+ sendMessage(message);
+ }
+ else
+ {
+// std::cerr << "MediaPluginWebKit::receiveMessage: unknown base message: " << message_name << std::endl;
+ }
+ }
+ else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA)
+ {
+ if(message_name == "init")
+ {
+ // Plugin gets to decide the texture parameters to use.
+ mDepth = 4;
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params");
+ message.setValueS32("default_width", 1024);
+ message.setValueS32("default_height", 1024);
+ message.setValueS32("depth", mDepth);
+ message.setValueU32("internalformat", GL_RGBA);
+ message.setValueU32("format", GL_RGBA);
+ message.setValueU32("type", GL_UNSIGNED_BYTE);
+ message.setValueBoolean("coords_opengl", true);
+ sendMessage(message);
+ }
+ else if(message_name == "size_change")
+ {
+ std::string name = message_in.getValue("name");
+ S32 width = message_in.getValueS32("width");
+ S32 height = message_in.getValueS32("height");
+ S32 texture_width = message_in.getValueS32("texture_width");
+ S32 texture_height = message_in.getValueS32("texture_height");
+
+ if(!name.empty())
+ {
+ // Find the shared memory region with this name
+ SharedSegmentMap::iterator iter = mSharedSegments.find(name);
+ if(iter != mSharedSegments.end())
+ {
+ mPixels = (unsigned char*)iter->second.mAddress;
+ mWidth = width;
+ mHeight = height;
+
+ mTextureWidth = texture_width;
+ mTextureHeight = texture_height;
+ };
+ };
+
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response");
+ message.setValue("name", name);
+ message.setValueS32("width", width);
+ message.setValueS32("height", height);
+ message.setValueS32("texture_width", texture_width);
+ message.setValueS32("texture_height", texture_height);
+ sendMessage(message);
+
+ }
+ else if(message_name == "load_uri")
+ {
+ }
+ else if(message_name == "mouse_event")
+ {
+ std::string event = message_in.getValue("event");
+ if(event == "down")
+ {
+
+ }
+ else if(event == "up")
+ {
+ }
+ else if(event == "double_click")
+ {
+ }
+ }
+ }
+ else
+ {
+// std::cerr << "MediaPluginWebKit::receiveMessage: unknown message class: " << message_class << std::endl;
+ };
+ }
}
////////////////////////////////////////////////////////////////////////////////
//
void MediaPluginExample::write_pixel( int x, int y, unsigned char r, unsigned char g, unsigned char b )
{
- // make sure we don't write outside the buffer
- if ( ( x < 0 ) || ( x >= mWidth ) || ( y < 0 ) || ( y >= mHeight ) )
- return;
-
- if ( mBackgroundPixels != NULL )
- {
- unsigned char *pixel = mBackgroundPixels;
- pixel += y * mWidth * mDepth;
- pixel += ( x * mDepth );
- pixel[ 0 ] = b;
- pixel[ 1 ] = g;
- pixel[ 2 ] = r;
-
- setDirty( x, y, x + 1, y + 1 );
- };
+ // make sure we don't write outside the buffer
+ if ( ( x < 0 ) || ( x >= mWidth ) || ( y < 0 ) || ( y >= mHeight ) )
+ return;
+
+ if ( mBackgroundPixels != NULL )
+ {
+ unsigned char *pixel = mBackgroundPixels;
+ pixel += y * mWidth * mDepth;
+ pixel += ( x * mDepth );
+ pixel[ 0 ] = b;
+ pixel[ 1 ] = g;
+ pixel[ 2 ] = r;
+
+ setDirty( x, y, x + 1, y + 1 );
+ };
}
////////////////////////////////////////////////////////////////////////////////
//
void MediaPluginExample::update( F64 milliseconds )
{
- if ( mWidth < 1 || mWidth > 2048 || mHeight < 1 || mHeight > 2048 )
- return;
-
- if ( mPixels == 0 )
- return;
-
- if ( mFirstTime )
- {
- for( int n = 0; n < ENumObjects; ++n )
- {
- mXpos[ n ] = ( mWidth / 2 ) + rand() % ( mWidth / 16 ) - ( mWidth / 32 );
- mYpos[ n ] = ( mHeight / 2 ) + rand() % ( mHeight / 16 ) - ( mHeight / 32 );
-
- mColorR[ n ] = rand() % 0x60 + 0x60;
- mColorG[ n ] = rand() % 0x60 + 0x60;
- mColorB[ n ] = rand() % 0x60 + 0x60;
-
- mXInc[ n ] = 0;
- while ( mXInc[ n ] == 0 )
- mXInc[ n ] = rand() % 7 - 3;
-
- mYInc[ n ] = 0;
- while ( mYInc[ n ] == 0 )
- mYInc[ n ] = rand() % 9 - 4;
-
- mBlockSize[ n ] = rand() % 0x30 + 0x10;
- };
-
- delete [] mBackgroundPixels;
-
- mBackgroundPixels = new unsigned char[ mWidth * mHeight * mDepth ];
-
- mFirstTime = false;
- };
-
- if ( mStopAction )
- return;
-
- if ( time( NULL ) > mLastUpdateTime + 3 )
- {
- const int num_squares = rand() % 20 + 4;
- int sqr1_r = rand() % 0x80 + 0x20;
- int sqr1_g = rand() % 0x80 + 0x20;
- int sqr1_b = rand() % 0x80 + 0x20;
- int sqr2_r = rand() % 0x80 + 0x20;
- int sqr2_g = rand() % 0x80 + 0x20;
- int sqr2_b = rand() % 0x80 + 0x20;
-
- for ( int y1 = 0; y1 < num_squares; ++y1 )
- {
- for ( int x1 = 0; x1 < num_squares; ++x1 )
- {
- int px_start = mWidth * x1 / num_squares;
- int px_end = ( mWidth * ( x1 + 1 ) ) / num_squares;
- int py_start = mHeight * y1 / num_squares;
- int py_end = ( mHeight * ( y1 + 1 ) ) / num_squares;
-
- for( int y2 = py_start; y2 < py_end; ++y2 )
- {
- for( int x2 = px_start; x2 < px_end; ++x2 )
- {
- int rowspan = mWidth * mDepth;
-
- if ( ( y1 % 2 ) ^ ( x1 % 2 ) )
- {
- mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 0 ] = sqr1_r;
- mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 1 ] = sqr1_g;
- mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 2 ] = sqr1_b;
- }
- else
- {
- mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 0 ] = sqr2_r;
- mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 1 ] = sqr2_g;
- mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 2 ] = sqr2_b;
- };
- };
- };
- };
- };
-
- time( &mLastUpdateTime );
- };
-
- memcpy( mPixels, mBackgroundPixels, mWidth * mHeight * mDepth );
-
- for( int n = 0; n < ENumObjects; ++n )
- {
- if ( rand() % 50 == 0 )
- {
- mXInc[ n ] = 0;
- while ( mXInc[ n ] == 0 )
- mXInc[ n ] = rand() % 7 - 3;
-
- mYInc[ n ] = 0;
- while ( mYInc[ n ] == 0 )
- mYInc[ n ] = rand() % 9 - 4;
- };
-
- if ( mXpos[ n ] + mXInc[ n ] < 0 || mXpos[ n ] + mXInc[ n ] >= mWidth - mBlockSize[ n ] )
- mXInc[ n ] =- mXInc[ n ];
-
- if ( mYpos[ n ] + mYInc[ n ] < 0 || mYpos[ n ] + mYInc[ n ] >= mHeight - mBlockSize[ n ] )
- mYInc[ n ] =- mYInc[ n ];
-
- mXpos[ n ] += mXInc[ n ];
- mYpos[ n ] += mYInc[ n ];
-
- for( int y = 0; y < mBlockSize[ n ]; ++y )
- {
- for( int x = 0; x < mBlockSize[ n ]; ++x )
- {
- mPixels[ ( mXpos[ n ] + x ) * mDepth + ( mYpos[ n ] + y ) * mDepth * mWidth + 0 ] = mColorR[ n ];
- mPixels[ ( mXpos[ n ] + x ) * mDepth + ( mYpos[ n ] + y ) * mDepth * mWidth + 1 ] = mColorG[ n ];
- mPixels[ ( mXpos[ n ] + x ) * mDepth + ( mYpos[ n ] + y ) * mDepth * mWidth + 2 ] = mColorB[ n ];
- };
- };
- };
-
- setDirty( 0, 0, mWidth, mHeight );
+ if ( mWidth < 1 || mWidth > 2048 || mHeight < 1 || mHeight > 2048 )
+ return;
+
+ if ( mPixels == 0 )
+ return;
+
+ if ( mFirstTime )
+ {
+ for( int n = 0; n < ENumObjects; ++n )
+ {
+ mXpos[ n ] = ( mWidth / 2 ) + rand() % ( mWidth / 16 ) - ( mWidth / 32 );
+ mYpos[ n ] = ( mHeight / 2 ) + rand() % ( mHeight / 16 ) - ( mHeight / 32 );
+
+ mColorR[ n ] = rand() % 0x60 + 0x60;
+ mColorG[ n ] = rand() % 0x60 + 0x60;
+ mColorB[ n ] = rand() % 0x60 + 0x60;
+
+ mXInc[ n ] = 0;
+ while ( mXInc[ n ] == 0 )
+ mXInc[ n ] = rand() % 7 - 3;
+
+ mYInc[ n ] = 0;
+ while ( mYInc[ n ] == 0 )
+ mYInc[ n ] = rand() % 9 - 4;
+
+ mBlockSize[ n ] = rand() % 0x30 + 0x10;
+ };
+
+ delete [] mBackgroundPixels;
+
+ mBackgroundPixels = new unsigned char[ mWidth * mHeight * mDepth ];
+
+ mFirstTime = false;
+ };
+
+ if ( mStopAction )
+ return;
+
+ if ( time( NULL ) > mLastUpdateTime + 3 )
+ {
+ const int num_squares = rand() % 20 + 4;
+ int sqr1_r = rand() % 0x80 + 0x20;
+ int sqr1_g = rand() % 0x80 + 0x20;
+ int sqr1_b = rand() % 0x80 + 0x20;
+ int sqr2_r = rand() % 0x80 + 0x20;
+ int sqr2_g = rand() % 0x80 + 0x20;
+ int sqr2_b = rand() % 0x80 + 0x20;
+
+ for ( int y1 = 0; y1 < num_squares; ++y1 )
+ {
+ for ( int x1 = 0; x1 < num_squares; ++x1 )
+ {
+ int px_start = mWidth * x1 / num_squares;
+ int px_end = ( mWidth * ( x1 + 1 ) ) / num_squares;
+ int py_start = mHeight * y1 / num_squares;
+ int py_end = ( mHeight * ( y1 + 1 ) ) / num_squares;
+
+ for( int y2 = py_start; y2 < py_end; ++y2 )
+ {
+ for( int x2 = px_start; x2 < px_end; ++x2 )
+ {
+ int rowspan = mWidth * mDepth;
+
+ if ( ( y1 % 2 ) ^ ( x1 % 2 ) )
+ {
+ mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 0 ] = sqr1_r;
+ mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 1 ] = sqr1_g;
+ mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 2 ] = sqr1_b;
+ }
+ else
+ {
+ mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 0 ] = sqr2_r;
+ mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 1 ] = sqr2_g;
+ mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 2 ] = sqr2_b;
+ };
+ };
+ };
+ };
+ };
+
+ time( &mLastUpdateTime );
+ };
+
+ memcpy( mPixels, mBackgroundPixels, mWidth * mHeight * mDepth );
+
+ for( int n = 0; n < ENumObjects; ++n )
+ {
+ if ( rand() % 50 == 0 )
+ {
+ mXInc[ n ] = 0;
+ while ( mXInc[ n ] == 0 )
+ mXInc[ n ] = rand() % 7 - 3;
+
+ mYInc[ n ] = 0;
+ while ( mYInc[ n ] == 0 )
+ mYInc[ n ] = rand() % 9 - 4;
+ };
+
+ if ( mXpos[ n ] + mXInc[ n ] < 0 || mXpos[ n ] + mXInc[ n ] >= mWidth - mBlockSize[ n ] )
+ mXInc[ n ] =- mXInc[ n ];
+
+ if ( mYpos[ n ] + mYInc[ n ] < 0 || mYpos[ n ] + mYInc[ n ] >= mHeight - mBlockSize[ n ] )
+ mYInc[ n ] =- mYInc[ n ];
+
+ mXpos[ n ] += mXInc[ n ];
+ mYpos[ n ] += mYInc[ n ];
+
+ for( int y = 0; y < mBlockSize[ n ]; ++y )
+ {
+ for( int x = 0; x < mBlockSize[ n ]; ++x )
+ {
+ mPixels[ ( mXpos[ n ] + x ) * mDepth + ( mYpos[ n ] + y ) * mDepth * mWidth + 0 ] = mColorR[ n ];
+ mPixels[ ( mXpos[ n ] + x ) * mDepth + ( mYpos[ n ] + y ) * mDepth * mWidth + 1 ] = mColorG[ n ];
+ mPixels[ ( mXpos[ n ] + x ) * mDepth + ( mYpos[ n ] + y ) * mDepth * mWidth + 2 ] = mColorB[ n ];
+ };
+ };
+ };
+
+ setDirty( 0, 0, mWidth, mHeight );
};
////////////////////////////////////////////////////////////////////////////////
//
bool MediaPluginExample::init()
{
- LLPluginMessage message( LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text" );
- message.setValue( "name", "Example Plugin" );
- sendMessage( message );
+ LLPluginMessage message( LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text" );
+ message.setValue( "name", "Example Plugin" );
+ sendMessage( message );
- return true;
+ return true;
};
////////////////////////////////////////////////////////////////////////////////
//
int init_media_plugin( LLPluginInstance::sendMessageFunction host_send_func,
- void* host_user_data,
- LLPluginInstance::sendMessageFunction *plugin_send_func,
- void **plugin_user_data )
+ void* host_user_data,
+ LLPluginInstance::sendMessageFunction *plugin_send_func,
+ void **plugin_user_data )
{
- MediaPluginExample* self = new MediaPluginExample( host_send_func, host_user_data );
- *plugin_send_func = MediaPluginExample::staticReceiveMessage;
- *plugin_user_data = ( void* )self;
+ MediaPluginExample* self = new MediaPluginExample( host_send_func, host_user_data );
+ *plugin_send_func = MediaPluginExample::staticReceiveMessage;
+ *plugin_user_data = ( void* )self;
- return 0;
+ return 0;
}
+
diff --git a/indra/media_plugins/webkit/CMakeLists.txt b/indra/media_plugins/webkit/CMakeLists.txt
index 05f1236606..b36291f0e8 100644
--- a/indra/media_plugins/webkit/CMakeLists.txt
+++ b/indra/media_plugins/webkit/CMakeLists.txt
@@ -27,6 +27,7 @@ include_directories(
${LLIMAGE_INCLUDE_DIRS}
${LLRENDER_INCLUDE_DIRS}
${LLWINDOW_INCLUDE_DIRS}
+ ${LLQTWEBKIT_INCLUDE_DIR}
)
@@ -120,8 +121,8 @@ if (DARWIN)
add_custom_command(
TARGET media_plugin_webkit POST_BUILD
# OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/libllqtwebkit.dylib
- COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/../libraries/universal-darwin/lib_release/libllqtwebkit.dylib ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/
- DEPENDS media_plugin_webkit ${CMAKE_SOURCE_DIR}/../libraries/universal-darwin/lib_release/libllqtwebkit.dylib
+ COMMAND ${CMAKE_COMMAND} -E copy ${ARCH_PREBUILT_DIRS_RELEASE}/libllqtwebkit.dylib ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/
+ DEPENDS media_plugin_webkit ${ARCH_PREBUILT_DIRS_RELEASE}/libllqtwebkit.dylib
)
endif (DARWIN)
diff --git a/indra/media_plugins/webkit/media_plugin_webkit.cpp b/indra/media_plugins/webkit/media_plugin_webkit.cpp
index bd1a44a930..9ba8edbb59 100644
--- a/indra/media_plugins/webkit/media_plugin_webkit.cpp
+++ b/indra/media_plugins/webkit/media_plugin_webkit.cpp
@@ -341,7 +341,7 @@ private:
url << std::setfill('0') << std::setw(2) << std::hex << int(mBackgroundB * 255.0f);
url << "%22%3E%3C/body%3E%3C/html%3E";
- lldebugs << "data url is: " << url.str() << llendl;
+ //lldebugs << "data url is: " << url.str() << llendl;
LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, url.str() );
// LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, "about:blank" );
@@ -407,6 +407,8 @@ private:
{
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_begin");
message.setValue("uri", event.getEventUri());
+ message.setValueBoolean("history_back_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_BACK));
+ message.setValueBoolean("history_forward_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_FORWARD));
sendMessage(message);
setStatus(STATUS_LOADING);
@@ -490,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)
@@ -517,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);
}
@@ -569,6 +585,57 @@ private:
return blockingPickFile();
}
+ std::string mAuthUsername;
+ std::string mAuthPassword;
+ bool mAuthOK;
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // virtual
+ bool onAuthRequest(const std::string &in_url, const std::string &in_realm, std::string &out_username, std::string &out_password)
+ {
+ mAuthOK = false;
+
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "auth_request");
+ message.setValue("url", in_url);
+ message.setValue("realm", in_realm);
+ message.setValueBoolean("blocking_request", true);
+
+ // The "blocking_request" key in the message means this sendMessage call will block until a response is received.
+ sendMessage(message);
+
+ if(mAuthOK)
+ {
+ out_username = mAuthUsername;
+ out_password = mAuthPassword;
+ }
+
+ return mAuthOK;
+ }
+
+ void authResponse(LLPluginMessage &message)
+ {
+ mAuthOK = message.getValueBoolean("ok");
+ if(mAuthOK)
+ {
+ mAuthUsername = message.getValue("username");
+ mAuthPassword = message.getValue("password");
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // virtual
+ void onLinkHovered(const EventType& event)
+ {
+ if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
+ {
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "link_hovered");
+ message.setValue("link", event.getEventUri());
+ message.setValue("title", event.getStringValue());
+ message.setValue("text", event.getStringValue2());
+ sendMessage(message);
+ }
+ }
+
LLQtWebKit::EKeyboardModifier decodeModifiers(std::string &modifiers)
{
int result = 0;
@@ -1096,6 +1163,10 @@ void MediaPluginWebKit::receiveMessage(const char *message_string)
{
onPickFileResponse(message_in.getValue("file"));
}
+ if(message_name == "auth_response")
+ {
+ authResponse(message_in);
+ }
else
{
// std::cerr << "MediaPluginWebKit::receiveMessage: unknown media message: " << message_string << std::endl;
@@ -1174,7 +1245,9 @@ void MediaPluginWebKit::receiveMessage(const char *message_string)
std::string url = message_in.getValue("url");
if ( 404 == code ) // browser lib only supports 404 right now
{
- LLQtWebKit::getInstance()->set404RedirectUrl( mBrowserWindowId, url );
+#if LLQTWEBKIT_API_VERSION < 8
+ LLQtWebKit::getInstance()->set404RedirectUrl( mBrowserWindowId, url );
+#endif
};
}
else if(message_name == "set_user_agent")
@@ -1182,6 +1255,22 @@ void MediaPluginWebKit::receiveMessage(const char *message_string)
mUserAgent = message_in.getValue("user_agent");
LLQtWebKit::getInstance()->setBrowserAgentId( mUserAgent );
}
+ else if(message_name == "ignore_ssl_cert_errors")
+ {
+#if LLQTWEBKIT_API_VERSION >= 3
+ LLQtWebKit::getInstance()->setIgnoreSSLCertErrors( message_in.getValueBoolean("ignore") );
+#else
+ llwarns << "Ignoring ignore_ssl_cert_errors message (llqtwebkit version is too old)." << llendl;
+#endif
+ }
+ else if(message_name == "add_certificate_file_path")
+ {
+#if LLQTWEBKIT_API_VERSION >= 6
+ LLQtWebKit::getInstance()->addCAFile( message_in.getValue("path") );
+#else
+ llwarns << "Ignoring add_certificate_file_path message (llqtwebkit version is too old)." << llendl;
+#endif
+ }
else if(message_name == "init_history")
{
// Initialize browser history
diff --git a/indra/media_plugins/winmmshim/CMakeLists.txt b/indra/media_plugins/winmmshim/CMakeLists.txt
index 387214088f..bf74f81809 100644
--- a/indra/media_plugins/winmmshim/CMakeLists.txt
+++ b/indra/media_plugins/winmmshim/CMakeLists.txt
@@ -3,6 +3,12 @@
project(winmm_shim)
### winmm_shim
+# *HACK - override msvcrt implementation (intialized on 00-Common) to be
+# statically linked for winmm.dll this relies on vc taking the last flag on
+# the command line
+set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
+set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /MT")
+set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
set(winmm_shim_SOURCE_FILES
forwarding_api.cpp
diff --git a/indra/media_plugins/winmmshim/forwarding_api.cpp b/indra/media_plugins/winmmshim/forwarding_api.cpp
index eff7e20451..495e08942b 100644
--- a/indra/media_plugins/winmmshim/forwarding_api.cpp
+++ b/indra/media_plugins/winmmshim/forwarding_api.cpp
@@ -389,90 +389,105 @@ void init_function_pointers(HMODULE winmm_handle)
extern "C" {
LRESULT WINAPI CloseDriver( HDRVR hDriver, LPARAM lParam1, LPARAM lParam2)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"CloseDriver\n");
return CloseDriver_orig( hDriver, lParam1, lParam2);
}
HDRVR WINAPI OpenDriver( LPCWSTR szDriverName, LPCWSTR szSectionName, LPARAM lParam2)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"OpenDriver\n");
return OpenDriver_orig( szDriverName, szSectionName, lParam2);
}
LRESULT WINAPI SendDriverMessage( HDRVR hDriver, UINT message, LPARAM lParam1, LPARAM lParam2)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"SendDriverMessage\n");
return SendDriverMessage_orig( hDriver, message, lParam1, lParam2);
}
HMODULE WINAPI DrvGetModuleHandle( HDRVR hDriver)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"DrvGetModuleHandle\n");
return DrvGetModuleHandle_orig( hDriver);
}
HMODULE WINAPI GetDriverModuleHandle( HDRVR hDriver)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"GetDriverModuleHandle\n");
return GetDriverModuleHandle_orig( hDriver);
}
LRESULT WINAPI DefDriverProc( DWORD_PTR dwDriverIdentifier, HDRVR hdrvr, UINT uMsg, LPARAM lParam1, LPARAM lParam2)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"DefDriverProc\n");
return DefDriverProc_orig( dwDriverIdentifier, hdrvr, uMsg, lParam1, lParam2);
}
BOOL WINAPI DriverCallback( DWORD dwCallBack, DWORD dwFlags, HDRVR hdrvr, DWORD msg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"DriverCallback\n");
return DriverCallback_orig(dwCallBack, dwFlags, hdrvr, msg, dwUser, dwParam1, dwParam2);
}
UINT WINAPI mmsystemGetVersion(void)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mmsystemGetVersion\n");
return mmsystemGetVersion_orig();
}
BOOL WINAPI sndPlaySoundA( LPCSTR pszSound, UINT fuSound)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"sndPlaySoundA\n");
return sndPlaySoundA_orig( pszSound, fuSound);
}
BOOL WINAPI sndPlaySoundW( LPCWSTR pszSound, UINT fuSound)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"sndPlaySoundW\n");
return sndPlaySoundW_orig( pszSound, fuSound);
}
BOOL WINAPI PlaySoundA( LPCSTR pszSound, HMODULE hmod, DWORD fdwSound)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"PlaySoundA\n");
return PlaySoundA_orig( pszSound, hmod, fdwSound);
}
BOOL WINAPI PlaySoundW( LPCWSTR pszSound, HMODULE hmod, DWORD fdwSound)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"PlaySoundW\n");
return PlaySoundW_orig( pszSound, hmod, fdwSound);
}
UINT WINAPI waveOutGetNumDevs(void)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"waveOutGetNumDevs\n");
return waveOutGetNumDevs_orig();
}
MMRESULT WINAPI waveOutGetDevCapsA( UINT_PTR uDeviceID, LPWAVEOUTCAPSA pwoc, UINT cbwoc)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"waveOutGetDevCapsA\n");
return waveOutGetDevCapsA_orig( uDeviceID, pwoc, cbwoc);
}
MMRESULT WINAPI waveOutGetDevCapsW( UINT_PTR uDeviceID, LPWAVEOUTCAPSW pwoc, UINT cbwoc)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"waveOutGetDevCapsW\n");
return waveOutGetDevCapsW_orig( uDeviceID, pwoc, cbwoc);
}
@@ -480,24 +495,28 @@ extern "C" {
MMRESULT WINAPI waveOutGetVolume( HWAVEOUT hwo, LPDWORD pdwVolume)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"waveOutGetVolume\n");
return waveOutGetVolume_orig( hwo, pdwVolume);
}
MMRESULT WINAPI waveOutSetVolume( HWAVEOUT hwo, DWORD dwVolume)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"waveOutSetVolume\n");
return waveOutSetVolume_orig( hwo, dwVolume);
}
MMRESULT WINAPI waveOutGetErrorTextA( MMRESULT mmrError, LPSTR pszText, UINT cchText)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"waveOutGetErrorTextA\n");
return waveOutGetErrorTextA_orig( mmrError, pszText, cchText);
}
MMRESULT WINAPI waveOutGetErrorTextW( MMRESULT mmrError, LPWSTR pszText, UINT cchText)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"waveOutGetErrorTextW\n");
return waveOutGetErrorTextW_orig( mmrError, pszText, cchText);
}
@@ -516,12 +535,14 @@ extern "C" {
MMRESULT WINAPI waveOutPrepareHeader( HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"waveOutPrepareHeader\n");
return waveOutPrepareHeader_orig( hwo, pwh, cbwh);
}
MMRESULT WINAPI waveOutUnprepareHeader( HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"waveOutUnprepareHeader\n");
return waveOutUnprepareHeader_orig( hwo, pwh, cbwh);
}
@@ -535,834 +556,973 @@ extern "C" {
MMRESULT WINAPI waveOutPause( HWAVEOUT hwo)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"waveOutPause\n");
return waveOutPause_orig( hwo);
}
MMRESULT WINAPI waveOutRestart( HWAVEOUT hwo)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"waveOutRestart\n");
return waveOutRestart_orig( hwo);
}
MMRESULT WINAPI waveOutReset( HWAVEOUT hwo)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"waveOutReset\n");
return waveOutReset_orig( hwo);
}
MMRESULT WINAPI waveOutBreakLoop( HWAVEOUT hwo)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"waveOutBreakLoop\n");
return waveOutBreakLoop_orig( hwo);
}
MMRESULT WINAPI waveOutGetPosition( HWAVEOUT hwo, LPMMTIME pmmt, UINT cbmmt)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"waveOutGetPosition\n");
return waveOutGetPosition_orig( hwo, pmmt, cbmmt);
}
MMRESULT WINAPI waveOutGetPitch( HWAVEOUT hwo, LPDWORD pdwPitch)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"waveOutGetPitch\n");
return waveOutGetPitch_orig( hwo, pdwPitch);
}
MMRESULT WINAPI waveOutSetPitch( HWAVEOUT hwo, DWORD dwPitch)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"waveOutSetPitch\n");
return waveOutSetPitch_orig( hwo, dwPitch);
}
MMRESULT WINAPI waveOutGetPlaybackRate( HWAVEOUT hwo, LPDWORD pdwRate)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"waveOutGetPlaybackRate\n");
return waveOutGetPlaybackRate_orig( hwo, pdwRate);
}
MMRESULT WINAPI waveOutSetPlaybackRate( HWAVEOUT hwo, DWORD dwRate)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"waveOutSetPlaybackRate\n");
return waveOutSetPlaybackRate_orig( hwo, dwRate);
}
MMRESULT WINAPI waveOutGetID( HWAVEOUT hwo, LPUINT puDeviceID)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"waveOutGetID\n");
return waveOutGetID_orig( hwo, puDeviceID);
}
MMRESULT WINAPI waveOutMessage( HWAVEOUT hwo, UINT uMsg, DWORD_PTR dw1, DWORD_PTR dw2)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"waveOutMessage\n");
return waveOutMessage_orig( hwo, uMsg, dw1, dw2);
}
UINT WINAPI waveInGetNumDevs(void)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"waveInGetNumDevs\n");
return waveInGetNumDevs_orig();
}
MMRESULT WINAPI waveInGetDevCapsA( UINT_PTR uDeviceID, LPWAVEINCAPSA pwic, UINT cbwic)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"waveInGetDevCapsA\n");
return waveInGetDevCapsA_orig( uDeviceID, pwic, cbwic);
}
MMRESULT WINAPI waveInGetDevCapsW( UINT_PTR uDeviceID, LPWAVEINCAPSW pwic, UINT cbwic)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"waveInGetDevCapsW\n");
return waveInGetDevCapsW_orig( uDeviceID, pwic, cbwic);
}
MMRESULT WINAPI waveInGetErrorTextA(MMRESULT mmrError, LPSTR pszText, UINT cchText)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"waveInGetErrorTextA\n");
return waveInGetErrorTextA_orig(mmrError, pszText, cchText);
}
MMRESULT WINAPI waveInGetErrorTextW(MMRESULT mmrError, LPWSTR pszText, UINT cchText)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"waveInGetErrorTextW\n");
return waveInGetErrorTextW_orig(mmrError, pszText, cchText);
}
MMRESULT WINAPI waveInOpen( LPHWAVEIN phwi, UINT uDeviceID, LPCWAVEFORMATEX pwfx, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"waveInOpen\n");
return waveInOpen_orig(phwi, uDeviceID, pwfx, dwCallback, dwInstance, fdwOpen);
}
MMRESULT WINAPI waveInClose( HWAVEIN hwi)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"waveInClose\n");
return waveInClose_orig( hwi);
}
MMRESULT WINAPI waveInPrepareHeader( HWAVEIN hwi, LPWAVEHDR pwh, UINT cbwh)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"waveInPrepareHeader\n");
return waveInPrepareHeader_orig( hwi, pwh, cbwh);
}
MMRESULT WINAPI waveInUnprepareHeader( HWAVEIN hwi, LPWAVEHDR pwh, UINT cbwh)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"waveInUnprepareHeader\n");
return waveInUnprepareHeader_orig( hwi, pwh, cbwh);
}
MMRESULT WINAPI waveInAddBuffer( HWAVEIN hwi, LPWAVEHDR pwh, UINT cbwh)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"waveInAddBuffer\n");
return waveInAddBuffer_orig( hwi, pwh, cbwh);
}
MMRESULT WINAPI waveInStart( HWAVEIN hwi)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"waveInStart\n");
return waveInStart_orig( hwi);
}
MMRESULT WINAPI waveInStop( HWAVEIN hwi)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"waveInStop\n");
return waveInStop_orig(hwi);
}
MMRESULT WINAPI waveInReset( HWAVEIN hwi)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"waveInReset\n");
return waveInReset_orig(hwi);
}
MMRESULT WINAPI waveInGetPosition( HWAVEIN hwi, LPMMTIME pmmt, UINT cbmmt)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"waveInGetPosition\n");
return waveInGetPosition_orig( hwi, pmmt, cbmmt);
}
MMRESULT WINAPI waveInGetID( HWAVEIN hwi, LPUINT puDeviceID)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"waveInGetID\n");
return waveInGetID_orig( hwi, puDeviceID);
}
MMRESULT WINAPI waveInMessage( HWAVEIN hwi, UINT uMsg, DWORD_PTR dw1, DWORD_PTR dw2)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"waveInMessage\n");
return waveInMessage_orig( hwi, uMsg, dw1, dw2);
}
UINT WINAPI midiOutGetNumDevs(void)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"midiOutGetNumDevs\n");
return midiOutGetNumDevs_orig();
}
MMRESULT WINAPI midiStreamOpen( LPHMIDISTRM phms, LPUINT puDeviceID, DWORD cMidi, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"midiStreamOpen\n");
return midiStreamOpen_orig( phms, puDeviceID, cMidi, dwCallback, dwInstance, fdwOpen);
}
MMRESULT WINAPI midiStreamClose( HMIDISTRM hms)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"midiStreamClose\n");
return midiStreamClose_orig( hms);
}
MMRESULT WINAPI midiStreamProperty( HMIDISTRM hms, LPBYTE lppropdata, DWORD dwProperty)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"midiStreamProperty\n");
return midiStreamProperty_orig( hms, lppropdata, dwProperty);
}
MMRESULT WINAPI midiStreamPosition( HMIDISTRM hms, LPMMTIME lpmmt, UINT cbmmt)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"midiStreamPosition\n");
return midiStreamPosition_orig( hms, lpmmt, cbmmt);
}
MMRESULT WINAPI midiStreamOut( HMIDISTRM hms, LPMIDIHDR pmh, UINT cbmh)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"midiStreamOut\n");
return midiStreamOut_orig( hms, pmh, cbmh);
}
MMRESULT WINAPI midiStreamPause( HMIDISTRM hms)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"midiStreamPause\n");
return midiStreamPause_orig( hms);
}
MMRESULT WINAPI midiStreamRestart( HMIDISTRM hms)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"midiStreamRestart\n");
return midiStreamRestart_orig( hms);
}
MMRESULT WINAPI midiStreamStop( HMIDISTRM hms)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"midiStreamStop\n");
return midiStreamStop_orig( hms);
}
MMRESULT WINAPI midiConnect( HMIDI hmi, HMIDIOUT hmo, LPVOID pReserved)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"midiConnect\n");
return midiConnect_orig( hmi, hmo, pReserved);
}
MMRESULT WINAPI midiDisconnect( HMIDI hmi, HMIDIOUT hmo, LPVOID pReserved)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"midiDisconnect\n");
return midiDisconnect_orig( hmi, hmo, pReserved);
}
MMRESULT WINAPI midiOutGetDevCapsA( UINT_PTR uDeviceID, LPMIDIOUTCAPSA pmoc, UINT cbmoc)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"midiOutGetDevCapsA\n");
return midiOutGetDevCapsA_orig( uDeviceID, pmoc, cbmoc);
}
MMRESULT WINAPI midiOutGetDevCapsW( UINT_PTR uDeviceID, LPMIDIOUTCAPSW pmoc, UINT cbmoc)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"midiOutGetDevCapsW\n");
return midiOutGetDevCapsW_orig( uDeviceID, pmoc, cbmoc);
}
MMRESULT WINAPI midiOutGetVolume( HMIDIOUT hmo, LPDWORD pdwVolume)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"midiOutGetVolume\n");
return midiOutGetVolume_orig( hmo, pdwVolume);
}
MMRESULT WINAPI midiOutSetVolume( HMIDIOUT hmo, DWORD dwVolume)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"midiOutSetVolume\n");
return midiOutSetVolume_orig( hmo, dwVolume);
}
MMRESULT WINAPI midiOutGetErrorTextA( MMRESULT mmrError, LPSTR pszText, UINT cchText)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"midiOutGetErrorTextA\n");
return midiOutGetErrorTextA_orig( mmrError, pszText, cchText);
}
MMRESULT WINAPI midiOutGetErrorTextW( MMRESULT mmrError, LPWSTR pszText, UINT cchText)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"midiOutGetErrorTextW\n");
return midiOutGetErrorTextW_orig( mmrError, pszText, cchText);
}
MMRESULT WINAPI midiOutOpen( LPHMIDIOUT phmo, UINT uDeviceID, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"midiOutOpen\n");
return midiOutOpen_orig(phmo, uDeviceID, dwCallback, dwInstance, fdwOpen);
}
MMRESULT WINAPI midiOutClose( HMIDIOUT hmo)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"midiOutClose\n");
return midiOutClose_orig( hmo);
}
MMRESULT WINAPI midiOutPrepareHeader( HMIDIOUT hmo, LPMIDIHDR pmh, UINT cbmh)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"midiOutPrepareHeader\n");
return midiOutPrepareHeader_orig( hmo, pmh, cbmh);
}
MMRESULT WINAPI midiOutUnprepareHeader(HMIDIOUT hmo, LPMIDIHDR pmh, UINT cbmh)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"midiOutUnprepareHeader\n");
return midiOutUnprepareHeader_orig(hmo, pmh, cbmh);
}
MMRESULT WINAPI midiOutShortMsg( HMIDIOUT hmo, DWORD dwMsg)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"midiOutShortMsg\n");
return midiOutShortMsg_orig( hmo, dwMsg);
}
MMRESULT WINAPI midiOutLongMsg(HMIDIOUT hmo, LPMIDIHDR pmh, UINT cbmh)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"midiOutLongMsg\n");
return midiOutLongMsg_orig(hmo, pmh, cbmh);
}
MMRESULT WINAPI midiOutReset( HMIDIOUT hmo)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"midiOutReset\n");
return midiOutReset_orig( hmo);
}
MMRESULT WINAPI midiOutCachePatches( HMIDIOUT hmo, UINT uBank, LPWORD pwpa, UINT fuCache)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"midiOutCachePatches\n");
return midiOutCachePatches_orig( hmo, uBank, pwpa, fuCache);
}
MMRESULT WINAPI midiOutCacheDrumPatches( HMIDIOUT hmo, UINT uPatch, LPWORD pwkya, UINT fuCache)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"midiOutCacheDrumPatches\n");
return midiOutCacheDrumPatches_orig( hmo, uPatch, pwkya, fuCache);
}
MMRESULT WINAPI midiOutGetID( HMIDIOUT hmo, LPUINT puDeviceID)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"midiOutGetID\n");
return midiOutGetID_orig( hmo, puDeviceID);
}
MMRESULT WINAPI midiOutMessage( HMIDIOUT hmo, UINT uMsg, DWORD_PTR dw1, DWORD_PTR dw2)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"midiOutMessage\n");
return midiOutMessage_orig( hmo, uMsg, dw1, dw2);
}
UINT WINAPI midiInGetNumDevs(void)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"midiInGetNumDevs\n");
return midiInGetNumDevs_orig();
}
MMRESULT WINAPI midiInGetDevCapsA( UINT_PTR uDeviceID, LPMIDIINCAPSA pmic, UINT cbmic)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"midiInGetDevCapsA\n");
return midiInGetDevCapsA_orig( uDeviceID, pmic, cbmic);
}
MMRESULT WINAPI midiInGetDevCapsW( UINT_PTR uDeviceID, LPMIDIINCAPSW pmic, UINT cbmic)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"midiInGetDevCapsW\n");
return midiInGetDevCapsW_orig( uDeviceID, pmic, cbmic);
}
MMRESULT WINAPI midiInGetErrorTextA( MMRESULT mmrError, LPSTR pszText, UINT cchText)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"midiInGetErrorTextA\n");
return midiInGetErrorTextA_orig( mmrError, pszText, cchText);
}
MMRESULT WINAPI midiInGetErrorTextW( MMRESULT mmrError, LPWSTR pszText, UINT cchText)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"midiInGetErrorTextW\n");
return midiInGetErrorTextW_orig( mmrError, pszText, cchText);
}
MMRESULT WINAPI midiInOpen( LPHMIDIIN phmi, UINT uDeviceID, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"midiInOpen\n");
return midiInOpen_orig(phmi, uDeviceID, dwCallback, dwInstance, fdwOpen);
}
MMRESULT WINAPI midiInClose( HMIDIIN hmi)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"midiInClose\n");
return midiInClose_orig( hmi);
}
MMRESULT WINAPI midiInPrepareHeader( HMIDIIN hmi, LPMIDIHDR pmh, UINT cbmh)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"midiInPrepareHeader\n");
return midiInPrepareHeader_orig( hmi, pmh, cbmh);
}
MMRESULT WINAPI midiInUnprepareHeader( HMIDIIN hmi, LPMIDIHDR pmh, UINT cbmh)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"midiInUnprepareHeader\n");
return midiInUnprepareHeader_orig( hmi, pmh, cbmh);
}
MMRESULT WINAPI midiInAddBuffer( HMIDIIN hmi, LPMIDIHDR pmh, UINT cbmh)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"midiInAddBuffer\n");
return midiInAddBuffer_orig( hmi, pmh, cbmh);
}
MMRESULT WINAPI midiInStart( HMIDIIN hmi)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"midiInStart\n");
return midiInStart_orig( hmi);
}
MMRESULT WINAPI midiInStop( HMIDIIN hmi)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"midiInStop\n");
return midiInStop_orig(hmi);
}
MMRESULT WINAPI midiInReset( HMIDIIN hmi)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"midiInReset\n");
return midiInReset_orig( hmi);
}
MMRESULT WINAPI midiInGetID( HMIDIIN hmi, LPUINT puDeviceID)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"midiInGetID\n");
return midiInGetID_orig( hmi, puDeviceID);
}
MMRESULT WINAPI midiInMessage( HMIDIIN hmi, UINT uMsg, DWORD_PTR dw1, DWORD_PTR dw2)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"midiInMessage\n");
return midiInMessage_orig( hmi, uMsg, dw1, dw2);
}
UINT WINAPI auxGetNumDevs(void)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"auxGetNumDevs\n");
return auxGetNumDevs_orig();
}
MMRESULT WINAPI auxGetDevCapsA( UINT_PTR uDeviceID, LPAUXCAPSA pac, UINT cbac)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"auxGetDevCapsA\n");
return auxGetDevCapsA_orig( uDeviceID, pac, cbac);
}
MMRESULT WINAPI auxGetDevCapsW( UINT_PTR uDeviceID, LPAUXCAPSW pac, UINT cbac)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"auxGetDevCapsW\n");
return auxGetDevCapsW_orig( uDeviceID, pac, cbac);
}
MMRESULT WINAPI auxSetVolume( UINT uDeviceID, DWORD dwVolume)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"auxSetVolume\n");
return auxSetVolume_orig( uDeviceID, dwVolume);
}
MMRESULT WINAPI auxGetVolume( UINT uDeviceID, LPDWORD pdwVolume)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"auxGetVolume\n");
return auxGetVolume_orig( uDeviceID, pdwVolume);
}
MMRESULT WINAPI auxOutMessage( UINT uDeviceID, UINT uMsg, DWORD_PTR dw1, DWORD_PTR dw2)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"auxOutMessage\n");
return auxOutMessage_orig( uDeviceID, uMsg, dw1, dw2);
}
UINT WINAPI mixerGetNumDevs(void)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mixerGetNumDevs\n");
return mixerGetNumDevs_orig();
}
MMRESULT WINAPI mixerGetDevCapsA( UINT_PTR uMxId, LPMIXERCAPSA pmxcaps, UINT cbmxcaps)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mixerGetDevCapsA\n");
return mixerGetDevCapsA_orig( uMxId, pmxcaps, cbmxcaps);
}
MMRESULT WINAPI mixerGetDevCapsW( UINT_PTR uMxId, LPMIXERCAPSW pmxcaps, UINT cbmxcaps)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mixerGetDevCapsW\n");
return mixerGetDevCapsW_orig( uMxId, pmxcaps, cbmxcaps);
}
MMRESULT WINAPI mixerOpen( LPHMIXER phmx, UINT uMxId, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mixerOpen\n");
return mixerOpen_orig( phmx, uMxId, dwCallback, dwInstance, fdwOpen);
}
MMRESULT WINAPI mixerClose( HMIXER hmx)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mixerClose\n");
return mixerClose_orig( hmx);
}
DWORD WINAPI mixerMessage( HMIXER hmx, UINT uMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mixerMessage\n");
return mixerMessage_orig( hmx, uMsg, dwParam1, dwParam2);
}
MMRESULT WINAPI mixerGetLineInfoA( HMIXEROBJ hmxobj, LPMIXERLINEA pmxl, DWORD fdwInfo)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mixerGetLineInfoA\n");
return mixerGetLineInfoA_orig( hmxobj, pmxl, fdwInfo);
}
MMRESULT WINAPI mixerGetLineInfoW( HMIXEROBJ hmxobj, LPMIXERLINEW pmxl, DWORD fdwInfo)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mixerGetLineInfoW\n");
return mixerGetLineInfoW_orig( hmxobj, pmxl, fdwInfo);
}
MMRESULT WINAPI mixerGetID( HMIXEROBJ hmxobj, UINT FAR *puMxId, DWORD fdwId)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mixerGetID\n");
return mixerGetID_orig( hmxobj, puMxId, fdwId);
}
MMRESULT WINAPI mixerGetLineControlsA( HMIXEROBJ hmxobj, LPMIXERLINECONTROLSA pmxlc, DWORD fdwControls)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mixerGetLineControlsA\n");
return mixerGetLineControlsA_orig( hmxobj, pmxlc, fdwControls);
}
MMRESULT WINAPI mixerGetLineControlsW( HMIXEROBJ hmxobj, LPMIXERLINECONTROLSW pmxlc, DWORD fdwControls)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mixerGetLineControlsW\n");
return mixerGetLineControlsW_orig( hmxobj, pmxlc, fdwControls);
}
MMRESULT WINAPI mixerGetControlDetailsA( HMIXEROBJ hmxobj, LPMIXERCONTROLDETAILS pmxcd, DWORD fdwDetails)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mixerGetControlDetailsA\n");
return mixerGetControlDetailsA_orig( hmxobj, pmxcd, fdwDetails);
}
MMRESULT WINAPI mixerGetControlDetailsW( HMIXEROBJ hmxobj, LPMIXERCONTROLDETAILS pmxcd, DWORD fdwDetails)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mixerGetControlDetailsW\n");
return mixerGetControlDetailsW_orig( hmxobj, pmxcd, fdwDetails);
}
MMRESULT WINAPI mixerSetControlDetails( HMIXEROBJ hmxobj, LPMIXERCONTROLDETAILS pmxcd, DWORD fdwDetails)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mixerSetControlDetails\n");
return mixerSetControlDetails_orig( hmxobj, pmxcd, fdwDetails);
}
DWORD WINAPI mmGetCurrentTask(void)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mmGetCurrentTask\n");
return mmGetCurrentTask_orig();
}
void WINAPI mmTaskBlock(DWORD val)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mmTaskBlock\n");
return mmTaskBlock_orig(val);
}
UINT WINAPI mmTaskCreate(LPTASKCALLBACK a, HANDLE* b, DWORD_PTR c)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mmTaskCreate\n");
return mmTaskCreate_orig(a, b, c);
}
BOOL WINAPI mmTaskSignal(DWORD a)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mmTaskSignal\n");
return mmTaskSignal_orig(a);
}
VOID WINAPI mmTaskYield()
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mmTaskYield\n");
mmTaskYield_orig();
}
MMRESULT WINAPI timeGetSystemTime( LPMMTIME pmmt, UINT cbmmt)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"timeGetSystemTime\n");
return timeGetSystemTime_orig( pmmt, cbmmt);
}
DWORD WINAPI timeGetTime(void)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"timeGetTime\n");
return timeGetTime_orig();
}
MMRESULT WINAPI timeSetEvent( UINT uDelay, UINT uResolution, LPTIMECALLBACK fptc, DWORD_PTR dwUser, UINT fuEvent)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"timeSetEvent\n");
return timeSetEvent_orig(uDelay, uResolution, fptc, dwUser, fuEvent);
}
MMRESULT WINAPI timeKillEvent( UINT uTimerID)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"timeKillEvent\n");
return timeKillEvent_orig( uTimerID);
}
MMRESULT WINAPI timeGetDevCaps( LPTIMECAPS ptc, UINT cbtc)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"timeGetDevCaps\n");
return timeGetDevCaps_orig( ptc, cbtc);
}
MMRESULT WINAPI timeBeginPeriod( UINT uPeriod)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"timeBeginPeriod\n");
return timeBeginPeriod_orig( uPeriod);
}
MMRESULT WINAPI timeEndPeriod( UINT uPeriod)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"timeEndPeriod\n");
return timeEndPeriod_orig( uPeriod);
}
UINT WINAPI joyGetNumDevs(void)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"joyGetNumDevs\n");
return joyGetNumDevs_orig();
}
MMRESULT WINAPI joyConfigChanged(DWORD dwFlags)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"joyConfigChanged\n");
return joyConfigChanged_orig(dwFlags);
}
MMRESULT WINAPI joyGetDevCapsA( UINT_PTR uJoyID, LPJOYCAPSA pjc, UINT cbjc)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"joyGetDevCapsA\n");
return joyGetDevCapsA_orig( uJoyID, pjc, cbjc);
}
MMRESULT WINAPI joyGetDevCapsW( UINT_PTR uJoyID, LPJOYCAPSW pjc, UINT cbjc)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"joyGetDevCapsW\n");
return joyGetDevCapsW_orig( uJoyID, pjc, cbjc);
}
MMRESULT WINAPI joyGetPos( UINT uJoyID, LPJOYINFO pji)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"joyGetPos\n");
return joyGetPos_orig( uJoyID, pji);
}
MMRESULT WINAPI joyGetPosEx( UINT uJoyID, LPJOYINFOEX pji)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"joyGetPosEx\n");
return joyGetPosEx_orig( uJoyID, pji);
}
MMRESULT WINAPI joyGetThreshold( UINT uJoyID, LPUINT puThreshold)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"joyGetThreshold\n");
return joyGetThreshold_orig( uJoyID, puThreshold);
}
MMRESULT WINAPI joyReleaseCapture( UINT uJoyID)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"joyReleaseCapture\n");
return joyReleaseCapture_orig( uJoyID);
}
MMRESULT WINAPI joySetCapture( HWND hwnd, UINT uJoyID, UINT uPeriod, BOOL fChanged)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"joySetCapture\n");
return joySetCapture_orig(hwnd, uJoyID, uPeriod, fChanged);
}
MMRESULT WINAPI joySetThreshold( UINT uJoyID, UINT uThreshold)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"joySetThreshold\n");
return joySetThreshold_orig( uJoyID, uThreshold);
}
BOOL WINAPI mciDriverNotify(HWND hwndCallback, UINT uDeviceID, UINT uStatus)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mciDriverNotify\n");
return mciDriverNotify_orig(hwndCallback, uDeviceID, uStatus);
}
UINT WINAPI mciDriverYield(UINT uDeviceID)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mciDriverYield\n");
return mciDriverYield_orig(uDeviceID);
}
FOURCC WINAPI mmioStringToFOURCCA( LPCSTR sz, UINT uFlags)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mmioStringToFOURCCA\n");
return mmioStringToFOURCCA_orig( sz, uFlags);
}
FOURCC WINAPI mmioStringToFOURCCW( LPCWSTR sz, UINT uFlags)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mmioStringToFOURCCW\n");
return mmioStringToFOURCCW_orig( sz, uFlags);
}
LPMMIOPROC WINAPI mmioInstallIOProcA( FOURCC fccIOProc, LPMMIOPROC pIOProc, DWORD dwFlags)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mmioInstallIOProcA\n");
return mmioInstallIOProcA_orig( fccIOProc, pIOProc, dwFlags);
}
LPMMIOPROC WINAPI mmioInstallIOProcW( FOURCC fccIOProc, LPMMIOPROC pIOProc, DWORD dwFlags)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mmioInstallIOProcW\n");
return mmioInstallIOProcW_orig( fccIOProc, pIOProc, dwFlags);
}
HMMIO WINAPI mmioOpenA( LPSTR pszFileName, LPMMIOINFO pmmioinfo, DWORD fdwOpen)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mmioOpenA\n");
return mmioOpenA_orig( pszFileName, pmmioinfo, fdwOpen);
}
HMMIO WINAPI mmioOpenW( LPWSTR pszFileName, LPMMIOINFO pmmioinfo, DWORD fdwOpen)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mmioOpenW\n");
return mmioOpenW_orig( pszFileName, pmmioinfo, fdwOpen);
}
MMRESULT WINAPI mmioRenameA( LPCSTR pszFileName, LPCSTR pszNewFileName, LPCMMIOINFO pmmioinfo, DWORD fdwRename)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mmioRenameA\n");
return mmioRenameA_orig( pszFileName, pszNewFileName, pmmioinfo, fdwRename);
}
MMRESULT WINAPI mmioRenameW( LPCWSTR pszFileName, LPCWSTR pszNewFileName, LPCMMIOINFO pmmioinfo, DWORD fdwRename)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mmioRenameW\n");
return mmioRenameW_orig( pszFileName, pszNewFileName, pmmioinfo, fdwRename);
}
MMRESULT WINAPI mmioClose( HMMIO hmmio, UINT fuClose)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mmioClose\n");
return mmioClose_orig( hmmio, fuClose);
}
LONG WINAPI mmioRead( HMMIO hmmio, HPSTR pch, LONG cch)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mmioRead\n");
return mmioRead_orig( hmmio, pch, cch);
}
LONG WINAPI mmioWrite( HMMIO hmmio, const char _huge* pch, LONG cch)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mmioWrite\n");
return mmioWrite_orig( hmmio, pch, cch);
}
LONG WINAPI mmioSeek( HMMIO hmmio, LONG lOffset, int iOrigin)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mmioSeek\n");
return mmioSeek_orig(hmmio, lOffset, iOrigin);
}
MMRESULT WINAPI mmioGetInfo( HMMIO hmmio, LPMMIOINFO pmmioinfo, UINT fuInfo)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mmioGetInfo\n");
return mmioGetInfo_orig( hmmio, pmmioinfo, fuInfo);
}
MMRESULT WINAPI mmioSetInfo( HMMIO hmmio, LPCMMIOINFO pmmioinfo, UINT fuInfo)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mmioSetInfo\n");
return mmioSetInfo_orig( hmmio, pmmioinfo, fuInfo);
}
MMRESULT WINAPI mmioSetBuffer( HMMIO hmmio, LPSTR pchBuffer, LONG cchBuffer, UINT fuBuffer)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mmioSetBuffer\n");
return mmioSetBuffer_orig(hmmio, pchBuffer, cchBuffer, fuBuffer);
}
MMRESULT WINAPI mmioFlush( HMMIO hmmio, UINT fuFlush)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mmioFlush\n");
return mmioFlush_orig( hmmio, fuFlush);
}
MMRESULT WINAPI mmioAdvance( HMMIO hmmio, LPMMIOINFO pmmioinfo, UINT fuAdvance)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mmioAdvance\n");
return mmioAdvance_orig( hmmio, pmmioinfo, fuAdvance);
}
LRESULT WINAPI mmioSendMessage( HMMIO hmmio, UINT uMsg, LPARAM lParam1, LPARAM lParam2)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mmioSendMessage\n");
return mmioSendMessage_orig(hmmio, uMsg, lParam1, lParam2);
}
MMRESULT WINAPI mmioDescend( HMMIO hmmio, LPMMCKINFO pmmcki, const MMCKINFO FAR* pmmckiParent, UINT fuDescend)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mmioDescend\n");
return mmioDescend_orig(hmmio, pmmcki, pmmckiParent, fuDescend);
}
MMRESULT WINAPI mmioAscend( HMMIO hmmio, LPMMCKINFO pmmcki, UINT fuAscend)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mmioAscend\n");
return mmioAscend_orig( hmmio, pmmcki, fuAscend);
}
MMRESULT WINAPI mmioCreateChunk(HMMIO hmmio, LPMMCKINFO pmmcki, UINT fuCreate)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mmioCreateChunk\n");
return mmioCreateChunk_orig(hmmio, pmmcki, fuCreate);
}
MCIERROR WINAPI mciSendCommandA( MCIDEVICEID mciId, UINT uMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mciSendCommandA\n");
return mciSendCommandA_orig( mciId, uMsg, dwParam1, dwParam2);
}
MCIERROR WINAPI mciSendCommandW( MCIDEVICEID mciId, UINT uMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mciSendCommandW\n");
return mciSendCommandW_orig( mciId, uMsg, dwParam1, dwParam2);
}
MCIERROR WINAPI mciSendStringA( LPCSTR lpstrCommand, LPSTR lpstrReturnString, UINT uReturnLength, HWND hwndCallback)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mciSendStringA\n");
return mciSendStringA_orig( lpstrCommand, lpstrReturnString, uReturnLength, hwndCallback);
}
MCIERROR WINAPI mciSendStringW( LPCWSTR lpstrCommand, LPWSTR lpstrReturnString, UINT uReturnLength, HWND hwndCallback)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mciSendStringW\n");
return mciSendStringW_orig( lpstrCommand, lpstrReturnString, uReturnLength, hwndCallback);
}
@@ -1375,72 +1535,84 @@ extern "C" {
MCIDEVICEID WINAPI mciGetDeviceIDW( LPCWSTR pszDevice)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mciGetDeviceIDW\n");
return mciGetDeviceIDW_orig( pszDevice);
}
MCIDEVICEID WINAPI mciGetDeviceIDFromElementIDA( DWORD dwElementID, LPCSTR lpstrType )
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mciGetDeviceIDFromElementIDA\n");
return mciGetDeviceIDFromElementIDA_orig( dwElementID, lpstrType );
}
MCIDEVICEID WINAPI mciGetDeviceIDFromElementIDW( DWORD dwElementID, LPCWSTR lpstrType )
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mciGetDeviceIDFromElementIDW\n");
return mciGetDeviceIDFromElementIDW_orig( dwElementID, lpstrType );
}
DWORD_PTR WINAPI mciGetDriverData(UINT uDeviceID)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mciGetDriverData\n");
return mciGetDriverData_orig(uDeviceID);
}
BOOL WINAPI mciGetErrorStringA( MCIERROR mcierr, LPSTR pszText, UINT cchText)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mciGetErrorStringA\n");
return mciGetErrorStringA_orig( mcierr, pszText, cchText);
}
BOOL WINAPI mciGetErrorStringW( MCIERROR mcierr, LPWSTR pszText, UINT cchText)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mciGetErrorStringW\n");
return mciGetErrorStringW_orig( mcierr, pszText, cchText);
}
BOOL WINAPI mciSetDriverData(UINT uDeviceID, DWORD_PTR dwData)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mciSetDriverData_type\n");
return mciSetDriverData_orig( uDeviceID, dwData );
}
BOOL WINAPI mciSetYieldProc( MCIDEVICEID mciId, YIELDPROC fpYieldProc, DWORD dwYieldData)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mciSetYieldProc\n");
return mciSetYieldProc_orig(mciId, fpYieldProc, dwYieldData);
}
BOOL WINAPI mciFreeCommandResource(UINT uTable)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mciFreeCommandResource\n");
return mciFreeCommandResource_orig(uTable);
}
HTASK WINAPI mciGetCreatorTask( MCIDEVICEID mciId)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mciGetCreatorTask\n");
return mciGetCreatorTask_orig( mciId);
}
YIELDPROC WINAPI mciGetYieldProc( MCIDEVICEID mciId, LPDWORD pdwYieldData)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mciGetYieldProc\n");
return mciGetYieldProc_orig( mciId, pdwYieldData);
}
UINT WINAPI mciLoadCommandResource(HINSTANCE hInstance, LPCWSTR lpResName, UINT uType)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mciLoadCommandResource");
return mciLoadCommandResource_orig(hInstance, lpResName, uType);
}
@@ -1448,6 +1620,7 @@ extern "C" {
BOOL WINAPI mciExecute(LPCSTR pszCommand)
{
+ ll_winmm_shim_initialize();
//OutputDebugString(L"mciExecute\n");
return mciExecute_orig(pszCommand);
}
diff --git a/indra/media_plugins/winmmshim/forwarding_api.h b/indra/media_plugins/winmmshim/forwarding_api.h
index 89a6b347f3..076a08f769 100644
--- a/indra/media_plugins/winmmshim/forwarding_api.h
+++ b/indra/media_plugins/winmmshim/forwarding_api.h
@@ -30,6 +30,7 @@
#include <mmsystem.h>
void init_function_pointers(HMODULE winmm_handle);
+void ll_winmm_shim_initialize();
typedef VOID (*LPTASKCALLBACK)(DWORD_PTR dwInst);
diff --git a/indra/media_plugins/winmmshim/winmm_shim.cpp b/indra/media_plugins/winmmshim/winmm_shim.cpp
index 9563a3b664..47a1e5c018 100644
--- a/indra/media_plugins/winmmshim/winmm_shim.cpp
+++ b/indra/media_plugins/winmmshim/winmm_shim.cpp
@@ -32,14 +32,21 @@ using std::wstring;
static float sVolumeLevel = 1.f;
static bool sMute = false;
+static CRITICAL_SECTION sCriticalSection;
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
+ InitializeCriticalSection(&sCriticalSection);
+ return TRUE;
+}
+
+void ll_winmm_shim_initialize(){
static bool initialized = false;
// do this only once
+ EnterCriticalSection(&sCriticalSection);
if (!initialized)
{ // bind to original winmm.dll
TCHAR system_path[MAX_PATH];
@@ -54,13 +61,15 @@ BOOL APIENTRY DllMain( HMODULE hModule,
{ // we have a dll, let's get out pointers!
initialized = true;
init_function_pointers(winmm_handle);
- return true;
+ ::OutputDebugStringA("WINMM_SHIM.DLL: real winmm.dll initialized successfully\n");
+ }
+ else
+ {
+ // failed to initialize real winmm.dll
+ ::OutputDebugStringA("WINMM_SHIM.DLL: Failed to initialize real winmm.dll\n");
}
-
- // failed to initialize real winmm.dll
- return false;
}
- return true;
+ LeaveCriticalSection(&sCriticalSection);
}
@@ -79,6 +88,7 @@ extern "C"
MMRESULT WINAPI waveOutOpen( LPHWAVEOUT phwo, UINT uDeviceID, LPCWAVEFORMATEX pwfx, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen)
{
+ ll_winmm_shim_initialize();
if (pwfx->wFormatTag != WAVE_FORMAT_PCM
|| (pwfx->wBitsPerSample != 8 && pwfx->wBitsPerSample != 16))
{ // uncompressed 8 and 16 bit sound are the only types we support
@@ -97,6 +107,7 @@ extern "C"
MMRESULT WINAPI waveOutClose( HWAVEOUT hwo)
{
+ ll_winmm_shim_initialize();
wave_out_map_t::iterator found_it = sWaveOuts.find(hwo);
if (found_it != sWaveOuts.end())
{ // forget what we know about this handle
@@ -108,6 +119,7 @@ extern "C"
MMRESULT WINAPI waveOutWrite( HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh)
{
+ ll_winmm_shim_initialize();
MMRESULT result = MMSYSERR_NOERROR;
if (sMute)
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index bf885e5934..cbf22b75e8 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -9,7 +9,7 @@ include(DBusGlib)
include(DirectX)
include(OpenSSL)
include(DragDrop)
-include(ELFIO)
+include(EXPAT)
include(FMOD)
include(OPENAL)
include(FindOpenGL)
@@ -17,6 +17,7 @@ include(JsonCpp)
include(LLAudio)
include(LLCharacter)
include(LLCommon)
+include(LLConvexDecomposition)
include(LLImage)
include(LLImageJ2COJ)
include(LLInventory)
@@ -40,16 +41,20 @@ include(UnixInstall)
include(LLKDU)
include(ViewerMiscLibs)
include(LLLogin)
+include(GLOD)
include(CMakeCopyIfDifferent)
include_directories(
${DBUSGLIB_INCLUDE_DIRS}
- ${ELFIO_INCLUDE_DIR}
${JSONCPP_INCLUDE_DIRS}
+ ${GLOD_INCLUDE_DIR}
${LLAUDIO_INCLUDE_DIRS}
${LLCHARACTER_INCLUDE_DIRS}
${LLCOMMON_INCLUDE_DIRS}
+ ${LLCONVEXDECOMP_INCLUDE_DIRS}
+ ${FMOD_INCLUDE_DIR}
${LLIMAGE_INCLUDE_DIRS}
+ ${LLKDU_INCLUDE_DIRS}
${LLINVENTORY_INCLUDE_DIRS}
${LLMATH_INCLUDE_DIRS}
${LLMESSAGE_INCLUDE_DIRS}
@@ -64,9 +69,14 @@ include_directories(
${LSCRIPT_INCLUDE_DIRS}
${LSCRIPT_INCLUDE_DIRS}/lscript_compile
${LLLOGIN_INCLUDE_DIRS}
+ ${UPDATER_INCLUDE_DIRS}
+ ${LIBS_PREBUILT_DIR}/include/collada
+ ${OPENAL_LIB_INCLUDE_DIRS}
+ ${LIBS_PREBUILT_DIR}/include/collada/1.4
)
set(viewer_SOURCE_FILES
+ groupchatlistener.cpp
llagent.cpp
llagentaccess.cpp
llagentcamera.cpp
@@ -143,6 +153,7 @@ set(viewer_SOURCE_FILES
lleventnotifier.cpp
lleventpoll.cpp
llexpandabletextbox.cpp
+ llexternaleditor.cpp
llface.cpp
llfasttimerview.cpp
llfavoritesbar.cpp
@@ -191,6 +202,8 @@ set(viewer_SOURCE_FILES
llfloatermediabrowser.cpp
llfloatermediasettings.cpp
llfloatermemleak.cpp
+ llfloatermodelpreview.cpp
+ llfloatermodelwizard.cpp
llfloaternamedesc.cpp
llfloaternotificationsconsole.cpp
llfloateropenobject.cpp
@@ -200,6 +213,7 @@ set(viewer_SOURCE_FILES
llfloaterpostprocess.cpp
llfloaterpreference.cpp
llfloaterproperties.cpp
+ llfloaterregiondebugconsole.cpp
llfloaterregioninfo.cpp
llfloaterreporter.cpp
llfloaterscriptdebug.cpp
@@ -209,6 +223,7 @@ set(viewer_SOURCE_FILES
llfloatersettingsdebug.cpp
llfloatersidetraytab.cpp
llfloatersnapshot.cpp
+ llfloatersounddevices.cpp
llfloatertelehub.cpp
llfloatertestinspectors.cpp
llfloatertestlistview.cpp
@@ -219,6 +234,7 @@ set(viewer_SOURCE_FILES
llfloaterurlentry.cpp
llfloatervoiceeffect.cpp
llfloaterwater.cpp
+ llfloaterwebcontent.cpp
llfloaterwhitelistentry.cpp
llfloaterwindlight.cpp
llfloaterwindowsize.cpp
@@ -241,6 +257,7 @@ set(viewer_SOURCE_FILES
llhudeffectlookat.cpp
llhudeffectpointat.cpp
llhudeffecttrail.cpp
+ llhudeffectblob.cpp
llhudicon.cpp
llhudmanager.cpp
llhudnametag.cpp
@@ -282,6 +299,7 @@ set(viewer_SOURCE_FILES
llloginhandler.cpp
lllogininstance.cpp
llmachineid.cpp
+ llmainlooprepeater.cpp
llmanip.cpp
llmaniprotate.cpp
llmanipscale.cpp
@@ -290,7 +308,7 @@ set(viewer_SOURCE_FILES
llmediadataclient.cpp
llmemoryview.cpp
llmenucommands.cpp
- llmetricperformancetester.cpp
+ llmeshrepository.cpp
llmimetypes.cpp
llmorphview.cpp
llmoveview.cpp
@@ -373,6 +391,8 @@ set(viewer_SOURCE_FILES
llparcelselection.cpp
llparticipantlist.cpp
llpatchvertexarray.cpp
+ llphysicsmotion.cpp
+ llphysicsshapebuilderutil.cpp
llplacesinventorybridge.cpp
llplacesinventorypanel.cpp
llpopupview.cpp
@@ -392,20 +412,24 @@ set(viewer_SOURCE_FILES
llremoteparcelrequest.cpp
llsavedsettingsglue.cpp
llsaveoutfitcombobtn.cpp
+ llsceneview.cpp
llscreenchannel.cpp
llscriptfloater.cpp
llscrollingpanelparam.cpp
+ llscrollingpanelparambase.cpp
llsearchcombobox.cpp
llsearchhistory.cpp
llsecapi.cpp
llsechandler_basic.cpp
llselectmgr.cpp
+ llshareavatarhandler.cpp
llsidepanelappearance.cpp
llsidepanelinventory.cpp
llsidepanelinventorysubpanel.cpp
llsidepaneliteminfo.cpp
llsidepaneltaskinfo.cpp
llsidetray.cpp
+ llsidetraylistener.cpp
llsidetraypanelcontainer.cpp
llsky.cpp
llslurl.cpp
@@ -444,6 +468,7 @@ set(viewer_SOURCE_FILES
lltoastimpanel.cpp
lltoastnotifypanel.cpp
lltoastpanel.cpp
+ lltoastscripttextbox.cpp
lltool.cpp
lltoolbrush.cpp
lltoolcomp.cpp
@@ -477,6 +502,7 @@ set(viewer_SOURCE_FILES
llvectorperfoptions.cpp
llversioninfo.cpp
llviewchildren.cpp
+ llviewerassetstats.cpp
llviewerassetstorage.cpp
llviewerassettype.cpp
llviewerattachmenu.cpp
@@ -522,6 +548,7 @@ set(viewer_SOURCE_FILES
llviewerregion.cpp
llviewershadermgr.cpp
llviewerstats.cpp
+ llviewerstatsrecorder.cpp
llviewertexteditor.cpp
llviewertexture.cpp
llviewertextureanim.cpp
@@ -539,6 +566,7 @@ set(viewer_SOURCE_FILES
llvoclouds.cpp
llvograss.cpp
llvoground.cpp
+ llvoicecallhandler.cpp
llvoicechannel.cpp
llvoiceclient.cpp
llvoicevisualizer.cpp
@@ -597,6 +625,7 @@ endif (LINUX)
set(viewer_HEADER_FILES
CMakeLists.txt
ViewerInstall.cmake
+ groupchatlistener.h
llagent.h
llagentaccess.h
llagentcamera.h
@@ -675,6 +704,7 @@ set(viewer_HEADER_FILES
lleventnotifier.h
lleventpoll.h
llexpandabletextbox.h
+ llexternaleditor.h
llface.h
llfasttimerview.h
llfavoritesbar.h
@@ -723,6 +753,8 @@ set(viewer_HEADER_FILES
llfloatermediabrowser.h
llfloatermediasettings.h
llfloatermemleak.h
+ llfloatermodelpreview.h
+ llfloatermodelwizard.h
llfloaternamedesc.h
llfloaternotificationsconsole.h
llfloateropenobject.h
@@ -732,6 +764,7 @@ set(viewer_HEADER_FILES
llfloaterpostprocess.h
llfloaterpreference.h
llfloaterproperties.h
+ llfloaterregiondebugconsole.h
llfloaterregioninfo.h
llfloaterreporter.h
llfloaterscriptdebug.h
@@ -741,6 +774,7 @@ set(viewer_HEADER_FILES
llfloatersettingsdebug.h
llfloatersidetraytab.h
llfloatersnapshot.h
+ llfloatersounddevices.h
llfloatertelehub.h
llfloatertestinspectors.h
llfloatertestlistview.h
@@ -751,6 +785,7 @@ set(viewer_HEADER_FILES
llfloaterurlentry.h
llfloatervoiceeffect.h
llfloaterwater.h
+ llfloaterwebcontent.h
llfloaterwhitelistentry.h
llfloaterwindlight.h
llfloaterwindowsize.h
@@ -773,6 +808,7 @@ set(viewer_HEADER_FILES
llhudeffectlookat.h
llhudeffectpointat.h
llhudeffecttrail.h
+ llhudeffectblob.h
llhudicon.h
llhudmanager.h
llhudnametag.h
@@ -814,6 +850,7 @@ set(viewer_HEADER_FILES
llloginhandler.h
lllogininstance.h
llmachineid.h
+ llmainlooprepeater.h
llmanip.h
llmaniprotate.h
llmanipscale.h
@@ -822,7 +859,7 @@ set(viewer_HEADER_FILES
llmediadataclient.h
llmemoryview.h
llmenucommands.h
- llmetricperformancetester.h
+ llmeshrepository.h
llmimetypes.h
llmorphview.h
llmoveview.h
@@ -899,6 +936,8 @@ set(viewer_HEADER_FILES
llparcelselection.h
llparticipantlist.h
llpatchvertexarray.h
+ llphysicsmotion.h
+ llphysicsshapebuilderutil.h
llplacesinventorybridge.h
llplacesinventorypanel.h
llpolymesh.h
@@ -920,9 +959,11 @@ set(viewer_HEADER_FILES
llrootview.h
llsavedsettingsglue.h
llsaveoutfitcombobtn.h
+ llsceneview.h
llscreenchannel.h
llscriptfloater.h
llscrollingpanelparam.h
+ llscrollingpanelparambase.h
llsearchcombobox.h
llsearchhistory.h
llsecapi.h
@@ -934,6 +975,7 @@ set(viewer_HEADER_FILES
llsidepaneliteminfo.h
llsidepaneltaskinfo.h
llsidetray.h
+ llsidetraylistener.h
llsidetraypanelcontainer.h
llsky.h
llslurl.h
@@ -973,6 +1015,7 @@ set(viewer_HEADER_FILES
lltoastimpanel.h
lltoastnotifypanel.h
lltoastpanel.h
+ lltoastscripttextbox.h
lltool.h
lltoolbrush.h
lltoolcomp.h
@@ -1007,6 +1050,7 @@ set(viewer_HEADER_FILES
llvectorperfoptions.h
llversioninfo.h
llviewchildren.h
+ llviewerassetstats.h
llviewerassetstorage.h
llviewerassettype.h
llviewerattachmenu.h
@@ -1049,6 +1093,7 @@ set(viewer_HEADER_FILES
llviewerregion.h
llviewershadermgr.h
llviewerstats.h
+ llviewerstatsrecorder.h
llviewertexteditor.h
llviewertexture.h
llviewertextureanim.h
@@ -1273,8 +1318,6 @@ if (WINDOWS)
if (INTEL_MEMOPS_LIBRARY)
list(APPEND viewer_LIBRARIES ${INTEL_MEMOPS_LIBRARY})
endif (INTEL_MEMOPS_LIBRARY)
-
- use_prebuilt_binary(dbghelp)
endif (WINDOWS)
# Add the xui files. This is handy for searching for xui elements
@@ -1282,22 +1325,20 @@ endif (WINDOWS)
set(viewer_XUI_FILES
skins/default/colors.xml
skins/default/textures/textures.xml
+ skins/minimal/colors.xml
+ skins/minimal/textures/textures.xml
)
file(GLOB DEFAULT_XUI_FILE_GLOB_LIST
- ${CMAKE_CURRENT_SOURCE_DIR}/skins/default/xui/en/*.xml)
+ ${CMAKE_CURRENT_SOURCE_DIR}/skins/*/xui/en/*.xml)
list(APPEND viewer_XUI_FILES ${DEFAULT_XUI_FILE_GLOB_LIST})
file(GLOB DEFAULT_WIDGET_FILE_GLOB_LIST
- ${CMAKE_CURRENT_SOURCE_DIR}/skins/default/xui/en/widgets/*.xml)
+ ${CMAKE_CURRENT_SOURCE_DIR}/skins/*/xui/en/widgets/*.xml)
list(APPEND viewer_XUI_FILES ${DEFAULT_WIDGET_FILE_GLOB_LIST})
-file(GLOB SILVER_XUI_FILE_GLOB_LIST
- ${CMAKE_CURRENT_SOURCE_DIR}/skins/silver/xui/en-us/*.xml)
-list(APPEND viewer_XUI_FILES ${SILVER_XUI_FILE_GLOB_LIST})
-
# Cannot append empty lists in CMake, wait until we have files here.
#file(GLOB SILVER_WIDGET_FILE_GLOB_LIST
# ${CMAKE_CURRENT_SOURCE_DIR}/skins/silver/xui/en-us/widgets/*.xml)
@@ -1318,7 +1359,7 @@ set(viewer_APPSETTINGS_FILES
app_settings/grass.xml
app_settings/high_graphics.xml
app_settings/ignorable_dialogs.xml
- app_settings/keys.ini
+ app_settings/keys.xml
app_settings/keywords.ini
app_settings/logcontrol.xml
app_settings/low_graphics.xml
@@ -1327,6 +1368,7 @@ set(viewer_APPSETTINGS_FILES
app_settings/settings_crash_behavior.xml
app_settings/settings_files.xml
app_settings/settings_per_account.xml
+ app_settings/settings_minimal.xml
app_settings/std_bump.ini
app_settings/trees.xml
app_settings/ultra_graphics.xml
@@ -1417,19 +1459,13 @@ set(PACKAGE ON CACHE BOOL
"Add a package target that builds an installer package.")
if (WINDOWS)
- if(MSVC71)
- set(release_flags "/MAP:Release/${VIEWER_BINARY_NAME}.map /MAPINFO:LINES")
- else(MSVC71)
- set(release_flags "/MAP:Release/${VIEWER_BINARY_NAME}.map")
- endif(MSVC71)
-
- set_target_properties(${VIEWER_BINARY_NAME}
+ set_target_properties(${VIEWER_BINARY_NAME}
PROPERTIES
# *TODO -reenable this once we get server usage sorted out
#LINK_FLAGS "/debug /NODEFAULTLIB:LIBCMT /SUBSYSTEM:WINDOWS /INCLUDE:\"__tcmalloc\""
- LINK_FLAGS "/debug /NODEFAULTLIB:LIBCMT /SUBSYSTEM:WINDOWS"
+ LINK_FLAGS "/debug /NODEFAULTLIB:LIBCMT /SUBSYSTEM:WINDOWS /INCLUDE:__tcmalloc"
LINK_FLAGS_DEBUG "/NODEFAULTLIB:\"LIBCMT;LIBCMTD;MSVCRT\" /INCREMENTAL:NO"
- LINK_FLAGS_RELEASE ${release_flags}
+ LINK_FLAGS_RELEASE ""
)
if(USE_PRECOMPILED_HEADERS)
set_target_properties(
@@ -1446,11 +1482,6 @@ if (WINDOWS)
# In the meantime, if you have any ideas on how to easily maintain one list, either here or in viewer_manifest.py
# and have the build deps get tracked *please* tell me about it.
- if(LLKDU_LIBRARY)
- # Configure a var for llkdu which may not exist for all builds.
- set(LLKDU_DLL_SOURCE ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/llkdu.dll)
- endif(LLKDU_LIBRARY)
-
if(USE_GOOGLE_PERFTOOLS)
# Configure a var for tcmalloc location, if used.
# Note the need to specify multiple names explicitly.
@@ -1467,26 +1498,28 @@ if (WINDOWS)
#${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/libtcmalloc_minimal.dll => None ... Skipping libtcmalloc_minimal.dll
${CMAKE_SOURCE_DIR}/../etc/message.xml
${CMAKE_SOURCE_DIR}/../scripts/messages/message_template.msg
- ${LLKDU_DLL_SOURCE}
${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/llcommon.dll
${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/libapr-1.dll
${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/libaprutil-1.dll
${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/libapriconv-1.dll
+ ${SHARED_LIB_STAGING_DIR}/Release/glod.dll
+ ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/glod.dll
+ ${SHARED_LIB_STAGING_DIR}/Debug/glod.dll
+ ${SHARED_LIB_STAGING_DIR}/Release/libcollada14dom22.dll
+ ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/libcollada14dom22.dll
+ ${SHARED_LIB_STAGING_DIR}/Debug/libcollada14dom22-d.dll
${SHARED_LIB_STAGING_DIR}/Release/openjpeg.dll
${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/openjpeg.dll
${SHARED_LIB_STAGING_DIR}/Debug/openjpegd.dll
${SHARED_LIB_STAGING_DIR}/Release/fmod.dll
${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/fmod.dll
${SHARED_LIB_STAGING_DIR}/Debug/fmod.dll
- ${SHARED_LIB_STAGING_DIR}/Release/msvcr80.dll
- ${SHARED_LIB_STAGING_DIR}/Release/msvcp80.dll
- ${SHARED_LIB_STAGING_DIR}/Release/Microsoft.VC80.CRT.manifest
- ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/msvcr80.dll
- ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/msvcp80.dll
- ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/Microsoft.VC80.CRT.manifest
- ${SHARED_LIB_STAGING_DIR}/Debug/msvcr80d.dll
- ${SHARED_LIB_STAGING_DIR}/Debug/msvcp80d.dll
- ${SHARED_LIB_STAGING_DIR}/Debug/Microsoft.VC80.DebugCRT.manifest
+ ${SHARED_LIB_STAGING_DIR}/Release/msvcr100.dll
+ ${SHARED_LIB_STAGING_DIR}/Release/msvcp100.dll
+ ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/msvcr100.dll
+ ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/msvcp100.dll
+ ${SHARED_LIB_STAGING_DIR}/Debug/msvcr100d.dll
+ ${SHARED_LIB_STAGING_DIR}/Debug/msvcp100d.dll
${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/SLVoice.exe
${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/vivoxsdk.dll
${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/ortp.dll
@@ -1498,7 +1531,6 @@ if (WINDOWS)
${CMAKE_CURRENT_SOURCE_DIR}/licenses-win32.txt
${CMAKE_CURRENT_SOURCE_DIR}/featuretable.txt
${CMAKE_CURRENT_SOURCE_DIR}/featuretable_xp.txt
- ${CMAKE_CURRENT_SOURCE_DIR}/dbghelp.dll
${ARCH_PREBUILT_DIRS_RELEASE}/libeay32.dll
${ARCH_PREBUILT_DIRS_RELEASE}/qtcore4.dll
${ARCH_PREBUILT_DIRS_RELEASE}/qtgui4.dll
@@ -1637,16 +1669,21 @@ if (WINDOWS)
# sorted out on the parabuild cluster...
#${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/event_host.tar.bz2)
- check_message_template(package)
-
endif (PACKAGE)
endif (WINDOWS)
+# *NOTE - this list is very sensitive to ordering, test carefully on all
+# platforms if you change the releative order of the entries here.
+# In particular, cmake 2.6.4 (when buidling with linux/makefile generators)
+# appears to sometimes de-duplicate redundantly listed dependencies improperly.
+# To work around this, higher level modules should be listed before the modules
+# that they depend upon. -brad
target_link_libraries(${VIEWER_BINARY_NAME}
+ ${UPDATER_LIBRARIES}
+ ${GOOGLE_PERFTOOLS_LIBRARIES}
${LLAUDIO_LIBRARIES}
${LLCHARACTER_LIBRARIES}
${LLIMAGE_LIBRARIES}
- ${LLIMAGEJ2COJ_LIBRARIES}
${LLINVENTORY_LIBRARIES}
${LLMESSAGE_LIBRARIES}
${LLPLUGIN_LIBRARIES}
@@ -1668,20 +1705,33 @@ target_link_libraries(${VIEWER_BINARY_NAME}
${DBUSGLIB_LIBRARIES}
${OPENGL_LIBRARIES}
${FMODWRAPPER_LIBRARY} # must come after LLAudio
+ ${GLOD_LIBRARIES}
${OPENGL_LIBRARIES}
${JSONCPP_LIBRARIES}
${SDL_LIBRARY}
${SMARTHEAP_LIBRARY}
${UI_LIBRARIES}
${WINDOWS_LIBRARIES}
+ ${EXPAT_LIBRARIES}
${XMLRPCEPI_LIBRARIES}
- ${ELFIO_LIBRARIES}
${OPENSSL_LIBRARIES}
${CRYPTO_LIBRARIES}
${LLLOGIN_LIBRARIES}
- ${GOOGLE_PERFTOOLS_LIBRARIES}
+ ${LLCONVEXDECOMP_LIBRARY}
+ ${TCMALLOC_LIBRARIES}
)
+if (USE_KDU)
+ target_link_libraries(${VIEWER_BINARY_NAME}
+ ${LLKDU_LIBRARIES}
+ ${KDU_LIBRARY}
+ )
+else (USE_KDU)
+ target_link_libraries(${VIEWER_BINARY_NAME}
+ ${LLIMAGEJ2COJ_LIBRARIES}
+ )
+endif (USE_KDU)
+
build_version(viewer)
set(ARTWORK_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE PATH
@@ -1691,6 +1741,17 @@ set(ARTWORK_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE PATH
if (LINUX)
set(product SecondLife-${ARCH}-${viewer_VERSION})
+ # These are the generated targets that are copied to package/
+ set(COPY_INPUT_DEPENDENCIES
+ ${VIEWER_BINARY_NAME}
+ linux-crash-logger
+ linux-updater
+ SLPlugin
+ media_plugin_webkit
+ media_plugin_gstreamer010
+ llcommon
+ )
+
add_custom_command(
OUTPUT ${product}.tar.bz2
COMMAND ${PYTHON_EXECUTABLE}
@@ -1708,18 +1769,13 @@ if (LINUX)
--login_channel=${VIEWER_LOGIN_CHANNEL}
--source=${CMAKE_CURRENT_SOURCE_DIR}
--touch=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/.${product}.touched
- DEPENDS ${VIEWER_BINARY_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py
+ DEPENDS
+ ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py
+ ${COPY_INPUT_DEPENDENCIES}
)
- add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_gstreamer010 media_plugin_webkit)
-
if (PACKAGE)
- add_custom_target(package ALL DEPENDS ${product}.tar.bz2)
- add_dependencies(package linux-crash-logger-target)
- add_dependencies(package linux-updater-target)
- check_message_template(package)
endif (PACKAGE)
-
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/.${product}.copy_touched
COMMAND ${PYTHON_EXECUTABLE}
@@ -1741,7 +1797,13 @@ if (LINUX)
)
add_custom_target(copy_l_viewer_manifest ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/.${product}.copy_touched)
- add_dependencies(copy_l_viewer_manifest "${VIEWER_BINARY_NAME}" linux-crash-logger-target linux-updater-target)
+
+ if (PACKAGE)
+ add_custom_target(package ALL DEPENDS ${product}.tar.bz2)
+ # Make sure we don't run two instances of viewer_manifest.py at the same time.
+ add_dependencies(package copy_l_viewer_manifest)
+ check_message_template(package)
+ endif (PACKAGE)
endif (LINUX)
if (DARWIN)
@@ -1780,7 +1842,6 @@ if (DARWIN)
if (PACKAGE)
add_custom_target(package ALL DEPENDS ${VIEWER_BINARY_NAME})
- check_message_template(package)
add_custom_command(
TARGET package POST_BUILD
@@ -1811,7 +1872,9 @@ if (PACKAGE)
if (WINDOWS)
set(VIEWER_DIST_DIR "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}")
set(VIEWER_SYMBOL_FILE "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/secondlife-symbols-windows.tar.bz2")
- set(VIEWER_EXE_GLOBS "${VIEWER_BINARY_NAME}${CMAKE_EXECUTABLE_SUFFIX} slplugin.exe")
+ # slplugin.exe failing symbols dump - need to debug, might have to do with updated version of google breakpad
+ # set(VIEWER_EXE_GLOBS "${VIEWER_BINARY_NAME}${CMAKE_EXECUTABLE_SUFFIX} slplugin.exe")
+ set(VIEWER_EXE_GLOBS "${VIEWER_BINARY_NAME}${CMAKE_EXECUTABLE_SUFFIX}")
set(VIEWER_LIB_GLOB "*${CMAKE_SHARED_MODULE_SUFFIX}")
set(VIEWER_COPY_MANIFEST copy_w_viewer_manifest)
endif (WINDOWS)
@@ -1829,21 +1892,31 @@ if (PACKAGE)
set(VIEWER_COPY_MANIFEST copy_l_viewer_manifest)
endif (LINUX)
+ if(RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING)
+ if(CMAKE_CFG_INTDIR STREQUAL ".")
+ set(LLBUILD_CONFIG ${CMAKE_BUILD_TYPE})
+ else(CMAKE_CFG_INTDIR STREQUAL ".")
+ # set LLBUILD_CONFIG to be a shell variable evaluated at build time
+ # reflecting the configuration we are currently building.
+ set(LLBUILD_CONFIG ${CMAKE_CFG_INTDIR})
+ endif(CMAKE_CFG_INTDIR STREQUAL ".")
add_custom_command(OUTPUT "${VIEWER_SYMBOL_FILE}"
COMMAND "${PYTHON_EXECUTABLE}"
ARGS
"${CMAKE_CURRENT_SOURCE_DIR}/generate_breakpad_symbols.py"
+ "${LLBUILD_CONFIG}"
"${VIEWER_DIST_DIR}"
"${VIEWER_EXE_GLOBS}"
"${VIEWER_LIB_GLOB}"
- "${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/bin/dump_syms"
+ "${AUTOBUILD_INSTALL_DIR}/bin/dump_syms"
"${VIEWER_SYMBOL_FILE}"
DEPENDS generate_breakpad_symbols.py
- VERBATIM
- )
- add_custom_target(generate_breakpad_symbols ALL DEPENDS "${VIEWER_SYMBOL_FILE}")
+ VERBATIM)
+
+ add_custom_target(generate_breakpad_symbols DEPENDS "${VIEWER_SYMBOL_FILE}")
add_dependencies(generate_breakpad_symbols "${VIEWER_BINARY_NAME}" "${VIEWER_COPY_MANIFEST}")
add_dependencies(package generate_breakpad_symbols)
+ endif(RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING)
endif (PACKAGE)
if (LL_TESTS)
@@ -1855,7 +1928,11 @@ if (LL_TESTS)
lldateutil.cpp
llmediadataclient.cpp
lllogininstance.cpp
+ llremoteparcelrequest.cpp
llviewerhelputil.cpp
+ llversioninfo.cpp
+ llworldmap.cpp
+ llworldmipmap.cpp
)
##################################################
@@ -1931,14 +2008,23 @@ if (LL_TESTS)
"${test_libs}"
)
+ LL_ADD_INTEGRATION_TEST(llsimplestat
+ ""
+ "${test_libs}"
+ )
+
+ LL_ADD_INTEGRATION_TEST(llviewerassetstats
+ llviewerassetstats.cpp
+ "${test_libs}"
+ )
+
#ADD_VIEWER_BUILD_TEST(llmemoryview viewer)
#ADD_VIEWER_BUILD_TEST(llagentaccess viewer)
- #ADD_VIEWER_BUILD_TEST(llworldmap viewer)
- #ADD_VIEWER_BUILD_TEST(llworldmipmap viewer)
#ADD_VIEWER_BUILD_TEST(lltextureinfo viewer)
#ADD_VIEWER_BUILD_TEST(lltextureinfodetails viewer)
#ADD_VIEWER_BUILD_TEST(lltexturestatsuploader viewer)
endif (LL_TESTS)
+check_message_template(${VIEWER_BINARY_NAME})
diff --git a/indra/newview/English.lproj/InfoPlist.strings b/indra/newview/English.lproj/InfoPlist.strings
index 4bf67b1367..5c7cacedec 100644
--- a/indra/newview/English.lproj/InfoPlist.strings
+++ b/indra/newview/English.lproj/InfoPlist.strings
@@ -2,6 +2,6 @@
CFBundleName = "Second Life";
-CFBundleShortVersionString = "Second Life version 2.1.1.0";
-CFBundleGetInfoString = "Second Life version 2.1.1.0, Copyright 2004-2010 Linden Research, Inc.";
+CFBundleShortVersionString = "Second Life version 2.1.0.13828";
+CFBundleGetInfoString = "Second Life version 2.1.0.13828, Copyright 2004-2009 Linden Research, Inc.";
diff --git a/indra/newview/Info-SecondLife.plist b/indra/newview/Info-SecondLife.plist
index 3cda7467dd..f7b11b217c 100644
--- a/indra/newview/Info-SecondLife.plist
+++ b/indra/newview/Info-SecondLife.plist
@@ -60,7 +60,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
- <string>2.1.1.0</string>
+ <string>2.1.0.13828</string>
<key>CSResourcesFileMapped</key>
<true/>
</dict>
diff --git a/indra/newview/app_settings/CA.pem b/indra/newview/app_settings/CA.pem
index 11825bf906..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
------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
------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
+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-----
+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-----
+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
diff --git a/indra/newview/app_settings/cmd_line.xml b/indra/newview/app_settings/cmd_line.xml
index 00d69f805e..89e5949fbe 100644
--- a/indra/newview/app_settings/cmd_line.xml
+++ b/indra/newview/app_settings/cmd_line.xml
@@ -118,6 +118,8 @@
<map>
<key>desc</key>
<string>Log metrics for benchmarking</string>
+ <key>count</key>
+ <integer>1</integer>
<key>map-to</key>
<string>LogMetrics</string>
</map>
@@ -259,6 +261,24 @@
<!-- Special case. Mapped to settings procedurally. -->
</map>
+ <key>sessionsettings</key>
+ <map>
+ <key>desc</key>
+ <string>Specify the filename of a configuration file that contains temporary per-session configuration overrides.</string>
+ <key>count</key>
+ <integer>1</integer>
+ <!-- Special case. Mapped to settings procedurally. -->
+ </map>
+
+ <key>usersessionsettings</key>
+ <map>
+ <key>desc</key>
+ <string>Specify the filename of a configuration file that contains temporary per-session configuration user overrides.</string>
+ <key>count</key>
+ <integer>1</integer>
+ <!-- Special case. Mapped to settings procedurally. -->
+ </map>
+
<key>login</key>
<map>
<key>desc</key>
@@ -361,8 +381,7 @@
<map>
<key>count</key>
<integer>1</integer>
- <key>map-to</key>
- <string>VersionChannelName</string>
+ <!-- Special case. Not mapped to a setting. -->
</map>
<key>loginpage</key>
@@ -391,5 +410,12 @@
<string>CrashOnStartup</string>
</map>
+ <key>disablecrashlogger</key>
+ <map>
+ <key>desc</key>
+ <string>Disables the crash logger and lets the OS handle crashes</string>
+ <key>map-to</key>
+ <string>DisableCrashLogger</string>
+ </map>
</map>
</llsd>
diff --git a/indra/newview/app_settings/high_graphics.xml b/indra/newview/app_settings/high_graphics.xml
index 4da2b0fd00..5bc2e1b7e6 100644
--- a/indra/newview/app_settings/high_graphics.xml
+++ b/indra/newview/app_settings/high_graphics.xml
@@ -4,13 +4,15 @@
<RenderAvatarCloth value="FALSE"/>
<!--Default for now-->
<RenderAvatarLODFactor value="1.0"/>
+ <!--Default for now-->
+ <RenderAvatarPhysicsLODFactor value="0.9"/>
<!--NO SHADERS-->
<RenderAvatarVP value="TRUE"/>
<!--Short Range-->
<RenderFarClip value="128"/>
<!--Default for now-->
<RenderFlexTimeFactor value="1"/>
- <!--256... but they don't use this-->
+ <!--256... but they do not use this-->
<RenderGlowResolutionPow value="9"/>
<!--Low number-->
<RenderMaxPartCount value="4096"/>
@@ -24,8 +26,6 @@
<RenderTerrainLODFactor value="2"/>
<!--Default for now-->
<RenderTreeLODFactor value="0.5"/>
- <!--Default for now-->
- <RenderUseFBO value="1"/>
<!--Try Impostors-->
<RenderUseImpostors value="TRUE"/>
<!--Default for now-->
@@ -34,11 +34,10 @@
<VertexShaderEnable value="TRUE"/>
<!--NO SHADERS-->
<WindLightUseAtmosShaders value="TRUE"/>
- <!--Deferred Shading-->
- <RenderDeferred value="FALSE"/>
- <!--SSAO Disabled-->
- <RenderDeferredSSAO value="FALSE"/>
- <!--Sun Shadows-->
- <RenderShadowDetail value="0"/>
-
+ <!--Deferred Shading-->
+ <RenderDeferred value="FALSE"/>
+ <!--SSAO Disabled-->
+ <RenderDeferredSSAO value="FALSE"/>
+ <!--Sun Shadows-->
+ <RenderShadowDetail value="0"/>
</settings>
diff --git a/indra/newview/app_settings/ignorable_dialogs.xml b/indra/newview/app_settings/ignorable_dialogs.xml
index 9ddf007ce7..17d3d3c9c5 100644
--- a/indra/newview/app_settings/ignorable_dialogs.xml
+++ b/indra/newview/app_settings/ignorable_dialogs.xml
@@ -23,6 +23,17 @@
<key>Value</key>
<integer>1</integer>
</map>
+ <key>FirstNotUseAvatarPicker</key>
+ <map>
+ <key>Comment</key>
+ <string>Shows hint when resident doesn't activate avatar picker</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
<key>FirstNotUseSidePanel</key>
<map>
<key>Comment</key>
@@ -56,6 +67,17 @@
<key>Value</key>
<integer>1</integer>
</map>
+ <key>FirstViewPopup</key>
+ <map>
+ <key>Comment</key>
+ <string>Shows hint when resident opens view popup</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
<key>FirstReceiveLindens</key>
<map>
<key>Comment</key>
@@ -100,7 +122,17 @@
<key>Value</key>
<integer>1</integer>
</map>
-
+ <key>FirstSpeak</key>
+ <map>
+ <key>Comment</key>
+ <string>Shows hint for Speak button</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
<key>FirstSit</key>
<map>
<key>Comment</key>
diff --git a/indra/newview/app_settings/keys.ini b/indra/newview/app_settings/keys.ini
deleted file mode 100644
index b79e5bf508..0000000000
--- a/indra/newview/app_settings/keys.ini
+++ /dev/null
@@ -1,357 +0,0 @@
-# keys.ini
-#
-# keyboard binding initialization
-#
-# comments must have # in the first column
-# blank lines OK
-#
-# Format:
-# mode key mask function
-#
-# mode must be one of FIRST_PERSON, THIRD_PERSON, EDIT, EDIT_AVATAR, or CONVERSATION
-# key must be upper case, or SPACE, HOME, END, PGUP, PGDN, LEFT, RIGHT, UP, DOWN,
-# or one of ,.;'[]
-# mask must be NONE, SHIFT, ALT, ALT_SHIFT.
-# Control is reserved for user commands.
-# function must be a function named in llkeyboard.cpp
-
-FIRST_PERSON A NONE slide_left
-FIRST_PERSON D NONE slide_right
-FIRST_PERSON W NONE push_forward
-FIRST_PERSON S NONE push_backward
-FIRST_PERSON E NONE jump
-FIRST_PERSON C NONE push_down
-FIRST_PERSON F NONE toggle_fly
-
-FIRST_PERSON LEFT NONE slide_left
-FIRST_PERSON RIGHT NONE slide_right
-FIRST_PERSON UP NONE push_forward
-FIRST_PERSON DOWN NONE push_backward
-FIRST_PERSON PGUP NONE jump
-FIRST_PERSON PGDN NONE push_down
-FIRST_PERSON HOME NONE toggle_fly
-
-FIRST_PERSON PAD_LEFT NONE slide_left
-FIRST_PERSON PAD_RIGHT NONE slide_right
-FIRST_PERSON PAD_UP NONE push_forward
-FIRST_PERSON PAD_DOWN NONE push_backward
-FIRST_PERSON PAD_PGUP NONE jump
-FIRST_PERSON PAD_PGDN NONE push_down
-FIRST_PERSON PAD_HOME NONE toggle_fly
-FIRST_PERSON PAD_CENTER NONE stop_moving
-FIRST_PERSON PAD_ENTER NONE start_chat
-FIRST_PERSON PAD_DIVIDE NONE start_gesture
-
-FIRST_PERSON A SHIFT slide_left
-FIRST_PERSON D SHIFT slide_right
-FIRST_PERSON W SHIFT push_forward
-FIRST_PERSON S SHIFT push_backward
-FIRST_PERSON E SHIFT jump
-FIRST_PERSON C SHIFT push_down
-FIRST_PERSON F SHIFT toggle_fly
-
-FIRST_PERSON SPACE NONE stop_moving
-FIRST_PERSON ENTER NONE start_chat
-FIRST_PERSON DIVIDE NONE start_gesture
-
-FIRST_PERSON LEFT SHIFT slide_left
-FIRST_PERSON RIGHT SHIFT slide_right
-FIRST_PERSON UP SHIFT push_forward
-FIRST_PERSON DOWN SHIFT push_backward
-FIRST_PERSON PGUP SHIFT jump
-FIRST_PERSON PGDN SHIFT push_down
-
-FIRST_PERSON PAD_LEFT SHIFT slide_left
-FIRST_PERSON PAD_RIGHT SHIFT slide_right
-FIRST_PERSON PAD_UP SHIFT push_forward
-FIRST_PERSON PAD_DOWN SHIFT push_backward
-FIRST_PERSON PAD_PGUP SHIFT jump
-FIRST_PERSON PAD_PGDN SHIFT push_down
-FIRST_PERSON PAD_HOME SHIFT toggle_fly
-FIRST_PERSON PAD_ENTER SHIFT start_chat
-FIRST_PERSON PAD_DIVIDE SHIFT start_gesture
-
-THIRD_PERSON A NONE turn_left
-THIRD_PERSON D NONE turn_right
-THIRD_PERSON A SHIFT slide_left
-THIRD_PERSON D SHIFT slide_right
-THIRD_PERSON W NONE push_forward
-THIRD_PERSON S NONE push_backward
-THIRD_PERSON W SHIFT push_forward
-THIRD_PERSON S SHIFT push_backward
-THIRD_PERSON E NONE jump
-THIRD_PERSON C NONE push_down
-THIRD_PERSON E SHIFT jump
-THIRD_PERSON C SHIFT push_down
-
-THIRD_PERSON F NONE toggle_fly
-THIRD_PERSON F SHIFT toggle_fly
-
-THIRD_PERSON SPACE NONE stop_moving
-THIRD_PERSON ENTER NONE start_chat
-THIRD_PERSON DIVIDE NONE start_gesture
-
-THIRD_PERSON LEFT NONE turn_left
-THIRD_PERSON LEFT SHIFT slide_left
-THIRD_PERSON RIGHT NONE turn_right
-THIRD_PERSON RIGHT SHIFT slide_right
-THIRD_PERSON UP NONE push_forward
-THIRD_PERSON DOWN NONE push_backward
-THIRD_PERSON UP SHIFT push_forward
-THIRD_PERSON DOWN SHIFT push_backward
-THIRD_PERSON PGUP NONE jump
-THIRD_PERSON PGDN NONE push_down
-THIRD_PERSON PGUP SHIFT jump
-THIRD_PERSON PGDN SHIFT push_down
-THIRD_PERSON HOME SHIFT toggle_fly
-THIRD_PERSON HOME NONE toggle_fly
-
-THIRD_PERSON PAD_LEFT NONE turn_left
-THIRD_PERSON PAD_LEFT SHIFT slide_left
-THIRD_PERSON PAD_RIGHT NONE turn_right
-THIRD_PERSON PAD_RIGHT SHIFT slide_right
-THIRD_PERSON PAD_UP NONE push_forward
-THIRD_PERSON PAD_DOWN NONE push_backward
-THIRD_PERSON PAD_UP SHIFT push_forward
-THIRD_PERSON PAD_DOWN SHIFT push_backward
-THIRD_PERSON PAD_PGUP NONE jump
-THIRD_PERSON PAD_PGDN NONE push_down
-THIRD_PERSON PAD_PGUP SHIFT jump
-THIRD_PERSON PAD_PGDN SHIFT push_down
-THIRD_PERSON PAD_HOME NONE toggle_fly
-THIRD_PERSON PAD_HOME SHIFT toggle_fly
-THIRD_PERSON PAD_CENTER NONE stop_moving
-THIRD_PERSON PAD_CENTER SHIFT stop_moving
-THIRD_PERSON PAD_ENTER NONE start_chat
-THIRD_PERSON PAD_ENTER SHIFT start_chat
-THIRD_PERSON PAD_DIVIDE NONE start_gesture
-THIRD_PERSON PAD_DIVIDE SHIFT start_gesture
-
-# Camera controls in third person on Alt
-THIRD_PERSON LEFT ALT spin_around_cw
-THIRD_PERSON RIGHT ALT spin_around_ccw
-THIRD_PERSON UP ALT move_forward
-THIRD_PERSON DOWN ALT move_backward
-THIRD_PERSON PGUP ALT spin_over
-THIRD_PERSON PGDN ALT spin_under
-
-THIRD_PERSON A ALT spin_around_cw
-THIRD_PERSON D ALT spin_around_ccw
-THIRD_PERSON W ALT move_forward
-THIRD_PERSON S ALT move_backward
-THIRD_PERSON E ALT spin_over
-THIRD_PERSON C ALT spin_under
-
-THIRD_PERSON PAD_LEFT ALT spin_around_cw
-THIRD_PERSON PAD_RIGHT ALT spin_around_ccw
-THIRD_PERSON PAD_UP ALT move_forward
-THIRD_PERSON PAD_DOWN ALT move_backward
-THIRD_PERSON PAD_PGUP ALT spin_over
-THIRD_PERSON PAD_PGDN ALT spin_under
-THIRD_PERSON PAD_ENTER ALT start_chat
-THIRD_PERSON PAD_DIVIDE ALT start_gesture
-
-# mimic alt zoom behavior with keyboard only
-THIRD_PERSON A CTL_ALT spin_around_cw
-THIRD_PERSON D CTL_ALT spin_around_ccw
-THIRD_PERSON W CTL_ALT spin_over
-THIRD_PERSON S CTL_ALT spin_under
-THIRD_PERSON E CTL_ALT spin_over
-THIRD_PERSON C CTL_ALT spin_under
-
-THIRD_PERSON LEFT CTL_ALT spin_around_cw
-THIRD_PERSON RIGHT CTL_ALT spin_around_ccw
-THIRD_PERSON UP CTL_ALT spin_over
-THIRD_PERSON DOWN CTL_ALT spin_under
-THIRD_PERSON PGUP CTL_ALT spin_over
-THIRD_PERSON PGDN CTL_ALT spin_under
-
-THIRD_PERSON PAD_LEFT CTL_ALT spin_around_cw
-THIRD_PERSON PAD_RIGHT CTL_ALT spin_around_ccw
-THIRD_PERSON PAD_UP CTL_ALT spin_over
-THIRD_PERSON PAD_DOWN CTL_ALT spin_under
-THIRD_PERSON PAD_PGUP CTL_ALT spin_over
-THIRD_PERSON PAD_PGDN CTL_ALT spin_under
-THIRD_PERSON PAD_ENTER CTL_ALT start_chat
-THIRD_PERSON PAD_DIVIDE CTL_ALT start_gesture
-
-# Therefore pan on Alt-Shift
-THIRD_PERSON A CTL_ALT_SHIFT pan_left
-THIRD_PERSON D CTL_ALT_SHIFT pan_right
-THIRD_PERSON W CTL_ALT_SHIFT pan_up
-THIRD_PERSON S CTL_ALT_SHIFT pan_down
-
-THIRD_PERSON LEFT CTL_ALT_SHIFT pan_left
-THIRD_PERSON RIGHT CTL_ALT_SHIFT pan_right
-THIRD_PERSON UP CTL_ALT_SHIFT pan_up
-THIRD_PERSON DOWN CTL_ALT_SHIFT pan_down
-
-THIRD_PERSON PAD_LEFT CTL_ALT_SHIFT pan_left
-THIRD_PERSON PAD_RIGHT CTL_ALT_SHIFT pan_right
-THIRD_PERSON PAD_UP CTL_ALT_SHIFT pan_up
-THIRD_PERSON PAD_DOWN CTL_ALT_SHIFT pan_down
-THIRD_PERSON PAD_ENTER CTL_ALT_SHIFT start_chat
-THIRD_PERSON PAD_DIVIDE CTL_ALT_SHIFT start_gesture
-
-# Basic editing camera control
-EDIT A NONE spin_around_cw
-EDIT D NONE spin_around_ccw
-EDIT W NONE move_forward
-EDIT S NONE move_backward
-EDIT E NONE spin_over
-EDIT C NONE spin_under
-EDIT ENTER NONE start_chat
-EDIT DIVIDE NONE start_gesture
-EDIT PAD_ENTER NONE start_chat
-EDIT PAD_DIVIDE NONE start_gesture
-
-EDIT LEFT NONE spin_around_cw
-EDIT RIGHT NONE spin_around_ccw
-EDIT UP NONE move_forward
-EDIT DOWN NONE move_backward
-EDIT PGUP NONE spin_over
-EDIT PGDN NONE spin_under
-
-EDIT A SHIFT pan_left
-EDIT D SHIFT pan_right
-EDIT W SHIFT pan_up
-EDIT S SHIFT pan_down
-
-EDIT LEFT SHIFT pan_left
-EDIT RIGHT SHIFT pan_right
-EDIT UP SHIFT pan_up
-EDIT DOWN SHIFT pan_down
-
-# Walking works with ALT held down.
-EDIT A ALT slide_left
-EDIT D ALT slide_right
-EDIT W ALT push_forward
-EDIT S ALT push_backward
-EDIT E ALT jump
-EDIT C ALT push_down
-
-EDIT LEFT ALT slide_left
-EDIT RIGHT ALT slide_right
-EDIT UP ALT push_forward
-EDIT DOWN ALT push_backward
-EDIT PGUP ALT jump
-EDIT PGDN ALT push_down
-EDIT HOME ALT toggle_fly
-
-EDIT PAD_LEFT ALT slide_left
-EDIT PAD_RIGHT ALT slide_right
-EDIT PAD_UP ALT push_forward
-EDIT PAD_DOWN ALT push_backward
-EDIT PAD_PGUP ALT jump
-EDIT PAD_PGDN ALT push_down
-EDIT PAD_ENTER ALT start_chat
-EDIT PAD_DIVIDE ALT start_gesture
-
-SITTING A ALT spin_around_cw
-SITTING D ALT spin_around_ccw
-SITTING W ALT move_forward
-SITTING S ALT move_backward
-SITTING E ALT spin_over_sitting
-SITTING C ALT spin_under_sitting
-
-SITTING LEFT ALT spin_around_cw
-SITTING RIGHT ALT spin_around_ccw
-SITTING UP ALT move_forward
-SITTING DOWN ALT move_backward
-SITTING PGUP ALT spin_over
-SITTING PGDN ALT spin_under
-
-SITTING A CTL_ALT spin_around_cw
-SITTING D CTL_ALT spin_around_ccw
-SITTING W CTL_ALT spin_over
-SITTING S CTL_ALT spin_under
-SITTING E CTL_ALT spin_over
-SITTING C CTL_ALT spin_under
-
-SITTING LEFT CTL_ALT spin_around_cw
-SITTING RIGHT CTL_ALT spin_around_ccw
-SITTING UP CTL_ALT spin_over
-SITTING DOWN CTL_ALT spin_under
-SITTING PGUP CTL_ALT spin_over
-SITTING PGDN CTL_ALT spin_under
-
-
-SITTING A NONE spin_around_cw_sitting
-SITTING D NONE spin_around_ccw_sitting
-SITTING W NONE move_forward_sitting
-SITTING S NONE move_backward_sitting
-SITTING E NONE spin_over_sitting
-SITTING C NONE spin_under_sitting
-
-SITTING LEFT NONE spin_around_cw_sitting
-SITTING RIGHT NONE spin_around_ccw_sitting
-SITTING UP NONE move_forward_sitting
-SITTING DOWN NONE move_backward_sitting
-SITTING PGUP NONE spin_over_sitting
-SITTING PGDN NONE spin_under_sitting
-
-SITTING PAD_LEFT NONE spin_around_cw_sitting
-SITTING PAD_RIGHT NONE spin_around_ccw_sitting
-SITTING PAD_UP NONE move_forward_sitting
-SITTING PAD_DOWN NONE move_backward_sitting
-SITTING PAD_PGUP NONE spin_over_sitting
-SITTING PAD_PGDN NONE spin_under_sitting
-SITTING PAD_CENTER NONE stop_moving
-SITTING PAD_ENTER NONE start_chat
-SITTING PAD_DIVIDE NONE start_gesture
-
-# these are for passing controls when sitting on vehicles
-SITTING A SHIFT slide_left
-SITTING D SHIFT slide_right
-SITTING LEFT SHIFT slide_left
-SITTING RIGHT SHIFT slide_right
-
-SITTING PAD_LEFT SHIFT slide_left
-SITTING PAD_RIGHT SHIFT slide_right
-SITTING PAD_ENTER SHIFT start_chat
-SITTING PAD_DIVIDE SHIFT start_gesture
-
-# pan on Alt-Shift
-SITTING A CTL_ALT_SHIFT pan_left
-SITTING D CTL_ALT_SHIFT pan_right
-SITTING W CTL_ALT_SHIFT pan_up
-SITTING S CTL_ALT_SHIFT pan_down
-
-SITTING LEFT CTL_ALT_SHIFT pan_left
-SITTING RIGHT CTL_ALT_SHIFT pan_right
-SITTING UP CTL_ALT_SHIFT pan_up
-SITTING DOWN CTL_ALT_SHIFT pan_down
-
-SITTING PAD_LEFT CTL_ALT_SHIFT pan_left
-SITTING PAD_RIGHT CTL_ALT_SHIFT pan_right
-SITTING PAD_UP CTL_ALT_SHIFT pan_up
-SITTING PAD_DOWN CTL_ALT_SHIFT pan_down
-SITTING PAD_ENTER CTL_ALT_SHIFT start_chat
-SITTING PAD_DIVIDE CTL_ALT_SHIFT start_gesture
-
-SITTING ENTER NONE start_chat
-SITTING DIVIDE NONE start_gesture
-
-# Avatar editing camera controls
-EDIT_AVATAR A NONE edit_avatar_spin_cw
-EDIT_AVATAR D NONE edit_avatar_spin_ccw
-EDIT_AVATAR W NONE edit_avatar_move_forward
-EDIT_AVATAR S NONE edit_avatar_move_backward
-EDIT_AVATAR E NONE edit_avatar_spin_over
-EDIT_AVATAR C NONE edit_avatar_spin_under
-EDIT_AVATAR LEFT NONE edit_avatar_spin_cw
-EDIT_AVATAR RIGHT NONE edit_avatar_spin_ccw
-EDIT_AVATAR UP NONE edit_avatar_move_forward
-EDIT_AVATAR DOWN NONE edit_avatar_move_backward
-EDIT_AVATAR PGUP NONE edit_avatar_spin_over
-EDIT_AVATAR PGDN NONE edit_avatar_spin_under
-EDIT_AVATAR ENTER NONE start_chat
-EDIT_AVATAR DIVIDE NONE start_gesture
-EDIT_AVATAR PAD_LEFT NONE edit_avatar_spin_cw
-EDIT_AVATAR PAD_RIGHT NONE edit_avatar_spin_ccw
-EDIT_AVATAR PAD_UP NONE edit_avatar_move_forward
-EDIT_AVATAR PAD_DOWN NONE edit_avatar_move_backward
-EDIT_AVATAR PAD_PGUP NONE edit_avatar_spin_over
-EDIT_AVATAR PAD_PGDN NONE edit_avatar_spin_under
-EDIT_AVATAR PAD_ENTER NONE start_chat
-EDIT_AVATAR PAD_DIVIDE NONE start_gesture
diff --git a/indra/newview/app_settings/keys.xml b/indra/newview/app_settings/keys.xml
new file mode 100644
index 0000000000..d085475c6c
--- /dev/null
+++ b/indra/newview/app_settings/keys.xml
@@ -0,0 +1,350 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<keys>
+ <first_person>
+ <binding key="A" mask="NONE" command="slide_left"/>
+ <binding key="D" mask="NONE" command="slide_right"/>
+ <binding key="W" mask="NONE" command="push_forward"/>
+ <binding key="S" mask="NONE" command="push_backward"/>
+ <binding key="E" mask="NONE" command="jump"/>
+ <binding key="C" mask="NONE" command="push_down"/>
+ <binding key="F" mask="NONE" command="toggle_fly"/>
+
+ <binding key="LEFT" mask="NONE" command="slide_left"/>
+ <binding key="RIGHT" mask="NONE" command="slide_right"/>
+ <binding key="UP" mask="NONE" command="push_forward"/>
+ <binding key="DOWN" mask="NONE" command="push_backward"/>
+ <binding key="PGUP" mask="NONE" command="jump"/>
+ <binding key="PGDN" mask="NONE" command="push_down"/>
+ <binding key="HOME" mask="NONE" command="toggle_fly"/>
+
+ <binding key="PAD_LEFT" mask="NONE" command="slide_left"/>
+ <binding key="PAD_RIGHT" mask="NONE" command="slide_right"/>
+ <binding key="PAD_UP" mask="NONE" command="push_forward"/>
+ <binding key="PAD_DOWN" mask="NONE" command="push_backward"/>
+ <binding key="PAD_PGUP" mask="NONE" command="jump"/>
+ <binding key="PAD_PGDN" mask="NONE" command="push_down"/>
+ <binding key="PAD_HOME" mask="NONE" command="toggle_fly"/>
+ <binding key="PAD_CENTER" mask="NONE" command="stop_moving"/>
+ <binding key="PAD_ENTER" mask="NONE" command="start_chat"/>
+ <binding key="PAD_DIVIDE" mask="NONE" command="start_gesture"/>
+
+ <binding key="A" mask="SHIFT" command="slide_left"/>
+ <binding key="D" mask="SHIFT" command="slide_right"/>
+ <binding key="W" mask="SHIFT" command="push_forward"/>
+ <binding key="S" mask="SHIFT" command="push_backward"/>
+ <binding key="E" mask="SHIFT" command="jump"/>
+ <binding key="C" mask="SHIFT" command="push_down"/>
+ <binding key="F" mask="SHIFT" command="toggle_fly"/>
+
+ <binding key="SPACE" mask="NONE" command="stop_moving"/>
+ <binding key="ENTER" mask="NONE" command="start_chat"/>
+ <binding key="DIVIDE" mask="NONE" command="start_gesture"/>
+
+ <binding key="LEFT" mask="SHIFT" command="slide_left"/>
+ <binding key="RIGHT" mask="SHIFT" command="slide_right"/>
+ <binding key="UP" mask="SHIFT" command="push_forward"/>
+ <binding key="DOWN" mask="SHIFT" command="push_backward"/>
+ <binding key="PGUP" mask="SHIFT" command="jump"/>
+ <binding key="PGDN" mask="SHIFT" command="push_down"/>
+
+ <binding key="PAD_LEFT" mask="SHIFT" command="slide_left"/>
+ <binding key="PAD_RIGHT" mask="SHIFT" command="slide_right"/>
+ <binding key="PAD_UP" mask="SHIFT" command="push_forward"/>
+ <binding key="PAD_DOWN" mask="SHIFT" command="push_backward"/>
+ <binding key="PAD_PGUP" mask="SHIFT" command="jump"/>
+ <binding key="PAD_PGDN" mask="SHIFT" command="push_down"/>
+ <binding key="PAD_HOME" mask="SHIFT" command="toggle_fly"/>
+ <binding key="PAD_ENTER" mask="SHIFT" command="start_chat"/>
+ <binding key="PAD_DIVIDE" mask="SHIFT" command="start_gesture"/>
+ </first_person>
+ <third_person>
+ <binding key="A" mask="NONE" command="turn_left"/>
+ <binding key="D" mask="NONE" command="turn_right"/>
+ <binding key="A" mask="SHIFT" command="slide_left"/>
+ <binding key="D" mask="SHIFT" command="slide_right"/>
+ <binding key="W" mask="NONE" command="push_forward"/>
+ <binding key="S" mask="NONE" command="push_backward"/>
+ <binding key="W" mask="SHIFT" command="push_forward"/>
+ <binding key="S" mask="SHIFT" command="push_backward"/>
+ <binding key="E" mask="NONE" command="jump"/>
+ <binding key="C" mask="NONE" command="push_down"/>
+ <binding key="E" mask="SHIFT" command="jump"/>
+ <binding key="C" mask="SHIFT" command="push_down"/>
+
+ <binding key="F" mask="NONE" command="toggle_fly"/>
+ <binding key="F" mask="SHIFT" command="toggle_fly"/>
+
+ <binding key="SPACE" mask="NONE" command="stop_moving"/>
+ <binding key="ENTER" mask="NONE" command="start_chat"/>
+ <binding key="DIVIDE" mask="NONE" command="start_gesture"/>
+
+ <binding key="LEFT" mask="NONE" command="turn_left"/>
+ <binding key="LEFT" mask="SHIFT" command="slide_left"/>
+ <binding key="RIGHT" mask="NONE" command="turn_right"/>
+ <binding key="RIGHT" mask="SHIFT" command="slide_right"/>
+ <binding key="UP" mask="NONE" command="push_forward"/>
+ <binding key="DOWN" mask="NONE" command="push_backward"/>
+ <binding key="UP" mask="SHIFT" command="push_forward"/>
+ <binding key="DOWN" mask="SHIFT" command="push_backward"/>
+ <binding key="PGUP" mask="NONE" command="jump"/>
+ <binding key="PGDN" mask="NONE" command="push_down"/>
+ <binding key="PGUP" mask="SHIFT" command="jump"/>
+ <binding key="PGDN" mask="SHIFT" command="push_down"/>
+ <binding key="HOME" mask="SHIFT" command="toggle_fly"/>
+ <binding key="HOME" mask="NONE" command="toggle_fly"/>
+
+ <binding key="PAD_LEFT" mask="NONE" command="turn_left"/>
+ <binding key="PAD_LEFT" mask="SHIFT" command="slide_left"/>
+ <binding key="PAD_RIGHT" mask="NONE" command="turn_right"/>
+ <binding key="PAD_RIGHT" mask="SHIFT" command="slide_right"/>
+ <binding key="PAD_UP" mask="NONE" command="push_forward"/>
+ <binding key="PAD_DOWN" mask="NONE" command="push_backward"/>
+ <binding key="PAD_UP" mask="SHIFT" command="push_forward"/>
+ <binding key="PAD_DOWN" mask="SHIFT" command="push_backward"/>
+ <binding key="PAD_PGUP" mask="NONE" command="jump"/>
+ <binding key="PAD_PGDN" mask="NONE" command="push_down"/>
+ <binding key="PAD_PGUP" mask="SHIFT" command="jump"/>
+ <binding key="PAD_PGDN" mask="SHIFT" command="push_down"/>
+ <binding key="PAD_HOME" mask="NONE" command="toggle_fly"/>
+ <binding key="PAD_HOME" mask="SHIFT" command="toggle_fly"/>
+ <binding key="PAD_CENTER" mask="NONE" command="stop_moving"/>
+ <binding key="PAD_CENTER" mask="SHIFT" command="stop_moving"/>
+ <binding key="PAD_ENTER" mask="NONE" command="start_chat"/>
+ <binding key="PAD_ENTER" mask="SHIFT" command="start_chat"/>
+ <binding key="PAD_DIVIDE" mask="NONE" command="start_gesture"/>
+ <binding key="PAD_DIVIDE" mask="SHIFT" command="start_gesture"/>
+
+ <!--Camera controls in third person on Alt-->
+ <binding key="LEFT" mask="ALT" command="spin_around_cw"/>
+ <binding key="RIGHT" mask="ALT" command="spin_around_ccw"/>
+ <binding key="UP" mask="ALT" command="move_forward"/>
+ <binding key="DOWN" mask="ALT" command="move_backward"/>
+ <binding key="PGUP" mask="ALT" command="spin_over"/>
+ <binding key="PGDN" mask="ALT" command="spin_under"/>
+
+ <binding key="A" mask="ALT" command="spin_around_cw"/>
+ <binding key="D" mask="ALT" command="spin_around_ccw"/>
+ <binding key="W" mask="ALT" command="move_forward"/>
+ <binding key="S" mask="ALT" command="move_backward"/>
+ <binding key="E" mask="ALT" command="spin_over"/>
+ <binding key="C" mask="ALT" command="spin_under"/>
+
+ <binding key="PAD_LEFT" mask="ALT" command="spin_around_cw"/>
+ <binding key="PAD_RIGHT" mask="ALT" command="spin_around_ccw"/>
+ <binding key="PAD_UP" mask="ALT" command="move_forward"/>
+ <binding key="PAD_DOWN" mask="ALT" command="move_backward"/>
+ <binding key="PAD_PGUP" mask="ALT" command="spin_over"/>
+ <binding key="PAD_PGDN" mask="ALT" command="spin_under"/>
+ <binding key="PAD_ENTER" mask="ALT" command="start_chat"/>
+ <binding key="PAD_DIVIDE" mask="ALT" command="start_gesture"/>
+
+ <!--mimic alt zoom behavior with keyboard only-->
+ <binding key="A" mask="CTL_ALT" command="spin_around_cw"/>
+ <binding key="D" mask="CTL_ALT" command="spin_around_ccw"/>
+ <binding key="W" mask="CTL_ALT" command="spin_over"/>
+ <binding key="S" mask="CTL_ALT" command="spin_under"/>
+ <binding key="E" mask="CTL_ALT" command="spin_over"/>
+ <binding key="C" mask="CTL_ALT" command="spin_under"/>
+
+ <binding key="LEFT" mask="CTL_ALT" command="spin_around_cw"/>
+ <binding key="RIGHT" mask="CTL_ALT" command="spin_around_ccw"/>
+ <binding key="UP" mask="CTL_ALT" command="spin_over"/>
+ <binding key="DOWN" mask="CTL_ALT" command="spin_under"/>
+ <binding key="PGUP" mask="CTL_ALT" command="spin_over"/>
+ <binding key="PGDN" mask="CTL_ALT" command="spin_under"/>
+
+ <binding key="PAD_LEFT" mask="CTL_ALT" command="spin_around_cw"/>
+ <binding key="PAD_RIGHT" mask="CTL_ALT" command="spin_around_ccw"/>
+ <binding key="PAD_UP" mask="CTL_ALT" command="spin_over"/>
+ <binding key="PAD_DOWN" mask="CTL_ALT" command="spin_under"/>
+ <binding key="PAD_PGUP" mask="CTL_ALT" command="spin_over"/>
+ <binding key="PAD_PGDN" mask="CTL_ALT" command="spin_under"/>
+ <binding key="PAD_ENTER" mask="CTL_ALT" command="start_chat"/>
+ <binding key="PAD_DIVIDE" mask="CTL_ALT" command="start_gesture"/>
+
+ <!--Therefore pan on Alt-Shift-->
+ <binding key="A" mask="CTL_ALT_SHIFT" command="pan_left"/>
+ <binding key="D" mask="CTL_ALT_SHIFT" command="pan_right"/>
+ <binding key="W" mask="CTL_ALT_SHIFT" command="pan_up"/>
+ <binding key="S" mask="CTL_ALT_SHIFT" command="pan_down"/>
+
+ <binding key="LEFT" mask="CTL_ALT_SHIFT" command="pan_left"/>
+ <binding key="RIGHT" mask="CTL_ALT_SHIFT" command="pan_right"/>
+ <binding key="UP" mask="CTL_ALT_SHIFT" command="pan_up"/>
+ <binding key="DOWN" mask="CTL_ALT_SHIFT" command="pan_down"/>
+
+ <binding key="PAD_LEFT" mask="CTL_ALT_SHIFT" command="pan_left"/>
+ <binding key="PAD_RIGHT" mask="CTL_ALT_SHIFT" command="pan_right"/>
+ <binding key="PAD_UP" mask="CTL_ALT_SHIFT" command="pan_up"/>
+ <binding key="PAD_DOWN" mask="CTL_ALT_SHIFT" command="pan_down"/>
+ <binding key="PAD_ENTER" mask="CTL_ALT_SHIFT" command="start_chat"/>
+ <binding key="PAD_DIVIDE" mask="CTL_ALT_SHIFT" command="start_gesture"/>
+ </third_person>
+
+ # Basic editing camera control
+ <edit>
+ <binding key="A" mask="NONE" command="spin_around_cw"/>
+ <binding key="D" mask="NONE" command="spin_around_ccw"/>
+ <binding key="W" mask="NONE" command="move_forward"/>
+ <binding key="S" mask="NONE" command="move_backward"/>
+ <binding key="E" mask="NONE" command="spin_over"/>
+ <binding key="C" mask="NONE" command="spin_under"/>
+ <binding key="ENTER" mask="NONE" command="start_chat"/>
+ <binding key="DIVIDE" mask="NONE" command="start_gesture"/>
+ <binding key="PAD_ENTER" mask="NONE" command="start_chat"/>
+ <binding key="PAD_DIVIDE" mask="NONE" command="start_gesture"/>
+
+ <binding key="LEFT" mask="NONE" command="spin_around_cw"/>
+ <binding key="RIGHT" mask="NONE" command="spin_around_ccw"/>
+ <binding key="UP" mask="NONE" command="move_forward"/>
+ <binding key="DOWN" mask="NONE" command="move_backward"/>
+ <binding key="PGUP" mask="NONE" command="spin_over"/>
+ <binding key="PGDN" mask="NONE" command="spin_under"/>
+
+ <binding key="A" mask="SHIFT" command="pan_left"/>
+ <binding key="D" mask="SHIFT" command="pan_right"/>
+ <binding key="W" mask="SHIFT" command="pan_up"/>
+ <binding key="S" mask="SHIFT" command="pan_down"/>
+
+ <binding key="LEFT" mask="SHIFT" command="pan_left"/>
+ <binding key="RIGHT" mask="SHIFT" command="pan_right"/>
+ <binding key="UP" mask="SHIFT" command="pan_up"/>
+ <binding key="DOWN" mask="SHIFT" command="pan_down"/>
+
+ <!--Walking works with ALT held down.-->
+ <binding key="A" mask="ALT" command="slide_left"/>
+ <binding key="D" mask="ALT" command="slide_right"/>
+ <binding key="W" mask="ALT" command="push_forward"/>
+ <binding key="S" mask="ALT" command="push_backward"/>
+ <binding key="E" mask="ALT" command="jump"/>
+ <binding key="C" mask="ALT" command="push_down"/>
+
+ <binding key="LEFT" mask="ALT" command="slide_left"/>
+ <binding key="RIGHT" mask="ALT" command="slide_right"/>
+ <binding key="UP" mask="ALT" command="push_forward"/>
+ <binding key="DOWN" mask="ALT" command="push_backward"/>
+ <binding key="PGUP" mask="ALT" command="jump"/>
+ <binding key="PGDN" mask="ALT" command="push_down"/>
+ <binding key="HOME" mask="ALT" command="toggle_fly"/>
+
+ <binding key="PAD_LEFT" mask="ALT" command="slide_left"/>
+ <binding key="PAD_RIGHT" mask="ALT" command="slide_right"/>
+ <binding key="PAD_UP" mask="ALT" command="push_forward"/>
+ <binding key="PAD_DOWN" mask="ALT" command="push_backward"/>
+ <binding key="PAD_PGUP" mask="ALT" command="jump"/>
+ <binding key="PAD_PGDN" mask="ALT" command="push_down"/>
+ <binding key="PAD_ENTER" mask="ALT" command="start_chat"/>
+ <binding key="PAD_DIVIDE" mask="ALT" command="start_gesture"/>
+ </edit>
+ <sitting>
+ <binding key="A" mask="ALT" command="spin_around_cw"/>
+ <binding key="D" mask="ALT" command="spin_around_ccw"/>
+ <binding key="W" mask="ALT" command="move_forward"/>
+ <binding key="S" mask="ALT" command="move_backward"/>
+ <binding key="E" mask="ALT" command="spin_over_sitting"/>
+ <binding key="C" mask="ALT" command="spin_under_sitting"/>
+
+ <binding key="LEFT" mask="ALT" command="spin_around_cw"/>
+ <binding key="RIGHT" mask="ALT" command="spin_around_ccw"/>
+ <binding key="UP" mask="ALT" command="move_forward"/>
+ <binding key="DOWN" mask="ALT" command="move_backward"/>
+ <binding key="PGUP" mask="ALT" command="spin_over"/>
+ <binding key="PGDN" mask="ALT" command="spin_under"/>
+
+ <binding key="A" mask="CTL_ALT" command="spin_around_cw"/>
+ <binding key="D" mask="CTL_ALT" command="spin_around_ccw"/>
+ <binding key="W" mask="CTL_ALT" command="spin_over"/>
+ <binding key="S" mask="CTL_ALT" command="spin_under"/>
+ <binding key="E" mask="CTL_ALT" command="spin_over"/>
+ <binding key="C" mask="CTL_ALT" command="spin_under"/>
+
+ <binding key="LEFT" mask="CTL_ALT" command="spin_around_cw"/>
+ <binding key="RIGHT" mask="CTL_ALT" command="spin_around_ccw"/>
+ <binding key="UP" mask="CTL_ALT" command="spin_over"/>
+ <binding key="DOWN" mask="CTL_ALT" command="spin_under"/>
+ <binding key="PGUP" mask="CTL_ALT" command="spin_over"/>
+ <binding key="PGDN" mask="CTL_ALT" command="spin_under"/>
+
+
+ <binding key="A" mask="NONE" command="spin_around_cw_sitting"/>
+ <binding key="D" mask="NONE" command="spin_around_ccw_sitting"/>
+ <binding key="W" mask="NONE" command="move_forward_sitting"/>
+ <binding key="S" mask="NONE" command="move_backward_sitting"/>
+ <binding key="E" mask="NONE" command="spin_over_sitting"/>
+ <binding key="C" mask="NONE" command="spin_under_sitting"/>
+
+ <binding key="LEFT" mask="NONE" command="spin_around_cw_sitting"/>
+ <binding key="RIGHT" mask="NONE" command="spin_around_ccw_sitting"/>
+ <binding key="UP" mask="NONE" command="move_forward_sitting"/>
+ <binding key="DOWN" mask="NONE" command="move_backward_sitting"/>
+ <binding key="PGUP" mask="NONE" command="spin_over_sitting"/>
+ <binding key="PGDN" mask="NONE" command="spin_under_sitting"/>
+
+ <binding key="PAD_LEFT" mask="NONE" command="spin_around_cw_sitting"/>
+ <binding key="PAD_RIGHT" mask="NONE" command="spin_around_ccw_sitting"/>
+ <binding key="PAD_UP" mask="NONE" command="move_forward_sitting"/>
+ <binding key="PAD_DOWN" mask="NONE" command="move_backward_sitting"/>
+ <binding key="PAD_PGUP" mask="NONE" command="spin_over_sitting"/>
+ <binding key="PAD_PGDN" mask="NONE" command="spin_under_sitting"/>
+ <binding key="PAD_CENTER" mask="NONE" command="stop_moving"/>
+ <binding key="PAD_ENTER" mask="NONE" command="start_chat"/>
+ <binding key="PAD_DIVIDE" mask="NONE" command="start_gesture"/>
+
+ <!--these are for passing controls when sitting on vehicles-->
+ <binding key="A" mask="SHIFT" command="slide_left"/>
+ <binding key="D" mask="SHIFT" command="slide_right"/>
+ <binding key="LEFT" mask="SHIFT" command="slide_left"/>
+ <binding key="RIGHT" mask="SHIFT" command="slide_right"/>
+
+ <binding key="PAD_LEFT" mask="SHIFT" command="slide_left"/>
+ <binding key="PAD_RIGHT" mask="SHIFT" command="slide_right"/>
+ <binding key="PAD_ENTER" mask="SHIFT" command="start_chat"/>
+ <binding key="PAD_DIVIDE" mask="SHIFT" command="start_gesture"/>
+
+ <!--pan on Alt-Shift-->
+ <binding key="A" mask="CTL_ALT_SHIFT" command="pan_left"/>
+ <binding key="D" mask="CTL_ALT_SHIFT" command="pan_right"/>
+ <binding key="W" mask="CTL_ALT_SHIFT" command="pan_up"/>
+ <binding key="S" mask="CTL_ALT_SHIFT" command="pan_down"/>
+
+ <binding key="LEFT" mask="CTL_ALT_SHIFT" command="pan_left"/>
+ <binding key="RIGHT" mask="CTL_ALT_SHIFT" command="pan_right"/>
+ <binding key="UP" mask="CTL_ALT_SHIFT" command="pan_up"/>
+ <binding key="DOWN" mask="CTL_ALT_SHIFT" command="pan_down"/>
+
+ <binding key="PAD_LEFT" mask="CTL_ALT_SHIFT" command="pan_left"/>
+ <binding key="PAD_RIGHT" mask="CTL_ALT_SHIFT" command="pan_right"/>
+ <binding key="PAD_UP" mask="CTL_ALT_SHIFT" command="pan_up"/>
+ <binding key="PAD_DOWN" mask="CTL_ALT_SHIFT" command="pan_down"/>
+ <binding key="PAD_ENTER" mask="CTL_ALT_SHIFT" command="start_chat"/>
+ <binding key="PAD_DIVIDE" mask="CTL_ALT_SHIFT" command="start_gesture"/>
+
+ <binding key="ENTER" mask="NONE" command="start_chat"/>
+ <binding key="DIVIDE" mask="NONE" command="start_gesture"/>
+ </sitting>
+ <edit_avatar>
+ <!--Avatar editing camera controls-->
+ <binding key="A" mask="NONE" command="edit_avatar_spin_cw"/>
+ <binding key="D" mask="NONE" command="edit_avatar_spin_ccw"/>
+ <binding key="W" mask="NONE" command="edit_avatar_move_forward"/>
+ <binding key="S" mask="NONE" command="edit_avatar_move_backward"/>
+ <binding key="E" mask="NONE" command="edit_avatar_spin_over"/>
+ <binding key="C" mask="NONE" command="edit_avatar_spin_under"/>
+ <binding key="LEFT" mask="NONE" command="edit_avatar_spin_cw"/>
+ <binding key="RIGHT" mask="NONE" command="edit_avatar_spin_ccw"/>
+ <binding key="UP" mask="NONE" command="edit_avatar_move_forward"/>
+ <binding key="DOWN" mask="NONE" command="edit_avatar_move_backward"/>
+ <binding key="PGUP" mask="NONE" command="edit_avatar_spin_over"/>
+ <binding key="PGDN" mask="NONE" command="edit_avatar_spin_under"/>
+ <binding key="ENTER" mask="NONE" command="start_chat"/>
+ <binding key="DIVIDE" mask="NONE" command="start_gesture"/>
+ <binding key="PAD_LEFT" mask="NONE" command="edit_avatar_spin_cw"/>
+ <binding key="PAD_RIGHT" mask="NONE" command="edit_avatar_spin_ccw"/>
+ <binding key="PAD_UP" mask="NONE" command="edit_avatar_move_forward"/>
+ <binding key="PAD_DOWN" mask="NONE" command="edit_avatar_move_backward"/>
+ <binding key="PAD_PGUP" mask="NONE" command="edit_avatar_spin_over"/>
+ <binding key="PAD_PGDN" mask="NONE" command="edit_avatar_spin_under"/>
+ <binding key="PAD_ENTER" mask="NONE" command="start_chat"/>
+ <binding key="PAD_DIVIDE" mask="NONE" command="start_gesture"/>
+ </edit_avatar>
+</keys> \ No newline at end of file
diff --git a/indra/newview/app_settings/lindenlab.pem b/indra/newview/app_settings/lindenlab.pem
new file mode 100644
index 0000000000..eddae0426d
--- /dev/null
+++ b/indra/newview/app_settings/lindenlab.pem
@@ -0,0 +1,97 @@
+-----BEGIN CERTIFICATE-----
+MIIEUDCCA7mgAwIBAgIJAN4ppNGwj6yIMA0GCSqGSIb3DQEBBAUAMIHMMQswCQYD
+VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5j
+aXNjbzEZMBcGA1UEChMQTGluZGVuIExhYiwgSW5jLjEpMCcGA1UECxMgTGluZGVu
+IExhYiBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxKTAnBgNVBAMTIExpbmRlbiBMYWIg
+Q2VydGlmaWNhdGUgQXV0aG9yaXR5MR8wHQYJKoZIhvcNAQkBFhBjYUBsaW5kZW5s
+YWIuY29tMB4XDTA1MDQyMTAyNDAzMVoXDTI1MDQxNjAyNDAzMVowgcwxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNp
+c2NvMRkwFwYDVQQKExBMaW5kZW4gTGFiLCBJbmMuMSkwJwYDVQQLEyBMaW5kZW4g
+TGFiIENlcnRpZmljYXRlIEF1dGhvcml0eTEpMCcGA1UEAxMgTGluZGVuIExhYiBD
+ZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHzAdBgkqhkiG9w0BCQEWEGNhQGxpbmRlbmxh
+Yi5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKXh1MThucdTbMg9bYBO
+rAm8yWns32YojB0PRfbq8rUjepEhTm3/13s0u399Uc202v4ejcGhkIDWJZd2NZMF
+oKrhmRfxGHSKPCuFaXC3jh0lRECj7k8FoPkcmaPjSyodrDFDUUuv+C06oYJoI+rk
+8REyal9NwgHvqCzOrZtiTXAdAgMBAAGjggE2MIIBMjAdBgNVHQ4EFgQUO1zK2e1f
+1wO1fHAjq6DTJobKDrcwggEBBgNVHSMEgfkwgfaAFDtcytntX9cDtXxwI6ug0yaG
+yg63oYHSpIHPMIHMMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEW
+MBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEZMBcGA1UEChMQTGluZGVuIExhYiwgSW5j
+LjEpMCcGA1UECxMgTGluZGVuIExhYiBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxKTAn
+BgNVBAMTIExpbmRlbiBMYWIgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MR8wHQYJKoZI
+hvcNAQkBFhBjYUBsaW5kZW5sYWIuY29tggkA3imk0bCPrIgwDAYDVR0TBAUwAwEB
+/zANBgkqhkiG9w0BAQQFAAOBgQA/ZkgfvwHYqk1UIAKZS3kMCxz0HvYuEQtviwnu
+xA39CIJ65Zozs28Eg1aV9/Y+Of7TnWhW+U3J3/wD/GghaAGiKK6vMn9gJBIdBX/9
+e6ef37VGyiOEFFjnUIbuk0RWty0orN76q/lI/xjCi15XSA/VSq2j4vmnwfZcPTDu
+glmQ1A==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEkDCCA3igAwIBAgICTSUwDQYJKoZIhvcNAQEFBQAwQDELMAkGA1UEBhMCVVMx
+FzAVBgNVBAoTDkdlb1RydXN0LCBJbmMuMRgwFgYDVQQDEw9HZW9UcnVzdCBTU0wg
+Q0EwHhcNMTAxMjIwMTkxMTI2WhcNMTIwMjIxMTI1NDAzWjCBnzEpMCcGA1UEBRMg
+UkMteW9jbXIwdXRmRTdOMVBlaHJHQXdqL0lNc2hJZS0xCzAJBgNVBAYTAlVTMRMw
+EQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMR0wGwYD
+VQQKExRMaW5kZW4gUmVzZWFyY2ggSW5jLjEZMBcGA1UEAwwQKi5zZWNvbmRsaWZl
+LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN/VCCu1SZ5x4vNp
+XZZ8r3lzqeLwjxVZfMSQCKM4lV5DFbqiZMMBto4Y/ib7i0audzuTDnImCLsfzlTu
+7iZLoJNy42/43Rq4xtaDZ7joxALFmzXUKEipgHiTTbAbLQNCS4wPXts3tScODVZY
+/mhlmXdlLuGxJbqoyOEP6NEQbgXWDCKDERnAEG/FJBVHKyBfg3abrrIuQNwYCKCS
+2OZ5Z5MveGmY4tSKUOOi/c0vV9HsanQn/ymybZjxR5Kmb1CvQr7VVtbpR1MhlGkc
+sfJz1NFIFxdXkUggIny+XSG1dAAJRFFumyRM+X/eh0NHNmAI14JJ43hB6Zw3dzzl
+An9BSeECAwEAAaOCATIwggEuMB8GA1UdIwQYMBaAFEJ5VBthzVUrPmPVPEhX9Z/7
+Rc5KMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH
+AwIwKwYDVR0RBCQwIoIQKi5zZWNvbmRsaWZlLmNvbYIOc2Vjb25kbGlmZS5jb20w
+PQYDVR0fBDYwNDAyoDCgLoYsaHR0cDovL2d0c3NsLWNybC5nZW90cnVzdC5jb20v
+Y3Jscy9ndHNzbC5jcmwwHQYDVR0OBBYEFK9UTMkc4Fh/Ug4fVs6UVhxP6my0MAwG
+A1UdEwEB/wQCMAAwQwYIKwYBBQUHAQEENzA1MDMGCCsGAQUFBzAChidodHRwOi8v
+Z3Rzc2wtYWlhLmdlb3RydXN0LmNvbS9ndHNzbC5jcnQwDQYJKoZIhvcNAQEFBQAD
+ggEBACIR9yggGHDcZ60AMNdFmZ8XJeahTuv6q2X/It2JxqSQp5BVQUei0NGIYYOt
+yg0JFBZn5KqXiQ5Zz84K4hdvh/6grCEAn4v37sozSbkeZ92Lec8NOZR42HfYIOCo
+Hx9q7CNRxdhv6ehV4LekaRBxrtp5etVsIDaWvRZEswCWl46VuLrfjcpauj6DAdOQ
+FfPVAW+4nPgLr8KapZMnXYnabIwrj9DQLQ88w/D7durenu/SYJEahWW9mb++n9is
+eMjyuyzYW0PTUBTaDsj+2ZmHJtoR1tBiLqh0Q62UQnmDgsf5SK5PTb8jnta/1SvN
+3pirsuvjMPV19zuH6b9NpJfXfd0=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDfTCCAuagAwIBAgIDErvmMA0GCSqGSIb3DQEBBQUAME4xCzAJBgNVBAYTAlVT
+MRAwDgYDVQQKEwdFcXVpZmF4MS0wKwYDVQQLEyRFcXVpZmF4IFNlY3VyZSBDZXJ0
+aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDIwNTIxMDQwMDAwWhcNMTgwODIxMDQwMDAw
+WjBCMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UE
+AxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9m
+OSm9BXiLnTjoBbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIu
+T8rxh0PBFpVXLVDviS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6c
+JmTM386DGXHKTubU1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmR
+Cw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5asz
+PeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQABo4HwMIHtMB8GA1UdIwQYMBaAFEjm
+aPkr0rKV10fYIyAQTzOYkJ/UMB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrM
+TjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjA6BgNVHR8EMzAxMC+g
+LaArhilodHRwOi8vY3JsLmdlb3RydXN0LmNvbS9jcmxzL3NlY3VyZWNhLmNybDBO
+BgNVHSAERzBFMEMGBFUdIAAwOzA5BggrBgEFBQcCARYtaHR0cHM6Ly93d3cuZ2Vv
+dHJ1c3QuY29tL3Jlc291cmNlcy9yZXBvc2l0b3J5MA0GCSqGSIb3DQEBBQUAA4GB
+AHbhEm5OSxYShjAGsoEIz/AIx8dxfmbuwu3UOx//8PDITtZDOLC5MH0Y0FWDomrL
+NhGc6Ehmo21/uBPUR/6LWlxz/K7ZGzIZOKuXNBSqltLroxwUCEm2u+WR74M26x1W
+b8ravHNjkOR/ez4iyz0H7V84dJzjA1BOoa+Y7mHyhD8S
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIID2TCCAsGgAwIBAgIDAjbQMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
+MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
+YWwgQ0EwHhcNMTAwMjE5MjIzOTI2WhcNMjAwMjE4MjIzOTI2WjBAMQswCQYDVQQG
+EwJVUzEXMBUGA1UEChMOR2VvVHJ1c3QsIEluYy4xGDAWBgNVBAMTD0dlb1RydXN0
+IFNTTCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJCzgMHk5Uat
+cGA9uuUU3Z6KXot1WubKbUGlI+g5hSZ6p1V3mkihkn46HhrxJ6ujTDnMyz1Hr4Gu
+FmpcN+9FQf37mpc8oEOdxt8XIdGKolbCA0mEEoE+yQpUYGa5jFTk+eb5lPHgX3UR
+8im55IaisYmtph6DKWOy8FQchQt65+EuDa+kvc3nsVrXjAVaDktzKIt1XTTYdwvh
+dGLicTBi2LyKBeUxY0pUiWozeKdOVSQdl+8a5BLGDzAYtDRN4dgjOyFbLTAZJQ50
+96QhS6CkIMlszZhWwPKoXz4mdaAN+DaIiixafWcwqQ/RmXAueOFRJq9VeiS+jDkN
+d53eAsMMvR8CAwEAAaOB2TCB1jAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFEJ5
+VBthzVUrPmPVPEhX9Z/7Rc5KMB8GA1UdIwQYMBaAFMB6mGiNifurBWQMEX2qfWW4
+ysxOMBIGA1UdEwEB/wQIMAYBAf8CAQAwOgYDVR0fBDMwMTAvoC2gK4YpaHR0cDov
+L2NybC5nZW90cnVzdC5jb20vY3Jscy9ndGdsb2JhbC5jcmwwNAYIKwYBBQUHAQEE
+KDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5nZW90cnVzdC5jb20wDQYJKoZI
+hvcNAQEFBQADggEBANTvU4ToGr2hiwTAqfVfoRB4RV2yV2pOJMtlTjGXkZrUJPji
+J2ZwMZzBYlQG55cdOprApClICq8kx6jEmlTBfEx4TCtoLF0XplR4TEbigMMfOHES
+0tdT41SFULgCy+5jOvhWiU1Vuy7AyBh3hjELC3DwfjWDpCoTZFZnNF0WX3OsewYk
+2k9QbSqr0E1TQcKOu3EDSSmGGM8hQkx0YlEVxW+o78Qn5Rsz3VqI138S0adhJR/V
+4NwdzxoQ2KDLX4z6DOW/cf/lXUQdpj6HR/oaToODEj+IZpWYeZqF6wJHzSXj8gYE
+TpnKXKBuervdo5AaRTPvvz7SBMS24CqFZUE+ENQ=
+-----END CERTIFICATE-----
diff --git a/indra/newview/app_settings/llsd.xsd b/indra/newview/app_settings/llsd.xsd
new file mode 100644
index 0000000000..34612d9faa
--- /dev/null
+++ b/indra/newview/app_settings/llsd.xsd
@@ -0,0 +1,131 @@
+<?xml version="1.0"?>
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+
+ <!-- LLSD document has exactly one value -->
+ <xsd:element name="llsd">
+ <xsd:complexType>
+ <xsd:group ref="llsd-value" />
+ </xsd:complexType>
+ </xsd:element>
+
+ <!-- Value is one of undef, boolean, integer, real,
+ uuid, string, date, binary, array, or map -->
+ <xsd:group name="llsd-value">
+ <xsd:choice>
+ <xsd:element ref="undef"/>
+ <xsd:element ref="boolean"/>
+ <xsd:element ref="integer"/>
+ <xsd:element ref="real"/>
+ <xsd:element ref="uuid"/>
+ <xsd:element ref="string"/>
+ <xsd:element ref="date"/>
+ <xsd:element ref="uri"/>
+ <xsd:element ref="binary"/>
+ <xsd:element ref="array"/>
+ <xsd:element ref="map"/>
+ </xsd:choice>
+ </xsd:group>
+
+ <!-- Undefined is an empty eleemnt -->
+ <xsd:element name="undef">
+ <xsd:simpleType>
+ <xsd:restriction base="xsd:string">
+ <xsd:length value="0" />
+ </xsd:restriction>
+ </xsd:simpleType>
+ </xsd:element>
+
+ <!-- Boolean is true or false -->
+ <xsd:element name="boolean">
+ <xsd:simpleType>
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="true" />
+ <xsd:enumeration value="false" />
+
+ <!-- In practice, these other serializations are seen: -->
+ <xsd:enumeration value="" />
+ <xsd:enumeration value="1" />
+ <xsd:enumeration value="0" />
+ </xsd:restriction>
+ </xsd:simpleType>
+ </xsd:element>
+
+ <!-- Integer is restricted to 32-bit signed values -->
+ <xsd:element name="integer">
+ <xsd:simpleType>
+ <xsd:restriction base="xsd:int" />
+ </xsd:simpleType>
+ </xsd:element>
+
+ <!-- Real is an IEEE 754 "double" value, including Infinities and NaN -->
+ <xsd:element name="real">
+ <xsd:simpleType>
+ <!-- TODO: xsd:double uses "INF", "-INF", and "NaN",
+ whereas LLSD prefers "Infinity", "-Infinity" and "NaN" -->
+ <xsd:restriction base="xsd:double" />
+ </xsd:simpleType>
+ </xsd:element>
+
+ <!-- UUID per RFC 4122 -->
+ <xsd:element name="uuid">
+ <xsd:simpleType>
+ <xsd:restriction base="xsd:string">
+ <xsd:pattern value="[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|" />
+ </xsd:restriction>
+ </xsd:simpleType>
+ </xsd:element>
+
+ <!-- String is any sequence of Unicode characters -->
+ <xsd:element name="string">
+ <xsd:simpleType>
+ <xsd:restriction base="xsd:string" />
+ </xsd:simpleType>
+ </xsd:element>
+
+ <!-- Date is ISO 8601 in UTC -->
+ <xsd:element name="date">
+ <xsd:simpleType>
+ <xsd:restriction base="xsd:dateTime">
+ <!-- Restrict to UTC (Z) times -->
+ <xsd:pattern value="[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(\.[0-9]+)?Z" />
+ </xsd:restriction>
+ </xsd:simpleType>
+ </xsd:element>
+
+ <!-- URI per RFC 3986 -->
+ <xsd:element name="uri">
+ <xsd:simpleType>
+ <xsd:restriction base="xsd:anyURI" />
+ </xsd:simpleType>
+ </xsd:element>
+
+ <!-- Binary data is base64 encoded -->
+ <xsd:element name="binary">
+ <xsd:simpleType>
+ <!-- TODO: Require encoding attribute? -->
+ <xsd:restriction base="xsd:base64Binary" />
+ </xsd:simpleType>
+ </xsd:element>
+
+ <!-- Array is a sequence of zero or more values -->
+ <xsd:element name="array">
+ <xsd:complexType>
+ <xsd:group minOccurs="0" maxOccurs="unbounded" ref="llsd-value" />
+ </xsd:complexType>
+ </xsd:element>
+
+ <!-- Map is a sequence of zero or more key/value pairs -->
+ <xsd:element name="map">
+ <xsd:complexType>
+ <xsd:sequence minOccurs="0" maxOccurs="unbounded">
+ <xsd:element name="key">
+ <xsd:simpleType>
+ <xsd:restriction base="xsd:string" />
+ </xsd:simpleType>
+ </xsd:element>
+ <xsd:group ref="llsd-value" />
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+</xsd:schema>
diff --git a/indra/newview/app_settings/low_graphics.xml b/indra/newview/app_settings/low_graphics.xml
index 136087f69b..ca1dae0b86 100644
--- a/indra/newview/app_settings/low_graphics.xml
+++ b/indra/newview/app_settings/low_graphics.xml
@@ -4,15 +4,17 @@
<RenderAvatarCloth value="FALSE"/>
<!--Default for now-->
<RenderAvatarLODFactor value="0.5"/>
- <!--Default for now-->
- <RenderAvatarMaxVisible value="3"/>
+ <!--Default for now-->
+ <RenderAvatarPhysicsLODFactor value="0.0"/>
+ <!--Default for now-->
+ <RenderAvatarMaxVisible value="3"/>
<!--NO SHADERS-->
<RenderAvatarVP value="FALSE"/>
<!--Short Range-->
<RenderFarClip value="64"/>
<!--Default for now-->
<RenderFlexTimeFactor value="0.5"/>
- <!--256... but they don't use this-->
+ <!--256... but they do not use this-->
<RenderGlowResolutionPow value="8"/>
<!--Low number-->
<RenderMaxPartCount value="1024"/>
@@ -26,8 +28,6 @@
<RenderTerrainLODFactor value="1.0"/>
<!--Default for now-->
<RenderTreeLODFactor value="0.5"/>
- <!--Default for now-->
- <RenderUseFBO value="0"/>
<!--Try Impostors-->
<RenderUseImpostors value="TRUE"/>
<!--Default for now-->
@@ -36,11 +36,10 @@
<VertexShaderEnable value="FALSE"/>
<!--NO SHADERS-->
<WindLightUseAtmosShaders value="FALSE"/>
- <!--No Deferred Shading-->
- <RenderDeferred value="FALSE"/>
- <!--SSAO Disabled-->
- <RenderDeferredSSAO value="FALSE"/>
- <!--No Shadows-->
- <RenderShadowDetail value="0"/>
-
+ <!--No Deferred Shading-->
+ <RenderDeferred value="FALSE"/>
+ <!--SSAO Disabled-->
+ <RenderDeferredSSAO value="FALSE"/>
+ <!--No Shadows-->
+ <RenderShadowDetail value="0"/>
</settings>
diff --git a/indra/newview/app_settings/mid_graphics.xml b/indra/newview/app_settings/mid_graphics.xml
index c150a87cdf..01822fe64c 100644
--- a/indra/newview/app_settings/mid_graphics.xml
+++ b/indra/newview/app_settings/mid_graphics.xml
@@ -4,13 +4,15 @@
<RenderAvatarCloth value="FALSE"/>
<!--Default for now-->
<RenderAvatarLODFactor value="0.5"/>
+ <!--Default for now-->
+ <RenderAvatarPhysicsLODFactor value="0.75"/>
<!--NO SHADERS-->
<RenderAvatarVP value="TRUE"/>
<!--Short Range-->
<RenderFarClip value="96"/>
<!--Default for now-->
<RenderFlexTimeFactor value="1"/>
- <!--256... but they don't use this-->
+ <!--256... but they do not use this-->
<RenderGlowResolutionPow value="8"/>
<!--Low number-->
<RenderMaxPartCount value="2048"/>
@@ -24,8 +26,6 @@
<RenderTerrainLODFactor value="1.0"/>
<!--Default for now-->
<RenderTreeLODFactor value="0.5"/>
- <!--Default for now-->
- <RenderUseFBO value="0"/>
<!--Try Impostors-->
<RenderUseImpostors value="TRUE"/>
<!--Default for now-->
@@ -34,11 +34,10 @@
<VertexShaderEnable value="TRUE"/>
<!--NO SHADERS-->
<WindLightUseAtmosShaders value="FALSE"/>
- <!--No Deferred Shading-->
- <RenderDeferred value="FALSE"/>
- <!--SSAO Disabled-->
- <RenderDeferredSSAO value="FALSE"/>
- <!--No Shadows-->
- <RenderShadowDetail value="0"/>
-
+ <!--No Deferred Shading-->
+ <RenderDeferred value="FALSE"/>
+ <!--SSAO Disabled-->
+ <RenderDeferredSSAO value="FALSE"/>
+ <!--No Shadows-->
+ <RenderShadowDetail value="0"/>
</settings>
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index ee01ee7833..78db307d64 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" ?>
-<llsd>
+<llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:noNamespaceSchemaLocation="llsd.xsd">
<map>
<key>CrashHostUrl</key>
<map>
@@ -24,6 +25,28 @@
<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>
@@ -585,6 +608,17 @@
<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>
@@ -607,7 +641,17 @@
<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>AvatarSex</key>
<map>
<key>Comment</key>
@@ -619,6 +663,7 @@
<key>Value</key>
<integer>0</integer>
</map>
+
<key>BackgroundYieldTime</key>
<map>
<key>Comment</key>
@@ -652,6 +697,17 @@
<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>
@@ -883,39 +939,6 @@
<key>Value</key>
<integer>1</integer>
</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>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>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>
@@ -1128,18 +1151,7 @@
<key>CacheLocationTopFolder</key>
<map>
<key>Comment</key>
- <string>Controls the top folder 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 location of the local disk cache</string>
+ <string>Controls the top folder location of the the local disk cache</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
@@ -1156,7 +1168,7 @@
<key>Type</key>
<string>U32</string>
<key>Value</key>
- <integer>20000</integer>
+ <integer>128</integer>
</map>
<key>CacheSize</key>
<map>
@@ -1321,7 +1333,68 @@
<key>Value</key>
<integer>0</integer>
</map>
- <key>CertStore</key>
+
+ <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>
@@ -1343,6 +1416,17 @@
<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>
@@ -1818,10 +1902,21 @@
<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 depth buffer contents</string>
+ <string>Show stats about current scene</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
@@ -1829,6 +1924,17 @@
<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>
@@ -1840,10 +1946,21 @@
<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 depth buffer contents</string>
+ <string>Show time info</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
@@ -2523,7 +2640,18 @@
<key>Value</key>
<integer>10</integer>
</map>
- <key>DisableCameraConstraints</key>
+ <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>
@@ -2545,10 +2673,32 @@
<key>Value</key>
<integer>0</integer>
</map>
- <key>DisableRendering</key>
+ <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 GL rendering and GUI (load testing)</string>
+ <string>Disable highlighting and linking of URLs in XUI text boxes</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
@@ -2567,6 +2717,28 @@
<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>
@@ -2677,6 +2849,28 @@
<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>
@@ -2699,6 +2893,17 @@
<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>
@@ -2820,6 +3025,39 @@
<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>
@@ -2931,17 +3169,6 @@
<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>60.0</real>
- </map>
- <key>FPSLogFrequency</key>
<map>
<key>Comment</key>
<string>Seconds between display of FPS in log (0 for never)</string>
@@ -3054,7 +3281,18 @@
<key>FirstRunThisInstall</key>
<map>
<key>Comment</key>
- <string>Specifies that you have not run the viewer since you installed the latest update</string>
+ <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>
@@ -3513,72 +3751,6 @@
<key>Value</key>
<real>0.5</real>
</map>
- <key>FontMonospace</key>
- <map>
- <key>Comment</key>
- <string>Name of monospace font that definitely exists (Truetype file name)</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>DejaVuSansMono.ttf</string>
- </map>
- <key>FontSansSerif</key>
- <map>
- <key>Comment</key>
- <string>Name of primary sans-serif font that definitely exists (Truetype file name)</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>MtBkLfRg.ttf</string>
- </map>
- <key>FontSansSerifBundledFallback</key>
- <map>
- <key>Comment</key>
- <string>Name of secondary sans-serif font that definitely exists (Truetype file name)</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>DejaVuSansCondensed.ttf</string>
- </map>
- <key>FontSansSerifBold</key>
- <map>
- <key>Comment</key>
- <string>Name of bold font (Truetype file name)</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>MtBdLfRg.ttf</string>
- </map>
- <key>FontSansSerifFallback</key>
- <map>
- <key>Comment</key>
- <string>Name of sans-serif font (Truetype file name)</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string />
- </map>
- <key>FontSansSerifFallbackScale</key>
- <map>
- <key>Comment</key>
- <string>Scale of fallback font relative to huge font (fraction of huge font size)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.0</real>
- </map>
<key>FontScreenDPI</key>
<map>
<key>Comment</key>
@@ -3590,61 +3762,6 @@
<key>Value</key>
<real>96.0</real>
</map>
- <key>FontSizeHuge</key>
- <map>
- <key>Comment</key>
- <string>Size of huge font (points, or 1/72 of an inch)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>16.0</real>
- </map>
- <key>FontSizeLarge</key>
- <map>
- <key>Comment</key>
- <string>Size of large font (points, or 1/72 of an inch)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>12.0</real>
- </map>
- <key>FontSizeMedium</key>
- <map>
- <key>Comment</key>
- <string>Size of medium font (points, or 1/72 of an inch)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>10.0</real>
- </map>
- <key>FontSizeMonospace</key>
- <map>
- <key>Comment</key>
- <string>Size of monospaced font (points, or 1/72 of an inch)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>8.1</real>
- </map>
- <key>FontSizeSmall</key>
- <map>
- <key>Comment</key>
- <string>Size of small font (points, or 1/72 of an inch)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>9.0</real>
- </map>
<key>ForceAssetFail</key>
<map>
<key>Comment</key>
@@ -3837,7 +3954,7 @@
<key>Comment</key>
<string>URL pattern for help page; arguments will be encoded; see llviewerhelp.cpp:buildHelpURL for arguments</string>
<key>Persist</key>
- <integer>0</integer>
+ <integer>1</integer>
<key>Type</key>
<string>String</string>
<key>Value</key>
@@ -3865,6 +3982,28 @@
<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>
@@ -3887,6 +4026,17 @@
<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>
@@ -3925,7 +4075,7 @@
<key>Comment</key>
<string>Ignore all notifications so we never need user input on them.</string>
<key>Persist</key>
- <integer>0</integer>
+ <integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
@@ -3953,6 +4103,17 @@
<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>
@@ -4195,6 +4356,39 @@
<key>Value</key>
<real>0.25</real>
</map>
+ <key>Jpeg2000AdvancedCompression</key>
+ <map>
+ <key>Comment</key>
+ <string>Use advanced Jpeg2000 compression options (precincts, blocks, ordering, markers)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>Jpeg2000PrecinctsSize</key>
+ <map>
+ <key>Comment</key>
+ <string>Size of image precincts. Assumed square and same for all levels. Must be power of 2.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>256</integer>
+ </map>
+ <key>Jpeg2000BlocksSize</key>
+ <map>
+ <key>Comment</key>
+ <string>Size of encoding blocks. Assumed square and same for all levels. Must be power of 2. Max 64, Min 4.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>64</integer>
+ </map>
<key>KeepAspectForSnapshot</key>
<map>
<key>Comment</key>
@@ -4548,6 +4742,17 @@
<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>
@@ -4581,6 +4786,17 @@
<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>
@@ -4669,6 +4885,17 @@
<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>
@@ -5164,61 +5391,6 @@
<key>Value</key>
<real>60.0</real>
</map>
- <key>MeanCollisionBump</key>
- <map>
- <key>Comment</key>
- <string>You have experienced an abuse of being bumped by an object or avatar</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>MeanCollisionPhysical</key>
- <map>
- <key>Comment</key>
- <string>You have experienced an abuse from a physical object</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>MeanCollisionPushObject</key>
- <map>
- <key>Comment</key>
- <string>You have experienced an abuse of being pushed by a scripted object</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>MeanCollisionScripted</key>
- <map>
- <key>Comment</key>
- <string>You have experienced an abuse from a scripted object</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>MeanCollisionSelected</key>
- <map>
- <key>Comment</key>
- <string>You have experienced an abuse of being pushed via a selected object</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
<key>MediaControlFadeTime</key>
<map>
<key>Comment</key>
@@ -5384,7 +5556,40 @@
<key>Value</key>
<real>0</real>
</map>
- <key>MigrateCacheDirectory</key>
+ <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>MeshUseWholeModelUpload</key>
+ <map>
+ <key>Comment</key>
+ <string>Upload model in its entirety instead of mesh-by-mesh (new caps)</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>
@@ -5893,6 +6098,17 @@
<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>
@@ -5995,17 +6211,6 @@
<key>OutBandwidth</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>OutBandwidth</key>
- <map>
- <key>Comment</key>
<string>Outgoing bandwidth throttle (bps)</string>
<key>Persist</key>
<integer>1</integer>
@@ -6047,6 +6252,66 @@
<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>
@@ -6282,7 +6547,177 @@
<key>Value</key>
<integer>13</integer>
</map>
- <key>PrimMediaMasterEnabled</key>
+
+ <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>
@@ -6480,6 +6915,28 @@
<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>
@@ -6516,7 +6973,18 @@
<key>MediaBrowserWindowLimit</key>
<map>
<key>Comment</key>
- <string>Maximum number of media brower windows that can be open at once (0 for no limit)</string>
+ <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>
@@ -6711,6 +7179,17 @@
<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>
@@ -6722,7 +7201,31 @@
<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>
@@ -6859,7 +7362,7 @@
<string>Vector3</string>
<key>Value</key>
<array>
- <real>0.40</real>
+ <real>0.80</real>
<real>1.00</real>
<real>0.00</real>
</array>
@@ -6919,7 +7422,18 @@
<key>Value</key>
<integer>0</integer>
</map>
- <key>RenderDebugPipeline</key>
+ <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>
@@ -6952,6 +7466,7 @@
<key>Value</key>
<integer>0</integer>
</map>
+
<key>RenderAnimateRes</key>
<map>
<key>Comment</key>
@@ -6963,7 +7478,31 @@
<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>
@@ -7120,6 +7659,18 @@
<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>
@@ -7210,7 +7761,6 @@
<key>Value</key>
<real>0.01</real>
</map>
-
<key>RenderShadowBiasError</key>
<map>
<key>Comment</key>
@@ -7233,6 +7783,18 @@
<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>
@@ -7255,7 +7817,7 @@
<key>Type</key>
<string>F32</string>
<key>Value</key>
- <real>0.0</real>
+ <real>-0.001</real>
</map>
<key>RenderSpotShadowOffset</key>
<map>
@@ -7477,30 +8039,6 @@
<integer>1</integer>
</map>
- <key>RenderDeferredLocalLights</key>
- <map>
- <key>Comment</key>
- <string>Execute local lighting 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>RenderDeferredFullscreenLights</key>
- <map>
- <key>Comment</key>
- <string>Execute local lighting 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>
@@ -7543,7 +8081,7 @@
<key>Type</key>
<string>F32</string>
<key>Value</key>
- <real>1.1</real>
+ <real>0.8</real>
</map>
<key>RenderShadowGaussian</key>
@@ -7593,7 +8131,7 @@
<key>Type</key>
<string>F32</string>
<key>Value</key>
- <real>0.1</real>
+ <real>0</real>
</map>
<key>RenderGIAmbiance</key>
@@ -7737,17 +8275,6 @@
<key>Value</key>
<integer>1</integer>
</map>
- <key>RenderFastUI</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>RenderFlexTimeFactor</key>
<map>
<key>Comment</key>
@@ -7824,9 +8351,9 @@
<string>Vector3</string>
<key>Value</key>
<array>
- <real>0.299</real>
- <real>0.587</real>
- <real>0.114</real>
+ <real>1</real>
+ <real>0</real>
+ <real>0</real>
</array>
</map>
<key>RenderGlowMaxExtractAlpha</key>
@@ -7838,7 +8365,7 @@
<key>Type</key>
<string>F32</string>
<key>Value</key>
- <real>0.065</real>
+ <real>0.25</real>
</map>
<key>RenderGlowMinLuminance</key>
<map>
@@ -7849,7 +8376,7 @@
<key>Type</key>
<string>F32</string>
<key>Value</key>
- <real>2.5</real>
+ <real>9999</real>
</map>
<key>RenderGlowResolutionPow</key>
<map>
@@ -7963,7 +8490,7 @@
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
- <integer>1</integer>
+ <integer>0</integer>
</map>
<key>RenderHideGroupTitle</key>
<map>
@@ -8263,6 +8790,28 @@
<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>
@@ -8307,17 +8856,17 @@
<key>Value</key>
<integer>0</integer>
</map>
- <key>RenderUseFBO</key>
- <map>
- <key>Comment</key>
- <string>Whether we want to use GL_EXT_framebuffer_objects.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</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>
@@ -8384,6 +8933,17 @@
<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>
@@ -8395,7 +8955,18 @@
<key>Value</key>
<integer>1</integer>
</map>
- <key>RenderVolumeLODFactor</key>
+ <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>
@@ -8439,6 +9010,17 @@
<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>
@@ -8461,7 +9043,51 @@
<key>Value</key>
<real>1.0</real>
</map>
- <key>SafeMode</key>
+ <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>
@@ -8527,6 +9153,17 @@
<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>
@@ -9391,7 +10028,7 @@
<key>ShowNetStats</key>
<map>
<key>Comment</key>
- <string>Show the Search Bar in the Status Overlay</string>
+ <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>
@@ -9726,6 +10363,17 @@
<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>
@@ -9891,6 +10539,17 @@
<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>
@@ -10991,7 +11650,62 @@
<key>Value</key>
<integer>15</integer>
</map>
- <key>UploadBakedTexOld</key>
+ <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>
@@ -11143,6 +11857,17 @@
<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>
@@ -11220,8 +11945,6 @@
<key>Type</key>
<string>LLSD</string>
<key>Value</key>
- <map>
- </map>
</map>
<key>VFSOldSize</key>
<map>
@@ -11300,32 +12023,32 @@
<key>Value</key>
<integer>1</integer>
</map>
- <key>VerboseLogs</key>
+ <key>InterpolationTime</key>
<map>
<key>Comment</key>
- <string>Display source file and line number for each log item for debugging purposes</string>
+ <string>How long to extrapolate object motion after last packet received</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
- <string>Boolean</string>
+ <string>F32</string>
<key>Value</key>
- <integer>0</integer>
+ <integer>3</integer>
</map>
- <key>VersionChannelName</key>
+ <key>InterpolationPhaseOut</key>
<map>
<key>Comment</key>
- <string>Versioning Channel Name.</string>
+ <string>Seconds to phase out interpolated motion</string>
<key>Persist</key>
- <integer>0</integer>
+ <integer>1</integer>
<key>Type</key>
- <string>String</string>
+ <string>F32</string>
<key>Value</key>
- <string>Second Life Release</string>
+ <integer>1</integer>
</map>
- <key>VertexShaderEnable</key>
+ <key>VerboseLogs</key>
<map>
<key>Comment</key>
- <string>Enable/disable all GLSL shaders (debug)</string>
+ <string>Display source file and line number for each log item for debugging purposes</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
@@ -11333,10 +12056,10 @@
<key>Value</key>
<integer>0</integer>
</map>
- <key>VivoxAutoPostCrashDumps</key>
+ <key>VertexShaderEnable</key>
<map>
<key>Comment</key>
- <string>If true, SLVoice will automatically send crash dumps directly to Vivox.</string>
+ <string>Enable/disable all GLSL shaders (debug)</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
@@ -11344,27 +12067,27 @@
<key>Value</key>
<integer>0</integer>
</map>
- <key>VivoxDebugLevel</key>
+ <key>VivoxAutoPostCrashDumps</key>
<map>
<key>Comment</key>
- <string>Logging level to use when launching the vivox daemon</string>
+ <string>If true, SLVoice will automatically send crash dumps directly to Vivox.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
- <string>String</string>
+ <string>Boolean</string>
<key>Value</key>
- <string>-1</string>
+ <integer>0</integer>
</map>
- <key>VivoxDebugSIPURIHostName</key>
+ <key>VivoxDebugLevel</key>
<map>
<key>Comment</key>
- <string>Hostname portion of vivox SIP URIs (empty string for the default).</string>
+ <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></string>
+ <string>-1</string>
</map>
<key>VivoxDebugSIPURIHostName</key>
<map>
@@ -11421,6 +12144,28 @@
<key>Value</key>
<integer>0</integer>
</map>
+ <key>VoiceCallsRejectGroup</key>
+ <map>
+ <key>Comment</key>
+ <string>Silently reject all incoming group 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>
@@ -11663,6 +12408,33 @@
<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>
@@ -11729,6 +12501,17 @@
<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>
@@ -11795,10 +12578,10 @@
<key>Value</key>
<real>150000.0</real>
</map>
- <key>XUIEditor</key>
+ <key>ExternalEditor</key>
<map>
<key>Comment</key>
- <string>Path to program used to edit XUI files</string>
+ <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>
@@ -11861,6 +12644,17 @@
<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>
@@ -12026,6 +12820,7 @@
<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>
@@ -12065,6 +12860,7 @@
<key>Value</key>
<array>
<string>snapshot</string>
+ <string>postcard</string>
<string>mini_map</string>
</array>
</map>
@@ -12132,7 +12928,7 @@
<key>Type</key>
<string>F32</string>
<key>Value</key>
- <real>600.0</real>
+ <real>1200.0</real>
</map>
<key>SidePanelHintTimeout</key>
<map>
@@ -12145,5 +12941,302 @@
<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>EnablePlaceProfile</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable viewing of place profile 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>EnableInventory</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable opening inventory from web link</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>EnableSearch</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable opening search from web link</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>EnableAppearance</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable opening appearance 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>
+ <key>OpenIMOnVoice</key>
+ <map>
+ <key>Comment</key>
+ <string>Open the corresponding IM window when connecting to a voice call.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>AllowBottomTrayButtonReordering</key>
+ <map>
+ <key>Comment</key>
+ <string>Allow user to move and hide bottom tray buttons</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
</map>
</llsd>
diff --git a/indra/newview/app_settings/settings_crash_behavior.xml b/indra/newview/app_settings/settings_crash_behavior.xml
index cc7f5ac88b..97651ff4ca 100644
--- a/indra/newview/app_settings/settings_crash_behavior.xml
+++ b/indra/newview/app_settings/settings_crash_behavior.xml
@@ -9,7 +9,7 @@
<key>Type</key>
<string>S32</string>
<key>Value</key>
- <integer>0</integer>
+ <integer>1</integer>
</map>
</map>
</llsd>
diff --git a/indra/newview/app_settings/settings_files.xml b/indra/newview/app_settings/settings_files.xml
index aa5b301959..079a54f957 100644
--- a/indra/newview/app_settings/settings_files.xml
+++ b/indra/newview/app_settings/settings_files.xml
@@ -1,148 +1,64 @@
-<llsd>
- <map>
- <key>Locations</key>
- <map>
- <!--
- The Locations LLSD block specifies the usage pattern of
- the settings file types
- Each location is represented by a LLSD containing the following values:
- PathIndex = hard coded path indicies.
- Files = map of files to load
- Each file can have:
- Requirement = level of necessity for loading.
- 0 ( or Req. no key) = do not load
- 1 = required, fail if not found
- NameFromSetting = Use the given setting to specify the name. Not valid for
- "Default"
- -->
- <key>Comment</key>
- <string>List location from which to load files, and the rules about loading those files.</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>LLSD</string>
- <key>Value</key>
- <map>
- <key>Default</key>
- <map>
- <key>PathIndex</key>
- <integer>2</integer>
- <key>Files</key>
- <map>
- <key>Global</key>
- <map>
- <key>Name</key>
- <string>settings.xml</string>
- <key>Requirement</key>
- <integer>1</integer>
- </map>
- <key>PerAccount</key>
- <map>
- <key>Name</key>
- <string>settings_per_account.xml</string>
- <key>Requirement</key>
- <integer>1</integer>
- </map>
- <key>CrashSettings</key>
- <map>
- <key>Name</key>
- <string>settings_crash_behavior.xml</string>
- <key>Requirement</key>
- <integer>1</integer>
- </map>
- <key>Warnings</key>
- <map>
- <key>Name</key>
- <string>ignorable_dialogs.xml</string>
- <key>Requirement</key>
- <integer>1</integer>
- </map>
- </map>
- </map>
- <key>User</key>
- <map>
- <key>PathIndex</key>
- <integer>1</integer>
- <key>Files</key>
- <map>
- <key>Global</key>
- <map>
- <key>Name</key>
- <string>settings.xml</string>
- <key>NameFromSetting</key>
- <string>ClientSettingsFile</string>
- </map>
- <key>CrashSettings</key>
- <map>
- <key>Name</key>
- <string>settings_crash_behavior.xml</string>
- </map>
- <key>Warnings</key>
- <map>
- <key>Name</key>
- <string>ignorable_dialogs.xml</string>
- <key>NameFromSetting</key>
- <string>WarningSettingsFile</string>
- </map>
- </map>
- </map>
- <key>Account</key>
- <map>
- <key>PathIndex</key>
- <integer>3</integer>
- <key>Files</key>
- <map>
- <key>PerAccount</key>
- <map>
- <key>Name</key>
- <string>settings_per_account.xml</string>
- <key>NameFromSetting</key>
- <string>PerAccountSettingsFile</string>
- </map>
- </map>
- </map>
- <key>DefaultSkin</key>
- <map>
- <key>PathIndex</key>
- <integer>17</integer>
- <key>Files</key>
- <map>
- <key>Skinning</key>
- <map>
- <key>Name</key>
- <string>colors.xml</string>
- </map>
- </map>
- </map>
- <key>CurrentSkin</key>
- <map>
- <key>PathIndex</key>
- <integer>10</integer>
- <key>Files</key>
- <map>
- <key>Skinning</key>
- <map>
- <key>Name</key>
- <string>colors.xml</string>
- </map>
- </map>
- </map>
- <key>UserSkin</key>
- <map>
- <key>PathIndex</key>
- <integer>14</integer>
- <key>Files</key>
- <map>
- <key>Skinning</key>
- <map>
- <key>Name</key>
- <string>colors.xml</string>
- <key>NameFromSetting</key>
- <string>SkinningSettingsFile</string>
- </map>
- </map>
- </map>
- </map>
- </map>
- </map>
-</llsd>
+<settings_files>
+ <group name="Default"
+ path_index="2">
+ <file name="Global"
+ file_name="settings.xml"
+ required="true"/>
+ <file name="PerAccount"
+ file_name="settings_per_account.xml"
+ required="true"/>
+ <file name="CrashSettings"
+ file_name="settings_crash_behavior.xml"
+ required="true"/>
+ <file name="Warnings"
+ file_name="ignorable_dialogs.xml"
+ required="true"/>
+ </group>
+ <group name="User"
+ path_index="1">
+ <file name="Global"
+ file_name="settings.xml"
+ file_name_setting="ClientSettingsFile"/>
+ <file name="CrashSettings"
+ file_name="settings_crash_behavior"/>
+ <file name="Warnings"
+ file_name="ignorable_dialogs.xml"
+ file_name_setting="WarningSettingsFile"/>
+ </group>
+ <group name="Account"
+ path_index="3">
+ <file name="PerAccount"
+ file_name="settings_per_account.xml"
+ file_name_setting="PerAccountSettingsFile"/>
+ </group>
+ <group name="Session"
+ path_index="2">
+ <file name="Global"
+ file_name="session.xml"
+ file_name_setting="SessionSettingsFile"
+ persistent="false"/>
+ </group>
+ <group name="UserSession"
+ path_index="1">
+ <file name="Global"
+ file_name="session.xml"
+ file_name_setting="UserSessionSettingsFile"
+ persistent="false"/>
+ </group>
+ <group name="DefaultSkin"
+ path_index="17">
+ <file name="Skinning"
+ file_name="colors.xml"/>
+ </group>
+ <group name="CurrentSkin"
+ path_index="10">
+ <file name="Skinning"
+ file_name="colors.xml"/>
+ </group>
+ <group name="UserSkin"
+ path_index="14">
+ <file name="Skinning"
+ file_name="colors.xml"
+ file_name_setting="SkinningSettingsFile"/>
+ </group>
+</settings_files> \ No newline at end of file
diff --git a/indra/newview/app_settings/settings_minimal.xml b/indra/newview/app_settings/settings_minimal.xml
new file mode 100644
index 0000000000..70a75cb4ca
--- /dev/null
+++ b/indra/newview/app_settings/settings_minimal.xml
@@ -0,0 +1,463 @@
+<llsd>
+ <map>
+ <key>ChannelBottomPanelMargin</key>
+ <map>
+ <key>Comment</key>
+ <string>Space from a lower toast to the Bottom Tray</string>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>2</integer>
+ </map>
+ <key>ClickActionBuyEnabled</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable click to buy actions in tool pie menu</string>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ClickActionPayEnabled</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable click to pay actions in tool pie menu</string>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>EnableGrab</key>
+ <map>
+ <key>Comment</key>
+ <string>Use Ctrl+mouse to grab and manipulate objects</string>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>EnableMouselook</key>
+ <map>
+ <key>Comment</key>
+ <string>Allow first person perspective and mouse control of camera</string>
+ <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>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://common-flash-secondlife-com.s3.amazonaws.com/viewer/v2.6/agni/howto/index.html?topic=[TOPIC]</string>
+ </map>
+ <key>PreferredMaturity</key>
+ <map>
+ <key>Comment</key>
+ <string>Setting for the user&apos;s preferred maturity level (consts in indra_constants.h)</string>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>21</integer>
+ </map>
+ <key>RenderTrackerBeacon</key>
+ <map>
+ <key>Comment</key>
+ <string>Display tracking arrow and beacon to target avatar, teleport destination</string>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ShowScriptErrors</key>
+ <map>
+ <key>Comment</key>
+ <string>Show script errors</string>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ShowScriptErrorsLocation</key>
+ <map>
+ <key>Comment</key>
+ <string>Show script error in chat or window</string>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>SkinCurrent</key>
+ <map>
+ <key>Comment</key>
+ <string>The currently selected skin.</string>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>minimal</string>
+ </map>
+ <key>UseExternalBrowser</key>
+ <map>
+ <key>Comment</key>
+ <string>Use default browser when opening web pages instead of in-world browser.</string>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>VoiceCallsRejectGroup</key>
+ <map>
+ <key>Comment</key>
+ <string>Silently reject all incoming group voice calls.</string>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>VoiceDisableMic</key>
+ <map>
+ <key>Comment</key>
+ <string>Completely disable the ability to open the mic.</string>
+ <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>0</integer>
+ </map>
+ <key>ChatFontSize</key>
+ <map>
+ <key>Comment</key>
+ <string>Size of chat text in chat console (0 = small, 1 = big, 2 = extra large)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>AvatarPickerHintTimeout</key>
+ <map>
+ <key>Comment</key>
+ <string>Number of seconds to wait before telling resident about avatar picker.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.0</real>
+ </map>
+ <key>RenderShowGroupTitleAll</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>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>1</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.1</real>
+ </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>0</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>1</integer>
+ </map>
+ <key>EnableClassifieds</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable creation of new classified ads</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>EnableGroupInfo</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable viewing and editing of group info.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>EnablePlaceProfile</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable viewing of place profile from web link</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>EnablePicks</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable editing of picks</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</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>0</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>0</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>0</integer>
+ </map>
+ <key>EnableInventory</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable opening inventory from web link</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>EnableSearch</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable opening search from web link</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>EnableAppearance</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable opening appearance from web link</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>0</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>0</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>0</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>http://common-flash-secondlife-com.s3.amazonaws.com/viewer/v2.6/agni/guide.html</string>
+ </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>http://common-flash-secondlife-com.s3.amazonaws.com/viewer/v2.6/agni/avatars.html</string>
+ </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>0</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>0</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>1</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>0</integer>
+ </map>
+ <key>OpenIMOnVoice</key>
+ <map>
+ <key>Comment</key>
+ <string>Open the corresponding IM window when connecting to a voice call.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>AllowBottomTrayButtonReordering</key>
+ <map>
+ <key>Comment</key>
+ <string>Allow user to move and hide bottom tray buttons</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ </map>
+</llsd>
diff --git a/indra/newview/app_settings/settings_per_account.xml b/indra/newview/app_settings/settings_per_account.xml
index dc76a4e518..ff24efaf2c 100644
--- a/indra/newview/app_settings/settings_per_account.xml
+++ b/indra/newview/app_settings/settings_per_account.xml
@@ -44,6 +44,17 @@
<key>Value</key>
<integer>0</integer>
</map>
+ <key>LastPostcardRecipient</key>
+ <map>
+ <key>Comment</key>
+ <string>Last recipient of postcard</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string />
+ </map>
<key>LogNearbyChat</key>
<map>
<key>Comment</key>
@@ -110,7 +121,17 @@
<key>Value</key>
<string>00000000-0000-0000-0000-000000000000</string>
</map>
-
+ <key>LogFileNamewithDate</key>
+ <map>
+ <key>Comment</key>
+ <string>Add Date Stamp to chat and IM Logs with format chat-YYYY-MM-DD and 'IM file name'-YYYY-MM. To view old logs goto ..\Second Life\[login name]</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</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
@@ -150,6 +171,17 @@
<key>Value</key>
<integer>0</integer>
</map>
+ <key>ShowFavoritesOnLogin</key>
+ <map>
+ <key>Comment</key>
+ <string>Determines whether favorites of last logged in user will be saved on exit from viewer and shown on login screen</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
<!-- End of back compatibility settings -->
</map>
</llsd>
diff --git a/indra/newview/app_settings/shaders/class1/avatar/avatarF.glsl b/indra/newview/app_settings/shaders/class1/avatar/avatarF.glsl
index 5de9cb0790..3f6b8b3323 100644
--- a/indra/newview/app_settings/shaders/class1/avatar/avatarF.glsl
+++ b/indra/newview/app_settings/shaders/class1/avatar/avatarF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
void default_lighting();
diff --git a/indra/newview/app_settings/shaders/class1/avatar/avatarSkinV.glsl b/indra/newview/app_settings/shaders/class1/avatar/avatarSkinV.glsl
index 7e9818e54a..1ad87badfe 100644
--- a/indra/newview/app_settings/shaders/class1/avatar/avatarSkinV.glsl
+++ b/indra/newview/app_settings/shaders/class1/avatar/avatarSkinV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
attribute vec4 weight; //1
diff --git a/indra/newview/app_settings/shaders/class1/avatar/avatarV.glsl b/indra/newview/app_settings/shaders/class1/avatar/avatarV.glsl
index 9f06301cc7..a15846f192 100644
--- a/indra/newview/app_settings/shaders/class1/avatar/avatarV.glsl
+++ b/indra/newview/app_settings/shaders/class1/avatar/avatarV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol);
mat4 getSkinnedTransform();
diff --git a/indra/newview/app_settings/shaders/class1/avatar/eyeballF.glsl b/indra/newview/app_settings/shaders/class1/avatar/eyeballF.glsl
index 0feb88535a..05fe100372 100644
--- a/indra/newview/app_settings/shaders/class1/avatar/eyeballF.glsl
+++ b/indra/newview/app_settings/shaders/class1/avatar/eyeballF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
void default_lighting();
diff --git a/indra/newview/app_settings/shaders/class1/avatar/eyeballV.glsl b/indra/newview/app_settings/shaders/class1/avatar/eyeballV.glsl
index 30a2f10f62..4b8a7604a1 100644
--- a/indra/newview/app_settings/shaders/class1/avatar/eyeballV.glsl
+++ b/indra/newview/app_settings/shaders/class1/avatar/eyeballV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
vec4 calcLightingSpecular(vec3 pos, vec3 norm, vec4 color, inout vec4 specularColor, vec4 baseCol);
void calcAtmospherics(vec3 inPositionEye);
diff --git a/indra/newview/app_settings/shaders/class1/avatar/objectSkinV.glsl b/indra/newview/app_settings/shaders/class1/avatar/objectSkinV.glsl
new file mode 100644
index 0000000000..ef823c28b1
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/avatar/objectSkinV.glsl
@@ -0,0 +1,30 @@
+/**
+ * @file objectSkinV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#version 120
+
+attribute vec4 object_weight;
+
+uniform mat4 matrixPalette[32];
+
+mat4 getObjectSkinnedTransform()
+{
+ int i;
+
+ vec4 w = fract(object_weight);
+ vec4 index = floor(object_weight);
+
+ float scale = 1.0/(w.x+w.y+w.z+w.w);
+ w *= scale;
+
+ mat4 mat = matrixPalette[int(index.x)]*w.x;
+ mat += matrixPalette[int(index.y)]*w.y;
+ mat += matrixPalette[int(index.z)]*w.z;
+ mat += matrixPalette[int(index.w)]*w.w;
+
+ return mat;
+}
diff --git a/indra/newview/app_settings/shaders/class1/avatar/pickAvatarF.glsl b/indra/newview/app_settings/shaders/class1/avatar/pickAvatarF.glsl
index bcd710dc57..27ac59a840 100644
--- a/indra/newview/app_settings/shaders/class1/avatar/pickAvatarF.glsl
+++ b/indra/newview/app_settings/shaders/class1/avatar/pickAvatarF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
uniform sampler2D diffuseMap;
diff --git a/indra/newview/app_settings/shaders/class1/avatar/pickAvatarV.glsl b/indra/newview/app_settings/shaders/class1/avatar/pickAvatarV.glsl
index 299def1927..f1aa549a47 100644
--- a/indra/newview/app_settings/shaders/class1/avatar/pickAvatarV.glsl
+++ b/indra/newview/app_settings/shaders/class1/avatar/pickAvatarV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
mat4 getSkinnedTransform();
diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl
index 171a0e76f7..3b12a07a27 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl
@@ -4,11 +4,12 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
#extension GL_ARB_texture_rectangle : enable
uniform sampler2D diffuseMap;
-uniform sampler2D noiseMap;
uniform sampler2DRect depthMap;
uniform mat4 shadow_matrix[6];
@@ -22,7 +23,7 @@ varying vec3 vary_ambient;
varying vec3 vary_directional;
varying vec3 vary_fragcoord;
varying vec3 vary_position;
-varying vec3 vary_light;
+varying vec3 vary_pointlight_col;
uniform mat4 inv_proj;
@@ -44,18 +45,19 @@ void main()
vec2 frag = vary_fragcoord.xy/vary_fragcoord.z*0.5+0.5;
frag *= screen_res;
- vec3 samp_pos = getPosition(frag).xyz;
-
vec4 pos = vec4(vary_position, 1.0);
+ vec4 diff= texture2D(diffuseMap, gl_TexCoord[0].xy);
+
vec4 col = vec4(vary_ambient + vary_directional.rgb, gl_Color.a);
- vec4 color = texture2D(diffuseMap, gl_TexCoord[0].xy) * col;
+ vec4 color = diff * col;
color.rgb = atmosLighting(color.rgb);
color.rgb = scaleSoftClip(color.rgb);
- //gl_FragColor = gl_Color;
+ color.rgb += diff.rgb * vary_pointlight_col.rgb;
+
gl_FragColor = color;
//gl_FragColor = vec4(1,0,1,1);
//gl_FragColor = vec4(1,0,1,1)*shadow;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaSkinnedV.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaSkinnedV.glsl
new file mode 100644
index 0000000000..5addbbb176
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/alphaSkinnedV.glsl
@@ -0,0 +1,107 @@
+/**
+ * @file alphaSkinnedV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#version 120
+
+vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol);
+mat4 getObjectSkinnedTransform();
+void calcAtmospherics(vec3 inPositionEye);
+
+float calcDirectionalLight(vec3 n, vec3 l);
+
+vec3 atmosAmbient(vec3 light);
+vec3 atmosAffectDirectionalLight(float lightIntensity);
+vec3 scaleDownLight(vec3 light);
+vec3 scaleUpLight(vec3 light);
+
+varying vec3 vary_position;
+varying vec3 vary_ambient;
+varying vec3 vary_directional;
+varying vec3 vary_normal;
+varying vec3 vary_fragcoord;
+varying vec3 vary_pointlight_col;
+
+uniform float near_clip;
+
+float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float fa, float is_pointlight)
+{
+ //get light vector
+ vec3 lv = lp.xyz-v;
+
+ //get distance
+ float d = length(lv);
+
+ //normalize light vector
+ lv *= 1.0/d;
+
+ //distance attenuation
+ float dist2 = d*d/(la*la);
+ float da = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0);
+
+ // spotlight coefficient.
+ float spot = max(dot(-ln, lv), is_pointlight);
+ da *= spot*spot; // GL_SPOT_EXPONENT=2
+
+ //angular attenuation
+ da *= calcDirectionalLight(n, lv);
+
+ return da;
+}
+
+void main()
+{
+ gl_TexCoord[0] = gl_MultiTexCoord0;
+
+ vec4 pos;
+ vec3 norm;
+
+ mat4 trans = getObjectSkinnedTransform();
+ trans = gl_ModelViewMatrix * trans;
+
+ pos = trans * gl_Vertex;
+
+ norm = gl_Vertex.xyz + gl_Normal.xyz;
+ norm = normalize(( trans*vec4(norm, 1.0) ).xyz-pos.xyz);
+
+ vec4 frag_pos = gl_ProjectionMatrix * pos;
+ gl_Position = frag_pos;
+
+ vary_position = pos.xyz;
+ vary_normal = norm;
+
+ calcAtmospherics(pos.xyz);
+
+ vec4 col = vec4(0.0, 0.0, 0.0, gl_Color.a);
+
+ // Collect normal lights
+ col.rgb += gl_LightSource[2].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[2].position, gl_LightSource[2].spotDirection.xyz, gl_LightSource[2].linearAttenuation, gl_LightSource[2].quadraticAttenuation, gl_LightSource[2].specular.a);
+ col.rgb += gl_LightSource[3].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[3].position, gl_LightSource[3].spotDirection.xyz, gl_LightSource[3].linearAttenuation, gl_LightSource[3].quadraticAttenuation ,gl_LightSource[3].specular.a);
+ col.rgb += gl_LightSource[4].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[4].position, gl_LightSource[4].spotDirection.xyz, gl_LightSource[4].linearAttenuation, gl_LightSource[4].quadraticAttenuation, gl_LightSource[4].specular.a);
+ col.rgb += gl_LightSource[5].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[5].position, gl_LightSource[5].spotDirection.xyz, gl_LightSource[5].linearAttenuation, gl_LightSource[5].quadraticAttenuation, gl_LightSource[5].specular.a);
+ col.rgb += gl_LightSource[6].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[6].position, gl_LightSource[6].spotDirection.xyz, gl_LightSource[6].linearAttenuation, gl_LightSource[6].quadraticAttenuation, gl_LightSource[6].specular.a);
+ col.rgb += gl_LightSource[7].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[7].position, gl_LightSource[7].spotDirection.xyz, gl_LightSource[7].linearAttenuation, gl_LightSource[7].quadraticAttenuation, gl_LightSource[7].specular.a);
+
+ vary_pointlight_col = col.rgb*gl_Color.rgb;
+
+ col.rgb = vec3(0,0,0);
+
+ // Add windlight lights
+ col.rgb = atmosAmbient(vec3(0.));
+
+ vary_ambient = col.rgb*gl_Color.rgb;
+ vary_directional = gl_Color.rgb*atmosAffectDirectionalLight(max(calcDirectionalLight(norm, gl_LightSource[0].position.xyz), (1.0-gl_Color.a)*(1.0-gl_Color.a)));
+
+ col.rgb = min(col.rgb*gl_Color.rgb, 1.0);
+
+ gl_FrontColor = col;
+
+ gl_FogFragCoord = pos.z;
+
+ vary_fragcoord.xyz = frag_pos.xyz + vec3(0,0,near_clip);
+}
+
+
diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl
index fabbce0824..525b68c437 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl
@@ -5,11 +5,12 @@
* $/LicenseInfo$
*/
+#version 120
+
vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol);
void calcAtmospherics(vec3 inPositionEye);
float calcDirectionalLight(vec3 n, vec3 l);
-float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float is_pointlight);
vec3 atmosAmbient(vec3 light);
vec3 atmosAffectDirectionalLight(float lightIntensity);
@@ -21,11 +22,37 @@ varying vec3 vary_directional;
varying vec3 vary_fragcoord;
varying vec3 vary_position;
varying vec3 vary_light;
+varying vec3 vary_pointlight_col;
uniform float near_clip;
uniform float shadow_offset;
uniform float shadow_bias;
+float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float fa, float is_pointlight)
+{
+ //get light vector
+ vec3 lv = lp.xyz-v;
+
+ //get distance
+ float d = length(lv);
+
+ //normalize light vector
+ lv *= 1.0/d;
+
+ //distance attenuation
+ float dist2 = d*d/(la*la);
+ float da = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0);
+
+ // spotlight coefficient.
+ float spot = max(dot(-ln, lv), is_pointlight);
+ da *= spot*spot; // GL_SPOT_EXPONENT=2
+
+ //angular attenuation
+ da *= calcDirectionalLight(n, lv);
+
+ return da;
+}
+
void main()
{
//transform vertex
@@ -36,33 +63,35 @@ void main()
vec4 pos = (gl_ModelViewMatrix * gl_Vertex);
vec3 norm = normalize(gl_NormalMatrix * gl_Normal);
- vary_position = pos.xyz + norm.xyz * (-pos.z/64.0*shadow_offset+shadow_bias);
+ float dp_directional_light = max(0.0, dot(norm, gl_LightSource[0].position.xyz));
+ vary_position = pos.xyz + gl_LightSource[0].position.xyz * (1.0-dp_directional_light)*shadow_offset;
calcAtmospherics(pos.xyz);
//vec4 color = calcLighting(pos.xyz, norm, gl_Color, vec4(0.));
-
vec4 col = vec4(0.0, 0.0, 0.0, gl_Color.a);
- // Collect normal lights (need to be divided by two, as we later multiply by 2)
- col.rgb += gl_LightSource[2].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[2].position, gl_LightSource[2].spotDirection.xyz, gl_LightSource[2].linearAttenuation, gl_LightSource[2].specular.a);
- col.rgb += gl_LightSource[3].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[3].position, gl_LightSource[3].spotDirection.xyz, gl_LightSource[3].linearAttenuation, gl_LightSource[3].specular.a);
- col.rgb += gl_LightSource[4].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[4].position, gl_LightSource[4].spotDirection.xyz, gl_LightSource[4].linearAttenuation, gl_LightSource[4].specular.a);
- col.rgb += gl_LightSource[5].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[5].position, gl_LightSource[5].spotDirection.xyz, gl_LightSource[5].linearAttenuation, gl_LightSource[5].specular.a);
- col.rgb += gl_LightSource[6].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[6].position, gl_LightSource[6].spotDirection.xyz, gl_LightSource[6].linearAttenuation, gl_LightSource[6].specular.a);
- col.rgb += gl_LightSource[7].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[7].position, gl_LightSource[7].spotDirection.xyz, gl_LightSource[7].linearAttenuation, gl_LightSource[7].specular.a);
- col.rgb += gl_LightSource[1].diffuse.rgb*calcDirectionalLight(norm, gl_LightSource[1].position.xyz);
- col.rgb = scaleDownLight(col.rgb);
+ // Collect normal lights
+ col.rgb += gl_LightSource[2].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[2].position, gl_LightSource[2].spotDirection.xyz, gl_LightSource[2].linearAttenuation, gl_LightSource[2].quadraticAttenuation, gl_LightSource[2].specular.a);
+ col.rgb += gl_LightSource[3].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[3].position, gl_LightSource[3].spotDirection.xyz, gl_LightSource[3].linearAttenuation, gl_LightSource[3].quadraticAttenuation ,gl_LightSource[3].specular.a);
+ col.rgb += gl_LightSource[4].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[4].position, gl_LightSource[4].spotDirection.xyz, gl_LightSource[4].linearAttenuation, gl_LightSource[4].quadraticAttenuation, gl_LightSource[4].specular.a);
+ col.rgb += gl_LightSource[5].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[5].position, gl_LightSource[5].spotDirection.xyz, gl_LightSource[5].linearAttenuation, gl_LightSource[5].quadraticAttenuation, gl_LightSource[5].specular.a);
+ col.rgb += gl_LightSource[6].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[6].position, gl_LightSource[6].spotDirection.xyz, gl_LightSource[6].linearAttenuation, gl_LightSource[6].quadraticAttenuation, gl_LightSource[6].specular.a);
+ col.rgb += gl_LightSource[7].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[7].position, gl_LightSource[7].spotDirection.xyz, gl_LightSource[7].linearAttenuation, gl_LightSource[7].quadraticAttenuation, gl_LightSource[7].specular.a);
+ vary_pointlight_col = col.rgb*gl_Color.rgb;
+
+ col.rgb = vec3(0,0,0);
+
// Add windlight lights
- col.rgb += atmosAmbient(vec3(0.));
+ col.rgb = atmosAmbient(vec3(0.));
vary_light = gl_LightSource[0].position.xyz;
vary_ambient = col.rgb*gl_Color.rgb;
vary_directional.rgb = gl_Color.rgb*atmosAffectDirectionalLight(max(calcDirectionalLight(norm, gl_LightSource[0].position.xyz), (1.0-gl_Color.a)*(1.0-gl_Color.a)));
- col.rgb = min(col.rgb*gl_Color.rgb, 1.0);
+ col.rgb = col.rgb*gl_Color.rgb;
gl_FrontColor = col;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/attachmentShadowF.glsl b/indra/newview/app_settings/shaders/class1/deferred/attachmentShadowF.glsl
new file mode 100644
index 0000000000..164322c3a7
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/attachmentShadowF.glsl
@@ -0,0 +1,18 @@
+/**
+ * @file avatarShadowF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#version 120
+
+uniform sampler2D diffuseMap;
+
+
+void main()
+{
+ //gl_FragColor = vec4(1,1,1,gl_Color.a * texture2D(diffuseMap, gl_TexCoord[0].xy).a);
+ gl_FragColor = vec4(1,1,1,1);
+}
+
diff --git a/indra/newview/app_settings/shaders/class1/deferred/attachmentShadowV.glsl b/indra/newview/app_settings/shaders/class1/deferred/attachmentShadowV.glsl
new file mode 100644
index 0000000000..5ae41cb730
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/attachmentShadowV.glsl
@@ -0,0 +1,27 @@
+/**
+ * @file attachmentShadowV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#version 120
+
+mat4 getObjectSkinnedTransform();
+
+void main()
+{
+ //transform vertex
+ gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
+
+ mat4 mat = getObjectSkinnedTransform();
+
+ mat = gl_ModelViewMatrix * mat;
+ vec3 pos = (mat*gl_Vertex).xyz;
+
+ gl_FrontColor = gl_Color;
+
+ vec4 p = gl_ProjectionMatrix * vec4(pos, 1.0);
+ p.z = max(p.z, -p.w+0.01);
+ gl_Position = p;
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaF.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaF.glsl
deleted file mode 100644
index 82ce6d7377..0000000000
--- a/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaF.glsl
+++ /dev/null
@@ -1,68 +0,0 @@
-/**
- * @file avatarAlphaF.glsl
- *
- * $LicenseInfo:firstyear=2007&license=viewerlgpl$
- * $/LicenseInfo$
- */
-
-uniform sampler2D diffuseMap;
-uniform sampler2DShadow shadowMap0;
-uniform sampler2DShadow shadowMap1;
-uniform sampler2DShadow shadowMap2;
-uniform sampler2DShadow shadowMap3;
-uniform sampler2D noiseMap;
-
-uniform mat4 shadow_matrix[6];
-uniform vec4 shadow_clip;
-
-vec3 atmosLighting(vec3 light);
-vec3 scaleSoftClip(vec3 light);
-
-varying vec3 vary_ambient;
-varying vec3 vary_directional;
-varying vec4 vary_position;
-varying vec3 vary_normal;
-
-void main()
-{
- float shadow = 1.0;
- vec4 pos = vary_position;
- vec3 norm = normalize(vary_normal);
-
- vec3 nz = texture2D(noiseMap, gl_FragCoord.xy/128.0).xyz;
-
- if (pos.z > -shadow_clip.w)
- {
-
- if (pos.z < -shadow_clip.z)
- {
- vec4 lpos = shadow_matrix[3]*pos;
- shadow = shadow2DProj(shadowMap3, lpos).x;
- }
- else if (pos.z < -shadow_clip.y)
- {
- vec4 lpos = shadow_matrix[2]*pos;
- shadow = shadow2DProj(shadowMap2, lpos).x;
- }
- else if (pos.z < -shadow_clip.x)
- {
- vec4 lpos = shadow_matrix[1]*pos;
- shadow = shadow2DProj(shadowMap1, lpos).x;
- }
- else
- {
- vec4 lpos = shadow_matrix[0]*pos;
- shadow = shadow2DProj(shadowMap0, lpos).x;
- }
- }
-
-
- vec4 col = vec4(vary_ambient + vary_directional*shadow, gl_Color.a);
- vec4 color = texture2D(diffuseMap, gl_TexCoord[0].xy) * col;
-
- color.rgb = atmosLighting(color.rgb);
-
- color.rgb = scaleSoftClip(color.rgb);
-
- gl_FragColor = color;
-}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaV.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaV.glsl
index 21ddc2fad8..a2a7dea20d 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol);
mat4 getSkinnedTransform();
@@ -17,10 +19,38 @@ vec3 atmosAffectDirectionalLight(float lightIntensity);
vec3 scaleDownLight(vec3 light);
vec3 scaleUpLight(vec3 light);
-varying vec4 vary_position;
+varying vec3 vary_position;
varying vec3 vary_ambient;
varying vec3 vary_directional;
-varying vec3 vary_normal;
+varying vec3 vary_fragcoord;
+varying vec3 vary_pointlight_col;
+
+uniform float near_clip;
+
+float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float fa, float is_pointlight)
+{
+ //get light vector
+ vec3 lv = lp.xyz-v;
+
+ //get distance
+ float d = length(lv);
+
+ //normalize light vector
+ lv *= 1.0/d;
+
+ //distance attenuation
+ float dist2 = d*d/(la*la);
+ float da = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0);
+
+ // spotlight coefficient.
+ float spot = max(dot(-ln, lv), is_pointlight);
+ da *= spot*spot; // GL_SPOT_EXPONENT=2
+
+ //angular attenuation
+ da *= calcDirectionalLight(n, lv);
+
+ return da;
+}
void main()
{
@@ -40,9 +70,10 @@ void main()
norm.z = dot(trans[2].xyz, gl_Normal);
norm = normalize(norm);
- gl_Position = gl_ProjectionMatrix * pos;
- vary_position = pos;
- vary_normal = norm;
+ vec4 frag_pos = gl_ProjectionMatrix * pos;
+ gl_Position = frag_pos;
+
+ vary_position = pos.xyz;
calcAtmospherics(pos.xyz);
@@ -50,18 +81,20 @@ void main()
vec4 col = vec4(0.0, 0.0, 0.0, gl_Color.a);
- // Collect normal lights (need to be divided by two, as we later multiply by 2)
- col.rgb += gl_LightSource[2].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[2].position, gl_LightSource[2].spotDirection.xyz, gl_LightSource[2].linearAttenuation, gl_LightSource[2].specular.a);
- col.rgb += gl_LightSource[3].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[3].position, gl_LightSource[3].spotDirection.xyz, gl_LightSource[3].linearAttenuation, gl_LightSource[3].specular.a);
- col.rgb += gl_LightSource[4].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[4].position, gl_LightSource[4].spotDirection.xyz, gl_LightSource[4].linearAttenuation, gl_LightSource[4].specular.a);
- col.rgb += gl_LightSource[5].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[5].position, gl_LightSource[5].spotDirection.xyz, gl_LightSource[5].linearAttenuation, gl_LightSource[5].specular.a);
- col.rgb += gl_LightSource[6].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[6].position, gl_LightSource[6].spotDirection.xyz, gl_LightSource[6].linearAttenuation, gl_LightSource[6].specular.a);
- col.rgb += gl_LightSource[7].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[7].position, gl_LightSource[7].spotDirection.xyz, gl_LightSource[7].linearAttenuation, gl_LightSource[7].specular.a);
- col.rgb += gl_LightSource[1].diffuse.rgb*calcDirectionalLight(norm, gl_LightSource[1].position.xyz);
- col.rgb = scaleDownLight(col.rgb);
+ // Collect normal lights
+ col.rgb += gl_LightSource[2].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[2].position, gl_LightSource[2].spotDirection.xyz, gl_LightSource[2].linearAttenuation, gl_LightSource[2].quadraticAttenuation, gl_LightSource[2].specular.a);
+ col.rgb += gl_LightSource[3].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[3].position, gl_LightSource[3].spotDirection.xyz, gl_LightSource[3].linearAttenuation, gl_LightSource[3].quadraticAttenuation ,gl_LightSource[3].specular.a);
+ col.rgb += gl_LightSource[4].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[4].position, gl_LightSource[4].spotDirection.xyz, gl_LightSource[4].linearAttenuation, gl_LightSource[4].quadraticAttenuation, gl_LightSource[4].specular.a);
+ col.rgb += gl_LightSource[5].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[5].position, gl_LightSource[5].spotDirection.xyz, gl_LightSource[5].linearAttenuation, gl_LightSource[5].quadraticAttenuation, gl_LightSource[5].specular.a);
+ col.rgb += gl_LightSource[6].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[6].position, gl_LightSource[6].spotDirection.xyz, gl_LightSource[6].linearAttenuation, gl_LightSource[6].quadraticAttenuation, gl_LightSource[6].specular.a);
+ col.rgb += gl_LightSource[7].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[7].position, gl_LightSource[7].spotDirection.xyz, gl_LightSource[7].linearAttenuation, gl_LightSource[7].quadraticAttenuation, gl_LightSource[7].specular.a);
+ vary_pointlight_col = col.rgb*gl_Color.rgb;
+
+ col.rgb = vec3(0,0,0);
+
// Add windlight lights
- col.rgb += atmosAmbient(vec3(0.));
+ col.rgb = atmosAmbient(vec3(0.));
vary_ambient = col.rgb*gl_Color.rgb;
vary_directional = gl_Color.rgb*atmosAffectDirectionalLight(max(calcDirectionalLight(norm, gl_LightSource[0].position.xyz), (1.0-gl_Color.a)*(1.0-gl_Color.a)));
@@ -71,7 +104,8 @@ void main()
gl_FrontColor = col;
gl_FogFragCoord = pos.z;
-
+
+ vary_fragcoord.xyz = frag_pos.xyz + vec3(0,0,near_clip);
}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarF.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarF.glsl
index e376892e0a..9748727147 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/avatarF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/avatarF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
uniform sampler2D diffuseMap;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarShadowF.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarShadowF.glsl
index d88e3ecfd8..1b7ae06888 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/avatarShadowF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/avatarShadowF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
uniform sampler2D diffuseMap;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarShadowV.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarShadowV.glsl
index 2af8c8f5f7..cf6579a40d 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/avatarShadowV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/avatarShadowV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
mat4 getSkinnedTransform();
diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarV.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarV.glsl
index 988226fb7c..69c93799b5 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/avatarV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/avatarV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
mat4 getSkinnedTransform();
diff --git a/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl
index 258a9b7c40..d9f021b114 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
#extension GL_ARB_texture_rectangle : enable
@@ -37,44 +39,49 @@ vec4 getPosition(vec2 pos_screen)
void main()
{
- vec3 norm = texture2DRect(normalMap, vary_fragcoord.xy).xyz;
+ vec2 tc = vary_fragcoord.xy;
+ vec3 norm = texture2DRect(normalMap, tc).xyz;
norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm
- vec3 pos = getPosition(vary_fragcoord.xy).xyz;
- vec4 ccol = texture2DRect(lightMap, vary_fragcoord.xy).rgba;
+ vec3 pos = getPosition(tc).xyz;
+ vec4 ccol = texture2DRect(lightMap, tc).rgba;
vec2 dlt = kern_scale * delta / (1.0+norm.xy*norm.xy);
-
dlt /= max(-pos.z*dist_factor, 1.0);
vec2 defined_weight = kern[0].xy; // special case the first (centre) sample's weight in the blur; we have to sample it anyway so we get it for 'free'
vec4 col = defined_weight.xyxx * ccol;
-
+
+ // relax tolerance according to distance to avoid speckling artifacts, as angles and distances are a lot more abrupt within a small screen area at larger distances
+ float pointplanedist_tolerance_pow2 = pos.z*pos.z*0.00005;
+
+ // perturb sampling origin slightly in screen-space to hide edge-ghosting artifacts where smoothing radius is quite large
+ tc += ( (mod(tc.x+tc.y,2) - 0.5) * kern[1].z * dlt * 0.5 );
+
for (int i = 1; i < 4; i++)
{
- vec2 tc = vary_fragcoord.xy + kern[i].z*dlt;
- vec3 samppos = getPosition(tc).xyz;
+ vec2 samptc = tc + kern[i].z*dlt;
+ vec3 samppos = getPosition(samptc).xyz;
float d = dot(norm.xyz, samppos.xyz-pos.xyz);// dist from plane
- if (d*d <= 0.003)
+ if (d*d <= pointplanedist_tolerance_pow2)
{
- col += texture2DRect(lightMap, tc)*kern[i].xyxx;
+ col += texture2DRect(lightMap, samptc)*kern[i].xyxx;
defined_weight += kern[i].xy;
}
}
for (int i = 1; i < 4; i++)
{
- vec2 tc = vary_fragcoord.xy - kern[i].z*dlt;
- vec3 samppos = getPosition(tc).xyz;
+ vec2 samptc = tc - kern[i].z*dlt;
+ vec3 samppos = getPosition(samptc).xyz;
float d = dot(norm.xyz, samppos.xyz-pos.xyz);// dist from plane
- if (d*d <= 0.003)
+ if (d*d <= pointplanedist_tolerance_pow2)
{
- col += texture2DRect(lightMap, tc)*kern[i].xyxx;
+ col += texture2DRect(lightMap, samptc)*kern[i].xyxx;
defined_weight += kern[i].xy;
}
}
-
-
col /= defined_weight.xyxx;
+ col.y *= col.y;
gl_FragColor = col;
}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/blurLightV.glsl b/indra/newview/app_settings/shaders/class1/deferred/blurLightV.glsl
index b1b3f55f00..c2d05c601a 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/blurLightV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/blurLightV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
varying vec2 vary_fragcoord;
uniform vec2 screen_res;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl b/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl
index 35f334d58e..37bfaac32c 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
uniform sampler2D diffuseMap;
uniform sampler2D bumpMap;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/bumpSkinnedV.glsl b/indra/newview/app_settings/shaders/class1/deferred/bumpSkinnedV.glsl
new file mode 100644
index 0000000000..d884f2e4a5
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/bumpSkinnedV.glsl
@@ -0,0 +1,37 @@
+/**
+ * @file bumpV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#version 120
+
+varying vec3 vary_mat0;
+varying vec3 vary_mat1;
+varying vec3 vary_mat2;
+
+mat4 getObjectSkinnedTransform();
+
+void main()
+{
+ gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
+
+ mat4 mat = getObjectSkinnedTransform();
+
+ mat = gl_ModelViewMatrix * mat;
+
+ vec3 pos = (mat*gl_Vertex).xyz;
+
+
+ vec3 n = normalize((mat * vec4(gl_Normal.xyz+gl_Vertex.xyz, 1.0)).xyz-pos.xyz);
+ vec3 b = normalize((mat * vec4(gl_MultiTexCoord2.xyz+gl_Vertex.xyz, 1.0)).xyz-pos.xyz);
+ vec3 t = cross(b, n);
+
+ vary_mat0 = vec3(t.x, b.x, n.x);
+ vary_mat1 = vec3(t.y, b.y, n.y);
+ vary_mat2 = vec3(t.z, b.z, n.z);
+
+ gl_Position = gl_ProjectionMatrix*vec4(pos, 1.0);
+ gl_FrontColor = gl_Color;
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/bumpV.glsl b/indra/newview/app_settings/shaders/class1/deferred/bumpV.glsl
index 6c8550cb5b..9b109b2db6 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/bumpV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/bumpV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
varying vec3 vary_mat0;
varying vec3 vary_mat1;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl
index 9bd622a506..35cfb80c93 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
uniform sampler2D diffuseMap;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseSkinnedV.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseSkinnedV.glsl
new file mode 100644
index 0000000000..9a45c03237
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseSkinnedV.glsl
@@ -0,0 +1,33 @@
+/**
+ * @file diffuseSkinnedV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#version 120
+
+varying vec3 vary_normal;
+
+mat4 getObjectSkinnedTransform();
+
+void main()
+{
+ gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
+
+ mat4 mat = getObjectSkinnedTransform();
+
+ mat = gl_ModelViewMatrix * mat;
+ vec3 pos = (mat*gl_Vertex).xyz;
+
+ vec4 norm = gl_Vertex;
+ norm.xyz += gl_Normal.xyz;
+ norm.xyz = (mat*norm).xyz;
+ norm.xyz = normalize(norm.xyz-pos.xyz);
+
+ vary_normal = norm.xyz;
+
+ gl_FrontColor = gl_Color;
+
+ gl_Position = gl_ProjectionMatrix*vec4(pos, 1.0);
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl
index bd58096317..03d3322cb6 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
varying vec3 vary_normal;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl
index f53e15c6cc..3429877397 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
#extension GL_ARB_texture_rectangle : enable
diff --git a/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl b/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl
index dc8b2c6be4..6c38d220e2 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
void calcAtmospherics(vec3 inPositionEye);
diff --git a/indra/newview/app_settings/shaders/class1/deferred/giF.glsl b/indra/newview/app_settings/shaders/class1/deferred/giF.glsl
index e64e29a0d2..75b555e8ae 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/giF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/giF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
#extension GL_ARB_texture_rectangle : enable
diff --git a/indra/newview/app_settings/shaders/class1/deferred/giV.glsl b/indra/newview/app_settings/shaders/class1/deferred/giV.glsl
index 543527612e..8dc1410ea5 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/giV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/giV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
varying vec2 vary_fragcoord;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl b/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl
index 7f365fedc8..e3c15a2ab2 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
uniform sampler2D diffuseMap;
uniform sampler2D normalMap;
@@ -12,7 +14,7 @@ uniform sampler2D specularMap;
void main()
{
vec4 col = texture2D(diffuseMap, gl_TexCoord[0].xy);
- gl_FragData[0] = vec4(col.rgb, col.a <= 0.5 ? 0.0 : 0.005);
+ gl_FragData[0] = vec4(col.rgb, col.a * 0.005);
gl_FragData[1] = texture2D(specularMap, gl_TexCoord[0].xy);
gl_FragData[2] = vec4(texture2D(normalMap, gl_TexCoord[0].xy).xyz, 0.0);
}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/impostorV.glsl b/indra/newview/app_settings/shaders/class1/deferred/impostorV.glsl
index 4fc27d4412..37148b3f1a 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/impostorV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/impostorV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
void main()
{
diff --git a/indra/newview/app_settings/shaders/class1/deferred/luminanceF.glsl b/indra/newview/app_settings/shaders/class1/deferred/luminanceF.glsl
index acb3014d18..78df54d5dc 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/luminanceF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/luminanceF.glsl
@@ -5,6 +5,8 @@
* $/LicenseInfo$
*/
+#version 120
+
uniform sampler2DRect diffuseMap;
varying vec2 vary_fragcoord;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/luminanceV.glsl b/indra/newview/app_settings/shaders/class1/deferred/luminanceV.glsl
index 6368def830..0c820bfc6c 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/luminanceV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/luminanceV.glsl
@@ -5,6 +5,9 @@
* $/LicenseInfo$
*/
+#version 120
+
+
varying vec2 vary_fragcoord;
uniform vec2 screen_res;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl
index 6fca08ae6a..c5ddf31ac0 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl
@@ -5,6 +5,8 @@
* $/LicenseInfo$
*/
+#version 120
+
#extension GL_ARB_texture_rectangle : enable
uniform sampler2DRect depthMap;
diff --git a/indra/newview/app_settings/shaders/class2/deferred/blurLightV.glsl b/indra/newview/app_settings/shaders/class1/deferred/multiPointLightV.glsl
index b1b3f55f00..2e3e84dd15 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/blurLightV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/multiPointLightV.glsl
@@ -1,17 +1,20 @@
/**
- * @file blurLightF.glsl
+ * @file multiPointLightV.glsl
*
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
-varying vec2 vary_fragcoord;
-uniform vec2 screen_res;
+#version 120
+
+varying vec4 vary_fragcoord;
void main()
{
//transform vertex
- gl_Position = ftransform();
vec4 pos = gl_ModelViewProjectionMatrix * gl_Vertex;
- vary_fragcoord = (pos.xy*0.5+0.5)*screen_res;
+ vary_fragcoord = pos;
+
+ gl_Position = pos;
+ gl_FrontColor = gl_Color;
}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl
index 43da16436b..22ed9dcd40 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+ #version 120
#extension GL_ARB_texture_rectangle : enable
diff --git a/indra/newview/app_settings/shaders/class1/deferred/pointLightV.glsl b/indra/newview/app_settings/shaders/class1/deferred/pointLightV.glsl
index e056c3e896..8e74feb615 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/pointLightV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/pointLightV.glsl
@@ -5,6 +5,8 @@
* $/LicenseInfo$
*/
+#version 120
+
varying vec4 vary_light;
varying vec4 vary_fragcoord;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/postDeferredF.glsl b/indra/newview/app_settings/shaders/class1/deferred/postDeferredF.glsl
index 650e1a91a8..77f1b2224c 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/postDeferredF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/postDeferredF.glsl
@@ -4,54 +4,134 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
#extension GL_ARB_texture_rectangle : enable
uniform sampler2DRect diffuseRect;
-uniform sampler2DRect localLightMap;
-uniform sampler2DRect sunLightMap;
-uniform sampler2DRect giLightMap;
-uniform sampler2D luminanceMap;
-uniform sampler2DRect lightMap;
+uniform sampler2DRect edgeMap;
+uniform sampler2DRect depthMap;
+uniform sampler2DRect normalMap;
+uniform sampler2D bloomMap;
-uniform vec3 lum_quad;
-uniform float lum_lod;
-uniform vec4 ambient;
-
-uniform vec3 gi_quad;
+uniform float depth_cutoff;
+uniform float norm_cutoff;
+uniform float focal_distance;
+uniform float blur_constant;
+uniform float tan_pixel_angle;
+uniform float magnification;
+uniform mat4 inv_proj;
uniform vec2 screen_res;
+
varying vec2 vary_fragcoord;
-void main()
+float getDepth(vec2 pos_screen)
{
- vec2 tc = vary_fragcoord.xy;
- vec3 lum = texture2DLod(luminanceMap, tc/screen_res, lum_lod).rgb;
- float luminance = lum.r;
- luminance = luminance*lum_quad.y+lum_quad.z;
+ float z = texture2DRect(depthMap, pos_screen.xy).a;
+ z = z*2.0-1.0;
+ vec4 ndc = vec4(0.0, 0.0, z, 1.0);
+ vec4 p = inv_proj*ndc;
+ return p.z/p.w;
+}
- vec4 diff = texture2DRect(diffuseRect, vary_fragcoord.xy);
+float calc_cof(float depth)
+{
+ float sc = abs(depth-focal_distance)/-depth*blur_constant;
+
+ sc /= magnification;
+
+ // tan_pixel_angle = pixel_length/-depth;
+ float pixel_length = tan_pixel_angle*-focal_distance;
+
+ sc = sc/pixel_length;
+ sc *= 1.414;
+
+ return sc;
+}
- float ambocc = texture2DRect(lightMap, vary_fragcoord.xy).g;
-
- vec3 gi_col = texture2DRect(giLightMap, vary_fragcoord.xy).rgb;
- gi_col = gi_col*gi_col*gi_quad.x + gi_col*gi_quad.y+gi_quad.z*ambocc*ambient.rgb;
- gi_col *= diff;
+void dofSampleNear(inout vec4 diff, inout float w, float cur_sc, vec2 tc)
+{
+ float d = getDepth(tc);
- vec4 sun_col = texture2DRect(sunLightMap, vary_fragcoord.xy);
+ float sc = calc_cof(d);
- vec3 local_col = texture2DRect(localLightMap, vary_fragcoord.xy).rgb;
+ float wg = 0.25;
+ vec4 s = texture2DRect(diffuseRect, tc);
+ // de-weight dull areas to make highlights 'pop'
+ wg += s.r+s.g+s.b;
+
+ diff += wg*s;
+
+ w += wg;
+}
+
+void dofSample(inout vec4 diff, inout float w, float min_sc, float cur_depth, vec2 tc)
+{
+ float d = getDepth(tc);
+
+ float sc = calc_cof(d);
+
+ if (sc > min_sc //sampled pixel is more "out of focus" than current sample radius
+ || d < cur_depth) //sampled pixel is further away than current pixel
+ {
+ float wg = 0.25;
- sun_col *= 1.0/min(luminance, 1.0);
- gi_col *= 1.0/luminance;
+ vec4 s = texture2DRect(diffuseRect, tc);
+ // de-weight dull areas to make highlights 'pop'
+ wg += s.r+s.g+s.b;
+
+ diff += wg*s;
+
+ w += wg;
+ }
+}
+
+
+void main()
+{
+ vec3 norm = texture2DRect(normalMap, vary_fragcoord.xy).xyz;
+ norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm
- vec3 col = sun_col.rgb+gi_col+local_col;
+ vec2 tc = vary_fragcoord.xy;
- gl_FragColor.rgb = col.rgb;
- col.rgb = max(col.rgb-vec3(1.0,1.0,1.0), vec3(0.0, 0.0, 0.0));
+ float depth = getDepth(tc);
- gl_FragColor.a = 0.0; // max(dot(col.rgb,col.rgb)*lum_quad.x, sun_col.a);
+ vec4 diff = texture2DRect(diffuseRect, vary_fragcoord.xy);
- //gl_FragColor.rgb = vec3(lum_lod);
+ {
+ float w = 1.0;
+
+ float sc = calc_cof(depth);
+ sc = min(abs(sc), 10.0);
+
+ float fd = depth*0.5f;
+
+ float PI = 3.14159265358979323846264;
+
+ // sample quite uniformly spaced points within a circle, for a circular 'bokeh'
+ //if (depth < focal_distance)
+ {
+ while (sc > 0.5)
+ {
+ int its = int(max(1.0,(sc*3.7)));
+ for (int i=0; i<its; ++i)
+ {
+ float ang = sc+i*2*PI/its; // sc is added for rotary perturbance
+ float samp_x = sc*sin(ang);
+ float samp_y = sc*cos(ang);
+ // you could test sample coords against an interesting non-circular aperture shape here, if desired.
+ dofSample(diff, w, sc, depth, vary_fragcoord.xy + vec2(samp_x,samp_y));
+ }
+ sc -= 1.0;
+ }
+ }
+
+ diff /= w;
+ }
+
+ vec4 bloom = texture2D(bloomMap, vary_fragcoord.xy/screen_res);
+ gl_FragColor = diff + bloom;
}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/postDeferredNoDoFF.glsl b/indra/newview/app_settings/shaders/class1/deferred/postDeferredNoDoFF.glsl
new file mode 100644
index 0000000000..ab48d08bbb
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/postDeferredNoDoFF.glsl
@@ -0,0 +1,24 @@
+/**
+ * @file postDeferredF.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * $/LicenseInfo$
+ */
+
+#version 120
+
+#extension GL_ARB_texture_rectangle : enable
+
+uniform sampler2DRect diffuseRect;
+uniform sampler2D bloomMap;
+
+uniform vec2 screen_res;
+varying vec2 vary_fragcoord;
+
+void main()
+{
+ vec4 diff = texture2DRect(diffuseRect, vary_fragcoord.xy);
+
+ vec4 bloom = texture2D(bloomMap, vary_fragcoord.xy/screen_res);
+ gl_FragColor = diff + bloom;
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/postDeferredV.glsl b/indra/newview/app_settings/shaders/class1/deferred/postDeferredV.glsl
index 0ec81dcb02..12983baa94 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/postDeferredV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/postDeferredV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
varying vec2 vary_fragcoord;
uniform vec2 screen_res;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/postgiF.glsl b/indra/newview/app_settings/shaders/class1/deferred/postgiF.glsl
index e8e58f50e1..63b3c9f205 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/postgiF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/postgiF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
uniform sampler2DRect depthMap;
uniform sampler2DRect normalMap;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/postgiV.glsl b/indra/newview/app_settings/shaders/class1/deferred/postgiV.glsl
index e5f6217644..ae57227fe5 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/postgiV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/postgiV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
varying vec2 vary_fragcoord;
uniform vec2 screen_res;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/shadowF.glsl b/indra/newview/app_settings/shaders/class1/deferred/shadowF.glsl
index 378a3295ec..6674c4a5aa 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/shadowF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/shadowF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
uniform sampler2D diffuseMap;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/shadowV.glsl b/indra/newview/app_settings/shaders/class1/deferred/shadowV.glsl
index 666f909f01..db3bddc6be 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/shadowV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/shadowV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
varying vec4 post_pos;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl
index 5fbeceba81..29340c7e9f 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
#extension GL_ARB_texture_rectangle : enable
@@ -268,14 +270,10 @@ void main()
vec4 diffuse = texture2DRect(diffuseRect, tc);
vec4 spec = texture2DRect(specularRect, vary_fragcoord.xy);
- vec2 scol_ambocc = texture2DRect(lightMap, vary_fragcoord.xy).rg;
- float scol = max(scol_ambocc.r, diffuse.a);
- float ambocc = scol_ambocc.g;
-
- calcAtmospherics(pos.xyz, ambocc);
+ calcAtmospherics(pos.xyz, 1.0);
vec3 col = atmosAmbient(vec3(0));
- col += atmosAffectDirectionalLight(max(min(da, scol), diffuse.a));
+ col += atmosAffectDirectionalLight(max(min(da, 1.0), diffuse.a));
col *= diffuse.rgb;
@@ -285,7 +283,7 @@ void main()
//
vec3 refnormpersp = normalize(reflect(pos.xyz, norm.xyz));
float sa = dot(refnormpersp, vary_light.xyz);
- vec3 dumbshiny = vary_SunlitColor*scol_ambocc.r*texture2D(lightFunc, vec2(sa, spec.a)).a;
+ vec3 dumbshiny = vary_SunlitColor*texture2D(lightFunc, vec2(sa, spec.a)).a;
/*
// screen-space cheap fakey reflection map
diff --git a/indra/newview/app_settings/shaders/class1/deferred/softenLightV.glsl b/indra/newview/app_settings/shaders/class1/deferred/softenLightV.glsl
index 9d187b46e2..8f0bcca76b 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/softenLightV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/softenLightV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
uniform vec2 screen_res;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/sunLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/sunLightF.glsl
index d4d686bbb7..00093836a2 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/sunLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/sunLightF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
//class 1, no shadow, no SSAO, should never be called
diff --git a/indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOF.glsl b/indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOF.glsl
index cdbed4b791..cd91351ad4 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOF.glsl
@@ -4,6 +4,8 @@
* Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
* $License$
*/
+
+#version 120
#extension GL_ARB_texture_rectangle : enable
@@ -13,8 +15,6 @@ uniform sampler2DRect depthMap;
uniform sampler2DRect normalMap;
uniform sampler2D noiseMap;
-uniform sampler2D lightFunc;
-
// Inputs
uniform mat4 shadow_matrix[6];
@@ -51,57 +51,49 @@ float calcAmbientOcclusion(vec4 pos, vec3 norm)
{
float ret = 1.0;
- float dist = dot(pos.xyz,pos.xyz);
-
- if (dist < 64.0*64.0)
- {
- vec2 kern[8];
- // exponentially (^2) distant occlusion samples spread around origin
- kern[0] = vec2(-1.0, 0.0) * 0.125*0.125;
- kern[1] = vec2(1.0, 0.0) * 0.250*0.250;
- kern[2] = vec2(0.0, 1.0) * 0.375*0.375;
- kern[3] = vec2(0.0, -1.0) * 0.500*0.500;
- kern[4] = vec2(0.7071, 0.7071) * 0.625*0.625;
- kern[5] = vec2(-0.7071, -0.7071) * 0.750*0.750;
- kern[6] = vec2(-0.7071, 0.7071) * 0.875*0.875;
- kern[7] = vec2(0.7071, -0.7071) * 1.000*1.000;
+ vec2 kern[8];
+ // exponentially (^2) distant occlusion samples spread around origin
+ kern[0] = vec2(-1.0, 0.0) * 0.125*0.125;
+ kern[1] = vec2(1.0, 0.0) * 0.250*0.250;
+ kern[2] = vec2(0.0, 1.0) * 0.375*0.375;
+ kern[3] = vec2(0.0, -1.0) * 0.500*0.500;
+ kern[4] = vec2(0.7071, 0.7071) * 0.625*0.625;
+ kern[5] = vec2(-0.7071, -0.7071) * 0.750*0.750;
+ kern[6] = vec2(-0.7071, 0.7071) * 0.875*0.875;
+ kern[7] = vec2(0.7071, -0.7071) * 1.000*1.000;
- vec2 pos_screen = vary_fragcoord.xy;
- vec3 pos_world = pos.xyz;
- vec2 noise_reflect = texture2D(noiseMap, vary_fragcoord.xy/128.0).xy;
+ vec2 pos_screen = vary_fragcoord.xy;
+ vec3 pos_world = pos.xyz;
+ vec2 noise_reflect = texture2D(noiseMap, vary_fragcoord.xy/128.0).xy;
- float angle_hidden = 0.0;
- int points = 0;
+ float angle_hidden = 0.0;
+ int points = 0;
- float scale = min(ssao_radius / -pos_world.z, ssao_max_radius);
+ float scale = min(ssao_radius / -pos_world.z, ssao_max_radius);
- // it was found that keeping # of samples a constant was the fastest, probably due to compiler optimizations (unrolling?)
- for (int i = 0; i < 8; i++)
- {
- vec2 samppos_screen = pos_screen + scale * reflect(kern[i], noise_reflect);
- vec3 samppos_world = getPosition(samppos_screen).xyz;
+ // it was found that keeping # of samples a constant was the fastest, probably due to compiler optimizations unrolling?)
+ for (int i = 0; i < 8; i++)
+ {
+ vec2 samppos_screen = pos_screen + scale * reflect(kern[i], noise_reflect);
+ vec3 samppos_world = getPosition(samppos_screen).xyz;
- vec3 diff = pos_world - samppos_world;
- float dist2 = dot(diff, diff);
+ vec3 diff = pos_world - samppos_world;
+ float dist2 = dot(diff, diff);
- // assume each sample corresponds to an occluding sphere with constant radius, constant x-sectional area
- // --> solid angle shrinking by the square of distance
- //radius is somewhat arbitrary, can approx with just some constant k * 1 / dist^2
- //(k should vary inversely with # of samples, but this is taken care of later)
+ // assume each sample corresponds to an occluding sphere with constant radius, constant x-sectional area
+ // --> solid angle shrinking by the square of distance
+ //radius is somewhat arbitrary, can approx with just some constant k * 1 / dist^2
+ //(k should vary inversely with # of samples, but this is taken care of later)
- //if (dot((samppos_world - 0.05*norm - pos_world), norm) > 0.0) // -0.05*norm to shift sample point back slightly for flat surfaces
- // angle_hidden += min(1.0/dist2, ssao_factor_inv); // dist != 0 follows from conditional. max of 1.0 (= ssao_factor_inv * ssao_factor)
- angle_hidden = angle_hidden + float(dot((samppos_world - 0.05*norm - pos_world), norm) > 0.0) * min(1.0/dist2, ssao_factor_inv);
+ angle_hidden = angle_hidden + float(dot((samppos_world - 0.05*norm - pos_world), norm) > 0.0) * min(1.0/dist2, ssao_factor_inv);
- // 'blocked' samples (significantly closer to camera relative to pos_world) are "no data", not "no occlusion"
- points = points + int(diff.z > -1.0);
- }
+ // 'blocked' samples (significantly closer to camera relative to pos_world) are "no data", not "no occlusion"
+ points = points + int(diff.z > -1.0);
+ }
- angle_hidden = min(ssao_factor*angle_hidden/float(points), 1.0);
+ angle_hidden = min(ssao_factor*angle_hidden/float(points), 1.0);
- ret = (1.0 - (float(points != 0) * angle_hidden));
- ret += max((dist-32.0*32.0)/(32.0*32.0), 0.0);
- }
+ ret = (1.0 - (float(points != 0) * angle_hidden));
return min(ret, 1.0);
}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/sunLightV.glsl b/indra/newview/app_settings/shaders/class1/deferred/sunLightV.glsl
index 9d092d9cea..9beb513ad8 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/sunLightV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/sunLightV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
varying vec4 vary_light;
varying vec2 vary_fragcoord;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/terrainF.glsl b/indra/newview/app_settings/shaders/class1/deferred/terrainF.glsl
index 9ba508a30c..0edae47918 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/terrainF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/terrainF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
uniform sampler2D detail_0;
uniform sampler2D detail_1;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/terrainV.glsl b/indra/newview/app_settings/shaders/class1/deferred/terrainV.glsl
index 789e53b789..a6163063be 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/terrainV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/terrainV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
varying vec3 vary_normal;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/treeF.glsl b/indra/newview/app_settings/shaders/class1/deferred/treeF.glsl
index 1c1725a95c..c54d9a1e3e 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/treeF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/treeF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
uniform sampler2D diffuseMap;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/treeV.glsl b/indra/newview/app_settings/shaders/class1/deferred/treeV.glsl
index 45832e350f..29689ecbaf 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/treeV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/treeV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
varying vec3 vary_normal;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl b/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl
index ea531de24a..e76f598d09 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
#extension GL_ARB_texture_rectangle : enable
diff --git a/indra/newview/app_settings/shaders/class1/deferred/waterV.glsl b/indra/newview/app_settings/shaders/class1/deferred/waterV.glsl
index e002d75ebe..649e392630 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/waterV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/waterV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
void calcAtmospherics(vec3 inPositionEye);
diff --git a/indra/newview/app_settings/shaders/class1/effects/glowExtractF.glsl b/indra/newview/app_settings/shaders/class1/effects/glowExtractF.glsl
index 2d40a19fa6..f2023fa5ea 100644
--- a/indra/newview/app_settings/shaders/class1/effects/glowExtractF.glsl
+++ b/indra/newview/app_settings/shaders/class1/effects/glowExtractF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
#extension GL_ARB_texture_rectangle : enable
diff --git a/indra/newview/app_settings/shaders/class1/effects/glowExtractV.glsl b/indra/newview/app_settings/shaders/class1/effects/glowExtractV.glsl
index fe45898ed2..0ca0608b45 100644
--- a/indra/newview/app_settings/shaders/class1/effects/glowExtractV.glsl
+++ b/indra/newview/app_settings/shaders/class1/effects/glowExtractV.glsl
@@ -5,6 +5,7 @@
* $/LicenseInfo$
*/
+#version 120
void main()
{
diff --git a/indra/newview/app_settings/shaders/class1/effects/glowF.glsl b/indra/newview/app_settings/shaders/class1/effects/glowF.glsl
index 5b4e8b3ecc..65fc2e9f99 100644
--- a/indra/newview/app_settings/shaders/class1/effects/glowF.glsl
+++ b/indra/newview/app_settings/shaders/class1/effects/glowF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
uniform sampler2D diffuseMap;
uniform float glowStrength;
diff --git a/indra/newview/app_settings/shaders/class1/effects/glowV.glsl b/indra/newview/app_settings/shaders/class1/effects/glowV.glsl
index 97696e4719..0bd44cec90 100644
--- a/indra/newview/app_settings/shaders/class1/effects/glowV.glsl
+++ b/indra/newview/app_settings/shaders/class1/effects/glowV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
uniform vec2 glowDelta;
diff --git a/indra/newview/app_settings/shaders/class1/environment/terrainF.glsl b/indra/newview/app_settings/shaders/class1/environment/terrainF.glsl
index 3a852239fb..ac00f15b35 100644
--- a/indra/newview/app_settings/shaders/class1/environment/terrainF.glsl
+++ b/indra/newview/app_settings/shaders/class1/environment/terrainF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
uniform sampler2D detail0;
uniform sampler2D detail1;
diff --git a/indra/newview/app_settings/shaders/class1/environment/terrainV.glsl b/indra/newview/app_settings/shaders/class1/environment/terrainV.glsl
index 0d781fd849..1e19ee7699 100644
--- a/indra/newview/app_settings/shaders/class1/environment/terrainV.glsl
+++ b/indra/newview/app_settings/shaders/class1/environment/terrainV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol);
diff --git a/indra/newview/app_settings/shaders/class1/environment/terrainWaterF.glsl b/indra/newview/app_settings/shaders/class1/environment/terrainWaterF.glsl
index 99c340d91a..34f78565a5 100644
--- a/indra/newview/app_settings/shaders/class1/environment/terrainWaterF.glsl
+++ b/indra/newview/app_settings/shaders/class1/environment/terrainWaterF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
// this class1 shader is just a copy of terrainF
diff --git a/indra/newview/app_settings/shaders/class1/environment/underWaterF.glsl b/indra/newview/app_settings/shaders/class1/environment/underWaterF.glsl
index 66458ec66d..0dfac84a6e 100644
--- a/indra/newview/app_settings/shaders/class1/environment/underWaterF.glsl
+++ b/indra/newview/app_settings/shaders/class1/environment/underWaterF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
uniform sampler2D diffuseMap;
uniform sampler2D bumpMap;
diff --git a/indra/newview/app_settings/shaders/class1/environment/waterF.glsl b/indra/newview/app_settings/shaders/class1/environment/waterF.glsl
index 5f1fbee1df..4e9c09b1ea 100644
--- a/indra/newview/app_settings/shaders/class1/environment/waterF.glsl
+++ b/indra/newview/app_settings/shaders/class1/environment/waterF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
vec3 scaleSoftClip(vec3 inColor);
vec3 atmosTransport(vec3 inColor);
diff --git a/indra/newview/app_settings/shaders/class1/environment/waterFogF.glsl b/indra/newview/app_settings/shaders/class1/environment/waterFogF.glsl
index e5eb25f3fa..a34cf23790 100644
--- a/indra/newview/app_settings/shaders/class1/environment/waterFogF.glsl
+++ b/indra/newview/app_settings/shaders/class1/environment/waterFogF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
vec4 applyWaterFog(vec4 color)
{
diff --git a/indra/newview/app_settings/shaders/class1/environment/waterV.glsl b/indra/newview/app_settings/shaders/class1/environment/waterV.glsl
index 608a7a5807..161c794c68 100644
--- a/indra/newview/app_settings/shaders/class1/environment/waterV.glsl
+++ b/indra/newview/app_settings/shaders/class1/environment/waterV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
void calcAtmospherics(vec3 inPositionEye);
diff --git a/indra/newview/app_settings/shaders/class1/interface/highlightF.glsl b/indra/newview/app_settings/shaders/class1/interface/highlightF.glsl
index 5ac9e96601..6f821f893d 100644
--- a/indra/newview/app_settings/shaders/class1/interface/highlightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/interface/highlightF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
uniform sampler2D diffuseMap;
diff --git a/indra/newview/app_settings/shaders/class1/interface/highlightV.glsl b/indra/newview/app_settings/shaders/class1/interface/highlightV.glsl
index c5f69c4ad4..d1c98bf70c 100644
--- a/indra/newview/app_settings/shaders/class1/interface/highlightV.glsl
+++ b/indra/newview/app_settings/shaders/class1/interface/highlightV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
void main()
{
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightF.glsl
index ad128dae8d..9c59e8c3ad 100644
--- a/indra/newview/app_settings/shaders/class1/lighting/lightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
uniform sampler2D diffuseMap;
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightF.glsl
index 1742b9fc1c..1fee99c446 100644
--- a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
uniform sampler2D diffuseMap;
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyF.glsl
index 68b6603b4a..fb5da21c72 100644
--- a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyF.glsl
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
uniform sampler2D diffuseMap;
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyWaterF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyWaterF.glsl
new file mode 100644
index 0000000000..1bdaccf9b8
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyWaterF.glsl
@@ -0,0 +1,17 @@
+/**
+ * @file lightFullbrightShinyWaterF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+
+#version 120
+
+uniform sampler2D diffuseMap;
+uniform samplerCube environmentMap;
+
+void fullbright_shiny_lighting_water()
+{
+ gl_FragColor = texture2D(diffuseMap, gl_TexCoord[0].xy);
+}
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterF.glsl
index 693ed289f2..2e94d3bbf1 100644
--- a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterF.glsl
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterF.glsl
@@ -5,6 +5,8 @@
* $/LicenseInfo$
*/
+
+#version 120
uniform sampler2D diffuseMap;
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFuncSpecularV.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFuncSpecularV.glsl
index b888e70325..714f9a2551 100644
--- a/indra/newview/app_settings/shaders/class1/lighting/lightFuncSpecularV.glsl
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightFuncSpecularV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
float calcDirectionalLight(vec3 n, vec3 l)
{
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFuncV.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFuncV.glsl
index 4b6d95e177..65b45f8081 100644
--- a/indra/newview/app_settings/shaders/class1/lighting/lightFuncV.glsl
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightFuncV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
float calcDirectionalLight(vec3 n, vec3 l)
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightShinyF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightShinyF.glsl
index b127b1f8ea..7f65ea76f7 100644
--- a/indra/newview/app_settings/shaders/class1/lighting/lightShinyF.glsl
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightShinyF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
uniform sampler2D diffuseMap;
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightShinyWaterF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightShinyWaterF.glsl
index 05ad3256af..8f13e6dc04 100644
--- a/indra/newview/app_settings/shaders/class1/lighting/lightShinyWaterF.glsl
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightShinyWaterF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
uniform sampler2D diffuseMap;
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightSpecularV.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightSpecularV.glsl
index b1a7cb46ff..56f31f6a79 100644
--- a/indra/newview/app_settings/shaders/class1/lighting/lightSpecularV.glsl
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightSpecularV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
float calcDirectionalLight(vec3 n, vec3 l);
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightV.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightV.glsl
index f6afa6a3ae..64d549ff52 100644
--- a/indra/newview/app_settings/shaders/class1/lighting/lightV.glsl
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
float calcDirectionalLight(vec3 n, vec3 l);
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightWaterF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightWaterF.glsl
index e5e6ddc2d8..c5d084c132 100644
--- a/indra/newview/app_settings/shaders/class1/lighting/lightWaterF.glsl
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightWaterF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
uniform sampler2D diffuseMap;
diff --git a/indra/newview/app_settings/shaders/class1/lighting/sumLightsSpecularV.glsl b/indra/newview/app_settings/shaders/class1/lighting/sumLightsSpecularV.glsl
index a0649aea88..732d246471 100644
--- a/indra/newview/app_settings/shaders/class1/lighting/sumLightsSpecularV.glsl
+++ b/indra/newview/app_settings/shaders/class1/lighting/sumLightsSpecularV.glsl
@@ -4,6 +4,9 @@
* $LicenseInfo:firstyear=2005&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
+
float calcDirectionalLightSpecular(inout vec4 specular, vec3 view, vec3 n, vec3 l, vec3 lightCol, float da);
vec3 atmosAmbient(vec3 light);
vec3 atmosAffectDirectionalLight(float lightIntensity);
diff --git a/indra/newview/app_settings/shaders/class1/lighting/sumLightsV.glsl b/indra/newview/app_settings/shaders/class1/lighting/sumLightsV.glsl
index c7d40d853f..73e1a1ec26 100644
--- a/indra/newview/app_settings/shaders/class1/lighting/sumLightsV.glsl
+++ b/indra/newview/app_settings/shaders/class1/lighting/sumLightsV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2005&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
float calcDirectionalLight(vec3 n, vec3 l);
diff --git a/indra/newview/app_settings/shaders/class1/objects/fullbrightF.glsl b/indra/newview/app_settings/shaders/class1/objects/fullbrightF.glsl
index 9da4c2c92b..afc3dc89bf 100644
--- a/indra/newview/app_settings/shaders/class1/objects/fullbrightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/objects/fullbrightF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
void fullbright_lighting();
diff --git a/indra/newview/app_settings/shaders/class1/objects/fullbrightShinyF.glsl b/indra/newview/app_settings/shaders/class1/objects/fullbrightShinyF.glsl
index 1c8a9a1a30..3dc4294f67 100644
--- a/indra/newview/app_settings/shaders/class1/objects/fullbrightShinyF.glsl
+++ b/indra/newview/app_settings/shaders/class1/objects/fullbrightShinyF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
void fullbright_shiny_lighting();
diff --git a/indra/newview/app_settings/shaders/class1/objects/fullbrightShinySkinnedV.glsl b/indra/newview/app_settings/shaders/class1/objects/fullbrightShinySkinnedV.glsl
new file mode 100644
index 0000000000..f0baeeeee5
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/objects/fullbrightShinySkinnedV.glsl
@@ -0,0 +1,39 @@
+/**
+ * @file shinySimpleSkinnedV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#version 120
+
+void calcAtmospherics(vec3 inPositionEye);
+mat4 getObjectSkinnedTransform();
+
+attribute vec4 object_weight;
+
+void main()
+{
+ mat4 mat = getObjectSkinnedTransform();
+
+ mat = gl_ModelViewMatrix * mat;
+ vec3 pos = (mat*gl_Vertex).xyz;
+
+ vec4 norm = gl_Vertex;
+ norm.xyz += gl_Normal.xyz;
+ norm.xyz = (mat*norm).xyz;
+ norm.xyz = normalize(norm.xyz-pos.xyz);
+
+ vec3 ref = reflect(pos.xyz, -norm.xyz);
+
+ gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
+ gl_TexCoord[1] = gl_TextureMatrix[1]*vec4(ref,1.0);
+
+ calcAtmospherics(pos.xyz);
+
+ gl_FrontColor = gl_Color;
+
+ gl_Position = gl_ProjectionMatrix*vec4(pos, 1.0);
+
+ gl_FogFragCoord = pos.z;
+}
diff --git a/indra/newview/app_settings/shaders/class1/objects/fullbrightShinyV.glsl b/indra/newview/app_settings/shaders/class1/objects/fullbrightShinyV.glsl
index 032def63b3..02367b9439 100644
--- a/indra/newview/app_settings/shaders/class1/objects/fullbrightShinyV.glsl
+++ b/indra/newview/app_settings/shaders/class1/objects/fullbrightShinyV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
void calcAtmospherics(vec3 inPositionEye);
diff --git a/indra/newview/app_settings/shaders/class1/objects/fullbrightShinyWaterF.glsl b/indra/newview/app_settings/shaders/class1/objects/fullbrightShinyWaterF.glsl
new file mode 100644
index 0000000000..5daf66fb31
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/objects/fullbrightShinyWaterF.glsl
@@ -0,0 +1,15 @@
+/**
+ * @file fullbrightShinyWaterF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#version 120
+
+void fullbright_shiny_lighting_water();
+
+void main()
+{
+ fullbright_shiny_lighting_water();
+}
diff --git a/indra/newview/app_settings/shaders/class1/objects/fullbrightSkinnedV.glsl b/indra/newview/app_settings/shaders/class1/objects/fullbrightSkinnedV.glsl
new file mode 100644
index 0000000000..02ff3cc2a9
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/objects/fullbrightSkinnedV.glsl
@@ -0,0 +1,37 @@
+/**
+ * @file fullbrightSkinnedV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#version 120
+
+void calcAtmospherics(vec3 inPositionEye);
+mat4 getObjectSkinnedTransform();
+
+attribute vec4 object_weight;
+
+void main()
+{
+ //transform vertex
+ gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
+
+ mat4 mat = getObjectSkinnedTransform();
+
+ mat = gl_ModelViewMatrix * mat;
+ vec3 pos = (mat*gl_Vertex).xyz;
+
+ vec4 norm = gl_Vertex;
+ norm.xyz += gl_Normal.xyz;
+ norm.xyz = (mat*norm).xyz;
+ norm.xyz = normalize(norm.xyz-pos.xyz);
+
+ calcAtmospherics(pos.xyz);
+
+ gl_FrontColor = gl_Color;
+
+ gl_Position = gl_ProjectionMatrix*vec4(pos, 1.0);
+
+ gl_FogFragCoord = pos.z;
+}
diff --git a/indra/newview/app_settings/shaders/class1/objects/fullbrightV.glsl b/indra/newview/app_settings/shaders/class1/objects/fullbrightV.glsl
index 914e417ca0..38e07dbd80 100644
--- a/indra/newview/app_settings/shaders/class1/objects/fullbrightV.glsl
+++ b/indra/newview/app_settings/shaders/class1/objects/fullbrightV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
void calcAtmospherics(vec3 inPositionEye);
diff --git a/indra/newview/app_settings/shaders/class1/objects/fullbrightWaterF.glsl b/indra/newview/app_settings/shaders/class1/objects/fullbrightWaterF.glsl
index df76e9e1eb..afaac4f69c 100644
--- a/indra/newview/app_settings/shaders/class1/objects/fullbrightWaterF.glsl
+++ b/indra/newview/app_settings/shaders/class1/objects/fullbrightWaterF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
void fullbright_lighting_water();
diff --git a/indra/newview/app_settings/shaders/class1/objects/shinyF.glsl b/indra/newview/app_settings/shaders/class1/objects/shinyF.glsl
index 6bcd44506d..2cf7a69baa 100644
--- a/indra/newview/app_settings/shaders/class1/objects/shinyF.glsl
+++ b/indra/newview/app_settings/shaders/class1/objects/shinyF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
void shiny_lighting();
diff --git a/indra/newview/app_settings/shaders/class1/objects/shinySimpleSkinnedV.glsl b/indra/newview/app_settings/shaders/class1/objects/shinySimpleSkinnedV.glsl
new file mode 100644
index 0000000000..4146646058
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/objects/shinySimpleSkinnedV.glsl
@@ -0,0 +1,39 @@
+/**
+ * @file shinySimpleSkinnedV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#version 120
+
+vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol);
+void calcAtmospherics(vec3 inPositionEye);
+mat4 getObjectSkinnedTransform();
+
+attribute vec4 object_weight;
+
+void main()
+{
+ mat4 mat = getObjectSkinnedTransform();
+
+ mat = gl_ModelViewMatrix * mat;
+ vec3 pos = (mat*gl_Vertex).xyz;
+
+ vec4 norm = gl_Vertex;
+ norm.xyz += gl_Normal.xyz;
+ norm.xyz = (mat*norm).xyz;
+ norm.xyz = normalize(norm.xyz-pos.xyz);
+
+ vec3 ref = reflect(pos.xyz, -norm.xyz);
+
+ gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
+ gl_TexCoord[1] = gl_TextureMatrix[1]*vec4(ref,1.0);
+
+ calcAtmospherics(pos.xyz);
+
+ vec4 color = calcLighting(pos.xyz, norm.xyz, gl_Color, vec4(0.));
+ gl_FrontColor = color;
+
+ gl_Position = gl_ProjectionMatrix*vec4(pos, 1.0);
+}
diff --git a/indra/newview/app_settings/shaders/class1/objects/shinyV.glsl b/indra/newview/app_settings/shaders/class1/objects/shinyV.glsl
index 074892c98e..6ea83b721d 100644
--- a/indra/newview/app_settings/shaders/class1/objects/shinyV.glsl
+++ b/indra/newview/app_settings/shaders/class1/objects/shinyV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
void calcAtmospherics(vec3 inPositionEye);
@@ -12,7 +14,7 @@ uniform vec4 origin;
void main()
{
//transform vertex
- gl_Position = ftransform(); //gl_ModelViewProjectionMatrix * gl_Vertex;
+ gl_Position = ftransform();
vec4 pos = (gl_ModelViewMatrix * gl_Vertex);
vec3 norm = normalize(gl_NormalMatrix * gl_Normal);
diff --git a/indra/newview/app_settings/shaders/class1/objects/shinyWaterF.glsl b/indra/newview/app_settings/shaders/class1/objects/shinyWaterF.glsl
index 54b30573e7..e3babe2210 100644
--- a/indra/newview/app_settings/shaders/class1/objects/shinyWaterF.glsl
+++ b/indra/newview/app_settings/shaders/class1/objects/shinyWaterF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
void shiny_lighting_water();
diff --git a/indra/newview/app_settings/shaders/class1/objects/simpleF.glsl b/indra/newview/app_settings/shaders/class1/objects/simpleF.glsl
index 61c2ce4272..d449d37c0c 100644
--- a/indra/newview/app_settings/shaders/class1/objects/simpleF.glsl
+++ b/indra/newview/app_settings/shaders/class1/objects/simpleF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
void default_lighting();
diff --git a/indra/newview/app_settings/shaders/class1/objects/simpleSkinnedV.glsl b/indra/newview/app_settings/shaders/class1/objects/simpleSkinnedV.glsl
new file mode 100644
index 0000000000..be38a14d52
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/objects/simpleSkinnedV.glsl
@@ -0,0 +1,39 @@
+/**
+ * @file simpleSkinnedV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#version 120
+
+vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol);
+void calcAtmospherics(vec3 inPositionEye);
+mat4 getObjectSkinnedTransform();
+
+attribute vec4 object_weight;
+
+void main()
+{
+ //transform vertex
+ gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
+
+ mat4 mat = getObjectSkinnedTransform();
+
+ mat = gl_ModelViewMatrix * mat;
+ vec3 pos = (mat*gl_Vertex).xyz;
+
+ vec4 norm = gl_Vertex;
+ norm.xyz += gl_Normal.xyz;
+ norm.xyz = (mat*norm).xyz;
+ norm.xyz = normalize(norm.xyz-pos.xyz);
+
+ calcAtmospherics(pos.xyz);
+
+ vec4 color = calcLighting(pos.xyz, norm.xyz, gl_Color, vec4(0.));
+ gl_FrontColor = color;
+
+ gl_Position = gl_ProjectionMatrix*vec4(pos, 1.0);
+
+ gl_FogFragCoord = pos.z;
+}
diff --git a/indra/newview/app_settings/shaders/class1/objects/simpleV.glsl b/indra/newview/app_settings/shaders/class1/objects/simpleV.glsl
index ced1a4be01..0d8e14e2e3 100644
--- a/indra/newview/app_settings/shaders/class1/objects/simpleV.glsl
+++ b/indra/newview/app_settings/shaders/class1/objects/simpleV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol);
void calcAtmospherics(vec3 inPositionEye);
diff --git a/indra/newview/app_settings/shaders/class1/objects/simpleWaterF.glsl b/indra/newview/app_settings/shaders/class1/objects/simpleWaterF.glsl
index 5e44212aed..68bd81e029 100644
--- a/indra/newview/app_settings/shaders/class1/objects/simpleWaterF.glsl
+++ b/indra/newview/app_settings/shaders/class1/objects/simpleWaterF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
void default_lighting_water();
diff --git a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsF.glsl b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsF.glsl
index 7a05b8c8c6..f337bde329 100644
--- a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsF.glsl
+++ b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2005&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
vec3 atmosLighting(vec3 light)
{
diff --git a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsHelpersV.glsl b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsHelpersV.glsl
index 874f2b4843..4b402a7028 100644
--- a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsHelpersV.glsl
+++ b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsHelpersV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2005&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
vec3 atmosAmbient(vec3 light)
{
diff --git a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsV.glsl b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsV.glsl
index 7ead9ddf26..20948b1e46 100644
--- a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsV.glsl
+++ b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2005&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
void setPositionEye(vec3 v);
diff --git a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsF.glsl b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsF.glsl
index f6032f8d41..8a2c2a7186 100644
--- a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsF.glsl
+++ b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
varying vec3 vary_PositionEye;
diff --git a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsV.glsl b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsV.glsl
index a696ddf607..a1dd4ed5fe 100644
--- a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsV.glsl
+++ b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
varying vec3 vary_PositionEye;
diff --git a/indra/newview/app_settings/shaders/class1/windlight/gammaF.glsl b/indra/newview/app_settings/shaders/class1/windlight/gammaF.glsl
index 4a1899798a..7aed1fd3b5 100644
--- a/indra/newview/app_settings/shaders/class1/windlight/gammaF.glsl
+++ b/indra/newview/app_settings/shaders/class1/windlight/gammaF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
uniform vec4 gamma;
diff --git a/indra/newview/app_settings/shaders/class1/windlight/transportF.glsl b/indra/newview/app_settings/shaders/class1/windlight/transportF.glsl
index b78b90545e..6780dc4d3e 100644
--- a/indra/newview/app_settings/shaders/class1/windlight/transportF.glsl
+++ b/indra/newview/app_settings/shaders/class1/windlight/transportF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2005&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
vec3 atmosTransport(vec3 light)
{
diff --git a/indra/newview/app_settings/shaders/class2/avatar/eyeballV.glsl b/indra/newview/app_settings/shaders/class2/avatar/eyeballV.glsl
index 47300f0b39..172c2ca078 100644
--- a/indra/newview/app_settings/shaders/class2/avatar/eyeballV.glsl
+++ b/indra/newview/app_settings/shaders/class2/avatar/eyeballV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
vec4 calcLightingSpecular(vec3 pos, vec3 norm, vec4 color, inout vec4 specularColor, vec4 baseCol);
void calcAtmospherics(vec3 inPositionEye);
diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl
index e2d7cd94da..6dfc1b952c 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
#extension GL_ARB_texture_rectangle : enable
@@ -12,7 +14,6 @@ uniform sampler2DRectShadow shadowMap0;
uniform sampler2DRectShadow shadowMap1;
uniform sampler2DRectShadow shadowMap2;
uniform sampler2DRectShadow shadowMap3;
-uniform sampler2D noiseMap;
uniform sampler2DRect depthMap;
uniform mat4 shadow_matrix[6];
@@ -27,7 +28,7 @@ varying vec3 vary_ambient;
varying vec3 vary_directional;
varying vec3 vary_fragcoord;
varying vec3 vary_position;
-varying vec3 vary_light;
+varying vec3 vary_pointlight_col;
uniform float shadow_bias;
@@ -68,8 +69,6 @@ void main()
vec2 frag = vary_fragcoord.xy/vary_fragcoord.z*0.5+0.5;
frag *= screen_res;
- vec3 samp_pos = getPosition(frag).xyz;
-
float shadow = 1.0;
vec4 pos = vec4(vary_position, 1.0);
@@ -106,16 +105,21 @@ void main()
}
}
+ vec4 diff= texture2D(diffuseMap, gl_TexCoord[0].xy);
+
vec4 col = vec4(vary_ambient + vary_directional.rgb*shadow, gl_Color.a);
- vec4 color = texture2D(diffuseMap, gl_TexCoord[0].xy) * col;
+ vec4 color = diff * col;
color.rgb = atmosLighting(color.rgb);
color.rgb = scaleSoftClip(color.rgb);
+ color.rgb += diff.rgb * vary_pointlight_col.rgb;
+
//gl_FragColor = gl_Color;
gl_FragColor = color;
- //gl_FragColor = vec4(1,0,1,1)*shadow;
+ //gl_FragColor.r = 0.0;
+ //gl_FragColor = vec4(1,shadow,1,1);
}
diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaSkinnedV.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaSkinnedV.glsl
new file mode 100644
index 0000000000..d227346163
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/deferred/alphaSkinnedV.glsl
@@ -0,0 +1,110 @@
+/**
+ * @file alphaSkinnedV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#version 120
+
+vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol);
+void calcAtmospherics(vec3 inPositionEye);
+
+float calcDirectionalLight(vec3 n, vec3 l);
+mat4 getObjectSkinnedTransform();
+vec3 atmosAmbient(vec3 light);
+vec3 atmosAffectDirectionalLight(float lightIntensity);
+vec3 scaleDownLight(vec3 light);
+vec3 scaleUpLight(vec3 light);
+
+varying vec3 vary_ambient;
+varying vec3 vary_directional;
+varying vec3 vary_fragcoord;
+varying vec3 vary_position;
+varying vec3 vary_pointlight_col;
+
+uniform float near_clip;
+uniform float shadow_offset;
+uniform float shadow_bias;
+
+float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float fa, float is_pointlight)
+{
+ //get light vector
+ vec3 lv = lp.xyz-v;
+
+ //get distance
+ float d = length(lv);
+
+ //normalize light vector
+ lv *= 1.0/d;
+
+ //distance attenuation
+ float dist2 = d*d/(la*la);
+ float da = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0);
+
+ // spotlight coefficient.
+ float spot = max(dot(-ln, lv), is_pointlight);
+ da *= spot*spot; // GL_SPOT_EXPONENT=2
+
+ //angular attenuation
+ da *= calcDirectionalLight(n, lv);
+
+ return da;
+}
+
+void main()
+{
+ gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
+
+ mat4 mat = getObjectSkinnedTransform();
+
+ mat = gl_ModelViewMatrix * mat;
+
+ vec3 pos = (mat*gl_Vertex).xyz;
+
+ gl_Position = gl_ProjectionMatrix * vec4(pos, 1.0);
+
+ vec4 n = gl_Vertex;
+ n.xyz += gl_Normal.xyz;
+ n.xyz = (mat*n).xyz;
+ n.xyz = normalize(n.xyz-pos.xyz);
+
+ vec3 norm = n.xyz;
+
+ float dp_directional_light = max(0.0, dot(norm, gl_LightSource[0].position.xyz));
+ vary_position = pos.xyz + gl_LightSource[0].position.xyz * (1.0-dp_directional_light)*shadow_offset;
+
+ calcAtmospherics(pos.xyz);
+
+ //vec4 color = calcLighting(pos.xyz, norm, gl_Color, vec4(0.));
+ vec4 col = vec4(0.0, 0.0, 0.0, gl_Color.a);
+
+ // Collect normal lights
+ col.rgb += gl_LightSource[2].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[2].position, gl_LightSource[2].spotDirection.xyz, gl_LightSource[2].linearAttenuation, gl_LightSource[2].quadraticAttenuation, gl_LightSource[2].specular.a);
+ col.rgb += gl_LightSource[3].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[3].position, gl_LightSource[3].spotDirection.xyz, gl_LightSource[3].linearAttenuation, gl_LightSource[3].quadraticAttenuation ,gl_LightSource[3].specular.a);
+ col.rgb += gl_LightSource[4].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[4].position, gl_LightSource[4].spotDirection.xyz, gl_LightSource[4].linearAttenuation, gl_LightSource[4].quadraticAttenuation, gl_LightSource[4].specular.a);
+ col.rgb += gl_LightSource[5].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[5].position, gl_LightSource[5].spotDirection.xyz, gl_LightSource[5].linearAttenuation, gl_LightSource[5].quadraticAttenuation, gl_LightSource[5].specular.a);
+ col.rgb += gl_LightSource[6].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[6].position, gl_LightSource[6].spotDirection.xyz, gl_LightSource[6].linearAttenuation, gl_LightSource[6].quadraticAttenuation, gl_LightSource[6].specular.a);
+ col.rgb += gl_LightSource[7].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[7].position, gl_LightSource[7].spotDirection.xyz, gl_LightSource[7].linearAttenuation, gl_LightSource[7].quadraticAttenuation, gl_LightSource[7].specular.a);
+
+ vary_pointlight_col = col.rgb*gl_Color.rgb;
+
+ col.rgb = vec3(0,0,0);
+
+ // Add windlight lights
+ col.rgb = atmosAmbient(vec3(0.));
+
+ vary_ambient = col.rgb*gl_Color.rgb;
+ vary_directional.rgb = gl_Color.rgb*atmosAffectDirectionalLight(max(calcDirectionalLight(norm, gl_LightSource[0].position.xyz), (1.0-gl_Color.a)*(1.0-gl_Color.a)));
+
+ col.rgb = min(col.rgb*gl_Color.rgb, 1.0);
+
+ gl_FrontColor = col;
+
+ gl_FogFragCoord = pos.z;
+
+ pos.xyz = (gl_ModelViewProjectionMatrix * gl_Vertex).xyz;
+ vary_fragcoord.xyz = pos.xyz + vec3(0,0,near_clip);
+
+}
+
diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaV.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaV.glsl
index 45f727951e..86f014df35 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/alphaV.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/alphaV.glsl
@@ -4,12 +4,13 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol);
void calcAtmospherics(vec3 inPositionEye);
float calcDirectionalLight(vec3 n, vec3 l);
-float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float is_pointlight);
vec3 atmosAmbient(vec3 light);
vec3 atmosAffectDirectionalLight(float lightIntensity);
@@ -20,12 +21,37 @@ varying vec3 vary_ambient;
varying vec3 vary_directional;
varying vec3 vary_fragcoord;
varying vec3 vary_position;
-varying vec3 vary_light;
+varying vec3 vary_pointlight_col;
uniform float near_clip;
uniform float shadow_offset;
uniform float shadow_bias;
+float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float fa, float is_pointlight)
+{
+ //get light vector
+ vec3 lv = lp.xyz-v;
+
+ //get distance
+ float d = length(lv);
+
+ //normalize light vector
+ lv *= 1.0/d;
+
+ //distance attenuation
+ float dist2 = d*d/(la*la);
+ float da = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0);
+
+ // spotlight coefficient.
+ float spot = max(dot(-ln, lv), is_pointlight);
+ da *= spot*spot; // GL_SPOT_EXPONENT=2
+
+ //angular attenuation
+ da *= calcDirectionalLight(n, lv);
+
+ return da;
+}
+
void main()
{
//transform vertex
@@ -44,25 +70,25 @@ void main()
//vec4 color = calcLighting(pos.xyz, norm, gl_Color, vec4(0.));
vec4 col = vec4(0.0, 0.0, 0.0, gl_Color.a);
- // Collect normal lights (need to be divided by two, as we later multiply by 2)
- col.rgb += gl_LightSource[2].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[2].position, gl_LightSource[2].spotDirection.xyz, gl_LightSource[2].linearAttenuation, gl_LightSource[2].specular.a);
- col.rgb += gl_LightSource[3].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[3].position, gl_LightSource[3].spotDirection.xyz, gl_LightSource[3].linearAttenuation, gl_LightSource[3].specular.a);
- col.rgb += gl_LightSource[4].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[4].position, gl_LightSource[4].spotDirection.xyz, gl_LightSource[4].linearAttenuation, gl_LightSource[4].specular.a);
- col.rgb += gl_LightSource[5].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[5].position, gl_LightSource[5].spotDirection.xyz, gl_LightSource[5].linearAttenuation, gl_LightSource[5].specular.a);
- col.rgb += gl_LightSource[6].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[6].position, gl_LightSource[6].spotDirection.xyz, gl_LightSource[6].linearAttenuation, gl_LightSource[6].specular.a);
- col.rgb += gl_LightSource[7].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[7].position, gl_LightSource[7].spotDirection.xyz, gl_LightSource[7].linearAttenuation, gl_LightSource[7].specular.a);
- col.rgb += gl_LightSource[1].diffuse.rgb*calcDirectionalLight(norm, gl_LightSource[1].position.xyz);
- col.rgb = scaleDownLight(col.rgb);
+ // Collect normal lights
+ col.rgb += gl_LightSource[2].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[2].position, gl_LightSource[2].spotDirection.xyz, gl_LightSource[2].linearAttenuation, gl_LightSource[2].quadraticAttenuation, gl_LightSource[2].specular.a);
+ col.rgb += gl_LightSource[3].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[3].position, gl_LightSource[3].spotDirection.xyz, gl_LightSource[3].linearAttenuation, gl_LightSource[3].quadraticAttenuation ,gl_LightSource[3].specular.a);
+ col.rgb += gl_LightSource[4].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[4].position, gl_LightSource[4].spotDirection.xyz, gl_LightSource[4].linearAttenuation, gl_LightSource[4].quadraticAttenuation, gl_LightSource[4].specular.a);
+ col.rgb += gl_LightSource[5].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[5].position, gl_LightSource[5].spotDirection.xyz, gl_LightSource[5].linearAttenuation, gl_LightSource[5].quadraticAttenuation, gl_LightSource[5].specular.a);
+ col.rgb += gl_LightSource[6].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[6].position, gl_LightSource[6].spotDirection.xyz, gl_LightSource[6].linearAttenuation, gl_LightSource[6].quadraticAttenuation, gl_LightSource[6].specular.a);
+ col.rgb += gl_LightSource[7].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[7].position, gl_LightSource[7].spotDirection.xyz, gl_LightSource[7].linearAttenuation, gl_LightSource[7].quadraticAttenuation, gl_LightSource[7].specular.a);
+ vary_pointlight_col = col.rgb*gl_Color.rgb;
+
+ col.rgb = vec3(0,0,0);
+
// Add windlight lights
- col.rgb += atmosAmbient(vec3(0.));
-
- vary_light = gl_LightSource[0].position.xyz;
+ col.rgb = atmosAmbient(vec3(0.));
vary_ambient = col.rgb*gl_Color.rgb;
vary_directional.rgb = gl_Color.rgb*atmosAffectDirectionalLight(max(calcDirectionalLight(norm, gl_LightSource[0].position.xyz), (1.0-gl_Color.a)*(1.0-gl_Color.a)));
- col.rgb = min(col.rgb*gl_Color.rgb, 1.0);
+ col.rgb = col.rgb*gl_Color.rgb;
gl_FrontColor = col;
diff --git a/indra/newview/app_settings/shaders/class2/deferred/avatarAlphaF.glsl b/indra/newview/app_settings/shaders/class2/deferred/avatarAlphaF.glsl
deleted file mode 100644
index 5ecbbd2c4f..0000000000
--- a/indra/newview/app_settings/shaders/class2/deferred/avatarAlphaF.glsl
+++ /dev/null
@@ -1,98 +0,0 @@
-/**
- * @file avatarAlphaF.glsl
- *
- * $LicenseInfo:firstyear=2007&license=viewerlgpl$
- * $/LicenseInfo$
- */
-
-#extension GL_ARB_texture_rectangle : enable
-
-uniform sampler2D diffuseMap;
-uniform sampler2DRectShadow shadowMap0;
-uniform sampler2DRectShadow shadowMap1;
-uniform sampler2DRectShadow shadowMap2;
-uniform sampler2DRectShadow shadowMap3;
-uniform sampler2D noiseMap;
-
-uniform mat4 shadow_matrix[6];
-uniform vec4 shadow_clip;
-uniform vec2 screen_res;
-uniform vec2 shadow_res;
-
-vec3 atmosLighting(vec3 light);
-vec3 scaleSoftClip(vec3 light);
-
-varying vec3 vary_ambient;
-varying vec3 vary_directional;
-varying vec3 vary_position;
-varying vec3 vary_normal;
-
-uniform float shadow_bias;
-
-float pcfShadow(sampler2DRectShadow shadowMap, vec4 stc, float scl)
-{
- stc.xyz /= stc.w;
- stc.z += shadow_bias;
-
- float cs = shadow2DRect(shadowMap, stc.xyz).x;
- float shadow = cs;
-
- shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(scl, scl, 0.0)).x, cs);
- shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(scl, -scl, 0.0)).x, cs);
- shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(-scl, scl, 0.0)).x, cs);
- shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(-scl, -scl, 0.0)).x, cs);
-
- return shadow/5.0;
-}
-
-void main()
-{
- float shadow = 1.0;
- vec4 pos = vec4(vary_position, 1.0);
- vec3 norm = normalize(vary_normal);
-
- //vec3 nz = texture2D(noiseMap, gl_FragCoord.xy/128.0).xyz;
-
- vec4 spos = pos;
-
- if (spos.z > -shadow_clip.w)
- {
- vec4 lpos;
-
- if (spos.z < -shadow_clip.z)
- {
- lpos = shadow_matrix[3]*spos;
- lpos.xy *= shadow_res;
- shadow = pcfShadow(shadowMap3, lpos, 1.5);
- shadow += max((pos.z+shadow_clip.z)/(shadow_clip.z-shadow_clip.w)*2.0-1.0, 0.0);
- }
- else if (spos.z < -shadow_clip.y)
- {
- lpos = shadow_matrix[2]*spos;
- lpos.xy *= shadow_res;
- shadow = pcfShadow(shadowMap2, lpos, 1.5);
- }
- else if (spos.z < -shadow_clip.x)
- {
- lpos = shadow_matrix[1]*spos;
- lpos.xy *= shadow_res;
- shadow = pcfShadow(shadowMap1, lpos, 1.5);
- }
- else
- {
- lpos = shadow_matrix[0]*spos;
- lpos.xy *= shadow_res;
- shadow = pcfShadow(shadowMap0, lpos, 1.5);
- }
- }
-
-
- vec4 col = vec4(vary_ambient + vary_directional*shadow, gl_Color.a);
- vec4 color = texture2D(diffuseMap, gl_TexCoord[0].xy) * col;
-
- color.rgb = atmosLighting(color.rgb);
-
- color.rgb = scaleSoftClip(color.rgb);
-
- gl_FragColor = color;
-}
diff --git a/indra/newview/app_settings/shaders/class2/deferred/avatarAlphaV.glsl b/indra/newview/app_settings/shaders/class2/deferred/avatarAlphaV.glsl
index d7d1111ba8..495e86c8db 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/avatarAlphaV.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/avatarAlphaV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol);
mat4 getSkinnedTransform();
@@ -20,12 +22,38 @@ vec3 scaleUpLight(vec3 light);
varying vec3 vary_position;
varying vec3 vary_ambient;
varying vec3 vary_directional;
-varying vec3 vary_normal;
+varying vec3 vary_fragcoord;
+varying vec3 vary_pointlight_col;
uniform float near_clip;
uniform float shadow_offset;
uniform float shadow_bias;
+float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float fa, float is_pointlight)
+{
+ //get light vector
+ vec3 lv = lp.xyz-v;
+
+ //get distance
+ float d = length(lv);
+
+ //normalize light vector
+ lv *= 1.0/d;
+
+ //distance attenuation
+ float dist2 = d*d/(la*la);
+ float da = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0);
+
+ // spotlight coefficient.
+ float spot = max(dot(-ln, lv), is_pointlight);
+ da *= spot*spot; // GL_SPOT_EXPONENT=2
+
+ //angular attenuation
+ da *= calcDirectionalLight(n, lv);
+
+ return da;
+}
+
void main()
{
gl_TexCoord[0] = gl_MultiTexCoord0;
@@ -48,7 +76,6 @@ void main()
float dp_directional_light = max(0.0, dot(norm, gl_LightSource[0].position.xyz));
vary_position = pos.xyz + gl_LightSource[0].position.xyz * (1.0-dp_directional_light)*shadow_offset;
- vary_normal = norm;
calcAtmospherics(pos.xyz);
@@ -56,18 +83,20 @@ void main()
vec4 col = vec4(0.0, 0.0, 0.0, gl_Color.a);
- // Collect normal lights (need to be divided by two, as we later multiply by 2)
- col.rgb += gl_LightSource[2].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[2].position, gl_LightSource[2].spotDirection.xyz, gl_LightSource[2].linearAttenuation, gl_LightSource[2].specular.a);
- col.rgb += gl_LightSource[3].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[3].position, gl_LightSource[3].spotDirection.xyz, gl_LightSource[3].linearAttenuation, gl_LightSource[3].specular.a);
- col.rgb += gl_LightSource[4].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[4].position, gl_LightSource[4].spotDirection.xyz, gl_LightSource[4].linearAttenuation, gl_LightSource[4].specular.a);
- col.rgb += gl_LightSource[5].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[5].position, gl_LightSource[5].spotDirection.xyz, gl_LightSource[5].linearAttenuation, gl_LightSource[5].specular.a);
- col.rgb += gl_LightSource[6].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[6].position, gl_LightSource[6].spotDirection.xyz, gl_LightSource[6].linearAttenuation, gl_LightSource[6].specular.a);
- col.rgb += gl_LightSource[7].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[7].position, gl_LightSource[7].spotDirection.xyz, gl_LightSource[7].linearAttenuation, gl_LightSource[7].specular.a);
- col.rgb += gl_LightSource[1].diffuse.rgb*calcDirectionalLight(norm, gl_LightSource[1].position.xyz);
- col.rgb = scaleDownLight(col.rgb);
+ // Collect normal lights
+ col.rgb += gl_LightSource[2].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[2].position, gl_LightSource[2].spotDirection.xyz, gl_LightSource[2].linearAttenuation, gl_LightSource[2].quadraticAttenuation, gl_LightSource[2].specular.a);
+ col.rgb += gl_LightSource[3].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[3].position, gl_LightSource[3].spotDirection.xyz, gl_LightSource[3].linearAttenuation, gl_LightSource[3].quadraticAttenuation ,gl_LightSource[3].specular.a);
+ col.rgb += gl_LightSource[4].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[4].position, gl_LightSource[4].spotDirection.xyz, gl_LightSource[4].linearAttenuation, gl_LightSource[4].quadraticAttenuation, gl_LightSource[4].specular.a);
+ col.rgb += gl_LightSource[5].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[5].position, gl_LightSource[5].spotDirection.xyz, gl_LightSource[5].linearAttenuation, gl_LightSource[5].quadraticAttenuation, gl_LightSource[5].specular.a);
+ col.rgb += gl_LightSource[6].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[6].position, gl_LightSource[6].spotDirection.xyz, gl_LightSource[6].linearAttenuation, gl_LightSource[6].quadraticAttenuation, gl_LightSource[6].specular.a);
+ col.rgb += gl_LightSource[7].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[7].position, gl_LightSource[7].spotDirection.xyz, gl_LightSource[7].linearAttenuation, gl_LightSource[7].quadraticAttenuation, gl_LightSource[7].specular.a);
+ vary_pointlight_col = col.rgb*gl_Color.rgb;
+
+ col.rgb = vec3(0,0,0);
+
// Add windlight lights
- col.rgb += atmosAmbient(vec3(0.));
+ col.rgb = atmosAmbient(vec3(0.));
vary_ambient = col.rgb*gl_Color.rgb;
vary_directional = gl_Color.rgb*atmosAffectDirectionalLight(max(calcDirectionalLight(norm, gl_LightSource[0].position.xyz), (1.0-gl_Color.a)*(1.0-gl_Color.a)));
@@ -77,7 +106,7 @@ void main()
gl_FrontColor = col;
gl_FogFragCoord = pos.z;
-
+ vary_fragcoord.xyz = pos.xyz + vec3(0,0,near_clip);
}
diff --git a/indra/newview/app_settings/shaders/class2/deferred/blurLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/blurLightF.glsl
deleted file mode 100644
index 258a9b7c40..0000000000
--- a/indra/newview/app_settings/shaders/class2/deferred/blurLightF.glsl
+++ /dev/null
@@ -1,81 +0,0 @@
-/**
- * @file blurLightF.glsl
- *
- * $LicenseInfo:firstyear=2007&license=viewerlgpl$
- * $/LicenseInfo$
- */
-
-#extension GL_ARB_texture_rectangle : enable
-
-uniform sampler2DRect depthMap;
-uniform sampler2DRect normalMap;
-uniform sampler2DRect lightMap;
-
-uniform float dist_factor;
-uniform float blur_size;
-uniform vec2 delta;
-uniform vec3 kern[4];
-uniform float kern_scale;
-
-varying vec2 vary_fragcoord;
-
-uniform mat4 inv_proj;
-uniform vec2 screen_res;
-
-vec4 getPosition(vec2 pos_screen)
-{
- float depth = texture2DRect(depthMap, pos_screen.xy).a;
- vec2 sc = pos_screen.xy*2.0;
- sc /= screen_res;
- sc -= vec2(1.0,1.0);
- vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0);
- vec4 pos = inv_proj * ndc;
- pos /= pos.w;
- pos.w = 1.0;
- return pos;
-}
-
-void main()
-{
- vec3 norm = texture2DRect(normalMap, vary_fragcoord.xy).xyz;
- norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm
- vec3 pos = getPosition(vary_fragcoord.xy).xyz;
- vec4 ccol = texture2DRect(lightMap, vary_fragcoord.xy).rgba;
-
- vec2 dlt = kern_scale * delta / (1.0+norm.xy*norm.xy);
-
- dlt /= max(-pos.z*dist_factor, 1.0);
-
- vec2 defined_weight = kern[0].xy; // special case the first (centre) sample's weight in the blur; we have to sample it anyway so we get it for 'free'
- vec4 col = defined_weight.xyxx * ccol;
-
- for (int i = 1; i < 4; i++)
- {
- vec2 tc = vary_fragcoord.xy + kern[i].z*dlt;
- vec3 samppos = getPosition(tc).xyz;
- float d = dot(norm.xyz, samppos.xyz-pos.xyz);// dist from plane
- if (d*d <= 0.003)
- {
- col += texture2DRect(lightMap, tc)*kern[i].xyxx;
- defined_weight += kern[i].xy;
- }
- }
- for (int i = 1; i < 4; i++)
- {
- vec2 tc = vary_fragcoord.xy - kern[i].z*dlt;
- vec3 samppos = getPosition(tc).xyz;
- float d = dot(norm.xyz, samppos.xyz-pos.xyz);// dist from plane
- if (d*d <= 0.003)
- {
- col += texture2DRect(lightMap, tc)*kern[i].xyxx;
- defined_weight += kern[i].xy;
- }
- }
-
-
-
- col /= defined_weight.xyxx;
-
- gl_FragColor = col;
-}
-
diff --git a/indra/newview/app_settings/shaders/class2/deferred/edgeF.glsl b/indra/newview/app_settings/shaders/class2/deferred/edgeF.glsl
index ff32a15c54..3155f3f929 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/edgeF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/edgeF.glsl
@@ -4,14 +4,14 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
#extension GL_ARB_texture_rectangle : enable
uniform sampler2DRect depthMap;
uniform sampler2DRect normalMap;
-uniform float gi_dist_cutoff;
-
varying vec2 vary_fragcoord;
uniform float depth_cutoff;
diff --git a/indra/newview/app_settings/shaders/class2/deferred/edgeV.glsl b/indra/newview/app_settings/shaders/class2/deferred/edgeV.glsl
index 74f2bd9818..b3413c301f 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/edgeV.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/edgeV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
varying vec2 vary_fragcoord;
uniform vec2 screen_res;
diff --git a/indra/newview/app_settings/shaders/class2/deferred/postDeferredF.glsl b/indra/newview/app_settings/shaders/class2/deferred/postDeferredF.glsl
deleted file mode 100644
index 757e3e7aab..0000000000
--- a/indra/newview/app_settings/shaders/class2/deferred/postDeferredF.glsl
+++ /dev/null
@@ -1,59 +0,0 @@
-/**
- * @file postDeferredF.glsl
- *
- * $LicenseInfo:firstyear=2007&license=viewerlgpl$
- * $/LicenseInfo$
- */
-
-uniform sampler2DRect diffuseRect;
-uniform sampler2DRect localLightMap;
-uniform sampler2DRect sunLightMap;
-uniform sampler2DRect giLightMap;
-uniform sampler2D luminanceMap;
-uniform sampler2DRect lightMap;
-
-uniform vec3 gi_lum_quad;
-uniform vec3 sun_lum_quad;
-uniform vec3 lum_quad;
-uniform float lum_lod;
-uniform vec4 ambient;
-
-uniform vec3 gi_quad;
-
-uniform vec2 screen_res;
-varying vec2 vary_fragcoord;
-
-void main()
-{
- vec2 tc = vary_fragcoord.xy;
- vec3 lcol = texture2DLod(luminanceMap, tc/screen_res, lum_lod).rgb;
-
- float lum = sqrt(lcol.r)*lum_quad.x+lcol.r*lcol.r*lum_quad.y+lcol.r*lum_quad.z;
-
- vec4 diff = texture2DRect(diffuseRect, vary_fragcoord.xy);
-
- float ambocc = texture2DRect(lightMap, vary_fragcoord.xy).g;
-
- vec3 gi_col = texture2DRect(giLightMap, vary_fragcoord.xy).rgb;
- gi_col = gi_col*gi_col*gi_quad.x + gi_col*gi_quad.y+gi_quad.z*ambocc*ambient.rgb;
- gi_col *= diff;
-
- vec4 sun_col = texture2DRect(sunLightMap, vary_fragcoord.xy);
-
- vec3 local_col = texture2DRect(localLightMap, vary_fragcoord.xy).rgb;
-
-
- float sun_lum = 1.0-lum;
- sun_lum = sun_lum*sun_lum*sun_lum_quad.x + sun_lum*sun_lum_quad.y+sun_lum_quad.z;
-
- float gi_lum = lum;
- gi_lum = gi_lum*gi_lum*gi_lum_quad.x+gi_lum*gi_lum_quad.y+gi_lum_quad.z;
- gi_col *= 1.0/gi_lum;
-
- vec3 col = sun_col.rgb*(1.0+max(sun_lum,0.0))+gi_col+local_col;
-
- gl_FragColor.rgb = col.rgb;
- gl_FragColor.a = max(sun_lum*min(sun_col.r+sun_col.g+sun_col.b, 1.0), sun_col.a);
-
- //gl_FragColor.rgb = texture2DRect(giLightMap, vary_fragcoord.xy).rgb;
-}
diff --git a/indra/newview/app_settings/shaders/class2/deferred/postDeferredV.glsl b/indra/newview/app_settings/shaders/class2/deferred/postDeferredV.glsl
deleted file mode 100644
index 0ec81dcb02..0000000000
--- a/indra/newview/app_settings/shaders/class2/deferred/postDeferredV.glsl
+++ /dev/null
@@ -1,17 +0,0 @@
-/**
- * @file postDeferredV.glsl
- *
- * $LicenseInfo:firstyear=2007&license=viewerlgpl$
- * $/LicenseInfo$
- */
-
-varying vec2 vary_fragcoord;
-uniform vec2 screen_res;
-
-void main()
-{
- //transform vertex
- gl_Position = ftransform();
- vec4 pos = gl_ModelViewProjectionMatrix * gl_Vertex;
- vary_fragcoord = (pos.xy*0.5+0.5)*screen_res;
-}
diff --git a/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
index 1067be1e6e..0160e84278 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
#extension GL_ARB_texture_rectangle : enable
diff --git a/indra/newview/app_settings/shaders/class2/deferred/softenLightV.glsl b/indra/newview/app_settings/shaders/class2/deferred/softenLightV.glsl
index 9d187b46e2..8f0bcca76b 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/softenLightV.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/softenLightV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
uniform vec2 screen_res;
diff --git a/indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl
index d0e242c2d4..50b9ef276e 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl
@@ -4,7 +4,7 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
-
+
#version 120
#extension GL_ARB_texture_rectangle : enable
diff --git a/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl
index f565d3bdb9..4369b3b34f 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
#extension GL_ARB_texture_rectangle : enable
@@ -17,9 +19,6 @@ uniform sampler2DRectShadow shadowMap2;
uniform sampler2DRectShadow shadowMap3;
uniform sampler2DShadow shadowMap4;
uniform sampler2DShadow shadowMap5;
-uniform sampler2D noiseMap;
-
-uniform sampler2D lightFunc;
// Inputs
diff --git a/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl b/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl
index 4e33a1af45..847b36b1ac 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl
@@ -4,6 +4,8 @@
* Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
* $License$
*/
+
+#version 120
#extension GL_ARB_texture_rectangle : enable
@@ -19,8 +21,6 @@ uniform sampler2DShadow shadowMap4;
uniform sampler2DShadow shadowMap5;
uniform sampler2D noiseMap;
-uniform sampler2D lightFunc;
-
// Inputs
uniform mat4 shadow_matrix[6];
uniform vec4 shadow_clip;
@@ -60,58 +60,50 @@ vec4 getPosition(vec2 pos_screen)
float calcAmbientOcclusion(vec4 pos, vec3 norm)
{
float ret = 1.0;
-
- float dist = dot(pos.xyz,pos.xyz);
-
- if (dist < 64.0*64.0)
- {
- vec2 kern[8];
- // exponentially (^2) distant occlusion samples spread around origin
- kern[0] = vec2(-1.0, 0.0) * 0.125*0.125;
- kern[1] = vec2(1.0, 0.0) * 0.250*0.250;
- kern[2] = vec2(0.0, 1.0) * 0.375*0.375;
- kern[3] = vec2(0.0, -1.0) * 0.500*0.500;
- kern[4] = vec2(0.7071, 0.7071) * 0.625*0.625;
- kern[5] = vec2(-0.7071, -0.7071) * 0.750*0.750;
- kern[6] = vec2(-0.7071, 0.7071) * 0.875*0.875;
- kern[7] = vec2(0.7071, -0.7071) * 1.000*1.000;
- vec2 pos_screen = vary_fragcoord.xy;
- vec3 pos_world = pos.xyz;
- vec2 noise_reflect = texture2D(noiseMap, vary_fragcoord.xy/128.0).xy;
+ vec2 kern[8];
+ // exponentially (^2) distant occlusion samples spread around origin
+ kern[0] = vec2(-1.0, 0.0) * 0.125*0.125;
+ kern[1] = vec2(1.0, 0.0) * 0.250*0.250;
+ kern[2] = vec2(0.0, 1.0) * 0.375*0.375;
+ kern[3] = vec2(0.0, -1.0) * 0.500*0.500;
+ kern[4] = vec2(0.7071, 0.7071) * 0.625*0.625;
+ kern[5] = vec2(-0.7071, -0.7071) * 0.750*0.750;
+ kern[6] = vec2(-0.7071, 0.7071) * 0.875*0.875;
+ kern[7] = vec2(0.7071, -0.7071) * 1.000*1.000;
+
+ vec2 pos_screen = vary_fragcoord.xy;
+ vec3 pos_world = pos.xyz;
+ vec2 noise_reflect = texture2D(noiseMap, vary_fragcoord.xy/128.0).xy;
- float angle_hidden = 0.0;
- int points = 0;
+ float angle_hidden = 0.0;
+ int points = 0;
- float scale = min(ssao_radius / -pos_world.z, ssao_max_radius);
+ float scale = min(ssao_radius / -pos_world.z, ssao_max_radius);
- // it was found that keeping # of samples a constant was the fastest, probably due to compiler optimizations (unrolling?)
- for (int i = 0; i < 8; i++)
- {
- vec2 samppos_screen = pos_screen + scale * reflect(kern[i], noise_reflect);
- vec3 samppos_world = getPosition(samppos_screen).xyz;
+ // it was found that keeping # of samples a constant was the fastest, probably due to compiler optimizations (unrolling?)
+ for (int i = 0; i < 8; i++)
+ {
+ vec2 samppos_screen = pos_screen + scale * reflect(kern[i], noise_reflect);
+ vec3 samppos_world = getPosition(samppos_screen).xyz;
- vec3 diff = pos_world - samppos_world;
- float dist2 = dot(diff, diff);
+ vec3 diff = pos_world - samppos_world;
+ float dist2 = dot(diff, diff);
- // assume each sample corresponds to an occluding sphere with constant radius, constant x-sectional area
- // --> solid angle shrinking by the square of distance
- //radius is somewhat arbitrary, can approx with just some constant k * 1 / dist^2
- //(k should vary inversely with # of samples, but this is taken care of later)
+ // assume each sample corresponds to an occluding sphere with constant radius, constant x-sectional area
+ // --> solid angle shrinking by the square of distance
+ //radius is somewhat arbitrary, can approx with just some constant k * 1 / dist^2
+ //(k should vary inversely with # of samples, but this is taken care of later)
- //if (dot((samppos_world - 0.05*norm - pos_world), norm) > 0.0) // -0.05*norm to shift sample point back slightly for flat surfaces
- // angle_hidden += min(1.0/dist2, ssao_factor_inv); // dist != 0 follows from conditional. max of 1.0 (= ssao_factor_inv * ssao_factor)
- angle_hidden = angle_hidden + float(dot((samppos_world - 0.05*norm - pos_world), norm) > 0.0) * min(1.0/dist2, ssao_factor_inv);
+ angle_hidden = angle_hidden + float(dot((samppos_world - 0.05*norm - pos_world), norm) > 0.0) * min(1.0/dist2, ssao_factor_inv);
- // 'blocked' samples (significantly closer to camera relative to pos_world) are "no data", not "no occlusion"
- points = points + int(diff.z > -1.0);
- }
+ // 'blocked' samples (significantly closer to camera relative to pos_world) are "no data", not "no occlusion"
+ points = points + int(diff.z > -1.0);
+ }
- angle_hidden = min(ssao_factor*angle_hidden/float(points), 1.0);
+ angle_hidden = min(ssao_factor*angle_hidden/float(points), 1.0);
- ret = (1.0 - (float(points != 0) * angle_hidden));
- ret += max((dist-32.0*32.0)/(32.0*32.0), 0.0);
- }
+ ret = (1.0 - (float(points != 0) * angle_hidden));
return min(ret, 1.0);
}
diff --git a/indra/newview/app_settings/shaders/class2/deferred/sunLightV.glsl b/indra/newview/app_settings/shaders/class2/deferred/sunLightV.glsl
index 9d092d9cea..9beb513ad8 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/sunLightV.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/sunLightV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
varying vec4 vary_light;
varying vec2 vary_fragcoord;
diff --git a/indra/newview/app_settings/shaders/class2/effects/blurF.glsl b/indra/newview/app_settings/shaders/class2/effects/blurF.glsl
index 4173709298..a4ad0bfa15 100644
--- a/indra/newview/app_settings/shaders/class2/effects/blurF.glsl
+++ b/indra/newview/app_settings/shaders/class2/effects/blurF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
uniform sampler2DRect RenderTexture;
uniform float bloomStrength;
diff --git a/indra/newview/app_settings/shaders/class2/effects/blurV.glsl b/indra/newview/app_settings/shaders/class2/effects/blurV.glsl
index f66609527d..d471a6c5e5 100644
--- a/indra/newview/app_settings/shaders/class2/effects/blurV.glsl
+++ b/indra/newview/app_settings/shaders/class2/effects/blurV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
uniform vec2 texelSize;
uniform vec2 blurDirection;
diff --git a/indra/newview/app_settings/shaders/class2/effects/colorFilterF.glsl b/indra/newview/app_settings/shaders/class2/effects/colorFilterF.glsl
index df41dae757..66880b958e 100644
--- a/indra/newview/app_settings/shaders/class2/effects/colorFilterF.glsl
+++ b/indra/newview/app_settings/shaders/class2/effects/colorFilterF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
uniform sampler2DRect RenderTexture;
uniform float brightness;
diff --git a/indra/newview/app_settings/shaders/class2/effects/drawQuadV.glsl b/indra/newview/app_settings/shaders/class2/effects/drawQuadV.glsl
index e836caf93f..c35c500d62 100644
--- a/indra/newview/app_settings/shaders/class2/effects/drawQuadV.glsl
+++ b/indra/newview/app_settings/shaders/class2/effects/drawQuadV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
void main(void)
{
diff --git a/indra/newview/app_settings/shaders/class2/effects/extractF.glsl b/indra/newview/app_settings/shaders/class2/effects/extractF.glsl
index 06d5fc9797..e77baa5bee 100644
--- a/indra/newview/app_settings/shaders/class2/effects/extractF.glsl
+++ b/indra/newview/app_settings/shaders/class2/effects/extractF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
uniform sampler2DRect RenderTexture;
uniform float extractLow;
diff --git a/indra/newview/app_settings/shaders/class2/effects/nightVisionF.glsl b/indra/newview/app_settings/shaders/class2/effects/nightVisionF.glsl
index 0a2767ad02..8e0eec6f5e 100644
--- a/indra/newview/app_settings/shaders/class2/effects/nightVisionF.glsl
+++ b/indra/newview/app_settings/shaders/class2/effects/nightVisionF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
uniform sampler2DRect RenderTexture;
uniform sampler2D NoiseTexture;
diff --git a/indra/newview/app_settings/shaders/class2/effects/simpleF.glsl b/indra/newview/app_settings/shaders/class2/effects/simpleF.glsl
index 29ad9a995b..98a50e22fc 100644
--- a/indra/newview/app_settings/shaders/class2/effects/simpleF.glsl
+++ b/indra/newview/app_settings/shaders/class2/effects/simpleF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
uniform sampler2DRect RenderTexture;
diff --git a/indra/newview/app_settings/shaders/class2/environment/terrainF.glsl b/indra/newview/app_settings/shaders/class2/environment/terrainF.glsl
index 32259acf1b..bbb8951f3a 100644
--- a/indra/newview/app_settings/shaders/class2/environment/terrainF.glsl
+++ b/indra/newview/app_settings/shaders/class2/environment/terrainF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
uniform sampler2D detail_0;
uniform sampler2D detail_1;
diff --git a/indra/newview/app_settings/shaders/class2/environment/terrainV.glsl b/indra/newview/app_settings/shaders/class2/environment/terrainV.glsl
index 2234f0bd89..84906c16bf 100644
--- a/indra/newview/app_settings/shaders/class2/environment/terrainV.glsl
+++ b/indra/newview/app_settings/shaders/class2/environment/terrainV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
void calcAtmospherics(vec3 inPositionEye);
diff --git a/indra/newview/app_settings/shaders/class2/environment/terrainWaterF.glsl b/indra/newview/app_settings/shaders/class2/environment/terrainWaterF.glsl
index 1650912fc8..7590c542ef 100644
--- a/indra/newview/app_settings/shaders/class2/environment/terrainWaterF.glsl
+++ b/indra/newview/app_settings/shaders/class2/environment/terrainWaterF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
uniform sampler2D detail_0;
uniform sampler2D detail_1;
diff --git a/indra/newview/app_settings/shaders/class2/environment/underWaterF.glsl b/indra/newview/app_settings/shaders/class2/environment/underWaterF.glsl
index 9e936a3790..900f1a6cb8 100644
--- a/indra/newview/app_settings/shaders/class2/environment/underWaterF.glsl
+++ b/indra/newview/app_settings/shaders/class2/environment/underWaterF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
uniform sampler2D diffuseMap;
uniform sampler2D bumpMap;
diff --git a/indra/newview/app_settings/shaders/class2/environment/waterF.glsl b/indra/newview/app_settings/shaders/class2/environment/waterF.glsl
index e477107c0b..f4f6b6e90f 100644
--- a/indra/newview/app_settings/shaders/class2/environment/waterF.glsl
+++ b/indra/newview/app_settings/shaders/class2/environment/waterF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
vec3 scaleSoftClip(vec3 inColor);
vec3 atmosTransport(vec3 inColor);
diff --git a/indra/newview/app_settings/shaders/class2/environment/waterFogF.glsl b/indra/newview/app_settings/shaders/class2/environment/waterFogF.glsl
index 7bcdcf5d5b..9f3328cbf0 100644
--- a/indra/newview/app_settings/shaders/class2/environment/waterFogF.glsl
+++ b/indra/newview/app_settings/shaders/class2/environment/waterFogF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
uniform vec4 lightnorm;
uniform vec4 waterPlane;
diff --git a/indra/newview/app_settings/shaders/class2/lighting/lightF.glsl b/indra/newview/app_settings/shaders/class2/lighting/lightF.glsl
index 269d11a085..342bc2ab66 100644
--- a/indra/newview/app_settings/shaders/class2/lighting/lightF.glsl
+++ b/indra/newview/app_settings/shaders/class2/lighting/lightF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
uniform sampler2D diffuseMap;
diff --git a/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightF.glsl b/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightF.glsl
index 9ffe3c6f4a..dad18b5883 100644
--- a/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightF.glsl
+++ b/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
uniform sampler2D diffuseMap;
diff --git a/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightShinyF.glsl b/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightShinyF.glsl
index b7181dec3a..73ff81e03a 100644
--- a/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightShinyF.glsl
+++ b/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightShinyF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
uniform sampler2D diffuseMap;
uniform samplerCube environmentMap;
diff --git a/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightShinyWaterF.glsl b/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightShinyWaterF.glsl
new file mode 100644
index 0000000000..9b4b584369
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightShinyWaterF.glsl
@@ -0,0 +1,31 @@
+/**
+ * @file lightFullbrightShinyWaterF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#version 120
+
+uniform sampler2D diffuseMap;
+uniform samplerCube environmentMap;
+
+vec3 fullbrightShinyAtmosTransport(vec3 light);
+vec3 fullbrightScaleSoftClip(vec3 light);
+vec4 applyWaterFog(vec4 color);
+
+void fullbright_shiny_lighting_water()
+{
+ vec4 color = texture2D(diffuseMap, gl_TexCoord[0].xy);
+ color.rgb *= gl_Color.rgb;
+
+ vec3 envColor = textureCube(environmentMap, gl_TexCoord[1].xyz).rgb;
+ color.rgb = mix(color.rgb, envColor.rgb, gl_Color.a);
+
+ color.rgb = fullbrightShinyAtmosTransport(color.rgb);
+ color.rgb = fullbrightScaleSoftClip(color.rgb);
+ color.a = max(color.a, gl_Color.a);
+
+ gl_FragColor = applyWaterFog(color);
+}
+
diff --git a/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightWaterF.glsl b/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightWaterF.glsl
index ee38790cc4..3d46c8d874 100644
--- a/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightWaterF.glsl
+++ b/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightWaterF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
uniform sampler2D diffuseMap;
diff --git a/indra/newview/app_settings/shaders/class2/lighting/lightShinyF.glsl b/indra/newview/app_settings/shaders/class2/lighting/lightShinyF.glsl
index b96b5d75bc..ebe21320b4 100644
--- a/indra/newview/app_settings/shaders/class2/lighting/lightShinyF.glsl
+++ b/indra/newview/app_settings/shaders/class2/lighting/lightShinyF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
uniform sampler2D diffuseMap;
uniform samplerCube environmentMap;
diff --git a/indra/newview/app_settings/shaders/class2/lighting/lightShinyWaterF.glsl b/indra/newview/app_settings/shaders/class2/lighting/lightShinyWaterF.glsl
index 0f5b2d6fcf..7f48e2cf1d 100644
--- a/indra/newview/app_settings/shaders/class2/lighting/lightShinyWaterF.glsl
+++ b/indra/newview/app_settings/shaders/class2/lighting/lightShinyWaterF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
uniform sampler2D diffuseMap;
diff --git a/indra/newview/app_settings/shaders/class2/lighting/lightSpecularV.glsl b/indra/newview/app_settings/shaders/class2/lighting/lightSpecularV.glsl
index 6400b45d9e..ad1dc4da77 100644
--- a/indra/newview/app_settings/shaders/class2/lighting/lightSpecularV.glsl
+++ b/indra/newview/app_settings/shaders/class2/lighting/lightSpecularV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
// All lights, no specular highlights
diff --git a/indra/newview/app_settings/shaders/class2/lighting/lightV.glsl b/indra/newview/app_settings/shaders/class2/lighting/lightV.glsl
index 89ef510d7c..a0f6e019ef 100644
--- a/indra/newview/app_settings/shaders/class2/lighting/lightV.glsl
+++ b/indra/newview/app_settings/shaders/class2/lighting/lightV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
// All lights, no specular highlights
diff --git a/indra/newview/app_settings/shaders/class2/lighting/lightWaterF.glsl b/indra/newview/app_settings/shaders/class2/lighting/lightWaterF.glsl
index 016258bd18..97eba92d7b 100644
--- a/indra/newview/app_settings/shaders/class2/lighting/lightWaterF.glsl
+++ b/indra/newview/app_settings/shaders/class2/lighting/lightWaterF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
uniform sampler2D diffuseMap;
diff --git a/indra/newview/app_settings/shaders/class2/lighting/sumLightsSpecularV.glsl b/indra/newview/app_settings/shaders/class2/lighting/sumLightsSpecularV.glsl
index 8cfeeb1cf9..fde32ed035 100644
--- a/indra/newview/app_settings/shaders/class2/lighting/sumLightsSpecularV.glsl
+++ b/indra/newview/app_settings/shaders/class2/lighting/sumLightsSpecularV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2005&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
float calcDirectionalLightSpecular(inout vec4 specular, vec3 view, vec3 n, vec3 l, vec3 lightCol, float da);
vec3 calcPointLightSpecular(inout vec4 specular, vec3 view, vec3 v, vec3 n, vec3 l, float r, float pw, vec3 lightCol);
diff --git a/indra/newview/app_settings/shaders/class2/lighting/sumLightsV.glsl b/indra/newview/app_settings/shaders/class2/lighting/sumLightsV.glsl
index a512b9d6fb..8fe49e3be0 100644
--- a/indra/newview/app_settings/shaders/class2/lighting/sumLightsV.glsl
+++ b/indra/newview/app_settings/shaders/class2/lighting/sumLightsV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2005&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
float calcDirectionalLight(vec3 n, vec3 l);
float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float is_pointlight);
diff --git a/indra/newview/app_settings/shaders/class2/objects/shinyV.glsl b/indra/newview/app_settings/shaders/class2/objects/shinyV.glsl
index c428bbb28e..4cebb06df0 100644
--- a/indra/newview/app_settings/shaders/class2/objects/shinyV.glsl
+++ b/indra/newview/app_settings/shaders/class2/objects/shinyV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol);
diff --git a/indra/newview/app_settings/shaders/class2/windlight/atmosphericsF.glsl b/indra/newview/app_settings/shaders/class2/windlight/atmosphericsF.glsl
index 8baff24dbd..77d15fba9a 100644
--- a/indra/newview/app_settings/shaders/class2/windlight/atmosphericsF.glsl
+++ b/indra/newview/app_settings/shaders/class2/windlight/atmosphericsF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
//////////////////////////////////////////////////////////
// The fragment shader for the terrain atmospherics
diff --git a/indra/newview/app_settings/shaders/class2/windlight/atmosphericsHelpersV.glsl b/indra/newview/app_settings/shaders/class2/windlight/atmosphericsHelpersV.glsl
index 6883edc1f1..8c5b864cbe 100644
--- a/indra/newview/app_settings/shaders/class2/windlight/atmosphericsHelpersV.glsl
+++ b/indra/newview/app_settings/shaders/class2/windlight/atmosphericsHelpersV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2005&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
// Output variables
vec3 getSunlitColor();
diff --git a/indra/newview/app_settings/shaders/class2/windlight/atmosphericsV.glsl b/indra/newview/app_settings/shaders/class2/windlight/atmosphericsV.glsl
index f5c513bbdd..8d365c15ca 100644
--- a/indra/newview/app_settings/shaders/class2/windlight/atmosphericsV.glsl
+++ b/indra/newview/app_settings/shaders/class2/windlight/atmosphericsV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2005&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
// varying param funcs
void setSunlitColor(vec3 v);
diff --git a/indra/newview/app_settings/shaders/class2/windlight/atmosphericsVarsF.glsl b/indra/newview/app_settings/shaders/class2/windlight/atmosphericsVarsF.glsl
index d0b60e918e..cf9ef30632 100644
--- a/indra/newview/app_settings/shaders/class2/windlight/atmosphericsVarsF.glsl
+++ b/indra/newview/app_settings/shaders/class2/windlight/atmosphericsVarsF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
varying vec3 vary_PositionEye;
diff --git a/indra/newview/app_settings/shaders/class2/windlight/atmosphericsVarsV.glsl b/indra/newview/app_settings/shaders/class2/windlight/atmosphericsVarsV.glsl
index 4b4baf50d0..398f1556a0 100644
--- a/indra/newview/app_settings/shaders/class2/windlight/atmosphericsVarsV.glsl
+++ b/indra/newview/app_settings/shaders/class2/windlight/atmosphericsVarsV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
varying vec3 vary_PositionEye;
diff --git a/indra/newview/app_settings/shaders/class2/windlight/cloudsF.glsl b/indra/newview/app_settings/shaders/class2/windlight/cloudsF.glsl
index 2a559440fc..13207997b2 100644
--- a/indra/newview/app_settings/shaders/class2/windlight/cloudsF.glsl
+++ b/indra/newview/app_settings/shaders/class2/windlight/cloudsF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2005&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
/////////////////////////////////////////////////////////////////////////
// The fragment shader for the sky
diff --git a/indra/newview/app_settings/shaders/class2/windlight/cloudsV.glsl b/indra/newview/app_settings/shaders/class2/windlight/cloudsV.glsl
index 865c0e9da8..267ef36d4d 100644
--- a/indra/newview/app_settings/shaders/class2/windlight/cloudsV.glsl
+++ b/indra/newview/app_settings/shaders/class2/windlight/cloudsV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2005&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
//////////////////////////////////////////////////////////////////////////
// The vertex shader for creating the atmospheric sky
diff --git a/indra/newview/app_settings/shaders/class2/windlight/gammaF.glsl b/indra/newview/app_settings/shaders/class2/windlight/gammaF.glsl
index ce4bd2358f..a658edd21f 100644
--- a/indra/newview/app_settings/shaders/class2/windlight/gammaF.glsl
+++ b/indra/newview/app_settings/shaders/class2/windlight/gammaF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
uniform vec4 gamma;
diff --git a/indra/newview/app_settings/shaders/class2/windlight/skyF.glsl b/indra/newview/app_settings/shaders/class2/windlight/skyF.glsl
index b69a88a45f..77ca4868a6 100644
--- a/indra/newview/app_settings/shaders/class2/windlight/skyF.glsl
+++ b/indra/newview/app_settings/shaders/class2/windlight/skyF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2005&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
/////////////////////////////////////////////////////////////////////////
// The fragment shader for the sky
diff --git a/indra/newview/app_settings/shaders/class2/windlight/skyV.glsl b/indra/newview/app_settings/shaders/class2/windlight/skyV.glsl
index 397db01378..03bca8f27e 100644
--- a/indra/newview/app_settings/shaders/class2/windlight/skyV.glsl
+++ b/indra/newview/app_settings/shaders/class2/windlight/skyV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2005&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
// SKY ////////////////////////////////////////////////////////////////////////
// The vertex shader for creating the atmospheric sky
diff --git a/indra/newview/app_settings/shaders/class2/windlight/transportF.glsl b/indra/newview/app_settings/shaders/class2/windlight/transportF.glsl
index b30313bdc8..7f1ad4d5b4 100644
--- a/indra/newview/app_settings/shaders/class2/windlight/transportF.glsl
+++ b/indra/newview/app_settings/shaders/class2/windlight/transportF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
//////////////////////////////////////////////////////////
// The fragment shader for the terrain atmospherics
diff --git a/indra/newview/app_settings/shaders/class3/avatar/avatarV.glsl b/indra/newview/app_settings/shaders/class3/avatar/avatarV.glsl
index c85ba0c734..a003e2a1f1 100644
--- a/indra/newview/app_settings/shaders/class3/avatar/avatarV.glsl
+++ b/indra/newview/app_settings/shaders/class3/avatar/avatarV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol);
mat4 getSkinnedTransform();
diff --git a/indra/newview/app_settings/shaders/class3/deferred/giDownsampleF.glsl b/indra/newview/app_settings/shaders/class3/deferred/giDownsampleF.glsl
index d26b244fa3..fc370ef367 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/giDownsampleF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/giDownsampleF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
uniform sampler2DRect giLightMap;
diff --git a/indra/newview/app_settings/shaders/class3/deferred/giDownsampleV.glsl b/indra/newview/app_settings/shaders/class3/deferred/giDownsampleV.glsl
index e5f6217644..ae57227fe5 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/giDownsampleV.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/giDownsampleV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
varying vec2 vary_fragcoord;
uniform vec2 screen_res;
diff --git a/indra/newview/app_settings/shaders/class3/deferred/giF.glsl b/indra/newview/app_settings/shaders/class3/deferred/giF.glsl
index 735150a78c..951e3e97ae 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/giF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/giF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
#extension GL_ARB_texture_rectangle : enable
diff --git a/indra/newview/app_settings/shaders/class3/deferred/giFinalF.glsl b/indra/newview/app_settings/shaders/class3/deferred/giFinalF.glsl
index e0f4a3e4f5..b2f8b2c633 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/giFinalF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/giFinalF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
#extension GL_ARB_texture_rectangle : enable
diff --git a/indra/newview/app_settings/shaders/class3/deferred/giFinalV.glsl b/indra/newview/app_settings/shaders/class3/deferred/giFinalV.glsl
index fbf2c17370..19c4e07b8b 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/giFinalV.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/giFinalV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
varying vec2 vary_fragcoord;
uniform vec2 screen_res;
diff --git a/indra/newview/app_settings/shaders/class3/deferred/giV.glsl b/indra/newview/app_settings/shaders/class3/deferred/giV.glsl
index 543527612e..8dc1410ea5 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/giV.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/giV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
varying vec2 vary_fragcoord;
diff --git a/indra/newview/app_settings/shaders/class3/deferred/luminanceF.glsl b/indra/newview/app_settings/shaders/class3/deferred/luminanceF.glsl
index d9483bc6e4..5f3bf68b24 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/luminanceF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/luminanceF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
#extension GL_ARB_texture_rectangle : enable
diff --git a/indra/newview/app_settings/shaders/class3/deferred/luminanceV.glsl b/indra/newview/app_settings/shaders/class3/deferred/luminanceV.glsl
index 6368def830..a24eda35dc 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/luminanceV.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/luminanceV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
varying vec2 vary_fragcoord;
diff --git a/indra/newview/app_settings/shaders/class3/deferred/postDeferredF.glsl b/indra/newview/app_settings/shaders/class3/deferred/postDeferredF.glsl
index 51ab579e3c..ab99a88971 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/postDeferredF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/postDeferredF.glsl
@@ -4,7 +4,9 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
-
+
+#version 120
+
#extension GL_ARB_texture_rectangle : enable
uniform sampler2DRect diffuseRect;
diff --git a/indra/newview/app_settings/shaders/class3/deferred/postDeferredV.glsl b/indra/newview/app_settings/shaders/class3/deferred/postDeferredV.glsl
index 0ec81dcb02..12983baa94 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/postDeferredV.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/postDeferredV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
varying vec2 vary_fragcoord;
uniform vec2 screen_res;
diff --git a/indra/newview/app_settings/shaders/class3/deferred/postgiF.glsl b/indra/newview/app_settings/shaders/class3/deferred/postgiF.glsl
index 24fa07f251..f037754708 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/postgiF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/postgiF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
#extension GL_ARB_texture_rectangle : enable
diff --git a/indra/newview/app_settings/shaders/class3/deferred/postgiV.glsl b/indra/newview/app_settings/shaders/class3/deferred/postgiV.glsl
index e5f6217644..ae57227fe5 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/postgiV.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/postgiV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
varying vec2 vary_fragcoord;
uniform vec2 screen_res;
diff --git a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl
index a2db247331..ce32f66000 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
#extension GL_ARB_texture_rectangle : enable
diff --git a/indra/newview/app_settings/shaders/class3/deferred/softenLightV.glsl b/indra/newview/app_settings/shaders/class3/deferred/softenLightV.glsl
index 9d187b46e2..8f0bcca76b 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/softenLightV.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/softenLightV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
uniform vec2 screen_res;
diff --git a/indra/newview/app_settings/shaders/class3/deferred/treeF.glsl b/indra/newview/app_settings/shaders/class3/deferred/treeF.glsl
index 1c1725a95c..c54d9a1e3e 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/treeF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/treeF.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
uniform sampler2D diffuseMap;
diff --git a/indra/newview/app_settings/shaders/class3/lighting/sumLightsSpecularV.glsl b/indra/newview/app_settings/shaders/class3/lighting/sumLightsSpecularV.glsl
index 2b44aedd5a..04533fdce1 100644
--- a/indra/newview/app_settings/shaders/class3/lighting/sumLightsSpecularV.glsl
+++ b/indra/newview/app_settings/shaders/class3/lighting/sumLightsSpecularV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2005&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
float calcDirectionalLightSpecular(inout vec4 specular, vec3 view, vec3 n, vec3 l, vec3 lightCol, float da);
vec3 calcPointLightSpecular(inout vec4 specular, vec3 view, vec3 v, vec3 n, vec3 l, float r, float pw, vec3 lightCol);
diff --git a/indra/newview/app_settings/shaders/class3/lighting/sumLightsV.glsl b/indra/newview/app_settings/shaders/class3/lighting/sumLightsV.glsl
index 329b0c4305..73bc18b866 100644
--- a/indra/newview/app_settings/shaders/class3/lighting/sumLightsV.glsl
+++ b/indra/newview/app_settings/shaders/class3/lighting/sumLightsV.glsl
@@ -4,6 +4,8 @@
* $LicenseInfo:firstyear=2005&license=viewerlgpl$
* $/LicenseInfo$
*/
+
+#version 120
float calcDirectionalLight(vec3 n, vec3 l);
float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float is_pointlight);
diff --git a/indra/newview/app_settings/shaders/shader_heirarchy.txt b/indra/newview/app_settings/shaders/shader_hierarchy.txt
index d8bbf69b38..d8bbf69b38 100644
--- a/indra/newview/app_settings/shaders/shader_heirarchy.txt
+++ b/indra/newview/app_settings/shaders/shader_hierarchy.txt
diff --git a/indra/newview/app_settings/ultra_graphics.xml b/indra/newview/app_settings/ultra_graphics.xml
index e7dce3b989..71459e5470 100644
--- a/indra/newview/app_settings/ultra_graphics.xml
+++ b/indra/newview/app_settings/ultra_graphics.xml
@@ -4,13 +4,15 @@
<RenderAvatarCloth value="TRUE"/>
<!--Default for now-->
<RenderAvatarLODFactor value="1.0"/>
+ <!--Default for now-->
+ <RenderAvatarPhysicsLODFactor value="1.0"/>
<!--NO SHADERS-->
<RenderAvatarVP value="TRUE"/>
<!--Short Range-->
<RenderFarClip value="256"/>
<!--Default for now-->
<RenderFlexTimeFactor value="1"/>
- <!--256... but they don't use this-->
+ <!--256... but they do not use this-->
<RenderGlowResolutionPow value="9"/>
<!--Low number-->
<RenderMaxPartCount value="4096"/>
@@ -24,8 +26,6 @@
<RenderTerrainLODFactor value="2.0"/>
<!--Default for now-->
<RenderTreeLODFactor value="1.0"/>
- <!--Default for now-->
- <RenderUseFBO value="1"/>
<!--Try Impostors-->
<RenderUseImpostors value="TRUE"/>
<!--Default for now-->
@@ -34,11 +34,10 @@
<VertexShaderEnable value="TRUE"/>
<!--NO SHADERS-->
<WindLightUseAtmosShaders value="TRUE"/>
- <!--Deferred Shading-->
- <RenderDeferred value="TRUE"/>
- <!--SSAO Enabled-->
- <RenderDeferredSSAO value="TRUE"/>
- <!--Full Shadows-->
- <RenderShadowDetail value="2"/>
-
+ <!--Deferred Shading-->
+ <RenderDeferred value="TRUE"/>
+ <!--SSAO Enabled-->
+ <RenderDeferredSSAO value="TRUE"/>
+ <!--Full Shadows-->
+ <RenderShadowDetail value="2"/>
</settings>
diff --git a/indra/newview/app_settings/windlight/postprocesseffects.xml b/indra/newview/app_settings/windlight/postprocesseffects.xml
index 4645215a47..60fbfd3483 100644
--- a/indra/newview/app_settings/windlight/postprocesseffects.xml
+++ b/indra/newview/app_settings/windlight/postprocesseffects.xml
@@ -1,2 +1 @@
<llsd><map><key>Asi Weird</key><map><key>bloom_strength</key><real>4.5799999237060547</real><key>bloom_width</key><real>12.539999961853027</real><key>brightness</key><real>0.89999997615814209</real><key>brightness_multiplier</key><real>3</real><key>contrast</key><real>0.22999998927116394</real><key>contrast_base</key><array><real>1</real><real>1</real><real>1</real><real>0.5</real></array><key>enable_bloom</key><integer>1</integer><key>enable_color_filter</key><integer>1</integer><key>enable_night_vision</key><boolean>0</boolean><key>extract_high</key><real>1</real><key>extract_low</key><real>0.47999998927116394</real><key>noise_size</key><real>25</real><key>noise_strength</key><real>0.40000000000000002</real><key>saturation</key><real>-1</real></map><key>NegativeSaturation</key><map><key>bloom_strength</key><real>1.5</real><key>bloom_width</key><real>2.25</real><key>brightness</key><real>1</real><key>brightness_multiplier</key><real>3</real><key>contrast</key><real>1</real><key>contrast_base</key><array><real>1</real><real>1</real><real>1</real><real>0.5</real></array><key>enable_bloom</key><boolean>0</boolean><key>enable_color_filter</key><integer>1</integer><key>enable_night_vision</key><boolean>0</boolean><key>extract_high</key><real>1</real><key>extract_low</key><real>0.94999999999999996</real><key>noise_size</key><real>25</real><key>noise_strength</key><real>0.40000000000000002</real><key>saturation</key><real>-1</real></map><key>NightVision</key><map><key>bloom_strength</key><real>1.5</real><key>bloom_width</key><real>2.25</real><key>brightness</key><real>1</real><key>brightness_multiplier</key><real>3</real><key>contrast</key><real>1</real><key>contrast_base</key><array><real>1</real><real>1</real><real>1</real><real>0.5</real></array><key>enable_bloom</key><boolean>0</boolean><key>enable_color_filter</key><boolean>0</boolean><key>enable_night_vision</key><integer>1</integer><key>extract_high</key><real>1</real><key>extract_low</key><real>0.94999999999999996</real><key>noise_size</key><real>25</real><key>noise_strength</key><real>0.40000000000000002</real><key>saturation</key><real>1</real></map><key>WGhost</key><map><key>bloom_strength</key><real>2.0399999618530273</real><key>bloom_width</key><real>2.25</real><key>brightness</key><real>1</real><key>brightness_multiplier</key><real>3</real><key>contrast</key><real>1</real><key>contrast_base</key><array><real>1</real><real>1</real><real>1</real><real>0.5</real></array><key>enable_bloom</key><integer>1</integer><key>enable_color_filter</key><boolean>0</boolean><key>enable_night_vision</key><boolean>0</boolean><key>extract_high</key><real>1</real><key>extract_low</key><real>0.22999998927116394</real><key>noise_size</key><real>25</real><key>noise_strength</key><real>0.40000000000000002</real><key>saturation</key><real>1</real></map><key>default</key><map><key>bloom_strength</key><real>1.5</real><key>bloom_width</key><real>2.25</real><key>brightness</key><real>1</real><key>brightness_multiplier</key><real>3</real><key>contrast</key><real>1</real><key>contrast_base</key><array><real>1</real><real>1</real><real>1</real><real>0.5</real></array><key>enable_bloom</key><boolean>0</boolean><key>enable_color_filter</key><boolean>0</boolean><key>enable_night_vision</key><boolean>0</boolean><key>extract_high</key><real>1</real><key>extract_low</key><real>0.94999999999999996</real><key>noise_size</key><real>25</real><key>noise_strength</key><real>0.40000000000000002</real><key>saturation</key><real>1</real></map></map></llsd>
-><map><key>bloom_strength</key><real>1.5</real><key>bloom_width</key><real>2.25</real><key>brightness</key><real>1</real><key>brightness_multiplier</key><real>3</real><key>contrast</key><real>1</real><key>contrast_base</key><array><real>1</real><real>1</real><real>1</real><real>0.5</real></array><key>enable_bloom</key><boolean>0</boolean><key>enable_color_filter</key><boolean>0</boolean><key>enable_night_vision</key><boolean>0</boolean><key>extract_high</key><real>1</real><key>extract_low</key><real>0.94999999999999996</real><key>noise_size</key><real>25</real><key>noise_strength</key><real>0.40000000000000002</real><key>saturation</key><real>1</real></map></map></llsd>
diff --git a/indra/newview/character/avatar_lad.xml b/indra/newview/character/avatar_lad.xml
index a9b4ff02c5..5d6b10c047 100644
--- a/indra/newview/character/avatar_lad.xml
+++ b/indra/newview/character/avatar_lad.xml
@@ -612,7 +612,7 @@
id="36"
group="0"
name="Shoulders"
- label="Shoulders"
+ label="Shoulders"
wearable="shape"
edit_group="shape_torso"
edit_group_order="4"
@@ -4040,7 +4040,6 @@
scale="0.0 0.0 0.01"
pos="0 0 -0.01"/>
</param_morph>
-
</param>
<param
@@ -4061,7 +4060,7 @@
camera_distance=".8">
<param_morph />
</param>
-
+
<param
id="628"
group="1"
@@ -4130,7 +4129,7 @@
camera_distance=".8">
<param_morph />
</param>
-
+
<param
id="685"
group="0"
@@ -4328,8 +4327,66 @@
</param>
<!--
+ #############
+ # physics morphs (not user controlled)
+ #############
+ -->
+ <param
+ id="1200"
+ group="1"
+ sex="female"
+ name="Breast_Physics_UpDown_Driven"
+ wearable="shape"
+ edit_group="driven"
+ value_default="0"
+ value_min="-3"
+ value_max="3">
+ <param_morph />
+ </param>
+
+ <param
+ id="1201"
+ group="1"
+ sex="female"
+ name="Breast_Physics_InOut_Driven"
+ wearable="shape"
+ edit_group="driven"
+ value_default="0"
+ value_min="-1.25"
+ value_max="1.25">
+ <param_morph />
+ </param>
+
+ <param
+ id="1204"
+ group="1"
+ name="Belly_Physics_Torso_UpDown_Driven"
+ wearable="physics"
+ cross_wearable="true"
+ edit_group="driven"
+ value_default="0"
+ value_min="-1"
+ value_max="1">
+ <param_morph />
+ </param>
+
+ <param
+ id="1207"
+ group="1"
+ name="Breast_Physics_LeftRight_Driven"
+ wearable="physics"
+ cross_wearable="true"
+ edit_group="driven"
+ value_default="0"
+ value_min="-2"
+ value_max="2">
+ <param_morph />
+ </param>
+
+ <!--
#end morph targets
-->
+
</mesh>
<mesh
@@ -4390,6 +4447,7 @@
<param_morph />
</param>
+
<param
id="151"
group="1"
@@ -4829,8 +4887,53 @@
</param>
<!--
+ #############
+ # physics morphs (not user controlled)
+ #############
+ -->
+ <param
+ id="1202"
+ group="1"
+ name="Belly_Physics_Legs_UpDown_Driven"
+ wearable="physics"
+ cross_wearable="true"
+ edit_group="driven"
+ value_min="-1"
+ value_max="1">
+ <param_morph />
+ </param>
+
+
+ <param
+ id="1205"
+ group="1"
+ name="Butt_Physics_UpDown_Driven"
+ wearable="physics"
+ cross_wearable="true"
+ edit_group="driven"
+ value_default="0"
+ value_min="-1"
+ value_max="1">
+ <param_morph />
+ </param>
+
+ <param
+ id="1206"
+ group="1"
+ name="Butt_Physics_LeftRight_Driven"
+ wearable="physics"
+ cross_wearable="true"
+ edit_group="driven"
+ value_default="0"
+ value_min="-1"
+ value_max="1">
+ <param_morph />
+ </param>
+
+ <!--
#end morph targets
-->
+
</mesh>
<mesh
@@ -5199,6 +5302,25 @@
value_max="1">
<param_morph />
</param>
+
+ <!--
+ #############
+ # physics morphs (not user controlled)
+ #############
+ -->
+ <param
+ id="1203"
+ group="1"
+ name="Belly_Physics_Skirt_UpDown_Driven"
+ wearable="physics"
+ cross_wearable="true"
+ edit_group="driven"
+ value_default="0"
+ value_min="-1"
+ value_max="1">
+ <param_morph />
+ </param>
+
</mesh>
<mesh
@@ -9074,12 +9196,13 @@ render_pass="bump">
<!-- =========================================================== -->
<driver_parameters>
+
<param
id="828"
group="0"
name="Loose Upper Clothing"
label="Shirt Fit"
- show_simple="true"
+ show_simple="true"
wearable="shirt"
edit_group="shirt"
edit_group_order="4"
@@ -11631,6 +11754,523 @@ render_pass="bump">
</param_driver>
</param>
+ <!-- ==PHYSICS PARAMETERS======================================= -->
+
+ <param
+ id="1100"
+ group="1"
+ sex="female"
+ wearable="physics"
+ name="Breast_Physics_UpDown_Controller"
+ label="Breast Physics UpDown Controller"
+ value_min="-1"
+ value_max="1"
+ value_default="0">
+ <param_driver>
+ <driven
+ id="1200" />
+ </param_driver>
+ </param>
+
+ <param
+ id="1101"
+ group="1"
+ sex="female"
+ wearable="physics"
+ name="Breast_Physics_InOut_Controller"
+ label="Breast Physics InOut Controller"
+ value_min="-1"
+ value_max="1"
+ value_default="0">
+ <param_driver>
+ <driven
+ id="1201" />
+ </param_driver>
+ </param>
+
+ <param
+ id="1102"
+ group="1"
+ wearable="physics"
+ name="Belly_Physics_UpDown_Controller"
+ label="Belly Physics UpDown Controller"
+ value_min="-1"
+ value_max="1"
+ value_default="0">
+ <param_driver>
+ <driven
+ id="1202" />
+ <driven
+ id="1203" />
+ <driven
+ id="1204" />
+ </param_driver>
+ </param>
+
+ <param
+ id="1103"
+ group="1"
+ wearable="shape"
+ name="Butt_Physics_UpDown_Controller"
+ label="Butt Physics UpDown Controller"
+ value_min="-1"
+ value_max="1"
+ value_default="0">
+ <param_driver>
+ <driven
+ id="1205" />
+ </param_driver>
+ </param>
+
+ <param
+ id="1104"
+ group="1"
+ wearable="shape"
+ name="Butt_Physics_LeftRight_Controller"
+ label="Butt Physics LeftRight Controller"
+ value_min="-1"
+ value_max="1"
+ value_default="0">
+ <param_driver>
+ <driven
+ id="1206" />
+ </param_driver>
+ </param>
+
+ <param
+ id="1105"
+ group="1"
+ wearable="shape"
+ name="Breast_Physics_LeftRight_Controller"
+ label="Breast Physics LeftRight Controller"
+ value_min="-1"
+ value_max="1"
+ value_default="0">
+ <param_driver>
+ <driven
+ id="1207" />
+ </param_driver>
+ </param>
+
+ <param
+ id="10000"
+ group="0"
+ sex="female"
+ name="Breast_Physics_Mass"
+ label="Breast Physics Mass"
+ wearable="physics"
+ edit_group="physics_advanced"
+ value_default=".1"
+ value_min=".1"
+ value_max="1">
+ <param_driver />
+ </param>
+ <param
+ id="10001"
+ group="0"
+ sex="female"
+ name="Breast_Physics_Gravity"
+ label="Breast Physics Gravity"
+ wearable="physics"
+ edit_group="physics_advanced"
+ value_default="0"
+ value_min="0"
+ value_max="30">
+ <param_driver />
+ </param>
+
+ <param
+ id="10002"
+ group="0"
+ sex="female"
+ name="Breast_Physics_Drag"
+ label="Breast Physics Drag"
+ wearable="physics"
+ edit_group="physics_advanced"
+ value_default="1"
+ value_min="0"
+ value_max="10">
+ <param_driver />
+ </param>
+
+ <param
+ id="10003"
+ group="0"
+ sex="female"
+ name="Breast_Physics_UpDown_Max_Effect"
+ label="Breast Physics UpDown Max Effect"
+ wearable="physics"
+ edit_group="physics_breasts_updown"
+ value_default="0"
+ value_min="0"
+ value_max="3">
+ <param_driver />
+ </param>
+ <param
+ id="10004"
+ group="0"
+ sex="female"
+ name="Breast_Physics_UpDown_Spring"
+ label="Breast Physics UpDown Spring"
+ wearable="physics"
+ edit_group="physics_breasts_updown"
+ value_default="10"
+ value_min="0"
+ value_max="100">
+ <param_driver />
+ </param>
+ <param
+ id="10005"
+ group="0"
+ sex="female"
+ name="Breast_Physics_UpDown_Gain"
+ label="Breast Physics UpDown Gain"
+ wearable="physics"
+ edit_group="physics_breasts_updown"
+ value_default="10"
+ value_min="1"
+ value_max="100">
+ <param_driver />
+ </param>
+ <param
+ id="10006"
+ group="0"
+ sex="female"
+ name="Breast_Physics_UpDown_Damping"
+ label="Breast Physics UpDown Damping"
+ wearable="physics"
+ edit_group="physics_breasts_updown"
+ value_default=".2"
+ value_min="0"
+ value_max="1">
+ <param_driver />
+ </param>
+
+ <param
+ id="10007"
+ group="0"
+ sex="female"
+ name="Breast_Physics_InOut_Max_Effect"
+ label="Breast Physics InOut Max Effect"
+ wearable="physics"
+ edit_group="physics_breasts_inout"
+ value_default="0"
+ value_min="0"
+ value_max="3">
+ <param_driver />
+ </param>
+ <param
+ id="10008"
+ group="0"
+ sex="female"
+ name="Breast_Physics_InOut_Spring"
+ label="Breast Physics InOut Spring"
+ wearable="physics"
+ edit_group="physics_breasts_inout"
+ value_default="10"
+ value_min="0"
+ value_max="100">
+ <param_driver />
+ </param>
+ <param
+ id="10009"
+ group="0"
+ sex="female"
+ name="Breast_Physics_InOut_Gain"
+ label="Breast Physics InOut Gain"
+ wearable="physics"
+ edit_group="physics_breasts_inout"
+ value_default="10"
+ value_min="1"
+ value_max="100">
+ <param_driver />
+ </param>
+ <param
+ id="10010"
+ group="0"
+ sex="female"
+ name="Breast_Physics_InOut_Damping"
+ label="Breast Physics InOut Damping"
+ wearable="physics"
+ edit_group="physics_breasts_inout"
+ value_default=".2"
+ value_min="0"
+ value_max="1">
+ <param_driver />
+ </param>
+
+ <param
+ id="10011"
+ group="0"
+ name="Belly_Physics_Mass"
+ label="Belly Physics Mass"
+ wearable="physics"
+ edit_group="physics_advanced"
+ value_default=".1"
+ value_min=".1"
+ value_max="1">
+ <param_driver />
+ </param>
+ <param
+ id="10012"
+ group="0"
+ name="Belly_Physics_Gravity"
+ label="Belly Physics Gravity"
+ wearable="physics"
+ edit_group="physics_advanced"
+ value_default="0"
+ value_min="0"
+ value_max="30">
+ <param_driver />
+ </param>
+ <param
+ id="10013"
+ group="0"
+ name="Belly_Physics_Drag"
+ label="Belly Physics Drag"
+ wearable="physics"
+ edit_group="physics_advanced"
+ value_default="1"
+ value_min="0"
+ value_max="10">
+ <param_driver />
+ </param>
+ <param
+ id="10014"
+ group="0"
+ name="Belly_Physics_UpDown_Max_Effect"
+ label="Belly Physics UpDown Max Effect"
+ wearable="physics"
+ edit_group="physics_belly_updown"
+ value_default="0"
+ value_min="0"
+ value_max="3">
+ <param_driver />
+ </param>
+ <param
+ id="10015"
+ group="0"
+ name="Belly_Physics_UpDown_Spring"
+ label="Belly Physics UpDown Spring"
+ wearable="physics"
+ edit_group="physics_belly_updown"
+ value_default="10"
+ value_min="0"
+ value_max="100">
+ <param_driver />
+ </param>
+ <param
+ id="10016"
+ group="0"
+ name="Belly_Physics_UpDown_Gain"
+ label="Belly Physics UpDown Gain"
+ wearable="physics"
+ edit_group="physics_belly_updown"
+ value_default="10"
+ value_min="1"
+ value_max="100">
+ <param_driver />
+ </param>
+ <param
+ id="10017"
+ group="0"
+ name="Belly_Physics_UpDown_Damping"
+ label="Belly Physics UpDown Damping"
+ wearable="physics"
+ edit_group="physics_belly_updown"
+ value_default=".2"
+ value_min="0"
+ value_max="1">
+ <param_driver />
+ </param>
+
+ <param
+ id="10018"
+ group="0"
+ name="Butt_Physics_Mass"
+ label="Butt Physics Mass"
+ wearable="physics"
+ edit_group="physics_advanced"
+ value_default=".1"
+ value_min=".1"
+ value_max="1">
+ <param_driver />
+ </param>
+ <param
+ id="10019"
+ group="0"
+ name="Butt_Physics_Gravity"
+ label="Butt Physics Gravity"
+ wearable="physics"
+ edit_group="physics_advanced"
+ value_default="0"
+ value_min="0"
+ value_max="30">
+ <param_driver />
+ </param>
+ <param
+ id="10020"
+ group="0"
+ name="Butt_Physics_Drag"
+ label="Butt Physics Drag"
+ wearable="physics"
+ edit_group="physics_advanced"
+ value_default="1"
+ value_min="0"
+ value_max="10">
+ <param_driver />
+ </param>
+
+ <param
+ id="10021"
+ group="0"
+ name="Butt_Physics_UpDown_Max_Effect"
+ label="Butt Physics UpDown Max Effect"
+ wearable="physics"
+ edit_group="physics_butt_updown"
+ value_default="0"
+ value_min="0"
+ value_max="3">
+ <param_driver />
+ </param>
+ <param
+ id="10022"
+ group="0"
+ name="Butt_Physics_UpDown_Spring"
+ label="Butt Physics UpDown Spring"
+ wearable="physics"
+ edit_group="physics_butt_updown"
+ value_default="10"
+ value_min="0"
+ value_max="100">
+ <param_driver />
+ </param>
+ <param
+ id="10023"
+ group="0"
+ name="Butt_Physics_UpDown_Gain"
+ label="Butt Physics UpDown Gain"
+ wearable="physics"
+ edit_group="physics_butt_updown"
+ value_default="10"
+ value_min="1"
+ value_max="100">
+ <param_driver />
+ </param>
+ <param
+ id="10024"
+ group="0"
+ name="Butt_Physics_UpDown_Damping"
+ label="Butt Physics UpDown Damping"
+ wearable="physics"
+ edit_group="physics_butt_updown"
+ value_default=".2"
+ value_min="0"
+ value_max="1">
+ <param_driver />
+ </param>
+
+ <param
+ id="10025"
+ group="0"
+ name="Butt_Physics_LeftRight_Max_Effect"
+ label="Butt Physics LeftRight Max Effect"
+ wearable="physics"
+ edit_group="physics_butt_leftright"
+ value_default="0"
+ value_min="0"
+ value_max="3">
+ <param_driver />
+ </param>
+ <param
+ id="10026"
+ group="0"
+ name="Butt_Physics_LeftRight_Spring"
+ label="Butt Physics LeftRight Spring"
+ wearable="physics"
+ edit_group="physics_butt_leftright"
+ value_default="10"
+ value_min="0"
+ value_max="100">
+ <param_driver />
+ </param>
+ <param
+ id="10027"
+ group="0"
+ name="Butt_Physics_LeftRight_Gain"
+ label="Butt Physics LeftRight Gain"
+ wearable="physics"
+ edit_group="physics_butt_leftright"
+ value_default="10"
+ value_min="1"
+ value_max="100">
+ <param_driver />
+ </param>
+ <param
+ id="10028"
+ group="0"
+ name="Butt_Physics_LeftRight_Damping"
+ label="Butt Physics LeftRight Damping"
+ wearable="physics"
+ edit_group="physics_butt_leftright"
+ value_default=".2"
+ value_min="0"
+ value_max="1">
+ <param_driver />
+ </param>
+
+ <param
+ id="10029"
+ group="0"
+ sex="female"
+ name="Breast_Physics_LeftRight_Max_Effect"
+ label="Breast Physics LeftRight Max Effect"
+ wearable="physics"
+ edit_group="physics_breasts_leftright"
+ value_default="0"
+ value_min="0"
+ value_max="3">
+ <param_driver />
+ </param>
+ <param
+ id="10030"
+ group="0"
+ sex="female"
+ name="Breast_Physics_LeftRight_Spring"
+ label="Breast Physics LeftRight Spring"
+ wearable="physics"
+ edit_group="physics_breasts_leftright"
+ value_default="10"
+ value_min="0"
+ value_max="100">
+ <param_driver />
+ </param>
+ <param
+ id="10031"
+ group="0"
+ sex="female"
+ name="Breast_Physics_LeftRight_Gain"
+ label="Breast Physics LeftRight Gain"
+ wearable="physics"
+ edit_group="physics_breasts_leftright"
+ value_default="10"
+ value_min="1"
+ value_max="100">
+ <param_driver />
+ </param>
+ <param
+ id="10032"
+ group="0"
+ sex="female"
+ name="Breast_Physics_LeftRight_Damping"
+ label="Breast Physics LeftRight Damping"
+ wearable="physics"
+ edit_group="physics_breasts_leftright"
+ value_default=".2"
+ value_min="0"
+ value_max="1">
+ <param_driver />
+ </param>
</driver_parameters>
diff --git a/indra/newview/featuretable.txt b/indra/newview/featuretable.txt
index d69842d5f1..dd8a88e558 100644
--- a/indra/newview/featuretable.txt
+++ b/indra/newview/featuretable.txt
@@ -1,4 +1,4 @@
-version 25
+version 27
// NOTE: This is mostly identical to featuretable_mac.txt with a few differences
// Should be combined into one table
@@ -26,6 +26,7 @@ list all
RenderAnisotropic 1 1
RenderAvatarCloth 1 1
RenderAvatarLODFactor 1 1.0
+RenderAvatarPhysicsLODFactor 1 1.0
RenderAvatarMaxVisible 1 12
RenderAvatarVP 1 1
RenderCubeMap 1 1
@@ -39,9 +40,11 @@ RenderGround 1 1
RenderMaxPartCount 1 8192
RenderNightBrightness 1 1.0
RenderObjectBump 1 1
+RenderLocalLights 1 1
RenderReflectionDetail 1 4
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 2.0
+RenderTransparentWater 1 1
RenderTreeLODFactor 1 1.0
RenderUseImpostors 1 1
RenderVBOEnable 1 1
@@ -55,13 +58,12 @@ Disregard128DefaultDrawDistance 1 1
Disregard96DefaultDrawDistance 1 1
RenderTextureMemoryMultiple 1 1.0
RenderShaderLightingMaxLevel 1 3
+RenderDeferred 1 1
SkyUseClassicClouds 1 1
-RenderDeferred 1 0
-RenderDeferredSSAO 1 0
-RenderShadowDetail 1 0
+RenderDeferredSSAO 1 1
+RenderShadowDetail 1 2
WatchdogDisabled 1 1
RenderUseStreamVBO 1 1
-RenderUseFBO 1 1
//
// Low Graphics Settings
@@ -70,6 +72,7 @@ list Low
RenderAnisotropic 1 0
RenderAvatarCloth 1 0
RenderAvatarLODFactor 1 0
+RenderAvatarPhysicsLODFactor 1 0
RenderAvatarMaxVisible 1 3
RenderAvatarVP 1 0
RenderFarClip 1 64
@@ -77,9 +80,11 @@ RenderFlexTimeFactor 1 0
RenderGlowResolutionPow 1 8
RenderMaxPartCount 1 0
RenderObjectBump 1 0
+RenderLocalLights 1 0
RenderReflectionDetail 1 0
RenderTerrainDetail 1 0
RenderTerrainLODFactor 1 1
+RenderTransparentWater 1 0
RenderTreeLODFactor 1 0
RenderUseImpostors 1 1
RenderVolumeLODFactor 1 0.5
@@ -90,7 +95,6 @@ SkyUseClassicClouds 1 0
RenderDeferred 1 0
RenderDeferredSSAO 1 0
RenderShadowDetail 1 0
-RenderUseFBO 1 0
//
// Mid Graphics Settings
@@ -99,15 +103,18 @@ list Mid
RenderAnisotropic 1 0
RenderAvatarCloth 1 0
RenderAvatarLODFactor 1 0.5
+RenderAvatarPhysicsLODFactor 1 0.75
RenderAvatarVP 1 1
RenderFarClip 1 96
RenderFlexTimeFactor 1 1.0
RenderGlowResolutionPow 1 8
RenderMaxPartCount 1 2048
RenderObjectBump 1 1
+RenderLocalLights 1 1
RenderReflectionDetail 1 0
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 1.0
+RenderTransparentWater 1 1
RenderTreeLODFactor 1 0.5
RenderUseImpostors 1 1
RenderVolumeLODFactor 1 1.125
@@ -117,7 +124,6 @@ WLSkyDetail 1 48
RenderDeferred 1 0
RenderDeferredSSAO 1 0
RenderShadowDetail 1 0
-RenderUseFBO 1 0
//
// High Graphics Settings (purty)
@@ -126,15 +132,18 @@ list High
RenderAnisotropic 1 1
RenderAvatarCloth 1 0
RenderAvatarLODFactor 1 1.0
+RenderAvatarPhysicsLODFactor 1 1.0
RenderAvatarVP 1 1
RenderFarClip 1 128
RenderFlexTimeFactor 1 1.0
RenderGlowResolutionPow 1 9
RenderMaxPartCount 1 4096
RenderObjectBump 1 1
-RenderReflectionDetail 1 2
+RenderLocalLights 1 1
+RenderReflectionDetail 1 0
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 2.0
+RenderTransparentWater 1 1
RenderTreeLODFactor 1 0.5
RenderUseImpostors 1 1
RenderVolumeLODFactor 1 1.125
@@ -144,7 +153,6 @@ WLSkyDetail 1 48
RenderDeferred 1 0
RenderDeferredSSAO 1 0
RenderShadowDetail 1 0
-RenderUseFBO 1 0
//
// Ultra graphics (REALLY PURTY!)
@@ -159,19 +167,20 @@ RenderFlexTimeFactor 1 1.0
RenderGlowResolutionPow 1 9
RenderMaxPartCount 1 8192
RenderObjectBump 1 1
+RenderLocalLights 1 1
RenderReflectionDetail 1 4
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 2.0
+RenderTransparentWater 1 1
RenderTreeLODFactor 1 1.0
RenderUseImpostors 1 1
RenderVolumeLODFactor 1 2.0
VertexShaderEnable 1 1
WindLightUseAtmosShaders 1 1
WLSkyDetail 1 128
-RenderDeferred 1 0
-RenderDeferredSSAO 1 0
-RenderShadowDetail 1 0
-RenderUseFBO 1 0
+RenderDeferred 1 1
+RenderDeferredSSAO 1 1
+RenderShadowDetail 1 2
//
// Class Unknown Hardware (unknown)
@@ -229,6 +238,7 @@ RenderDeferred 0 0
RenderDeferredSSAO 0 0
RenderShadowDetail 0 0
+
//
// "Default" setups for safe, low, medium, high
//
@@ -237,6 +247,7 @@ RenderAnisotropic 1 0
RenderAvatarCloth 0 0
RenderAvatarVP 0 0
RenderObjectBump 0 0
+RenderLocalLights 1 0
RenderMaxPartCount 1 1024
RenderTerrainDetail 1 0
RenderUseImpostors 0 0
@@ -246,8 +257,8 @@ WindLightUseAtmosShaders 0 0
RenderDeferred 0 0
RenderDeferredSSAO 0 0
RenderShadowDetail 0 0
-RenderUseFBO 1 0
+
//
// CPU based feature masks
//
@@ -268,6 +279,9 @@ RenderObjectBump 0 0
list OpenGLPre15
RenderVBOEnable 1 0
+list OpenGLPre30
+RenderDeferred 0 0
+
list Intel
RenderAnisotropic 1 0
@@ -453,6 +467,11 @@ RenderAvatarCloth 0 0
list ATI
RenderUseStreamVBO 1 0
+RenderAvatarVP 1 0
+
+// Disable vertex buffer objects by default for ATI cards with little video memory
+list ATIVramLT256
+RenderVBOEnable 1 0
/// Tweaked NVIDIA
@@ -553,3 +572,4 @@ list NVIDIA_GeForce_Go_7800
RenderShaderLightingMaxLevel 1 2
list NVIDIA_GeForce_Go_7900
RenderShaderLightingMaxLevel 1 2
+
diff --git a/indra/newview/featuretable_linux.txt b/indra/newview/featuretable_linux.txt
index efe29005f2..058bdcc730 100644
--- a/indra/newview/featuretable_linux.txt
+++ b/indra/newview/featuretable_linux.txt
@@ -1,4 +1,4 @@
-version 22
+version 23
// NOTE: This is mostly identical to featuretable_mac.txt with a few differences
// Should be combined into one table
@@ -26,6 +26,7 @@ list all
RenderAnisotropic 1 1
RenderAvatarCloth 1 1
RenderAvatarLODFactor 1 1.0
+RenderAvatarPhysicsLODFactor 1 1.0
RenderAvatarMaxVisible 1 12
RenderAvatarVP 1 1
RenderCubeMap 1 1
@@ -36,12 +37,14 @@ RenderFogRatio 1 4.0
RenderGamma 1 0
RenderGlowResolutionPow 1 9
RenderGround 1 1
+RenderLocalLights 1 1
RenderMaxPartCount 1 8192
RenderNightBrightness 1 1.0
RenderObjectBump 1 1
RenderReflectionDetail 1 4
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 2.0
+RenderTransparentWater 1 1
RenderTreeLODFactor 1 1.0
RenderUseImpostors 1 1
RenderVBOEnable 1 1
@@ -56,11 +59,9 @@ Disregard96DefaultDrawDistance 1 1
RenderTextureMemoryMultiple 1 1.0
SkyUseClassicClouds 1 1
RenderShaderLightingMaxLevel 1 3
-RenderDeferred 1 0
-RenderDeferredSSAO 1 0
-RenderShadowDetail 1 0
-WatchdogDisabled 1 1
-RenderUseFBO 1 1
+RenderDeferred 1 1
+RenderDeferredSSAO 1 1
+RenderShadowDetail 1 2
//
// Low Graphics Settings
@@ -69,16 +70,19 @@ list Low
RenderAnisotropic 1 0
RenderAvatarCloth 1 0
RenderAvatarLODFactor 1 0
+RenderAvatarPhysicsLODFactor 1 0
RenderAvatarMaxVisible 1 3
RenderAvatarVP 1 0
RenderFarClip 1 64
RenderFlexTimeFactor 1 0
RenderGlowResolutionPow 1 8
+RenderLocalLights 1 0
RenderMaxPartCount 1 0
RenderObjectBump 1 0
RenderReflectionDetail 1 0
RenderTerrainDetail 1 0
RenderTerrainLODFactor 1 1
+RenderTransparentWater 1 0
RenderTreeLODFactor 1 0
RenderUseImpostors 1 1
RenderVolumeLODFactor 1 0.5
@@ -89,7 +93,6 @@ SkyUseClassicClouds 1 0
RenderDeferred 1 0
RenderDeferredSSAO 1 0
RenderShadowDetail 1 0
-RenderUseFBO 1 0
//
// Mid Graphics Settings
@@ -98,15 +101,18 @@ list Mid
RenderAnisotropic 1 0
RenderAvatarCloth 1 0
RenderAvatarLODFactor 1 0.5
+RenderAvatarPhysicsLODFactor 1 0.75
RenderAvatarVP 1 1
RenderFarClip 1 96
RenderFlexTimeFactor 1 1.0
RenderGlowResolutionPow 1 8
+RenderLocalLights 1 1
RenderMaxPartCount 1 2048
RenderObjectBump 1 1
RenderReflectionDetail 1 0
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 1.0
+RenderTransparentWater 1 1
RenderTreeLODFactor 1 0.5
RenderUseImpostors 1 1
RenderVolumeLODFactor 1 1.125
@@ -116,7 +122,6 @@ WLSkyDetail 1 48
RenderDeferred 1 0
RenderDeferredSSAO 1 0
RenderShadowDetail 1 0
-RenderUseFBO 1 0
//
// High Graphics Settings (purty)
@@ -125,15 +130,18 @@ list High
RenderAnisotropic 1 1
RenderAvatarCloth 1 0
RenderAvatarLODFactor 1 1.0
+RenderAvatarPhysicsLODFactor 1 1.0
RenderAvatarVP 1 1
RenderFarClip 1 128
RenderFlexTimeFactor 1 1.0
RenderGlowResolutionPow 1 9
+RenderLocalLights 1 1
RenderMaxPartCount 1 4096
RenderObjectBump 1 1
-RenderReflectionDetail 1 2
+RenderReflectionDetail 1 0
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 2.0
+RenderTransparentWater 1 1
RenderTreeLODFactor 1 0.5
RenderUseImpostors 1 1
RenderVolumeLODFactor 1 1.125
@@ -143,7 +151,6 @@ WLSkyDetail 1 48
RenderDeferred 1 0
RenderDeferredSSAO 1 0
RenderShadowDetail 1 0
-RenderUseFBO 1 0
//
// Ultra graphics (REALLY PURTY!)
@@ -152,25 +159,27 @@ list Ultra
RenderAnisotropic 1 1
RenderAvatarCloth 1 1
RenderAvatarLODFactor 1 1.0
+RenderAvatarPhysicsLODFactor 1 1.0
RenderAvatarVP 1 1
RenderFarClip 1 256
RenderFlexTimeFactor 1 1.0
RenderGlowResolutionPow 1 9
+RenderLocalLights 1 1
RenderMaxPartCount 1 8192
RenderObjectBump 1 1
RenderReflectionDetail 1 4
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 2.0
+RenderTransparentWater 1 1
RenderTreeLODFactor 1 1.0
RenderUseImpostors 1 1
RenderVolumeLODFactor 1 2.0
VertexShaderEnable 1 1
WindLightUseAtmosShaders 1 1
WLSkyDetail 1 128
-RenderDeferred 1 0
-RenderDeferredSSAO 1 0
-RenderShadowDetail 1 0
-RenderUseFBO 1 0
+RenderDeferred 1 1
+RenderDeferredSSAO 1 1
+RenderShadowDetail 1 2
//
// Class Unknown Hardware (unknown)
@@ -245,7 +254,6 @@ WindLightUseAtmosShaders 0 0
RenderDeferred 0 0
RenderDeferredSSAO 0 0
RenderShadowDetail 0 0
-RenderUseFBO 1 0
//
diff --git a/indra/newview/featuretable_mac.txt b/indra/newview/featuretable_mac.txt
index f030c9f8e5..c075c660f3 100644
--- a/indra/newview/featuretable_mac.txt
+++ b/indra/newview/featuretable_mac.txt
@@ -1,4 +1,4 @@
-version 22
+version 23
// NOTE: This is mostly identical to featuretable_mac.txt with a few differences
// Should be combined into one table
@@ -24,10 +24,11 @@ version 22
//
list all
RenderAnisotropic 1 0
-RenderAvatarCloth 0 0
+RenderAvatarCloth 1 1
RenderAvatarLODFactor 1 1.0
+RenderAvatarPhysicsLODFactor 1 1.0
RenderAvatarMaxVisible 1 12
-RenderAvatarVP 1 0
+RenderAvatarVP 1 1
RenderCubeMap 1 1
RenderDelayVBUpdate 1 0
RenderFarClip 1 256
@@ -36,31 +37,33 @@ RenderFogRatio 1 4.0
RenderGamma 1 0
RenderGlowResolutionPow 1 9
RenderGround 1 1
-RenderLightingDetail 1 1
+RenderLocalLights 1 1
RenderMaxPartCount 1 8192
RenderNightBrightness 1 1.0
RenderObjectBump 1 1
-RenderReflectionDetail 1 3
+RenderReflectionDetail 1 4
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 2.0
+RenderTransparentWater 1 1
RenderTreeLODFactor 1 1.0
RenderUseImpostors 1 1
RenderVBOEnable 1 1
RenderVolumeLODFactor 1 2.0
-RenderWaterReflections 1 1
+UseStartScreen 1 1
UseOcclusion 1 1
VertexShaderEnable 1 1
WindLightUseAtmosShaders 1 1
WLSkyDetail 1 128
-RenderUseCleverUI 1 1
Disregard128DefaultDrawDistance 1 1
Disregard96DefaultDrawDistance 1 1
RenderTextureMemoryMultiple 1 0.5
-Disregard128DefaultDrawDistance 1 1
-Disregard96DefaultDrawDistance 1 1
+RenderShaderLightingMaxLevel 1 3
SkyUseClassicClouds 1 1
+RenderDeferred 1 1
+RenderDeferredSSAO 1 1
+RenderShadowDetail 1 2
WatchdogDisabled 1 1
-RenderUseFBO 1 1
+RenderUseStreamVBO 1 1
//
// Low Graphics Settings
@@ -69,26 +72,29 @@ list Low
RenderAnisotropic 1 0
RenderAvatarCloth 1 0
RenderAvatarLODFactor 1 0
+RenderAvatarPhysicsLODFactor 1 0
RenderAvatarMaxVisible 1 3
RenderAvatarVP 1 0
RenderFarClip 1 64
RenderFlexTimeFactor 1 0
RenderGlowResolutionPow 1 8
-RenderLightingDetail 1 0
+RenderLocalLights 1 0
RenderMaxPartCount 1 0
RenderObjectBump 1 0
RenderReflectionDetail 1 0
RenderTerrainDetail 1 0
RenderTerrainLODFactor 1 1
+RenderTransparentWater 1 0
RenderTreeLODFactor 1 0
RenderUseImpostors 1 1
RenderVolumeLODFactor 1 0.5
-RenderWaterReflections 1 0
VertexShaderEnable 1 0
WindLightUseAtmosShaders 1 0
WLSkyDetail 1 48
SkyUseClassicClouds 1 0
-RenderUseFBO 1 0
+RenderDeferred 1 0
+RenderDeferredSSAO 1 0
+RenderShadowDetail 1 0
//
// Mid Graphics Settings
@@ -97,24 +103,27 @@ list Mid
RenderAnisotropic 1 0
RenderAvatarCloth 1 0
RenderAvatarLODFactor 1 0.5
+RenderAvatarPhysicsLODFactor 1 0.75
RenderAvatarVP 1 1
RenderFarClip 1 96
RenderFlexTimeFactor 1 1.0
RenderGlowResolutionPow 1 8
-RenderLightingDetail 1 1
+RenderLocalLights 1 1
RenderMaxPartCount 1 2048
RenderObjectBump 1 1
RenderReflectionDetail 1 0
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 1.0
+RenderTransparentWater 1 1
RenderTreeLODFactor 1 0.5
RenderUseImpostors 1 1
RenderVolumeLODFactor 1 1.125
-RenderWaterReflections 1 0
VertexShaderEnable 1 1
WindLightUseAtmosShaders 1 0
WLSkyDetail 1 48
-RenderUseFBO 1 0
+RenderDeferred 1 0
+RenderDeferredSSAO 1 0
+RenderShadowDetail 1 0
//
// High Graphics Settings (purty)
@@ -123,24 +132,27 @@ list High
RenderAnisotropic 1 1
RenderAvatarCloth 1 0
RenderAvatarLODFactor 1 1.0
+RenderAvatarPhysicsLODFactor 1 1.0
RenderAvatarVP 1 1
RenderFarClip 1 128
RenderFlexTimeFactor 1 1.0
RenderGlowResolutionPow 1 9
-RenderLightingDetail 1 1
+RenderLocalLights 1 1
RenderMaxPartCount 1 4096
RenderObjectBump 1 1
-RenderReflectionDetail 1 2
+RenderReflectionDetail 1 0
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 2.0
+RenderTransparentWater 1 1
RenderTreeLODFactor 1 0.5
RenderUseImpostors 1 1
RenderVolumeLODFactor 1 1.125
-RenderWaterReflections 1 0
VertexShaderEnable 1 1
WindLightUseAtmosShaders 1 1
WLSkyDetail 1 48
-RenderUseFBO 1 0
+RenderDeferred 1 0
+RenderDeferredSSAO 1 0
+RenderShadowDetail 1 2
//
// Ultra graphics (REALLY PURTY!)
@@ -149,24 +161,27 @@ list Ultra
RenderAnisotropic 1 1
RenderAvatarCloth 1 1
RenderAvatarLODFactor 1 1.0
+RenderAvatarPhysicsLODFactor 1 1.0
RenderAvatarVP 1 1
RenderFarClip 1 256
RenderFlexTimeFactor 1 1.0
RenderGlowResolutionPow 1 9
-RenderLightingDetail 1 1
+RenderLocalLights 1 1
RenderMaxPartCount 1 8192
RenderObjectBump 1 1
-RenderReflectionDetail 1 3
+RenderReflectionDetail 1 4
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 2.0
+RenderTransparentWater 1 1
RenderTreeLODFactor 1 1.0
RenderUseImpostors 1 1
RenderVolumeLODFactor 1 2.0
-RenderWaterReflections 1 1
VertexShaderEnable 1 1
WindLightUseAtmosShaders 1 1
WLSkyDetail 1 128
-RenderUseFBO 1 0
+RenderDeferred 1 0
+RenderDeferredSSAO 1 0
+RenderShadowDetail 1 2
//
// Class Unknown Hardware (unknown)
@@ -204,9 +219,12 @@ RenderVBOEnable 1 1
list NoPixelShaders
RenderAvatarVP 0 0
RenderAvatarCloth 0 0
-RenderWaterReflections 0 0
+RenderReflectionDetail 0 0
VertexShaderEnable 0 0
WindLightUseAtmosShaders 0 0
+RenderDeferred 0 0
+RenderDeferredSSAO 0 0
+RenderShadowDetail 0 0
//
// No Vertex Shaders available
@@ -214,25 +232,31 @@ WindLightUseAtmosShaders 0 0
list NoVertexShaders
RenderAvatarVP 0 0
RenderAvatarCloth 0 0
-RenderWaterReflections 0 0
+RenderReflectionDetail 0 0
VertexShaderEnable 0 0
WindLightUseAtmosShaders 0 0
+RenderDeferred 0 0
+RenderDeferredSSAO 0 0
+RenderShadowDetail 0 0
+//
// "Default" setups for safe, low, medium, high
//
list safe
RenderAnisotropic 1 0
RenderAvatarCloth 0 0
RenderAvatarVP 0 0
-RenderLightingDetail 1 0
+RenderLocalLights 1 0
RenderObjectBump 0 0
RenderMaxPartCount 1 1024
RenderTerrainDetail 1 0
RenderUseImpostors 0 0
RenderVBOEnable 1 0
-RenderWaterReflections 0 0
+RenderReflectionDetail 0 0
WindLightUseAtmosShaders 0 0
-RenderUseFBO 1 0
+RenderDeferred 0 0
+RenderDeferredSSAO 0 0
+RenderShadowDetail 0 0
//
// CPU based feature masks
@@ -254,13 +278,16 @@ RenderObjectBump 0 0
list OpenGLPre15
RenderVBOEnable 1 0
+list TexUnit8orLess
+RenderDeferredSSAO 0 0
+
list Intel
RenderAnisotropic 1 0
-RenderLightingDetail 1 0
+RenderLocalLights 1 0
list GeForce2
RenderAnisotropic 1 0
-RenderLightingDetail 1 0
+RenderLocalLights 1 0
RenderMaxPartCount 1 2048
RenderTerrainDetail 1 0
RenderVBOEnable 1 1
@@ -377,7 +404,6 @@ list ATI_Radeon_X1500
Disregard128DefaultDrawDistance 1 0
list ATI_Radeon_X1600
Disregard128DefaultDrawDistance 1 0
-RenderUseFBO 0 0
list ATI_Radeon_X1700
Disregard128DefaultDrawDistance 1 0
list ATI_Mobility_Radeon_X1xxx
diff --git a/indra/newview/featuretable_xp.txt b/indra/newview/featuretable_xp.txt
index dae7705971..3339172a1a 100644
--- a/indra/newview/featuretable_xp.txt
+++ b/indra/newview/featuretable_xp.txt
@@ -1,4 +1,4 @@
-version 25
+version 27
// NOTE: This is mostly identical to featuretable_mac.txt with a few differences
// Should be combined into one table
@@ -26,6 +26,7 @@ list all
RenderAnisotropic 1 1
RenderAvatarCloth 1 1
RenderAvatarLODFactor 1 1.0
+RenderAvatarPhysicsLODFactor 1 1.0
RenderAvatarMaxVisible 1 12
RenderAvatarVP 1 1
RenderCubeMap 1 1
@@ -36,12 +37,14 @@ RenderFogRatio 1 4.0
RenderGamma 1 0
RenderGlowResolutionPow 1 9
RenderGround 1 1
+RenderLocalLights 1 1
RenderMaxPartCount 1 8192
RenderNightBrightness 1 1.0
RenderObjectBump 1 1
RenderReflectionDetail 1 4
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 2.0
+RenderTransparentWater 1 1
RenderTreeLODFactor 1 1.0
RenderUseImpostors 1 1
RenderVBOEnable 1 1
@@ -59,7 +62,6 @@ SkyUseClassicClouds 1 1
RenderDeferred 1 0
RenderDeferredSSAO 1 0
RenderShadowDetail 1 0
-RenderUseFBO 1 1
WatchdogDisabled 1 1
RenderUseStreamVBO 1 1
@@ -70,16 +72,19 @@ list Low
RenderAnisotropic 1 0
RenderAvatarCloth 1 0
RenderAvatarLODFactor 1 0
+RenderAvatarPhysicsLODFactor 1 0
RenderAvatarMaxVisible 1 3
RenderAvatarVP 1 0
RenderFarClip 1 64
RenderFlexTimeFactor 1 0
RenderGlowResolutionPow 1 8
+RenderLocalLights 1 0
RenderMaxPartCount 1 0
RenderObjectBump 1 0
RenderReflectionDetail 1 0
RenderTerrainDetail 1 0
RenderTerrainLODFactor 1 1
+RenderTransparentWater 1 0
RenderTreeLODFactor 1 0
RenderUseImpostors 1 1
RenderVolumeLODFactor 1 0.5
@@ -90,7 +95,6 @@ SkyUseClassicClouds 1 0
RenderDeferred 1 0
RenderDeferredSSAO 1 0
RenderShadowDetail 1 0
-RenderUseFBO 1 0
//
// Mid Graphics Settings
@@ -99,15 +103,18 @@ list Mid
RenderAnisotropic 1 0
RenderAvatarCloth 1 0
RenderAvatarLODFactor 1 0.5
+RenderAvatarPhysicsLODFactor 1 0.75
RenderAvatarVP 1 1
RenderFarClip 1 96
RenderFlexTimeFactor 1 1.0
RenderGlowResolutionPow 1 8
+RenderLocalLights 1 1
RenderMaxPartCount 1 2048
RenderObjectBump 1 1
RenderReflectionDetail 1 0
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 1.0
+RenderTransparentWater 1 1
RenderTreeLODFactor 1 0.5
RenderUseImpostors 1 1
RenderVolumeLODFactor 1 1.125
@@ -117,7 +124,6 @@ WLSkyDetail 1 48
RenderDeferred 1 0
RenderDeferredSSAO 1 0
RenderShadowDetail 1 0
-RenderUseFBO 1 0
//
// High Graphics Settings (purty)
@@ -126,15 +132,18 @@ list High
RenderAnisotropic 1 1
RenderAvatarCloth 1 0
RenderAvatarLODFactor 1 1.0
+RenderAvatarPhysicsLODFactor 1 1.0
RenderAvatarVP 1 1
RenderFarClip 1 128
RenderFlexTimeFactor 1 1.0
RenderGlowResolutionPow 1 9
+RenderLocalLights 1 1
RenderMaxPartCount 1 4096
RenderObjectBump 1 1
-RenderReflectionDetail 1 2
+RenderReflectionDetail 1 0
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 2.0
+RenderTransparentWater 1 1
RenderTreeLODFactor 1 0.5
RenderUseImpostors 1 1
RenderVolumeLODFactor 1 1.125
@@ -143,8 +152,7 @@ WindLightUseAtmosShaders 1 1
WLSkyDetail 1 48
RenderDeferred 1 0
RenderDeferredSSAO 1 0
-RenderShadowDetail 1 0
-RenderUseFBO 1 0
+RenderShadowDetail 1 2
//
// Ultra graphics (REALLY PURTY!)
@@ -153,15 +161,18 @@ list Ultra
RenderAnisotropic 1 1
RenderAvatarCloth 1 1
RenderAvatarLODFactor 1 1.0
+RenderAvatarPhysicsLODFactor 1 1.0
RenderAvatarVP 1 1
RenderFarClip 1 256
RenderFlexTimeFactor 1 1.0
RenderGlowResolutionPow 1 9
+RenderLocalLights 1 1
RenderMaxPartCount 1 8192
RenderObjectBump 1 1
RenderReflectionDetail 1 4
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 2.0
+RenderTransparentWater 1 1
RenderTreeLODFactor 1 1.0
RenderUseImpostors 1 1
RenderVolumeLODFactor 1 2.0
@@ -170,8 +181,7 @@ WindLightUseAtmosShaders 1 1
WLSkyDetail 1 128
RenderDeferred 1 0
RenderDeferredSSAO 1 0
-RenderShadowDetail 1 0
-RenderUseFBO 1 0
+RenderShadowDetail 1 2
//
// Class Unknown Hardware (unknown)
@@ -246,7 +256,6 @@ WindLightUseAtmosShaders 0 0
RenderDeferred 0 0
RenderDeferredSSAO 0 0
RenderShadowDetail 0 0
-RenderUseFBO 1 0
//
// CPU based feature masks
@@ -268,6 +277,9 @@ RenderObjectBump 0 0
list OpenGLPre15
RenderVBOEnable 1 0
+list OpenGLPre30
+RenderDeferred 0 0
+
list Intel
RenderAnisotropic 1 0
@@ -454,6 +466,11 @@ RenderAvatarCloth 0 0
list ATI
RenderUseStreamVBO 1 0
+RenderAvatarVP 1 0
+
+// Disable vertex buffer objects by default for ATI cards with little video memory
+list ATIVramLT256
+RenderVBOEnable 1 0
/// Tweaked NVIDIA
diff --git a/indra/newview/generate_breakpad_symbols.py b/indra/newview/generate_breakpad_symbols.py
index 8f2dfd2348..5ebec1563e 100644
--- a/indra/newview/generate_breakpad_symbols.py
+++ b/indra/newview/generate_breakpad_symbols.py
@@ -1,29 +1,31 @@
#!/usr/bin/env python
-# @file generate_breakpad_symbols.py
-# @author Brad Kittenbrink <brad@lindenlab.com>
-# @brief Simple tool for generating google_breakpad symbol information
-# for the crash reporter.
-#
-# $LicenseInfo:firstyear=2010&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$
+"""\
+@file generate_breakpad_symbols.py
+@author Brad Kittenbrink <brad@lindenlab.com>
+@brief Simple tool for generating google_breakpad symbol information
+ for the crash reporter.
+
+$LicenseInfo:firstyear=2010&license=viewerlgpl$
+Second Life Viewer Source Code
+Copyright (C) 2010-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$
+"""
import collections
@@ -31,6 +33,7 @@ import fnmatch
import itertools
import operator
import os
+import re
import sys
import shlex
import subprocess
@@ -45,8 +48,12 @@ class MissingModuleError(Exception):
Exception.__init__(self, "Failed to find required modules: %r" % modules)
self.modules = modules
-def main(viewer_dir, viewer_exes, libs_suffix, dump_syms_tool, viewer_symbol_file):
- print "generate_breakpad_symbols run with args: %s" % str((viewer_dir, viewer_exes, libs_suffix, dump_syms_tool, viewer_symbol_file))
+def main(configuration, viewer_dir, viewer_exes, libs_suffix, dump_syms_tool, viewer_symbol_file):
+ print "generate_breakpad_symbols run with args: %s" % str((configuration, viewer_dir, viewer_exes, libs_suffix, dump_syms_tool, viewer_symbol_file))
+
+ if not re.match("release", configuration, re.IGNORECASE):
+ print "skipping breakpad symbol generation for non-release build."
+ return 0
# split up list of viewer_exes
# "'Second Life' SLPlugin" becomes ['Second Life', 'SLPlugin']
@@ -122,7 +129,7 @@ def main(viewer_dir, viewer_exes, libs_suffix, dump_syms_tool, viewer_symbol_fil
return 0
if __name__ == "__main__":
- if len(sys.argv) != 6:
+ if len(sys.argv) != 7:
usage()
sys.exit(1)
sys.exit(main(*sys.argv[1:]))
diff --git a/indra/newview/gpu_table.txt b/indra/newview/gpu_table.txt
index da888bc64d..6ed4e3b7f7 100644
--- a/indra/newview/gpu_table.txt
+++ b/indra/newview/gpu_table.txt
@@ -1,10 +1,20 @@
-//
+//
// Categorizes graphics chips into various classes by name
//
-// The table contains chip names regular expressions to match
+// The table contains regular expressions to match
// against driver strings, a class number, and whether we claim
// to support them or not.
//
+// If you modify this table, use the (perl) gpu_table_tester
+// to compare the results of recognizing known cards (it is easy
+// to mess this up by putting things in the wrong order):
+//
+// perl ../../scripts/gpu_table_tester -g gpu_table.txt tests/gpus_seen.txt | diff - tests/gpus_results.txt
+//
+// Format:
+// Fields are separated by one or more tab (not space) characters
+// <recognizer name> <regular expression> <class> <supported>
+//
// Class Numbers:
// 0 - Defaults to low graphics settings. No shaders on by default
// 1 - Defaults to mid graphics settings. Basic shaders on by default
@@ -15,304 +25,495 @@
// 0 - We claim to not support this card.
// 1 - We claim to support this card.
//
-// Format:
-// <chip name> <regexp> <class> <supported>
-//
-3Dfx .*3Dfx.* 0 0
-3Dlabs .*3Dlabs.* 0 0
-ATI 3D-Analyze .*ATI.*3D-Analyze.* 0 0
-ATI All-in-Wonder 7500 .*ATI.*All-in-Wonder 75.* 0 1
-ATI All-in-Wonder 8500 .*ATI.*All-in-Wonder 85.* 0 1
-ATI All-in-Wonder 9200 .*ATI.*All-in-Wonder 92.* 0 1
-ATI All-in-Wonder 9xxx .*ATI.*All-in-Wonder 9.* 1 1
-ATI All-in-Wonder HD .*ATI.*All-in-Wonder HD.* 1 1
-ATI All-in-Wonder X600 .*ATI.*All-in-Wonder X6.* 1 1
-ATI All-in-Wonder X800 .*ATI.*All-in-Wonder X8.* 2 1
-ATI All-in-Wonder X1800 .*ATI.*All-in-Wonder X18.* 3 1
-ATI All-in-Wonder X1900 .*ATI.*All-in-Wonder X19.* 3 1
-ATI All-in-Wonder PCI-E .*ATI.*All-in-Wonder.*PCI-E.* 1 1
-ATI All-in-Wonder Radeon .*ATI.*All-in-Wonder Radeon.* 0 1
-ATI ASUS A9xxx .*ATI.*ASUS.*A9.* 1 1
-ATI ASUS AH24xx .*ATI.*ASUS.*AH24.* 1 1
-ATI ASUS AH26xx .*ATI.*ASUS.*AH26.* 3 1
-ATI ASUS AH34xx .*ATI.*ASUS.*AH34.* 1 1
-ATI ASUS AH36xx .*ATI.*ASUS.*AH36.* 3 1
-ATI ASUS AH46xx .*ATI.*ASUS.*AH46.* 3 1
-ATI ASUS AX3xx .*ATI.*ASUS.*AX3.* 1 1
-ATI ASUS AX5xx .*ATI.*ASUS.*AX5.* 1 1
-ATI ASUS AX8xx .*ATI.*ASUS.*AX8.* 2 1
-ATI ASUS EAH24xx .*ATI.*ASUS.*EAH24.* 2 1
-ATI ASUS EAH26xx .*ATI.*ASUS.*EAH26.* 3 1
-ATI ASUS EAH34xx .*ATI.*ASUS.*EAH34.* 1 1
-ATI ASUS EAH36xx .*ATI.*ASUS.*EAH36.* 3 1
-ATI ASUS EAH38xx .*ATI.*ASUS.*EAH38.* 3 1
-ATI ASUS EAH43xx .*ATI.*ASUS.*EAH43.* 1 1
-ATI ASUS EAH45xx .*ATI.*ASUS.*EAH45.* 1 1
-ATI ASUS EAH48xx .*ATI.*ASUS.*EAH48.* 3 1
-ATI ASUS EAH57xx .*ATI.*ASUS.*EAH57.* 3 1
-ATI ASUS EAH58xx .*ATI.*ASUS.*EAH58.* 3 1
-ATI Radeon X1xxx .*ATI.*ASUS.*X1.* 3 1
-ATI Radeon X7xx .*ATI.*ASUS.*X7.* 1 1
-ATI Radeon X500 .*ATI.*Diamond X5.* 1 1
-ATI Radeon X13xx .*ATI.*Diamond X13.* 1 1
-ATI Radeon X16xx .*ATI.*Diamond X16.* 1 1
-ATI Radeon X19xx .*ATI.*Diamond X19.* 1 1
-ATI Display Adapter .*ATI.*display adapter.* 0 1
-ATI FireGL 5200 .*ATI.*FireGL V52.* 0 1
-ATI FireGL 5xxx .*ATI.*FireGL V5.* 1 1
-ATI FireGL .*ATI.*Fire.*GL.* 0 1
-ATI FireMV .*ATI.*FireMV.* 0 0
-ATI Generic .*ATI.*Generic.* 0 0
-ATI Hercules 9800 .*ATI.*Hercules.*9800.* 1 1
-ATI IGP 340M .*ATI.*IGP.*340M.* 0 0
-ATI M52 .*ATI.*M52.* 1 1
-ATI M54 .*ATI.*M54.* 1 1
-ATI M56 .*ATI.*M56.* 1 1
-ATI M71 .*ATI.*M71.* 1 1
-ATI M72 .*ATI.*M72.* 1 1
-ATI M76 .*ATI.*M76.* 3 1
-ATI Mobility Radeon 4100 .*ATI.*Mobility *41.* 0 1
-ATI Mobility Radeon 7xxx .*ATI.*Mobility *Radeon 7.* 0 1
-ATI Mobility Radeon 8xxx .*ATI.*Mobility *Radeon 8.* 0 1
-ATI Mobility Radeon 9800 .*ATI.*Mobility *98.* 0 1
-ATI Mobility Radeon 9700 .*ATI.*Mobility *97.* 0 1
-ATI Mobility Radeon 9600 .*ATI.*Mobility *96.* 0 1
-ATI Mobility Radeon HD 2300 .*ATI.*Mobility *HD *23.* 1 1
-ATI Mobility Radeon HD 2400 .*ATI.*Mobility *HD *24.* 1 1
-ATI Mobility Radeon HD 2600 .*ATI.*Mobility *HD *26.* 3 1
-ATI Mobility Radeon HD 3400 .*ATI.*Mobility *HD *34.* 1 1
-ATI Mobility Radeon HD 3600 .*ATI.*Mobility *HD *36.* 3 1
-ATI Mobility Radeon HD 3800 .*ATI.*Mobility *HD *38.* 3 1
-ATI Mobility Radeon HD 5400 .*ATI.*Mobility *HD *54.* 1 1
-ATI Mobility Radeon HD 5500 .*ATI.*Mobility *HD *55.* 1 1
-ATI Mobility Radeon X1xxx .*ATI.*Mobility *X1.* 0 1
-ATI Mobility Radeon X2xxx .*ATI.*Mobility *X2.* 0 1
-ATI Mobility Radeon X3xx .*ATI.*Mobility *X3.* 1 1
-ATI Mobility Radeon X6xx .*ATI.*Mobility *X6.* 1 1
-ATI Mobility Radeon X7xx .*ATI.*Mobility *X7.* 1 1
-ATI Mobility Radeon Xxxx .*ATI.*Mobility *X.* 0 1
-ATI Radeon HD 2300 .*ATI.*Radeon HD *23.* 0 1
-ATI Radeon HD 2400 .*ATI.*Radeon HD *24.* 1 1
-ATI Radeon HD 2600 .*ATI.*Radeon HD *26.* 2 1
-ATI Radeon HD 2900 .*ATI.*Radeon HD *29.* 3 1
-ATI Radeon HD 3200 .*ATI.*Radeon *HD *32.* 0 1
-ATI Radeon HD 3300 .*ATI.*Radeon HD *33.* 1 1
-ATI Radeon HD 3400 .*ATI.*Radeon HD *34.* 1 1
-ATI Radeon HD 3600 .*ATI.*Radeon HD *36.* 3 1
-ATI Radeon HD 3800 .*ATI.*Radeon HD *38.* 3 1
-ATI Radeon HD 4200 .*ATI.*Radeon HD *42.* 1 1
-ATI Radeon HD 4300 .*ATI.*Radeon HD *43.* 1 1
-ATI Radeon HD 4500 .*ATI.*Radeon HD *45.* 3 1
-ATI Radeon HD 4600 .*ATI.*Radeon HD *46.* 3 1
-ATI Radeon HD 4700 .*ATI.*Radeon HD *47.* 3 1
-ATI Radeon HD 4800 .*ATI.*Radeon.*HD *48.* 3 1
-ATI Radeon HD 5400 .*ATI.*Radeon.*HD *54.* 3 1
-ATI Radeon HD 5500 .*ATI.*Radeon.*HD *55.* 3 1
-ATI Radeon HD 5600 .*ATI.*Radeon.*HD *56.* 3 1
-ATI Radeon HD 5700 .*ATI.*Radeon.*HD *57.* 3 1
-ATI Radeon HD 5800 .*ATI.*Radeon.*HD *58.* 3 1
-ATI Radeon HD 5900 .*ATI.*Radeon.*HD *59.* 3 1
-ATI Radeon OpenGL .*ATI.*Radeon OpenGL.* 0 0
-ATI Radeon 2100 .*ATI.*Radeon 21.* 0 1
-ATI Radeon 3000 .*ATI.*Radeon 30.* 0 1
-ATI Radeon 3100 .*ATI.*Radeon 31.* 0 1
-ATI Radeon 7xxx .*ATI.*Radeon 7.* 0 1
-ATI Radeon 8xxx .*ATI.*Radeon 8.* 0 1
-ATI Radeon 9000 .*ATI.*Radeon 90.* 0 1
-ATI Radeon 9100 .*ATI.*Radeon 91.* 0 1
-ATI Radeon 9200 .*ATI.*Radeon 92.* 0 1
-ATI Radeon 9500 .*ATI.*Radeon 95.* 0 1
-ATI Radeon 9600 .*ATI.*Radeon 96.* 0 1
-ATI Radeon 9700 .*ATI.*Radeon 97.* 1 1
-ATI Radeon 9800 .*ATI.*Radeon 98.* 1 1
-ATI Radeon RV250 .*ATI.*RV250.* 0 1
-ATI Radeon RV600 .*ATI.*RV6.* 1 1
-ATI Radeon RX700 .*ATI.*RX70.* 1 1
-ATI Radeon RX800 .*ATI.*Radeon *RX80.* 2 1
-ATI Radeon RX9550 .*ATI.*RX9550.* 1 1
-ATI Radeon VE .*ATI.*Radeon.*VE.* 0 0
-ATI Radeon X1000 .*ATI.*Radeon *X10.* 0 1
-ATI Radeon X1200 .*ATI.*Radeon *X12.* 0 1
-ATI Radeon X1300 .*ATI.*Radeon *X13.* 1 1
-ATI Radeon X1400 .*ATI.*Radeon *X14.* 1 1
-ATI Radeon X1500 .*ATI.*Radeon *X15.* 1 1
-ATI Radeon X1600 .*ATI.*Radeon *X16.* 1 1
-ATI Radeon X1700 .*ATI.*Radeon *X17.* 1 1
-ATI Radeon X1800 .*ATI.*Radeon *X18.* 3 1
-ATI Radeon X1900 .*ATI.*Radeon *X19.* 3 1
-ATI Radeon X300 .*ATI.*Radeon *X3.* 0 1
-ATI Radeon X400 .*ATI.*Radeon X4.* 0 1
-ATI Radeon X500 .*ATI.*Radeon X5.* 0 1
-ATI Radeon X600 .*ATI.*Radeon X6.* 1 1
-ATI Radeon X700 .*ATI.*Radeon X7.* 1 1
-ATI Radeon X800 .*ATI.*Radeon X8.* 2 1
-ATI Radeon X900 .*ATI.*Radeon X9.* 2 1
-ATI Radeon Xpress .*ATI.*Radeon Xpress.* 0 0
-ATI Rage 128 .*ATI.*Rage 128.* 0 1
-ATI RV250 .*ATI.*RV250.* 0 1
-ATI RV380 .*ATI.*RV380.* 0 1
-ATI RV530 .*ATI.*RV530.* 1 1
-ATI RX700 .*ATI.*RX700.* 1 1
-Intel X3100 .*Intel.*X3100.* 0 1
-Intel 830M .*Intel.*830M 0 0
-Intel 845G .*Intel.*845G 0 0
-Intel 855GM .*Intel.*855GM 0 0
-Intel 865G .*Intel.*865G 0 0
-Intel 900 .*Intel.*900.*900 0 0
-Intel 915GM .*Intel.*915GM 0 0
-Intel 915G .*Intel.*915G 0 0
-Intel 945GM .*Intel.*945GM.* 0 1
-Intel 945G .*Intel.*945G.* 0 1
-Intel 950 .*Intel.*950.* 0 1
-Intel 965 .*Intel.*965.* 0 1
-Intel G33 .*Intel.*G33.* 0 0
-Intel G41 .*Intel.*G41.* 0 1
-Intel G45 .*Intel.*G45.* 0 1
-Intel Bear Lake .*Intel.*Bear Lake.* 0 0
-Intel Broadwater .*Intel.*Broadwater.* 0 0
-Intel Brookdale .*Intel.*Brookdale.* 0 0
-Intel Cantiga .*Intel.*Cantiga.* 0 0
-Intel Eaglelake .*Intel.*Eaglelake.* 0 1
-Intel Graphics Media HD .*Intel(R) Graphics Media.*HD.* 0 1
-Intel HD Graphics .*Intel(R) HD Graphics.* 0 1
-Intel Mobile 4 Series .*Intel.*Mobile.*4 Series.* 0 1
-Intel Media Graphics HD .*Intel Media Graphics HD.* 0 1
-Intel Montara .*Intel.*Montara.* 0 0
-Intel Pineview .*Intel.*Pineview.* 0 1
-Intel Springdale .*Intel.*Springdale.* 0 0
-Matrox .*Matrox.* 0 0
-Mesa .*Mesa.* 0 0
-NVIDIA 310M .*NVIDIA.*GeForce 310M.* 0 1
-NVIDIA 310 .*NVIDIA.*GeForce 310.* 0 1
-NVIDIA 320M .*NVIDIA.*GeForce 320M.* 0 1
-NVIDIA G100M .*NVIDIA.*GeForce G *100M.* 0 1
-NVIDIA G102M .*NVIDIA.*GeForce G *102M.* 0 1
-NVIDIA G103M .*NVIDIA.*GeForce G *103M.* 0 1
-NVIDIA G105M .*NVIDIA.*GeForce G *105M.* 0 1
-NVIDIA G210M .*NVIDIA.*GeForce G210M.* 0 1
-NVIDIA GT 120 .*NVIDIA.*GeForce GT 12.* 1 1
-NVIDIA GT 130 .*NVIDIA.*GeForce GT 13.* 1 1
-NVIDIA GT 220 .*NVIDIA.*GeForce GT 22.* 1 1
-NVIDIA GT 230 .*NVIDIA.*GeForce GT 23.* 1 1
-NVIDIA GT 240 .*NVIDIA.*GeForce GT 24.* 1 1
-NVIDIA GT 320 .*NVIDIA.*GeForce GT 32.* 0 1
-NVIDIA GT 330M .*NVIDIA.*GeForce GT 330M.* 1 1
-NVIDIA GTS 240 .*NVIDIA.*GeForce GTS 24.* 1 1
-NVIDIA GTS 250 .*NVIDIA.*GeForce GTS 25.* 3 1
-NVIDIA GTS 360M .*NVIDIA.*GeForce GTS 360M.* 3 1
-NVIDIA GTX 260 .*NVIDIA.*GeForce GTX 26.* 3 1
-NVIDIA GTX 270 .*NVIDIA.*GeForce GTX 27.* 3 1
-NVIDIA GTX 280 .*NVIDIA.*GeForce GTX 28.* 3 1
-NVIDIA GTX 290 .*NVIDIA.*GeForce GTX 29.* 3 1
-NVIDIA GTX 470 .*NVIDIA.*GeForce GTX 47.* 3 1
-NVIDIA GTX 480 .*NVIDIA.*GeForce GTX 48.* 3 1
-NVIDIA C51 .*NVIDIA.*C51.* 0 1
-NVIDIA G72 .*NVIDIA.*G72.* 1 1
-NVIDIA G73 .*NVIDIA.*G73.* 1 1
-NVIDIA G84 .*NVIDIA.*G84.* 3 1
-NVIDIA G86 .*NVIDIA.*G86.* 3 1
-NVIDIA G92 .*NVIDIA.*G92.* 3 1
-NVIDIA GeForce .*GeForce 256.* 0 0
-NVIDIA GeForce 2 .*GeForce2.* 0 1
-NVIDIA GeForce 3 .*GeForce3.* 0 1
-NVIDIA GeForce 4 Go .*NVIDIA.*GeForce4.*Go.* 0 1
-NVIDIA GeForce 4 MX .*NVIDIA.*GeForce4 MX.* 0 1
-NVIDIA GeForce 4 Ti .*NVIDIA.*GeForce4 Ti.* 0 1
-NVIDIA GeForce 6100 .*NVIDIA.*GeForce 61.* 0 1
-NVIDIA GeForce 6200 .*NVIDIA.*GeForce 62.* 0 1
-NVIDIA GeForce 6500 .*NVIDIA.*GeForce 65.* 0 1
-NVIDIA GeForce 6600 .*NVIDIA.*GeForce 66.* 1 1
-NVIDIA GeForce 6700 .*NVIDIA.*GeForce 67.* 2 1
-NVIDIA GeForce 6800 .*NVIDIA.*GeForce 68.* 2 1
-NVIDIA GeForce 7000 .*NVIDIA.*GeForce 70.* 0 1
-NVIDIA GeForce 7100 .*NVIDIA.*GeForce 71.* 0 1
-NVIDIA GeForce 7200 .*NVIDIA.*GeForce 72.* 1 1
-NVIDIA GeForce 7300 .*NVIDIA.*GeForce 73.* 1 1
-NVIDIA GeForce 7500 .*NVIDIA.*GeForce 75.* 1 1
-NVIDIA GeForce 7600 .*NVIDIA.*GeForce 76.* 1 1
-NVIDIA GeForce 7800 .*NVIDIA.*GeForce 78.* 1 1
-NVIDIA GeForce 7900 .*NVIDIA.*GeForce 79.* 1 1
-NVIDIA GeForce 8100 .*NVIDIA.*GeForce 81.* 1 1
-NVIDIA GeForce 8200 .*NVIDIA.*GeForce 82.* 1 1
-NVIDIA GeForce 8300 .*NVIDIA.*GeForce 83.* 1 1
-NVIDIA GeForce 8400 .*NVIDIA.*GeForce 84.* 1 1
-NVIDIA GeForce 8500 .*GeForce 85.* 1 1
-NVIDIA GeForce 8600M .*NVIDIA.*GeForce.*8600M.* 1 1
-NVIDIA GeForce 8600 .*NVIDIA.*GeForce 86.* 3 1
-NVIDIA GeForce 8700 .*NVIDIA.*GeForce 87.* 3 1
-NVIDIA GeForce 8800 .*NVIDIA.*GeForce 88.* 3 1
-NVIDIA GeForce 9100 .*NVIDIA.*GeForce 9100.* 0 1
-NVIDIA GeForce 9200 .*NVIDIA.*GeForce 9200.* 0 1
-NVIDIA GeForce 9300M .*NVIDIA.*GeForce 9300M.* 1 1
-NVIDIA GeForce 9400M .*NVIDIA.*GeForce 9400M.* 1 1
-NVIDIA GeForce 9500M .*NVIDIA.*GeForce 9500M.* 2 1
-NVIDIA GeForce 9600M .*NVIDIA.*GeForce 9600M.* 3 1
-NVIDIA GeForce 9700M .*NVIDIA.*GeForce 9700M.* 3 1
-NVIDIA GeForce 9300 .*NVIDIA.*GeForce 93.* 1 1
-NVIDIA GeForce 9400 .*GeForce 94.* 1 1
-NVIDIA GeForce 9500 .*NVIDIA.*GeForce 95.* 2 1
-NVIDIA GeForce 9600 .*NVIDIA.*GeForce.*96.* 3 1
-NVIDIA GeForce 9800 .*NVIDIA.*GeForce.*98.* 3 1
-NVIDIA GeForce FX 5100 .*NVIDIA.*GeForce FX 51.* 0 1
-NVIDIA GeForce FX 5200 .*NVIDIA.*GeForce FX 52.* 0 1
-NVIDIA GeForce FX 5500 .*NVIDIA.*GeForce FX 55.* 0 1
-NVIDIA GeForce FX 5600 .*NVIDIA.*GeForce FX 56.* 0 1
-NVIDIA GeForce FX 5700 .*NVIDIA.*GeForce FX 57.* 1 1
-NVIDIA GeForce FX 5800 .*NVIDIA.*GeForce FX 58.* 1 1
-NVIDIA GeForce FX 5900 .*NVIDIA.*GeForce FX 59.* 1 1
-NVIDIA GeForce FX Go5100 .*NVIDIA.*GeForce FX Go51.* 0 1
-NVIDIA GeForce FX Go5200 .*NVIDIA.*GeForce FX Go52.* 0 1
-NVIDIA GeForce FX Go5300 .*NVIDIA.*GeForce FX Go53.* 0 1
-NVIDIA GeForce FX Go5500 .*NVIDIA.*GeForce FX Go55.* 0 1
-NVIDIA GeForce FX Go5600 .*NVIDIA.*GeForce FX Go56.* 0 1
-NVIDIA GeForce FX Go5700 .*NVIDIA.*GeForce FX Go57.* 1 1
-NVIDIA GeForce FX Go5800 .*NVIDIA.*GeForce FX Go58.* 1 1
-NVIDIA GeForce FX Go5900 .*NVIDIA.*GeForce FX Go59.* 1 1
-NVIDIA GeForce Go 6100 .*NVIDIA.*GeForce Go 61.* 0 1
-NVIDIA GeForce Go 6200 .*NVIDIA.*GeForce Go 62.* 0 1
-NVIDIA GeForce Go 6500 .*NVIDIA.*GeForce Go 65.* 1 1
-NVIDIA GeForce Go 6600 .*NVIDIA.*GeForce Go 66.* 1 1
-NVIDIA GeForce Go 6700 .*NVIDIA.*GeForce Go 67.* 1 1
-NVIDIA GeForce Go 6800 .*NVIDIA.*GeForce Go 68.* 1 1
-NVIDIA GeForce Go 7200 .*NVIDIA.*GeForce Go 72.* 1 1
-NVIDIA GeForce Go 7300 .*NVIDIA.*GeForce Go 73.* 1 1
-NVIDIA GeForce Go 7300 LE .*NVIDIA.*GeForce Go 73.*LE.* 0 1
-NVIDIA GeForce Go 7400 .*NVIDIA.*GeForce Go 74.* 1 1
-NVIDIA GeForce Go 7600 .*NVIDIA.*GeForce Go 76.* 2 1
-NVIDIA GeForce Go 7700 .*NVIDIA.*GeForce Go 77.* 2 1
-NVIDIA GeForce Go 7800 .*NVIDIA.*GeForce Go 78.* 2 1
-NVIDIA GeForce Go 7900 .*NVIDIA.*GeForce Go 79.* 2 1
-NVIDIA D9M .*D9M.* 1 1
-NVIDIA G84 .*G84.* 1 1
-NVIDIA G92 .*G92.* 3 1
-NVIDIA G94 .*G94.* 3 1
-NVIDIA GeForce Go 6 .*GeForce Go 6.* 1 1
-NVIDIA ION .*NVIDIA ION.* 1 1
-NVIDIA NB9M .*GeForce NB9M.* 1 1
-NVIDIA NB9P .*GeForce NB9P.* 1 1
-NVIDIA GeForce PCX .*GeForce PCX.* 0 1
-NVIDIA Generic .*NVIDIA.*Unknown.* 0 0
-NVIDIA NV17 .*GeForce NV17.* 0 1
-NVIDIA NV34 .*NVIDIA.*NV34.* 0 1
-NVIDIA NV35 .*NVIDIA.*NV35.* 0 1
-NVIDIA NV36 .*GeForce NV36.* 1 1
-NVIDIA NV43 .*NVIDIA.*NV43.* 1 1
-NVIDIA NV44 .*NVIDIA.*NV44.* 1 1
-NVIDIA nForce .*NVIDIA.*nForce.* 0 0
-NVIDIA MCP78 .*NVIDIA.*MCP78.* 1 1
-NVIDIA Quadro2 .*Quadro2.* 0 1
-NVIDIA Quadro4 .*Quadro4.* 0 1
-NVIDIA Quadro DCC .*Quadro DCC.* 0 1
-NVIDIA Quadro FX 4500 .*Quadro.*FX.*4500.* 3 1
-NVIDIA Quadro FX .*Quadro FX.* 1 1
-NVIDIA Quadro NVS .*Quadro NVS.* 0 1
-NVIDIA RIVA TNT .*RIVA TNT.* 0 0
-S3 .*S3 Graphics.* 0 0
-SiS SiS.* 0 0
-Trident Trident.* 0 0
-Tungsten Graphics Tungsten.* 0 0
-XGI XGI.* 0 0
-VIA VIA.* 0 0
-Apple Generic Apple.*Generic.* 0 0
-Apple Software Renderer Apple.*Software Renderer.* 0 0
+3Dfx .*3Dfx.* 0 0
+3Dlabs .*3Dlabs.* 0 0
+ATI 3D-Analyze .*ATI.*3D-Analyze.* 0 0
+ATI All-in-Wonder 7500 .*ATI.*All-in-Wonder 75.* 0 1
+ATI All-in-Wonder 8500 .*ATI.*All-in-Wonder 85.* 0 1
+ATI All-in-Wonder 9200 .*ATI.*All-in-Wonder 92.* 0 1
+ATI All-in-Wonder 9xxx .*ATI.*All-in-Wonder 9.* 1 1
+ATI All-in-Wonder HD .*ATI.*All-in-Wonder HD.* 1 1
+ATI All-in-Wonder X600 .*ATI.*All-in-Wonder X6.* 1 1
+ATI All-in-Wonder X800 .*ATI.*All-in-Wonder X8.* 2 1
+ATI All-in-Wonder X1800 .*ATI.*All-in-Wonder X18.* 3 1
+ATI All-in-Wonder X1900 .*ATI.*All-in-Wonder X19.* 3 1
+ATI All-in-Wonder PCI-E .*ATI.*All-in-Wonder.*PCI-E.* 1 1
+ATI All-in-Wonder Radeon .*ATI.*All-in-Wonder Radeon.* 0 1
+ATI ASUS A9xxx .*ATI.*ASUS.*A9.* 1 1
+ATI ASUS AH24xx .*ATI.*ASUS.*AH24.* 1 1
+ATI ASUS AH26xx .*ATI.*ASUS.*AH26.* 3 1
+ATI ASUS AH34xx .*ATI.*ASUS.*AH34.* 1 1
+ATI ASUS AH36xx .*ATI.*ASUS.*AH36.* 3 1
+ATI ASUS AH46xx .*ATI.*ASUS.*AH46.* 3 1
+ATI ASUS AX3xx .*ATI.*ASUS.*AX3.* 1 1
+ATI ASUS AX5xx .*ATI.*ASUS.*AX5.* 1 1
+ATI ASUS AX8xx .*ATI.*ASUS.*AX8.* 2 1
+ATI ASUS EAH24xx .*ATI.*ASUS.*EAH24.* 2 1
+ATI ASUS EAH26xx .*ATI.*ASUS.*EAH26.* 3 1
+ATI ASUS EAH34xx .*ATI.*ASUS.*EAH34.* 1 1
+ATI ASUS EAH36xx .*ATI.*ASUS.*EAH36.* 3 1
+ATI ASUS EAH38xx .*ATI.*ASUS.*EAH38.* 3 1
+ATI ASUS EAH43xx .*ATI.*ASUS.*EAH43.* 1 1
+ATI ASUS EAH45xx .*ATI.*ASUS.*EAH45.* 1 1
+ATI ASUS EAH48xx .*ATI.*ASUS.*EAH48.* 3 1
+ATI ASUS EAH57xx .*ATI.*ASUS.*EAH57.* 3 1
+ATI ASUS EAH58xx .*ATI.*ASUS.*EAH58.* 3 1
+ATI ASUS Radeon X1xxx .*ATI.*ASUS.*X1.* 3 1
+ATI Radeon X7xx .*ATI.*ASUS.*X7.* 1 1
+ATI Radeon X1xxx .*ATI.*X1.* 0 1
+ATI Radeon X13xx .*ATI.*Diamond X13.* 1 1
+ATI Radeon X16xx .*ATI.*Diamond X16.* 1 1
+ATI Radeon X19xx .*ATI.*Diamond X19.* 1 1
+ATI Display Adapter .*ATI.*display adapter.* 0 1
+ATI FireGL 5200 .*ATI.*FireGL V52.* 0 1
+ATI FireGL 5xxx .*ATI.*FireGL V5.* 1 1
+ATI FireGL .*ATI.*Fire.*GL.* 0 1
+ATI FirePro M3900 .*ATI.*FirePro.*M39.* 2 1
+ATI FirePro M5800 .*ATI.*FirePro.*M58.* 3 1
+ATI FirePro M7740 .*ATI.*FirePro.*M77.* 3 1
+ATI FirePro M7820 .*ATI.*FirePro.*M78.* 3 1
+ATI FireMV .*ATI.*FireMV.* 0 1
+ATI Geforce 9500 GT .*ATI.*Geforce 9500 *GT 2 1
+ATI Geforce 9800 GT .*ATI.*Geforce 9800 *GT 2 1
+ATI Generic .*ATI.*Generic.* 0 0
+ATI Hercules 9800 .*ATI.*Hercules.*9800.* 1 1
+ATI IGP 340M .*ATI.*IGP.*340M.* 0 0
+ATI M52 .*ATI.*M52.* 1 1
+ATI M54 .*ATI.*M54.* 1 1
+ATI M56 .*ATI.*M56.* 1 1
+ATI M71 .*ATI.*M71.* 1 1
+ATI M72 .*ATI.*M72.* 1 1
+ATI M76 .*ATI.*M76.* 3 1
+ATI Mobility Radeon 4100 .*ATI.*(Mobility|MOBILITY).*41.* 0 1
+ATI Mobility Radeon 7xxx .*ATI.*(Mobility|MOBILITY).*Radeon 7.* 0 1
+ATI Mobility Radeon 8xxx .*ATI.*(Mobility|MOBILITY).*Radeon 8.* 0 1
+ATI Mobility Radeon 9800 .*ATI.*(Mobility|MOBILITY).*98.* 1 1
+ATI Mobility Radeon 9700 .*ATI.*(Mobility|MOBILITY).*97.* 1 1
+ATI Mobility Radeon 9600 .*ATI.*(Mobility|MOBILITY).*96.* 0 1
+ATI Mobility Radeon HD 530v .*ATI.*(Mobility|MOBILITY).*HD *530v.* 1 1
+ATI Mobility Radeon HD 540v .*ATI.*(Mobility|MOBILITY).*HD *540v.* 2 1
+ATI Mobility Radeon HD 545v .*ATI.*(Mobility|MOBILITY).*HD *545v.* 2 1
+ATI Mobility Radeon HD 550v .*ATI.*(Mobility|MOBILITY).*HD *550v.* 2 1
+ATI Mobility Radeon HD 560v .*ATI.*(Mobility|MOBILITY).*HD *560v.* 2 1
+ATI Mobility Radeon HD 565v .*ATI.*(Mobility|MOBILITY).*HD *565v.* 2 1
+ATI Mobility Radeon HD 2300 .*ATI.*(Mobility|MOBILITY).*HD *23.* 1 1
+ATI Mobility Radeon HD 2400 .*ATI.*(Mobility|MOBILITY).*HD *24.* 1 1
+ATI Mobility Radeon HD 2600 .*ATI.*(Mobility|MOBILITY).*HD *26.* 3 1
+ATI Mobility Radeon HD 2700 .*ATI.*(Mobility|MOBILITY).*HD *27.* 3 1
+ATI Mobility Radeon HD 3100 .*ATI.*(Mobility|MOBILITY).*HD *31.* 0 1
+ATI Mobility Radeon HD 3200 .*ATI.*(Mobility|MOBILITY).*HD *32.* 0 1
+ATI Mobility Radeon HD 3400 .*ATI.*(Mobility|MOBILITY).*HD *34.* 2 1
+ATI Mobility Radeon HD 3600 .*ATI.*(Mobility|MOBILITY).*HD *36.* 3 1
+ATI Mobility Radeon HD 3800 .*ATI.*(Mobility|MOBILITY).*HD *38.* 3 1
+ATI Mobility Radeon HD 4200 .*ATI.*(Mobility|MOBILITY).*HD *42.* 2 1
+ATI Mobility Radeon HD 4300 .*ATI.*(Mobility|MOBILITY).*HD *43.* 2 1
+ATI Mobility Radeon HD 4500 .*ATI.*(Mobility|MOBILITY).*HD *45.* 3 1
+ATI Mobility Radeon HD 4600 .*ATI.*(Mobility|MOBILITY).*HD *46.* 3 1
+ATI Mobility Radeon HD 4800 .*ATI.*(Mobility|MOBILITY).*HD *48.* 3 1
+ATI Mobility Radeon HD 5100 .*ATI.*(Mobility|MOBILITY).*HD *51.* 2 1
+ATI Mobility Radeon HD 5300 .*ATI.*(Mobility|MOBILITY).*HD *53.* 2 1
+ATI Mobility Radeon HD 5400 .*ATI.*(Mobility|MOBILITY).*HD *54.* 2 1
+ATI Mobility Radeon HD 5500 .*ATI.*(Mobility|MOBILITY).*HD *55.* 2 1
+ATI Mobility Radeon HD 5600 .*ATI.*(Mobility|MOBILITY).*HD *56.* 2 1
+ATI Mobility Radeon HD 5700 .*ATI.*(Mobility|MOBILITY).*HD *57.* 3 1
+ATI Mobility Radeon HD 6200 .*ATI.*(Mobility|MOBILITY).*HD *62.* 2 1
+ATI Mobility Radeon HD 6300 .*ATI.*(Mobility|MOBILITY).*HD *63.* 2 1
+ATI Mobility Radeon HD 6400M .*ATI.*(Mobility|MOBILITY).*HD *64.* 3 1
+ATI Mobility Radeon HD 6500M .*ATI.*(Mobility|MOBILITY).*HD *65.* 3 1
+ATI Mobility Radeon HD 6600M .*ATI.*(Mobility|MOBILITY).*HD *66.* 3 1
+ATI Mobility Radeon HD 6700M .*ATI.*(Mobility|MOBILITY).*HD *67.* 3 1
+ATI Mobility Radeon HD 6800M .*ATI.*(Mobility|MOBILITY).*HD *68.* 3 1
+ATI Mobility Radeon HD 6900M .*ATI.*(Mobility|MOBILITY).*HD *69.* 3 1
+ATI Mobility Radeon X1xxx .*ATI.*(Mobility|MOBILITY).*X1.* 0 1
+ATI Mobility Radeon X2xxx .*ATI.*(Mobility|MOBILITY).*X2.* 0 1
+ATI Mobility Radeon X3xx .*ATI.*(Mobility|MOBILITY).*X3.* 1 1
+ATI Mobility Radeon X6xx .*ATI.*(Mobility|MOBILITY).*X6.* 1 1
+ATI Mobility Radeon X7xx .*ATI.*(Mobility|MOBILITY).*X7.* 1 1
+ATI Mobility Radeon Xxxx .*ATI.*(Mobility|MOBILITY).*X.* 0 1
+ATI Mobility Radeon .*ATI.*(Mobility|MOBILITY).* 0 1
+ATI Radeon HD 2300 .*ATI.*(Radeon|RADEON) HD *23.* 0 1
+ATI Radeon HD 2400 .*ATI.*(Radeon|RADEON) HD *24.* 1 1
+ATI Radeon HD 2600 .*ATI.*(Radeon|RADEON) HD *26.* 2 1
+ATI Radeon HD 2900 .*ATI.*(Radeon|RADEON) HD *29.* 3 1
+ATI Radeon HD 3000 .*ATI.*(Radeon|RADEON) HD *30.* 0 1
+ATI Radeon HD 3100 .*ATI.*(Radeon|RADEON) HD *31.* 1 1
+ATI Radeon HD 3200 .*ATI.*(Radeon|RADEON) HD *32.* 0 1
+ATI Radeon HD 3300 .*ATI.*(Radeon|RADEON) HD *33.* 1 1
+ATI Radeon HD 3400 .*ATI.*(Radeon|RADEON) HD *34.* 1 1
+ATI Radeon HD 3500 .*ATI.*(Radeon|RADEON) HD *35.* 1 1
+ATI Radeon HD 3600 .*ATI.*(Radeon|RADEON) HD *36.* 3 1
+ATI Radeon HD 3700 .*ATI.*(Radeon|RADEON) HD *37.* 3 1
+ATI Radeon HD 3800 .*ATI.*(Radeon|RADEON) HD *38.* 3 1
+ATI Radeon HD 4200 .*ATI.*(Radeon|RADEON) HD *42.* 1 1
+ATI Radeon HD 4300 .*ATI.*(Radeon|RADEON) HD *43.* 1 1
+ATI Radeon HD 4400 .*ATI.*(Radeon|RADEON) HD *44.* 1 1
+ATI Radeon HD 4500 .*ATI.*(Radeon|RADEON) HD *45.* 3 1
+ATI Radeon HD 4600 .*ATI.*(Radeon|RADEON) HD *46.* 3 1
+ATI Radeon HD 4700 .*ATI.*(Radeon|RADEON) HD *47.* 3 1
+ATI Radeon HD 4800 .*ATI.*(Radeon|RADEON) HD *48.* 3 1
+ATI Radeon HD 5400 .*ATI.*(Radeon|RADEON) HD *54.* 3 1
+ATI Radeon HD 5500 .*ATI.*(Radeon|RADEON) HD *55.* 3 1
+ATI Radeon HD 5600 .*ATI.*(Radeon|RADEON) HD *56.* 3 1
+ATI Radeon HD 5700 .*ATI.*(Radeon|RADEON) HD *57.* 3 1
+ATI Radeon HD 5800 .*ATI.*(Radeon|RADEON) HD *58.* 3 1
+ATI Radeon HD 5900 .*ATI.*(Radeon|RADEON) HD *59.* 3 1
+ATI Radeon HD 6200 .*ATI.*(Radeon|RADEON) HD *62.* 2 1
+ATI Radeon HD 6300 .*ATI.*(Radeon|RADEON) HD *63.* 2 1
+ATI Radeon HD 6400 .*ATI.*(Radeon|RADEON) HD *64.* 3 1
+ATI Radeon HD 6500 .*ATI.*(Radeon|RADEON) HD *65.* 3 1
+ATI Radeon HD 66xx .*ATI.*(Radeon|RADEON) HD *66.* 3 1
+ATI Radeon HD 6700 .*ATI.*(Radeon|RADEON) HD *67.* 3 1
+ATI Radeon HD 6800 .*ATI.*(Radeon|RADEON) HD *68.* 3 1
+ATI Radeon HD 6900 .*ATI.*(Radeon|RADEON) HD *69.* 3 1
+ATI Radeon OpenGL .*ATI.*(Radeon|RADEON) OpenGL.* 0 0
+ATI Radeon 2100 .*ATI.*(Radeon|RADEON) 21.* 0 1
+ATI Radeon 3000 .*ATI.*(Radeon|RADEON) 30.* 0 1
+ATI Radeon 3100 .*ATI.*(Radeon|RADEON) 31.* 1 1
+ATI Radeon 5xxx .*ATI.*(Radeon|RADEON) 5.* 3 1
+ATI Radeon 7xxx .*ATI.*(Radeon|RADEON) 7.* 0 1
+ATI Radeon 8xxx .*ATI.*(Radeon|RADEON) 8.* 0 1
+ATI Radeon 9000 .*ATI.*(Radeon|RADEON) 90.* 0 1
+ATI Radeon 9100 .*ATI.*(Radeon|RADEON) 91.* 0 1
+ATI Radeon 9200 .*ATI.*(Radeon|RADEON) 92.* 0 1
+ATI Radeon 9500 .*ATI.*(Radeon|RADEON) 95.* 0 1
+ATI Radeon 9600 .*ATI.*(Radeon|RADEON) 96.* 0 1
+ATI Radeon 9700 .*ATI.*(Radeon|RADEON) 97.* 1 1
+ATI Radeon 9800 .*ATI.*(Radeon|RADEON) 98.* 1 1
+ATI Radeon RV250 .*ATI.*RV250.* 0 1
+ATI Radeon RV600 .*ATI.*RV6.* 1 1
+ATI Radeon RX700 .*ATI.*RX70.* 1 1
+ATI Radeon RX800 .*ATI.*(Radeon|RADEON) *RX80.* 2 1
+ATI RS880M .*ATI.*RS880M 1 1
+ATI Radeon RX9550 .*ATI.*RX9550.* 1 1
+ATI Radeon VE .*ATI.*(Radeon|RADEON).*VE.* 0 0
+ATI Radeon X1000 .*ATI.*(Radeon|RADEON) *X10.* 0 1
+ATI Radeon X1200 .*ATI.*(Radeon|RADEON) *X12.* 0 1
+ATI Radeon X1300 .*ATI.*(Radeon|RADEON) *X13.* 1 1
+ATI Radeon X1400 .*ATI.*(Radeon|RADEON) *X14.* 1 1
+ATI Radeon X1500 .*ATI.*(Radeon|RADEON) *X15.* 1 1
+ATI Radeon X1600 .*ATI.*(Radeon|RADEON) *X16.* 1 1
+ATI Radeon X1700 .*ATI.*(Radeon|RADEON) *X17.* 1 1
+ATI Radeon X1800 .*ATI.*(Radeon|RADEON) *X18.* 3 1
+ATI Radeon X1900 .*ATI.*(Radeon|RADEON) *X19.* 3 1
+ATI Radeon X300 .*ATI.*(Radeon|RADEON) *X3.* 0 1
+ATI Radeon X400 .*ATI.*(Radeon|RADEON) X4.* 0 1
+ATI Radeon X500 .*ATI.*(Radeon|RADEON) X5.* 0 1
+ATI Radeon X600 .*ATI.*(Radeon|RADEON) X6.* 1 1
+ATI Radeon X700 .*ATI.*(Radeon|RADEON) X7.* 1 1
+ATI Radeon X800 .*ATI.*(Radeon|RADEON) X8.* 2 1
+ATI Radeon X900 .*ATI.*(Radeon|RADEON) X9.* 2 1
+ATI Radeon Xpress .*ATI.*(Radeon|RADEON) (Xpress|XPRESS).* 0 1
+ATI Rage 128 .*ATI.*Rage 128.* 0 1
+ATI R350 (9800) .*(ATI)?.*R350.* 1 1
+ATI R580 (X1900) .*(ATI)?.*R580.* 3 1
+ATI RC410 (Xpress 200) .*(ATI)?.*RC410.* 0 0
+ATI RS48x (Xpress 200x) .*(ATI)?.*RS48.* 0 0
+ATI RS600 (Xpress 3200) .*(ATI)?.*RS600.* 0 0
+ATI RV350 (9600) .*(ATI)?.*RV350.* 0 1
+ATI RV370 (X300) .*(ATI)?.*RV370.* 0 1
+ATI RV410 (X700) .*(ATI)?.*RV410.* 1 1
+ATI RV515 .*(ATI)?.*RV515.* 1 1
+ATI RV570 (X1900 GT/PRO) .*(ATI)?.*RV570.* 3 1
+ATI RV380 .*(ATI)?.*RV380.* 0 1
+ATI RV530 .*(ATI)?.*RV530.* 1 1
+ATI RX480 (Xpress 200P) .*(ATI)?.*RX480.* 0 1
+ATI RX700 .*(ATI)?.*RX700.* 1 1
+AMD ANTILLES (HD 6990) .*(AMD|ATI).*(Antilles|ANTILLES).* 3 1
+AMD BARTS (HD 6800) .*(AMD|ATI).*(Barts|BARTS).* 3 1
+AMD CAICOS (HD 6400) .*(AMD|ATI).*(Caicos|CAICOS).* 3 1
+AMD CAYMAN (HD 6900) .*(AMD|ATI).*(Cayman|CAYMAM).* 3 1
+AMD CEDAR (HD 5450) .*(AMD|ATI).*(Cedar|CEDAR).* 2 1
+AMD CYPRESS (HD 5800) .*(AMD|ATI).*(Cypress|CYPRESS).* 3 1
+AMD HEMLOCK (HD 5970) .*(AMD|ATI).*(Hemlock|HEMLOCK).* 3 1
+AMD JUNIPER (HD 5700) .*(AMD|ATI).*(Juniper|JUNIPER).* 3 1
+AMD PARK .*(AMD|ATI).*(Park|PARK).* 3 1
+AMD REDWOOD (HD 5500/5600) .*(AMD|ATI).*(Redwood|REDWOOD).* 3 1
+AMD TURKS (HD 6500/6600) .*(AMD|ATI).*(Turks|TURKS).* 3 1
+AMD RS780 (HD 3200) .*(AMD|ATI)?.*RS780.* 0 1
+AMD RS880 (HD 4200) .*(AMD|ATI)?.*RS880.* 1 1
+AMD RV610 (HD 2400) .*(AMD|ATI)?.*RV610.* 1 1
+AMD RV620 (HD 3400) .*(AMD|ATI)?.*RV620.* 1 1
+AMD RV630 (HD 2600) .*(AMD|ATI)?.*RV630.* 2 1
+AMD RV635 (HD 3600) .*(AMD|ATI)?.*RV635.* 3 1
+AMD RV670 (HD 3800) .*(AMD|ATI)?.*RV670.* 3 1
+AMD R680 (HD 3870 X2) .*(AMD|ATI)?.*R680.* 3 1
+AMD R700 (HD 4800 X2) .*(AMD|ATI)?.*R700.* 3 1
+AMD RV710 (HD 4300) .*(AMD|ATI)?.*RV710.* 1 1
+AMD RV730 (HD 4600) .*(AMD|ATI)?.*RV730.* 3 1
+AMD RV740 (HD 4700) .*(AMD|ATI)?.*RV740.* 3 1
+AMD RV770 (HD 4800) .*(AMD|ATI)?.*RV770.* 3 1
+AMD RV790 (HD 4800) .*(AMD|ATI)?.*RV790.* 3 1
+ATI 760G/Radeon 3000 .*ATI.*AMD 760G.* 1 1
+ATI 780L/Radeon 3000 .*ATI.*AMD 780L.* 1 1
+ATI Radeon DDR .*ATI.*(Radeon|RADEON) ?DDR.* 0 1
+ATI FirePro 2000 .*ATI.*FirePro 2.* 1 1
+ATI FirePro 3000 .*ATI.*FirePro V3.* 1 1
+ATI FirePro 4000 .*ATI.*FirePro V4.* 2 1
+ATI FirePro 5000 .*ATI.*FirePro V5.* 3 1
+ATI FirePro 7000 .*ATI.*FirePro V7.* 3 1
+ATI FirePro M .*ATI.*FirePro M.* 3 1
+ATI Technologies .*ATI *Technologies.* 0 1
+// This entry is last to work around the "R300" driver problem.
+ATI R300 (9700) .*(ATI)?.*R300.* 1 1
+ATI Radeon .*ATI.*Radeon.* 0 1
+Intel X3100 .*Intel.*X3100.* 0 1
+Intel 830M .*Intel.*830M 0 0
+Intel 845G .*Intel.*845G 0 0
+Intel 855GM .*Intel.*855GM 0 0
+Intel 865G .*Intel.*865G 0 0
+Intel 900 .*Intel.*900.*900 0 0
+Intel 915GM .*Intel.*915GM 0 0
+Intel 915G .*Intel.*915G 0 0
+Intel 945GM .*Intel.*945GM.* 0 1
+Intel 945G .*Intel.*945G.* 0 1
+Intel 950 .*Intel.*950.* 0 1
+Intel 965 .*Intel.*965.* 0 1
+Intel G33 .*Intel.*G33.* 0 0
+Intel G41 .*Intel.*G41.* 0 1
+Intel G45 .*Intel.*G45.* 0 1
+Intel Bear Lake .*Intel.*Bear Lake.* 0 0
+Intel Broadwater .*Intel.*Broadwater.* 0 0
+Intel Brookdale .*Intel.*Brookdale.* 0 0
+Intel Cantiga .*Intel.*Cantiga.* 0 0
+Intel Eaglelake .*Intel.*Eaglelake.* 0 1
+Intel Graphics Media HD .*Intel.*Graphics Media.*HD.* 0 1
+Intel HD Graphics .*Intel.*HD Graphics.* 2 1
+Intel Mobile 4 Series .*Intel.*Mobile *4 Series.* 0 1
+Intel Media Graphics HD .*Intel.*Media Graphics HD.* 0 1
+Intel Montara .*Intel.*Montara.* 0 0
+Intel Pineview .*Intel.*Pineview.* 0 1
+Intel Springdale .*Intel.*Springdale.* 0 0
+Intel HD Graphics 2000 .*Intel.*HD2000.* 1 1
+Intel HD Graphics 3000 .*Intel.*HD3000.* 2 1
+Matrox .*Matrox.* 0 0
+Mesa .*Mesa.* 0 0
+NVIDIA 205 .*NVIDIA.*GeForce 205.* 2 1
+NVIDIA 210 .*NVIDIA.*GeForce 210.* 2 1
+NVIDIA 310M .*NVIDIA.*GeForce 310M.* 1 1
+NVIDIA 310 .*NVIDIA.*GeForce 310.* 3 1
+NVIDIA 315M .*NVIDIA.*GeForce 315M.* 2 1
+NVIDIA 315 .*NVIDIA.*GeForce 315.* 3 1
+NVIDIA 320M .*NVIDIA.*GeForce 320M.* 2 1
+NVIDIA G100M .*NVIDIA *(GeForce)? *(G)? ?100M.* 0 1
+NVIDIA G100 .*NVIDIA *(GeForce)? *(G)? ?100.* 0 1
+NVIDIA G102M .*NVIDIA *(GeForce)? *(G)? ?102M.* 0 1
+NVIDIA G103M .*NVIDIA *(GeForce)? *(G)? ?103M.* 0 1
+NVIDIA G105M .*NVIDIA *(GeForce)? *(G)? ?105M.* 0 1
+NVIDIA G 110M .*NVIDIA *(GeForce)? *(G)? ?110M.* 0 1
+NVIDIA G 120M .*NVIDIA *(GeForce)? *(G)? ?120M.* 1 1
+NVIDIA G 200 .*NVIDIA *(GeForce)? *(G)? ?200(M)?.* 0 1
+NVIDIA G 205M .*NVIDIA *(GeForce)? *(G)? ?205(M)?.* 0 1
+NVIDIA G 210 .*NVIDIA *(GeForce)? *(G)? ?210(M)?.* 1 1
+NVIDIA 305M .*NVIDIA *(GeForce)? *(G)? ?305(M)?.* 1 1
+NVIDIA G 310M .*NVIDIA *(GeForce)? *(G)? ?310(M)?.* 2 1
+NVIDIA G 315 .*NVIDIA *(GeForce)? *(G)? ?315(M)?.* 2 1
+NVIDIA G 320M .*NVIDIA *(GeForce)? *(G)? ?320(M)?.* 2 1
+NVIDIA G 405 .*NVIDIA *(GeForce)? *(G)? ?405(M)?.* 1 1
+NVIDIA G 410M .*NVIDIA *(GeForce)? *(G)? ?410(M)?.* 1 1
+NVIDIA GT 120M .*NVIDIA.*(GeForce)? *GT *120(M)?.* 2 1
+NVIDIA GT 120 .*NVIDIA.*GT.*120 2 1
+NVIDIA GT 130M .*NVIDIA.*(GeForce)? *GT *130(M)?.* 2 1
+NVIDIA GT 140M .*NVIDIA.*(GeForce)? *GT *140(M)?.* 2 1
+NVIDIA GT 150M .*NVIDIA.*(GeForce)? *GT(S)? *150(M)?.* 2 1
+NVIDIA GT 160M .*NVIDIA.*(GeForce)? *GT *160(M)?.* 2 1
+NVIDIA GT 220M .*NVIDIA.*(GeForce)? *GT *220(M)?.* 2 1
+NVIDIA GT 230M .*NVIDIA.*(GeForce)? *GT *230(M)?.* 2 1
+NVIDIA GT 240M .*NVIDIA.*(GeForce)? *GT *240(M)?.* 2 1
+NVIDIA GT 250M .*NVIDIA.*(GeForce)? *GT *250(M)?.* 2 1
+NVIDIA GT 260M .*NVIDIA.*(GeForce)? *GT *260(M)?.* 2 1
+NVIDIA GT 320M .*NVIDIA.*(GeForce)? *GT *320(M)?.* 2 1
+NVIDIA GT 325M .*NVIDIA.*(GeForce)? *GT *325(M)?.* 0 1
+NVIDIA GT 330M .*NVIDIA.*(GeForce)? *GT *330(M)?.* 3 1
+NVIDIA GT 335M .*NVIDIA.*(GeForce)? *GT *335(M)?.* 1 1
+NVIDIA GT 340M .*NVIDIA.*(GeForce)? *GT *340(M)?.* 2 1
+NVIDIA GT 415M .*NVIDIA.*(GeForce)? *GT *415(M)?.* 2 1
+NVIDIA GT 420M .*NVIDIA.*(GeForce)? *GT *420(M)?.* 2 1
+NVIDIA GT 425M .*NVIDIA.*(GeForce)? *GT *425(M)?.* 3 1
+NVIDIA GT 430M .*NVIDIA.*(GeForce)? *GT *430(M)?.* 3 1
+NVIDIA GT 435M .*NVIDIA.*(GeForce)? *GT *435(M)?.* 3 1
+NVIDIA GT 440M .*NVIDIA.*(GeForce)? *GT *440(M)?.* 3 1
+NVIDIA GT 445M .*NVIDIA.*(GeForce)? *GT *445(M)?.* 3 1
+NVIDIA GT 450M .*NVIDIA.*(GeForce)? *GT *450(M)?.* 3 1
+NVIDIA GT 520M .*NVIDIA.*(GeForce)? *GT *520(M)?.* 3 1
+NVIDIA GT 525M .*NVIDIA.*(GeForce)? *GT *525(M)?.* 3 1
+NVIDIA GT 540M .*NVIDIA.*(GeForce)? *GT *540(M)?.* 3 1
+NVIDIA GT 550M .*NVIDIA.*(GeForce)? *GT *550(M)?.* 3 1
+NVIDIA GT 555M .*NVIDIA.*(GeForce)? *GT *555(M)?.* 3 1
+NVIDIA GTS 160M .*NVIDIA.*(GeForce)? *GT(S)? *160(M)?.* 2 1
+NVIDIA GTS 240 .*NVIDIA.*(GeForce)? *GTS *24.* 3 1
+NVIDIA GTS 250 .*NVIDIA.*(GeForce)? *GTS *25.* 3 1
+NVIDIA GTS 350M .*NVIDIA.*(GeForce)? *GTS *350M.* 3 1
+NVIDIA GTS 360M .*NVIDIA.*(GeForce)? *GTS *360M.* 3 1
+NVIDIA GTS 360 .*NVIDIA.*(GeForce)? *GTS *360.* 3 1
+NVIDIA GTS 450 .*NVIDIA.*(GeForce)? *GTS *45.* 3 1
+NVIDIA GTX 260 .*NVIDIA.*(GeForce)? *GTX *26.* 3 1
+NVIDIA GTX 275 .*NVIDIA.*(GeForce)? *GTX *275.* 3 1
+NVIDIA GTX 270 .*NVIDIA.*(GeForce)? *GTX *27.* 3 1
+NVIDIA GTX 285 .*NVIDIA.*(GeForce)? *GTX *285.* 3 1
+NVIDIA GTX 280 .*NVIDIA.*(GeForce)? *GTX *280.* 3 1
+NVIDIA GTX 290 .*NVIDIA.*(GeForce)? *GTX *290.* 3 1
+NVIDIA GTX 295 .*NVIDIA.*(GeForce)? *GTX *295.* 3 1
+NVIDIA GTX 460M .*NVIDIA.*(GeForce)? *GTX *460M.* 3 1
+NVIDIA GTX 465 .*NVIDIA.*(GeForce)? *GTX *465.* 3 1
+NVIDIA GTX 460 .*NVIDIA.*(GeForce)? *GTX *46.* 3 1
+NVIDIA GTX 470M .*NVIDIA.*(GeForce)? *GTX *470M.* 3 1
+NVIDIA GTX 470 .*NVIDIA.*(GeForce)? *GTX *47.* 3 1
+NVIDIA GTX 480M .*NVIDIA.*(GeForce)? *GTX *480M.* 3 1
+NVIDIA GTX 485M .*NVIDIA.*(GeForce)? *GTX *485M.* 3 1
+NVIDIA GTX 480 .*NVIDIA.*(GeForce)? *GTX *48.* 3 1
+NVIDIA GTX 530 .*NVIDIA.*(GeForce)? *GTX *53.* 3 1
+NVIDIA GTX 550 .*NVIDIA.*(GeForce)? *GTX *55.* 3 1
+NVIDIA GTX 560 .*NVIDIA.*(GeForce)? *GTX *56.* 3 1
+NVIDIA GTX 570 .*NVIDIA.*(GeForce)? *GTX *57.* 3 1
+NVIDIA GTX 580M .*NVIDIA.*(GeForce)? *GTX *580M.* 3 1
+NVIDIA GTX 580 .*NVIDIA.*(GeForce)? *GTX *58.* 3 1
+NVIDIA GTX 590 .*NVIDIA.*(GeForce)? *GTX *59.* 3 1
+NVIDIA C51 .*NVIDIA.*(GeForce)? *C51.* 0 1
+NVIDIA G72 .*NVIDIA.*(GeForce)? *G72.* 1 1
+NVIDIA G73 .*NVIDIA.*(GeForce)? *G73.* 1 1
+NVIDIA G84 .*NVIDIA.*(GeForce)? *G84.* 2 1
+NVIDIA G86 .*NVIDIA.*(GeForce)? *G86.* 3 1
+NVIDIA G92 .*NVIDIA.*(GeForce)? *G92.* 3 1
+NVIDIA GeForce .*GeForce 256.* 0 0
+NVIDIA GeForce 2 .*GeForce ?2 ?.* 0 1
+NVIDIA GeForce 3 .*GeForce ?3 ?.* 0 1
+NVIDIA GeForce 3 Ti .*GeForce ?3 Ti.* 0 1
+NVIDIA GeForce 4 .*NVIDIA.*GeForce ?4.* 0 1
+NVIDIA GeForce 4 Go .*NVIDIA.*GeForce ?4.*Go.* 0 1
+NVIDIA GeForce 4 MX .*NVIDIA.*GeForce ?4 MX.* 0 1
+NVIDIA GeForce 4 PCX .*NVIDIA.*GeForce ?4 PCX.* 0 1
+NVIDIA GeForce 4 Ti .*NVIDIA.*GeForce ?4 Ti.* 0 1
+NVIDIA GeForce 6100 .*NVIDIA.*GeForce 61.* 0 1
+NVIDIA GeForce 6200 .*NVIDIA.*GeForce 62.* 0 1
+NVIDIA GeForce 6500 .*NVIDIA.*GeForce 65.* 0 1
+NVIDIA GeForce 6600 .*NVIDIA.*GeForce 66.* 1 1
+NVIDIA GeForce 6700 .*NVIDIA.*GeForce 67.* 2 1
+NVIDIA GeForce 6800 .*NVIDIA.*GeForce 68.* 2 1
+NVIDIA GeForce 7000 .*NVIDIA.*GeForce 70.* 0 1
+NVIDIA GeForce 7100 .*NVIDIA.*GeForce 71.* 0 1
+NVIDIA GeForce 7200 .*NVIDIA.*GeForce 72.* 1 1
+NVIDIA GeForce 7300 .*NVIDIA.*GeForce 73.* 1 1
+NVIDIA GeForce 7500 .*NVIDIA.*GeForce 75.* 1 1
+NVIDIA GeForce 7600 .*NVIDIA.*GeForce 76.* 2 1
+NVIDIA GeForce 7800 .*NVIDIA.*GeForce 78.* 2 1
+NVIDIA GeForce 7900 .*NVIDIA.*GeForce 79.* 2 1
+NVIDIA GeForce 8100 .*NVIDIA.*GeForce 81.* 1 1
+NVIDIA GeForce 8200M .*NVIDIA.*GeForce 8200M.* 1 1
+NVIDIA GeForce 8200 .*NVIDIA.*GeForce 82.* 1 1
+NVIDIA GeForce 8300 .*NVIDIA.*GeForce 83.* 1 1
+NVIDIA GeForce 8400M .*NVIDIA.*GeForce 8400M.* 1 1
+NVIDIA GeForce 8400 .*NVIDIA.*GeForce 84.* 1 1
+NVIDIA GeForce 8500 .*NVIDIA.*GeForce 85.* 3 1
+NVIDIA GeForce 8600M .*NVIDIA.*GeForce 8600M.* 1 1
+NVIDIA GeForce 8600 .*NVIDIA.*GeForce 86.* 3 1
+NVIDIA GeForce 8700M .*NVIDIA.*GeForce 8700M.* 3 1
+NVIDIA GeForce 8700 .*NVIDIA.*GeForce 87.* 3 1
+NVIDIA GeForce 8800M .*NVIDIA.*GeForce 8800M.* 3 1
+NVIDIA GeForce 8800 .*NVIDIA.*GeForce 88.* 3 1
+NVIDIA GeForce 9100M .*NVIDIA.*GeForce 9100M.* 0 1
+NVIDIA GeForce 9100 .*NVIDIA.*GeForce 91.* 0 1
+NVIDIA GeForce 9200M .*NVIDIA.*GeForce 9200M.* 1 1
+NVIDIA GeForce 9200 .*NVIDIA.*GeForce 92.* 1 1
+NVIDIA GeForce 9300M .*NVIDIA.*GeForce 9300M.* 1 1
+NVIDIA GeForce 9300 .*NVIDIA.*GeForce 93.* 1 1
+NVIDIA GeForce 9400M .*NVIDIA.*GeForce 9400M.* 1 1
+NVIDIA GeForce 9400 .*NVIDIA.*GeForce 94.* 1 1
+NVIDIA GeForce 9500M .*NVIDIA.*GeForce 9500M.* 2 1
+NVIDIA GeForce 9500 .*NVIDIA.*GeForce 95.* 2 1
+NVIDIA GeForce 9600M .*NVIDIA.*GeForce 9600M.* 3 1
+NVIDIA GeForce 9600 .*NVIDIA.*GeForce 96.* 2 1
+NVIDIA GeForce 9700M .*NVIDIA.*GeForce 9700M.* 2 1
+NVIDIA GeForce 9800M .*NVIDIA.*GeForce 9800M.* 3 1
+NVIDIA GeForce 9800 .*NVIDIA.*GeForce 98.* 3 1
+NVIDIA GeForce FX 5100 .*NVIDIA.*GeForce FX 51.* 0 1
+NVIDIA GeForce FX 5200 .*NVIDIA.*GeForce FX 52.* 0 1
+NVIDIA GeForce FX 5300 .*NVIDIA.*GeForce FX 53.* 0 1
+NVIDIA GeForce FX 5500 .*NVIDIA.*GeForce FX 55.* 0 1
+NVIDIA GeForce FX 5600 .*NVIDIA.*GeForce FX 56.* 0 1
+NVIDIA GeForce FX 5700 .*NVIDIA.*GeForce FX 57.* 1 1
+NVIDIA GeForce FX 5800 .*NVIDIA.*GeForce FX 58.* 1 1
+NVIDIA GeForce FX 5900 .*NVIDIA.*GeForce FX 59.* 1 1
+NVIDIA GeForce FX Go5100 .*NVIDIA.*GeForce FX Go51.* 0 1
+NVIDIA GeForce FX Go5200 .*NVIDIA.*GeForce FX Go52.* 0 1
+NVIDIA GeForce FX Go5300 .*NVIDIA.*GeForce FX Go53.* 0 1
+NVIDIA GeForce FX Go5500 .*NVIDIA.*GeForce FX Go55.* 0 1
+NVIDIA GeForce FX Go5600 .*NVIDIA.*GeForce FX Go56.* 0 1
+NVIDIA GeForce FX Go5700 .*NVIDIA.*GeForce FX Go57.* 1 1
+NVIDIA GeForce FX Go5800 .*NVIDIA.*GeForce FX Go58.* 1 1
+NVIDIA GeForce FX Go5900 .*NVIDIA.*GeForce FX Go59.* 1 1
+NVIDIA GeForce FX Go5xxx .*NVIDIA.*GeForce FX Go.* 0 1
+NVIDIA GeForce Go 6100 .*NVIDIA.*GeForce Go 61.* 0 1
+NVIDIA GeForce Go 6200 .*NVIDIA.*GeForce Go 62.* 0 1
+NVIDIA GeForce Go 6400 .*NVIDIA.*GeForce Go 64.* 1 1
+NVIDIA GeForce Go 6500 .*NVIDIA.*GeForce Go 65.* 1 1
+NVIDIA GeForce Go 6600 .*NVIDIA.*GeForce Go 66.* 1 1
+NVIDIA GeForce Go 6700 .*NVIDIA.*GeForce Go 67.* 1 1
+NVIDIA GeForce Go 6800 .*NVIDIA.*GeForce Go 68.* 1 1
+NVIDIA GeForce Go 7200 .*NVIDIA.*GeForce Go 72.* 1 1
+NVIDIA GeForce Go 7300 LE .*NVIDIA.*GeForce Go 73.*LE.* 0 1
+NVIDIA GeForce Go 7300 .*NVIDIA.*GeForce Go 73.* 1 1
+NVIDIA GeForce Go 7400 .*NVIDIA.*GeForce Go 74.* 1 1
+NVIDIA GeForce Go 7600 .*NVIDIA.*GeForce Go 76.* 2 1
+NVIDIA GeForce Go 7700 .*NVIDIA.*GeForce Go 77.* 2 1
+NVIDIA GeForce Go 7800 .*NVIDIA.*GeForce Go 78.* 2 1
+NVIDIA GeForce Go 7900 .*NVIDIA.*GeForce Go 79.* 2 1
+NVIDIA D9M .*NVIDIA.*D9M.* 1 1
+NVIDIA G94 .*NVIDIA.*G94.* 3 1
+NVIDIA GeForce Go 6 .*GeForce Go 6.* 1 1
+NVIDIA ION 2 .*NVIDIA ION 2.* 2 1
+NVIDIA ION .*NVIDIA ION.* 2 1
+NVIDIA NB9M .*GeForce NB9M.* 1 1
+NVIDIA NB9P .*GeForce NB9P.* 1 1
+NVIDIA GeForce PCX .*GeForce PCX.* 0 1
+NVIDIA Generic .*NVIDIA.*Unknown.* 0 0
+NVIDIA NV17 .*GeForce NV17.* 0 1
+NVIDIA NV34 .*NVIDIA.*NV34.* 0 1
+NVIDIA NV35 .*NVIDIA.*NV35.* 0 1
+NVIDIA NV36 .*GeForce NV36.* 1 1
+NVIDIA NV43 .*NVIDIA *NV43.* 1 1
+NVIDIA NV44 .*NVIDIA *NV44.* 1 1
+NVIDIA nForce .*NVIDIA *nForce.* 0 0
+NVIDIA MCP78 .*NVIDIA *MCP78.* 1 1
+NVIDIA Quadro2 .*Quadro2.* 0 1
+NVIDIA Quadro 1000M .*Quadro.*1000M.* 2 1
+NVIDIA Quadro 2000 M/D .*Quadro.*2000(M|D)?.* 3 1
+NVIDIA Quadro 4000M .*Quadro.*4000M.* 3 1
+NVIDIA Quadro 4000 .*Quadro *4000.* 3 1
+NVIDIA Quadro 50x0 M .*Quadro.*50.0(M)?.* 3 1
+NVIDIA Quadro 6000 .*Quadro.*6000.* 3 1
+NVIDIA Quadro 400 .*Quadro.*400.* 2 1
+NVIDIA Quadro 600 .*Quadro.*600.* 2 1
+NVIDIA Quadro4 .*Quadro4.* 0 1
+NVIDIA Quadro DCC .*Quadro DCC.* 0 1
+NVIDIA Quadro FX 770M .*Quadro.*FX *770M.* 2 1
+NVIDIA Quadro FX 1500M .*Quadro.*FX *1500M.* 1 1
+NVIDIA Quadro FX 1600M .*Quadro.*FX *1600M.* 2 1
+NVIDIA Quadro FX 2500M .*Quadro.*FX *2500M.* 2 1
+NVIDIA Quadro FX 2700M .*Quadro.*FX *2700M.* 3 1
+NVIDIA Quadro FX 2800M .*Quadro.*FX *2800M.* 3 1
+NVIDIA Quadro FX 3500 .*Quadro.*FX *3500.* 2 1
+NVIDIA Quadro FX 3600 .*Quadro.*FX *3600.* 3 1
+NVIDIA Quadro FX 3700 .*Quadro.*FX *3700.* 3 1
+NVIDIA Quadro FX 3800 .*Quadro.*FX *3800.* 3 1
+NVIDIA Quadro FX 4500 .*Quadro.*FX *45.* 3 1
+NVIDIA Quadro FX 880M .*Quadro.*FX *880M.* 3 1
+NVIDIA Quadro FX 4800 .*NVIDIA.*Quadro *FX *4800.* 3 1
+NVIDIA Quadro FX .*Quadro FX.* 1 1
+NVIDIA Quadro NVS 1xxM .*Quadro NVS *1.[05]M.* 0 1
+NVIDIA Quadro NVS 300M .*NVIDIA.*NVS *300M.* 2 1
+NVIDIA Quadro NVS 320M .*NVIDIA.*NVS *320M.* 2 1
+NVIDIA Quadro NVS 2100M .*NVIDIA.*NVS *2100M.* 2 1
+NVIDIA Quadro NVS 3100M .*NVIDIA.*NVS *3100M.* 2 1
+NVIDIA Quadro NVS 4200M .*NVIDIA.*NVS *4200M.* 2 1
+NVIDIA Quadro NVS 5100M .*NVIDIA.*NVS *5100M.* 2 1
+NVIDIA Quadro NVS .*NVIDIA.*NVS 0 1
+NVIDIA RIVA TNT .*RIVA TNT.* 0 0
+S3 .*S3 Graphics.* 0 0
+SiS SiS.* 0 0
+Trident Trident.* 0 0
+Tungsten Graphics Tungsten.* 0 0
+XGI XGI.* 0 0
+VIA VIA.* 0 0
+Apple Generic Apple.*Generic.* 0 0
+Apple Software Renderer Apple.*Software Renderer.* 0 0
diff --git a/indra/newview/groupchatlistener.cpp b/indra/newview/groupchatlistener.cpp
new file mode 100644
index 0000000000..3758896b85
--- /dev/null
+++ b/indra/newview/groupchatlistener.cpp
@@ -0,0 +1,59 @@
+/**
+ * @file groupchatlistener.cpp
+ * @author Nat Goodspeed
+ * @date 2011-04-11
+ * @brief Implementation for groupchatlistener.
+ *
+ * $LicenseInfo:firstyear=2011&license=internal$
+ * Copyright (c) 2011, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+// Precompiled header
+#include "llviewerprecompiledheaders.h"
+// associated header
+#include "groupchatlistener.h"
+// STL headers
+// std headers
+// external library headers
+// other Linden headers
+#include "llgroupactions.h"
+#include "llimview.h"
+
+
+namespace {
+ void startIm_wrapper(LLSD const & event)
+ {
+ LLUUID session_id = LLGroupActions::startIM(event["id"].asUUID());
+ sendReply(LLSDMap("session_id", LLSD(session_id)), event);
+ }
+
+ void send_message_wrapper(const std::string& text, const LLUUID& session_id, const LLUUID& group_id)
+ {
+ LLIMModel::sendMessage(text, session_id, group_id, IM_SESSION_GROUP_START);
+ }
+}
+
+
+GroupChatListener::GroupChatListener():
+ LLEventAPI("GroupChat",
+ "API to enter, leave, send and intercept group chat messages")
+{
+ add("startIM",
+ "Enter a group chat in group with UUID [\"id\"]\n"
+ "Assumes the logged-in agent is already a member of this group.",
+ &startIm_wrapper);
+ add("endIM",
+ "Leave a group chat in group with UUID [\"id\"]\n"
+ "Assumes a prior successful startIM request.",
+ &LLGroupActions::endIM,
+ LLSDArray("id"));
+ add("sendIM",
+ "send a groupchat IM",
+ &send_message_wrapper,
+ LLSDArray("text")("session_id")("group_id"));
+}
+/*
+ static void sendMessage(const std::string& utf8_text, const LLUUID& im_session_id,
+ const LLUUID& other_participant_id, EInstantMessage dialog);
+*/
diff --git a/indra/newview/groupchatlistener.h b/indra/newview/groupchatlistener.h
new file mode 100644
index 0000000000..719e3e877f
--- /dev/null
+++ b/indra/newview/groupchatlistener.h
@@ -0,0 +1,23 @@
+/**
+ * @file groupchatlistener.h
+ * @author Nat Goodspeed
+ * @date 2011-04-11
+ * @brief
+ *
+ * $LicenseInfo:firstyear=2011&license=internal$
+ * Copyright (c) 2011, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#if ! defined(LL_GROUPCHATLISTENER_H)
+#define LL_GROUPCHATLISTENER_H
+
+#include "lleventapi.h"
+
+class GroupChatListener: public LLEventAPI
+{
+public:
+ GroupChatListener();
+};
+
+#endif /* ! defined(LL_GROUPCHATLISTENER_H) */
diff --git a/indra/newview/installers/windows/installer_template.nsi b/indra/newview/installers/windows/installer_template.nsi
index 4e8ed807ee..b5d43021ec 100644
--- a/indra/newview/installers/windows/installer_template.nsi
+++ b/indra/newview/installers/windows/installer_template.nsi
@@ -211,6 +211,25 @@ continue_install:
FunctionEnd
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Checks for CPU valid (must have SSE2 support)
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+Function CheckCPUFlags
+ Call GetWindowsVersion
+ Pop $R0
+ StrCmp $R0 "2000" OK_SSE ; sse check not available on win2k.
+
+ Push $1
+ System::Call 'kernel32::IsProcessorFeaturePresent(i) i(10) .r1'
+ IntCmp $1 1 OK_SSE
+ MessageBox MB_OKCANCEL $(MissingSSE2) /SD IDOK IDOK OK_SSE
+ Quit
+
+ OK_SSE:
+ Pop $1
+ Return
+FunctionEnd
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Close the program, if running. Modifies no variables.
; Allows user to bail out of install process.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -744,6 +763,7 @@ StrCpy $INSTEXE "${INSTEXE}"
StrCpy $INSTSHORTCUT "${SHORTCUT}"
Call CheckWindowsVersion ; warn if on Windows 98/ME
+Call CheckCPUFlags ; Make sure we have SSE2 support
Call CheckIfAdministrator ; Make sure the user can install/uninstall
Call CheckIfAlreadyCurrent ; Make sure that we haven't already installed this version
Call CloseSecondLife ; Make sure we're not running
diff --git a/indra/newview/installers/windows/lang_en-us.nsi b/indra/newview/installers/windows/lang_en-us.nsi
index a01541377d..da0d7f54d2 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/licenses-mac.txt b/indra/newview/licenses-mac.txt
index 1324fa1a86..af80bff5d9 100644
--- a/indra/newview/licenses-mac.txt
+++ b/indra/newview/licenses-mac.txt
@@ -315,516 +315,6 @@ This product includes cryptographic software written by Eric Young
Hudson (tjh@cryptsoft.com).
-===========
-Pth License
-===========
- ____ _ _
- | _ \| |_| |__ ``Ian Fleming was a UNIX fan!
- | |_) | __| '_ \ How do I know? Well, James Bond
- | __/| |_| | | | had the (license to kill) number 007,
- |_| \__|_| |_| i.e., he could execute anyone!''
-
- GNU Pth - The GNU Portable Threads
-
- LICENSE
- =======
-
- 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; either version 2.1 of the
- License, or (at your option) any later version.
-
- For some people, it is not clear, what is the real intention of the
- author by using the GNU Lesser General Public License (LGPL) as the
- distribution license for GNU Pth. This is, because the LGPL and the
- GPL can be (and are often) interpreted very differently and some
- interpretations seem to be not compatible with others. So an explicit
- clarification for the use of the LGPL for GNU Pth from the authors
- point of view might be useful.
-
- The author places this library under the LGPL to make sure that it
- can be used both commercially and non-commercially provided that
- modifications to the code base are always donated back to the official
- code base under the same license conditions. Please keep in mind that
- especially using this library in code not staying under the GPL or
- the LGPL _is_ allowed and that any taint or license creap into code
- that uses the library is not the authors intention. It is just the
- case that _including_ this library into the source tree of other
- applications is a little bit more inconvinient because of the LGPL.
- But it has to be this way for good reasons. And keep in mind that
- inconvinient doesn't mean not allowed or even impossible.
-
- Even if you want to use this library in some BSD-style licensed
- packages, this _is_ possible as long as you are a little bit
- carefully. Usually this means you have to make sure that the code is
- still clearly separated into the source tree and that modifications to
- this source area are done under the conditions of the LGPL. Read below
- for more details on the conditions. Contact the author if you have
- more questions.
-
- The license text of the GNU Lesser General Public License follows:
- __________________________________________________________________________
-
- GNU LESSER GENERAL PUBLIC LICENSE
- Version 2.1, February 1999
-
- Copyright (C) 1991, 1999 Free Software Foundation, Inc.
- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-[This is the first released version of the Lesser GPL. It also counts
- as the successor of the GNU Library Public License, version 2, hence
- the version number 2.1.]
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-Licenses are intended to guarantee your freedom to share and change
-free software--to make sure the software is free for all its users.
-
- This license, the Lesser General Public License, applies to some
-specially designated software packages--typically libraries--of the
-Free Software Foundation and other authors who decide to use it. You
-can use it too, but we suggest you first think carefully about whether
-this license or the ordinary General Public License is the better
-strategy to use in any particular case, based on the explanations below.
-
- When we speak of free software, we are referring to freedom of use,
-not price. Our General Public Licenses are designed to make sure that
-you have the freedom to distribute copies of free software (and charge
-for this service if you wish); that you receive source code or can get
-it if you want it; that you can change the software and use pieces of
-it in new free programs; and that you are informed that you can do
-these things.
-
- To protect your rights, we need to make restrictions that forbid
-distributors to deny you these rights or to ask you to surrender these
-rights. These restrictions translate to certain responsibilities for
-you if you distribute copies of the library or if you modify it.
-
- For example, if you distribute copies of the library, whether gratis
-or for a fee, you must give the recipients all the rights that we gave
-you. You must make sure that they, too, receive or can get the source
-code. If you link other code with the library, you must provide
-complete object files to the recipients, so that they can relink them
-with the library after making changes to the library and recompiling
-it. And you must show them these terms so they know their rights.
-
- We protect your rights with a two-step method: (1) we copyright the
-library, and (2) we offer you this license, which gives you legal
-permission to copy, distribute and/or modify the library.
-
- To protect each distributor, we want to make it very clear that
-there is no warranty for the free library. Also, if the library is
-modified by someone else and passed on, the recipients should know
-that what they have is not the original version, so that the original
-author's reputation will not be affected by problems that might be
-introduced by others.
-
- Finally, software patents pose a constant threat to the existence of
-any free program. We wish to make sure that a company cannot
-effectively restrict the users of a free program by obtaining a
-restrictive license from a patent holder. Therefore, we insist that
-any patent license obtained for a version of the library must be
-consistent with the full freedom of use specified in this license.
-
- Most GNU software, including some libraries, is covered by the
-ordinary GNU General Public License. This license, the GNU Lesser
-General Public License, applies to certain designated libraries, and
-is quite different from the ordinary General Public License. We use
-this license for certain libraries in order to permit linking those
-libraries into non-free programs.
-
- When a program is linked with a library, whether statically or using
-a shared library, the combination of the two is legally speaking a
-combined work, a derivative of the original library. The ordinary
-General Public License therefore permits such linking only if the
-entire combination fits its criteria of freedom. The Lesser General
-Public License permits more lax criteria for linking other code with
-the library.
-
- We call this license the "Lesser" General Public License because it
-does Less to protect the user's freedom than the ordinary General
-Public License. It also provides other free software developers Less
-of an advantage over competing non-free programs. These disadvantages
-are the reason we use the ordinary General Public License for many
-libraries. However, the Lesser license provides advantages in certain
-special circumstances.
-
- For example, on rare occasions, there may be a special need to
-encourage the widest possible use of a certain library, so that it becomes
-a de-facto standard. To achieve this, non-free programs must be
-allowed to use the library. A more frequent case is that a free
-library does the same job as widely used non-free libraries. In this
-case, there is little to gain by limiting the free library to free
-software only, so we use the Lesser General Public License.
-
- In other cases, permission to use a particular library in non-free
-programs enables a greater number of people to use a large body of
-free software. For example, permission to use the GNU C Library in
-non-free programs enables many more people to use the whole GNU
-operating system, as well as its variant, the GNU/Linux operating
-system.
-
- Although the Lesser General Public License is Less protective of the
-users' freedom, it does ensure that the user of a program that is
-linked with the Library has the freedom and the wherewithal to run
-that program using a modified version of the Library.
-
- The precise terms and conditions for copying, distribution and
-modification follow. Pay close attention to the difference between a
-"work based on the library" and a "work that uses the library". The
-former contains code derived from the library, whereas the latter must
-be combined with the library in order to run.
-
- GNU LESSER GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License Agreement applies to any software library or other
-program which contains a notice placed by the copyright holder or
-other authorized party saying it may be distributed under the terms of
-this Lesser General Public License (also called "this License").
-Each licensee is addressed as "you".
-
- A "library" means a collection of software functions and/or data
-prepared so as to be conveniently linked with application programs
-(which use some of those functions and data) to form executables.
-
- The "Library", below, refers to any such software library or work
-which has been distributed under these terms. A "work based on the
-Library" means either the Library or any derivative work under
-copyright law: that is to say, a work containing the Library or a
-portion of it, either verbatim or with modifications and/or translated
-straightforwardly into another language. (Hereinafter, translation is
-included without limitation in the term "modification".)
-
- "Source code" for a work means the preferred form of the work for
-making modifications to it. For a library, complete source code means
-all the source code for all modules it contains, plus any associated
-interface definition files, plus the scripts used to control compilation
-and installation of the library.
-
- Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running a program using the Library is not restricted, and output from
-such a program is covered only if its contents constitute a work based
-on the Library (independent of the use of the Library in a tool for
-writing it). Whether that is true depends on what the Library does
-and what the program that uses the Library does.
-
- 1. You may copy and distribute verbatim copies of the Library's
-complete source code as you receive it, in any medium, provided that
-you conspicuously and appropriately publish on each copy an
-appropriate copyright notice and disclaimer of warranty; keep intact
-all the notices that refer to this License and to the absence of any
-warranty; and distribute a copy of this License along with the
-Library.
-
- You may charge a fee for the physical act of transferring a copy,
-and you may at your option offer warranty protection in exchange for a
-fee.
-
- 2. You may modify your copy or copies of the Library or any portion
-of it, thus forming a work based on the Library, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) The modified work must itself be a software library.
-
- b) You must cause the files modified to carry prominent notices
- stating that you changed the files and the date of any change.
-
- c) You must cause the whole of the work to be licensed at no
- charge to all third parties under the terms of this License.
-
- d) If a facility in the modified Library refers to a function or a
- table of data to be supplied by an application program that uses
- the facility, other than as an argument passed when the facility
- is invoked, then you must make a good faith effort to ensure that,
- in the event an application does not supply such function or
- table, the facility still operates, and performs whatever part of
- its purpose remains meaningful.
-
- (For example, a function in a library to compute square roots has
- a purpose that is entirely well-defined independent of the
- application. Therefore, Subsection 2d requires that any
- application-supplied function or table used by this function must
- be optional: if the application does not supply it, the square
- root function must still compute square roots.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Library,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Library, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote
-it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Library.
-
-In addition, mere aggregation of another work not based on the Library
-with the Library (or with a work based on the Library) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may opt to apply the terms of the ordinary GNU General Public
-License instead of this License to a given copy of the Library. To do
-this, you must alter all the notices that refer to this License, so
-that they refer to the ordinary GNU General Public License, version 2,
-instead of to this License. (If a newer version than version 2 of the
-ordinary GNU General Public License has appeared, then you can specify
-that version instead if you wish.) Do not make any other change in
-these notices.
-
- Once this change is made in a given copy, it is irreversible for
-that copy, so the ordinary GNU General Public License applies to all
-subsequent copies and derivative works made from that copy.
-
- This option is useful when you wish to copy part of the code of
-the Library into a program that is not a library.
-
- 4. You may copy and distribute the Library (or a portion or
-derivative of it, under Section 2) in object code or executable form
-under the terms of Sections 1 and 2 above provided that you accompany
-it with the complete corresponding machine-readable source code, which
-must be distributed under the terms of Sections 1 and 2 above on a
-medium customarily used for software interchange.
-
- If distribution of object code is made by offering access to copy
-from a designated place, then offering equivalent access to copy the
-source code from the same place satisfies the requirement to
-distribute the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 5. A program that contains no derivative of any portion of the
-Library, but is designed to work with the Library by being compiled or
-linked with it, is called a "work that uses the Library". Such a
-work, in isolation, is not a derivative work of the Library, and
-therefore falls outside the scope of this License.
-
- However, linking a "work that uses the Library" with the Library
-creates an executable that is a derivative of the Library (because it
-contains portions of the Library), rather than a "work that uses the
-library". The executable is therefore covered by this License.
-Section 6 states terms for distribution of such executables.
-
- When a "work that uses the Library" uses material from a header file
-that is part of the Library, the object code for the work may be a
-derivative work of the Library even though the source code is not.
-Whether this is true is especially significant if the work can be
-linked without the Library, or if the work is itself a library. The
-threshold for this to be true is not precisely defined by law.
-
- If such an object file uses only numerical parameters, data
-structure layouts and accessors, and small macros and small inline
-functions (ten lines or less in length), then the use of the object
-file is unrestricted, regardless of whether it is legally a derivative
-work. (Executables containing this object code plus portions of the
-Library will still fall under Section 6.)
-
- Otherwise, if the work is a derivative of the Library, you may
-distribute the object code for the work under the terms of Section 6.
-Any executables containing that work also fall under Section 6,
-whether or not they are linked directly with the Library itself.
-
- 6. As an exception to the Sections above, you may also combine or
-link a "work that uses the Library" with the Library to produce a
-work containing portions of the Library, and distribute that work
-under terms of your choice, provided that the terms permit
-modification of the work for the customer's own use and reverse
-engineering for debugging such modifications.
-
- You must give prominent notice with each copy of the work that the
-Library is used in it and that the Library and its use are covered by
-this License. You must supply a copy of this License. If the work
-during execution displays copyright notices, you must include the
-copyright notice for the Library among them, as well as a reference
-directing the user to the copy of this License. Also, you must do one
-of these things:
-
- a) Accompany the work with the complete corresponding
- machine-readable source code for the Library including whatever
- changes were used in the work (which must be distributed under
- Sections 1 and 2 above); and, if the work is an executable linked
- with the Library, with the complete machine-readable "work that
- uses the Library", as object code and/or source code, so that the
- user can modify the Library and then relink to produce a modified
- executable containing the modified Library. (It is understood
- that the user who changes the contents of definitions files in the
- Library will not necessarily be able to recompile the application
- to use the modified definitions.)
-
- b) Use a suitable shared library mechanism for linking with the
- Library. A suitable mechanism is one that (1) uses at run time a
- copy of the library already present on the user's computer system,
- rather than copying library functions into the executable, and (2)
- will operate properly with a modified version of the library, if
- the user installs one, as long as the modified version is
- interface-compatible with the version that the work was made with.
-
- c) Accompany the work with a written offer, valid for at
- least three years, to give the same user the materials
- specified in Subsection 6a, above, for a charge no more
- than the cost of performing this distribution.
-
- d) If distribution of the work is made by offering access to copy
- from a designated place, offer equivalent access to copy the above
- specified materials from the same place.
-
- e) Verify that the user has already received a copy of these
- materials or that you have already sent this user a copy.
-
- For an executable, the required form of the "work that uses the
-Library" must include any data and utility programs needed for
-reproducing the executable from it. However, as a special exception,
-the materials to be distributed need not include anything that is
-normally distributed (in either source or binary form) with the major
-components (compiler, kernel, and so on) of the operating system on
-which the executable runs, unless that component itself accompanies
-the executable.
-
- It may happen that this requirement contradicts the license
-restrictions of other proprietary libraries that do not normally
-accompany the operating system. Such a contradiction means you cannot
-use both them and the Library together in an executable that you
-distribute.
-
- 7. You may place library facilities that are a work based on the
-Library side-by-side in a single library together with other library
-facilities not covered by this License, and distribute such a combined
-library, provided that the separate distribution of the work based on
-the Library and of the other library facilities is otherwise
-permitted, and provided that you do these two things:
-
- a) Accompany the combined library with a copy of the same work
- based on the Library, uncombined with any other library
- facilities. This must be distributed under the terms of the
- Sections above.
-
- b) Give prominent notice with the combined library of the fact
- that part of it is a work based on the Library, and explaining
- where to find the accompanying uncombined form of the same work.
-
- 8. You may not copy, modify, sublicense, link with, or distribute
-the Library except as expressly provided under this License. Any
-attempt otherwise to copy, modify, sublicense, link with, or
-distribute the Library is void, and will automatically terminate your
-rights under this License. However, parties who have received copies,
-or rights, from you under this License will not have their licenses
-terminated so long as such parties remain in full compliance.
-
- 9. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Library or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Library (or any work based on the
-Library), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Library or works based on it.
-
- 10. Each time you redistribute the Library (or any work based on the
-Library), the recipient automatically receives a license from the
-original licensor to copy, distribute, link with or modify the Library
-subject to these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties with
-this License.
-
- 11. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Library at all. For example, if a patent
-license would not permit royalty-free redistribution of the Library by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Library.
-
-If any portion of this section is held invalid or unenforceable under any
-particular circumstance, the balance of the section is intended to apply,
-and the section as a whole is intended to apply in other circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 12. If the distribution and/or use of the Library is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Library under this License may add
-an explicit geographical distribution limitation excluding those countries,
-so that distribution is permitted only in or among countries not thus
-excluded. In such case, this License incorporates the limitation as if
-written in the body of this License.
-
- 13. The Free Software Foundation may publish revised and/or new
-versions of the Lesser General Public License from time to time.
-Such new versions will be similar in spirit to the present version,
-but may differ in detail to address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Library
-specifies a version number of this License which applies to it and
-"any later version", you have the option of following the terms and
-conditions either of that version or of any later version published by
-the Free Software Foundation. If the Library does not specify a
-license version number, you may choose any version ever published by
-the Free Software Foundation.
-
- 14. If you wish to incorporate parts of the Library into other free
-programs whose distribution conditions are incompatible with these,
-write to the author to ask for permission. For software which is
-copyrighted by the Free Software Foundation, write to the Free
-Software Foundation; we sometimes make exceptions for this. Our
-decision will be guided by the two goals of preserving the free status
-of all derivatives of our free software and of promoting the sharing
-and reuse of software generally.
-
- NO WARRANTY
-
- 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
-WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
-EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
-OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
-KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
-LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
-THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
- 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
-WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
-AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
-FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
-CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
-LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
-RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
-FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
-SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
-DAMAGES.
-
- END OF TERMS AND CONDITIONS
-
-
=======================
Original SSLeay License
=======================
diff --git a/indra/newview/licenses-win32.txt b/indra/newview/licenses-win32.txt
index 7e6d4b4561..8736626907 100644
--- a/indra/newview/licenses-win32.txt
+++ b/indra/newview/licenses-win32.txt
@@ -769,3 +769,72 @@ 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.
+
+
+=============
+GLOD license
+=============
+The GLOD Open-Source License Version 1.0 June 16, 2004
+
+Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns
+Hopkins University and David Luebke, Brenden Schubert, University of
+Virginia. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, is permitted provided that the following conditions are
+met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer and
+ request.
+
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer and
+ request in the documentation and/or other materials provided with
+ the distribution.
+
+3. The name "GLOD" must not be used to endorse or promote products
+ derived from this software without prior written permission.
+
+4. Redistributions of any modified version of this source, whether in
+ source or binary form , must include a form of the following
+ acknowledgment: "This product is derived from the GLOD library,
+ which is available from http://www.cs.jhu.edu/~graphics/GLOD."
+
+5. Redistributions of any modified version of this source in binary
+ form must provide, free of charge, access to the modified version
+ of the code.
+
+6. This license shall be governed by and construed and enforced in
+ accordance with the laws of the State of Maryland, without
+ reference to its conflicts of law provisions. The exclusive
+ jurisdiction and venue for all legal actions relating to this
+ license shall be in courts of competent subject matter jurisdiction
+ located in the State of Maryland.
+
+TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, GLOD IS PROVIDED
+UNDER THIS LICENSE ON AN AS IS BASIS, WITHOUT WARRANTY OF ANY KIND,
+EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
+THAT GLOD IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR
+PURPOSE OR NON-INFRINGING. ALL WARRANTIES ARE DISCLAIMED AND THE
+ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE CODE IS WITH
+YOU. SHOULD ANY CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE
+COPYRIGHT HOLDER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY
+NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY
+CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY CODE IS
+AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
+
+TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT SHALL
+THE COPYRIGHT HOLDER OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
+SPECIAL, INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES FOR LOSS OF
+PROFITS, REVENUE, OR FOR LOSS OF INFORMATION OR ANY OTHER LOSS.
+
+YOU EXPRESSLY AGREE TO FOREVER INDEMNIFY, DEFEND AND HOLD HARMLESS THE
+COPYRIGHT HOLDERS AND CONTRIBUTORS OF GLOD AGAINST ALL CLAIMS,
+DEMANDS, SUITS OR OTHER ACTIONS ARISING DIRECTLY OR INDIRECTLY FROM
+YOUR ACCEPTANCE AND USE OF GLOD.
+
+Although NOT REQUIRED, we would appreciate it if active users of GLOD
+put a link on their web site to the GLOD web site when possible.
+
+
diff --git a/indra/newview/linux_tools/wrapper.sh b/indra/newview/linux_tools/wrapper.sh
index d2df968544..283a28a0aa 100755
--- a/indra/newview/linux_tools/wrapper.sh
+++ b/indra/newview/linux_tools/wrapper.sh
@@ -92,23 +92,23 @@ cd "${RUN_PATH}"
## subprocesses that care.
export SAVED_LD_LIBRARY_PATH="${LD_LIBRARY_PATH}"
-if [ -n "$LL_TCMALLOC" ]; then
- tcmalloc_libs='/usr/lib/libtcmalloc.so.0 /usr/lib/libstacktrace.so.0 /lib/libpthread.so.0'
- all=1
- for f in $tcmalloc_libs; do
- if [ ! -f $f ]; then
- all=0
- fi
- done
- if [ $all != 1 ]; then
- echo 'Cannot use tcmalloc libraries: components missing' 1>&2
- else
- export LD_PRELOAD=$(echo $tcmalloc_libs | tr ' ' :)
- if [ -z "$HEAPCHECK" -a -z "$HEAPPROFILE" ]; then
- export HEAPCHECK=${HEAPCHECK:-normal}
- fi
- fi
-fi
+# if [ -n "$LL_TCMALLOC" ]; then
+# tcmalloc_libs='/usr/lib/libtcmalloc.so.0 /usr/lib/libstacktrace.so.0 /lib/libpthread.so.0'
+# all=1
+# for f in $tcmalloc_libs; do
+# if [ ! -f $f ]; then
+# all=0
+# fi
+# done
+# if [ $all != 1 ]; then
+# echo 'Cannot use tcmalloc libraries: components missing' 1>&2
+# else
+# export LD_PRELOAD=$(echo $tcmalloc_libs | tr ' ' :)
+# if [ -z "$HEAPCHECK" -a -z "$HEAPPROFILE" ]; then
+# export HEAPCHECK=${HEAPCHECK:-normal}
+# fi
+# fi
+#fi
export SL_ENV='LD_LIBRARY_PATH="`pwd`"/lib:"${LD_LIBRARY_PATH}"'
export SL_CMD='$LL_WRAPPER bin/do-not-directly-run-secondlife-bin'
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index c9bd7851ed..08d71fc8fc 100644
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -25,10 +25,12 @@
*/
#include "llviewerprecompiledheaders.h"
+
#include "llagent.h"
#include "pipeline.h"
+#include "llagentaccess.h"
#include "llagentcamera.h"
#include "llagentlistener.h"
#include "llagentwearables.h"
@@ -36,6 +38,7 @@
#include "llanimationstates.h"
#include "llbottomtray.h"
#include "llcallingcard.h"
+#include "llcapabilitylistener.h"
#include "llchannelmanager.h"
#include "llconsole.h"
#include "llfirstuse.h"
@@ -55,15 +58,19 @@
#include "llpaneltopinfobar.h"
#include "llparcel.h"
#include "llrendersphere.h"
+#include "llsdmessage.h"
#include "llsdutil.h"
-#include "llsidetray.h"
#include "llsky.h"
+#include "llslurl.h"
#include "llsmoothstep.h"
+#include "llstartup.h"
#include "llstatusbar.h"
#include "llteleportflags.h"
#include "lltool.h"
+#include "lltoolpie.h"
#include "lltoolmgr.h"
#include "lltrans.h"
+#include "llurlentry.h"
#include "llviewercontrol.h"
#include "llviewerdisplay.h"
#include "llviewerjoystick.h"
@@ -72,6 +79,7 @@
#include "llviewerobjectlist.h"
#include "llviewerparcelmgr.h"
#include "llviewerstats.h"
+#include "llviewerwindow.h"
#include "llvoavatarself.h"
#include "llwindow.h"
#include "llworld.h"
@@ -170,7 +178,8 @@ LLAgent::LLAgent() :
mbRunning(false),
mbTeleportKeepsLookAt(false),
- mAgentAccess(gSavedSettings),
+ mAgentAccess(new LLAgentAccess(gSavedSettings)),
+ mTeleportSourceSLURL(new LLSLURL),
mTeleportState( TELEPORT_NONE ),
mRegionp(NULL),
@@ -207,7 +216,7 @@ LLAgent::LLAgent() :
mAutoPilotFinishedCallback(NULL),
mAutoPilotCallbackData(NULL),
- mEffectColor(LLColor4(0.f, 1.f, 1.f, 1.f)),
+ mEffectColor(new LLUIColor(LLColor4(0.f, 1.f, 1.f, 1.f))),
mHaveHomePosition(FALSE),
mHomeRegionHandle( 0 ),
@@ -218,7 +227,10 @@ LLAgent::LLAgent() :
mFirstLogin(FALSE),
mGenderChosen(FALSE),
- mAppearanceSerialNum(0)
+ mAppearanceSerialNum(0),
+
+ mMouselookModeInSignal(NULL),
+ mMouselookModeOutSignal(NULL)
{
for (U32 i = 0; i < TOTAL_CONTROLS; i++)
{
@@ -246,7 +258,7 @@ void LLAgent::init()
setFlying( gSavedSettings.getBOOL("FlyingAtExit") );
- mEffectColor = LLUIColorTable::instance().getColor("EffectColor");
+ *mEffectColor = LLUIColorTable::instance().getColor("EffectColor");
gSavedSettings.getControl("PreferredMaturity")->getValidateSignal()->connect(boost::bind(&LLAgent::validateMaturity, this, _2));
gSavedSettings.getControl("PreferredMaturity")->getSignal()->connect(boost::bind(&LLAgent::handleMaturity, this, _2));
@@ -269,7 +281,17 @@ LLAgent::~LLAgent()
{
cleanup();
- // *Note: this is where LLViewerCamera::getInstance() used to be deleted.
+ delete mMouselookModeInSignal;
+ mMouselookModeInSignal = NULL;
+ delete mMouselookModeOutSignal;
+ mMouselookModeOutSignal = NULL;
+
+ delete mAgentAccess;
+ mAgentAccess = NULL;
+ delete mEffectColor;
+ mEffectColor = NULL;
+ delete mTeleportSourceSLURL;
+ mTeleportSourceSLURL = NULL;
}
// Handle any actions that need to be performed when the main app gains focus
@@ -552,6 +574,8 @@ void LLAgent::setFlying(BOOL fly)
// static
void LLAgent::toggleFlying()
{
+ LLToolPie::instance().stopClickToWalk();
+
BOOL fly = !gAgent.getFlying();
gAgent.mMoveTimer.reset();
@@ -637,9 +661,16 @@ void LLAgent::setRegion(LLViewerRegion *regionp)
// Update all of the regions.
LLWorld::getInstance()->updateAgentOffset(mAgentOriginGlobal);
}
+
+ // Pass new region along to metrics components that care about this level of detail.
+ LLAppViewer::metricsUpdateRegion(regionp->getHandle());
}
mRegionp = regionp;
+ // Pass the region host to LLUrlEntryParcel to resolve parcel name
+ // with a server request.
+ LLUrlEntryParcel::setRegionHost(getRegionHost());
+
// Must shift hole-covering water object locations because local
// coordinate frame changed.
LLWorld::getInstance()->updateWaterObjects();
@@ -1105,12 +1136,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.
@@ -1199,7 +1224,13 @@ BOOL LLAgent::getBusy() const
//-----------------------------------------------------------------------------
// startAutoPilotGlobal()
//-----------------------------------------------------------------------------
-void LLAgent::startAutoPilotGlobal(const LLVector3d &target_global, const std::string& behavior_name, const LLQuaternion *target_rotation, void (*finish_callback)(BOOL, void *), void *callback_data, F32 stop_distance, F32 rot_threshold)
+void LLAgent::startAutoPilotGlobal(
+ const LLVector3d &target_global,
+ const std::string& behavior_name,
+ const LLQuaternion *target_rotation,
+ void (*finish_callback)(BOOL, void *),
+ void *callback_data,
+ F32 stop_distance, F32 rot_threshold)
{
if (!isAgentAvatarValid())
{
@@ -1230,7 +1261,7 @@ void LLAgent::startAutoPilotGlobal(const LLVector3d &target_global, const std::s
else
{
// Guess at a reasonable stop distance.
- mAutoPilotStopDistance = fsqrtf( distance );
+ mAutoPilotStopDistance = (F32) sqrt( distance );
if (mAutoPilotStopDistance < 0.5f)
{
mAutoPilotStopDistance = 0.5f;
@@ -1329,7 +1360,7 @@ void LLAgent::stopAutoPilot(BOOL user_cancel)
//NB: auto pilot can terminate for a reason other than reaching the destination
if (mAutoPilotFinishedCallback)
{
- mAutoPilotFinishedCallback(!user_cancel && dist_vec(gAgent.getPositionGlobal(), mAutoPilotTargetGlobal) < mAutoPilotStopDistance, mAutoPilotCallbackData);
+ mAutoPilotFinishedCallback(!user_cancel && dist_vec_squared(gAgent.getPositionGlobal(), mAutoPilotTargetGlobal) < (mAutoPilotStopDistance * mAutoPilotStopDistance), mAutoPilotCallbackData);
}
mLeaderID = LLUUID::null;
@@ -1670,11 +1701,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))
@@ -1726,15 +1752,17 @@ void LLAgent::endAnimationUpdateUI()
LLBottomTray::getInstance()->onMouselookModeOut();
- LLSideTray::getInstance()->getButtonsPanel()->setVisible(TRUE);
- LLSideTray::getInstance()->updateSidetrayVisibility();
-
LLPanelStandStopFlying::getInstance()->setVisible(TRUE);
LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset);
LLFloaterCamera::onLeavingMouseLook();
+ if (mMouselookModeOutSignal)
+ {
+ (*mMouselookModeOutSignal)();
+ }
+
// Only pop if we have pushed...
if (TRUE == mViewsPushed)
{
@@ -1828,9 +1856,6 @@ void LLAgent::endAnimationUpdateUI()
LLBottomTray::getInstance()->onMouselookModeIn();
- LLSideTray::getInstance()->getButtonsPanel()->setVisible(FALSE);
- LLSideTray::getInstance()->updateSidetrayVisibility();
-
LLPanelStandStopFlying::getInstance()->setVisible(FALSE);
// clear out camera lag effect
@@ -1843,6 +1868,11 @@ void LLAgent::endAnimationUpdateUI()
mViewsPushed = TRUE;
+ if (mMouselookModeInSignal)
+ {
+ (*mMouselookModeInSignal)();
+ }
+
// hide all floaters except the mini map
#if 0 // Use this once all floaters are registered
@@ -1902,7 +1932,6 @@ void LLAgent::endAnimationUpdateUI()
}
}
}
-
}
else if (gAgentCamera.getCameraMode() == CAMERA_MODE_CUSTOMIZE_AVATAR)
{
@@ -1934,6 +1963,18 @@ void LLAgent::endAnimationUpdateUI()
gAgentCamera.updateLastCamera();
}
+boost::signals2::connection LLAgent::setMouselookModeInCallback( const camera_signal_t::slot_type& cb )
+{
+ if (!mMouselookModeInSignal) mMouselookModeInSignal = new camera_signal_t();
+ return mMouselookModeInSignal->connect(cb);
+}
+
+boost::signals2::connection LLAgent::setMouselookModeOutCallback( const camera_signal_t::slot_type& cb )
+{
+ if (!mMouselookModeOutSignal) mMouselookModeOutSignal = new camera_signal_t();
+ return mMouselookModeOutSignal->connect(cb);
+}
+
//-----------------------------------------------------------------------------
// heardChat()
//-----------------------------------------------------------------------------
@@ -2121,32 +2162,32 @@ void LLAgent::onAnimStop(const LLUUID& id)
bool LLAgent::isGodlike() const
{
- return mAgentAccess.isGodlike();
+ return mAgentAccess->isGodlike();
}
bool LLAgent::isGodlikeWithoutAdminMenuFakery() const
{
- return mAgentAccess.isGodlikeWithoutAdminMenuFakery();
+ return mAgentAccess->isGodlikeWithoutAdminMenuFakery();
}
U8 LLAgent::getGodLevel() const
{
- return mAgentAccess.getGodLevel();
+ return mAgentAccess->getGodLevel();
}
bool LLAgent::wantsPGOnly() const
{
- return mAgentAccess.wantsPGOnly();
+ return mAgentAccess->wantsPGOnly();
}
bool LLAgent::canAccessMature() const
{
- return mAgentAccess.canAccessMature();
+ return mAgentAccess->canAccessMature();
}
bool LLAgent::canAccessAdult() const
{
- return mAgentAccess.canAccessAdult();
+ return mAgentAccess->canAccessAdult();
}
bool LLAgent::canAccessMaturityInRegion( U64 region_handle ) const
@@ -2181,37 +2222,37 @@ bool LLAgent::canAccessMaturityAtGlobal( LLVector3d pos_global ) const
bool LLAgent::prefersPG() const
{
- return mAgentAccess.prefersPG();
+ return mAgentAccess->prefersPG();
}
bool LLAgent::prefersMature() const
{
- return mAgentAccess.prefersMature();
+ return mAgentAccess->prefersMature();
}
bool LLAgent::prefersAdult() const
{
- return mAgentAccess.prefersAdult();
+ return mAgentAccess->prefersAdult();
}
bool LLAgent::isTeen() const
{
- return mAgentAccess.isTeen();
+ return mAgentAccess->isTeen();
}
bool LLAgent::isMature() const
{
- return mAgentAccess.isMature();
+ return mAgentAccess->isMature();
}
bool LLAgent::isAdult() const
{
- return mAgentAccess.isAdult();
+ return mAgentAccess->isAdult();
}
void LLAgent::setTeen(bool teen)
{
- mAgentAccess.setTeen(teen);
+ mAgentAccess->setTeen(teen);
}
//static
@@ -2256,37 +2297,37 @@ bool LLAgent::sendMaturityPreferenceToServer(int preferredMaturity)
BOOL LLAgent::getAdminOverride() const
{
- return mAgentAccess.getAdminOverride();
+ return mAgentAccess->getAdminOverride();
}
void LLAgent::setMaturity(char text)
{
- mAgentAccess.setMaturity(text);
+ mAgentAccess->setMaturity(text);
}
void LLAgent::setAdminOverride(BOOL b)
{
- mAgentAccess.setAdminOverride(b);
+ mAgentAccess->setAdminOverride(b);
}
void LLAgent::setGodLevel(U8 god_level)
{
- mAgentAccess.setGodLevel(god_level);
+ mAgentAccess->setGodLevel(god_level);
}
void LLAgent::setAOTransition()
{
- mAgentAccess.setTransition();
+ mAgentAccess->setTransition();
}
const LLAgentAccess& LLAgent::getAgentAccess()
{
- return mAgentAccess;
+ return *mAgentAccess;
}
bool LLAgent::validateMaturity(const LLSD& newvalue)
{
- return mAgentAccess.canSetMaturity(newvalue.asInteger());
+ return mAgentAccess->canSetMaturity(newvalue.asInteger());
}
void LLAgent::handleMaturity(const LLSD& newvalue)
@@ -2452,7 +2493,7 @@ BOOL LLAgent::setUserGroupFlags(const LLUUID& group_id, BOOL accept_notices, BOO
BOOL LLAgent::canJoinGroups() const
{
- return mGroups.count() < MAX_AGENT_GROUPS;
+ return mGroups.count() < gMaxAgentGroups;
}
LLQuaternion LLAgent::getHeadRotation()
@@ -2618,12 +2659,12 @@ BOOL LLAgent::allowOperation(PermissionBit op,
const LLColor4 &LLAgent::getEffectColor()
{
- return mEffectColor;
+ return *mEffectColor;
}
void LLAgent::setEffectColor(const LLColor4 &color)
{
- mEffectColor = color;
+ *mEffectColor = color;
}
void LLAgent::initOriginGlobal(const LLVector3d &origin_global)
@@ -3451,7 +3492,7 @@ void LLAgent::setTeleportState(ETeleportState state)
case TELEPORT_MOVING:
// We're outa here. Save "back" slurl.
- LLAgentUI::buildSLURL(mTeleportSourceSLURL);
+ LLAgentUI::buildSLURL(*mTeleportSourceSLURL);
break;
case TELEPORT_ARRIVING:
@@ -3784,6 +3825,11 @@ void LLAgent::parseTeleportMessages(const std::string& xml_filename)
}//end for (all message sets in xml file)
}
+const void LLAgent::getTeleportSourceSLURL(LLSLURL& slurl) const
+{
+ slurl = *mTeleportSourceSLURL;
+}
+
void LLAgent::sendAgentUpdateUserInfo(bool im_via_email, const std::string& directory_visibility )
{
gMessageSystem->newMessageFast(_PREHASH_UpdateUserInfo);
diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h
index 6c598d5d71..54c5649f97 100644
--- a/indra/newview/llagent.h
+++ b/indra/newview/llagent.h
@@ -29,14 +29,13 @@
#include "indra_constants.h"
#include "llevent.h" // LLObservable base class
-#include "llagentaccess.h"
#include "llagentconstants.h"
#include "llagentdata.h" // gAgentID, gAgentSessionID
-#include "llcharacter.h" // LLAnimPauseRequest
-#include "llpointer.h"
-#include "lluicolor.h"
+#include "llcharacter.h"
+#include "llcoordframe.h" // for mFrameAgent
#include "llvoavatardefines.h"
-#include "llslurl.h"
+
+#include <boost/signals2.hpp>
extern const BOOL ANIMATE;
extern const U8 AGENT_STATE_TYPING; // Typing indication
@@ -53,6 +52,10 @@ class LLFriendObserver;
class LLPickInfo;
class LLViewerObject;
class LLAgentDropGroupViewerNode;
+class LLAgentAccess;
+class LLSLURL;
+class LLPauseRequestHandle;
+class LLUIColor;
//--------------------------------------------------------------------
// Types
@@ -77,6 +80,8 @@ struct LLGroupData
class LLAgentListener;
+class LLAgentImpl;
+
//------------------------------------------------------------------------
// LLAgent
//------------------------------------------------------------------------
@@ -409,9 +414,15 @@ public:
BOOL getCustomAnim() const { return mCustomAnim; }
void setCustomAnim(BOOL anim) { mCustomAnim = anim; }
+ typedef boost::signals2::signal<void ()> camera_signal_t;
+ boost::signals2::connection setMouselookModeInCallback( const camera_signal_t::slot_type& cb );
+ boost::signals2::connection setMouselookModeOutCallback( const camera_signal_t::slot_type& cb );
+
private:
+ camera_signal_t* mMouselookModeInSignal;
+ camera_signal_t* mMouselookModeOutSignal;
BOOL mCustomAnim; // Current animation is ANIM_AGENT_CUSTOMIZE ?
- LLAnimPauseRequest mPauseRequest;
+ LLPointer<LLPauseRequestHandle> mPauseRequest;
BOOL mViewsPushed; // Keep track of whether or not we have pushed views
/** Animation
@@ -506,13 +517,13 @@ public:
public:
static void parseTeleportMessages(const std::string& xml_filename);
- const void getTeleportSourceSLURL(LLSLURL& slurl) const { slurl = mTeleportSourceSLURL; }
+ const void getTeleportSourceSLURL(LLSLURL& slurl) const;
public:
// ! TODO ! Define ERROR and PROGRESS enums here instead of exposing the mappings.
static std::map<std::string, std::string> sTeleportErrorMessages;
static std::map<std::string, std::string> sTeleportProgressMessages;
private:
- LLSLURL mTeleportSourceSLURL; // SLURL where last TP began
+ LLSLURL * mTeleportSourceSLURL; // SLURL where last TP began
//--------------------------------------------------------------------
// Teleport Actions
@@ -571,7 +582,7 @@ public:
// ! BACKWARDS COMPATIBILITY ! This function can go away after the AO transition (see llstartup.cpp).
void setAOTransition();
private:
- LLAgentAccess mAgentAccess;
+ LLAgentAccess * mAgentAccess;
//--------------------------------------------------------------------
// God
@@ -651,7 +662,7 @@ public:
const LLColor4 &getEffectColor();
void setEffectColor(const LLColor4 &color);
private:
- LLUIColor mEffectColor;
+ LLUIColor * mEffectColor;
/** Rendering
** **
diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp
index 68e408d3e4..c6b5a0113f 100644
--- a/indra/newview/llagentcamera.cpp
+++ b/indra/newview/llagentcamera.cpp
@@ -282,20 +282,20 @@ 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();
}
@@ -390,10 +390,12 @@ LLVector3 LLAgentCamera::calcFocusOffset(LLViewerObject *object, LLVector3 origi
{
return original_focus_point - obj_pos;
}
-
LLQuaternion inv_obj_rot = ~obj_rot; // get inverse of rotation
- LLVector3 object_extents = object->getScale();
+ LLVector3 object_extents;
+ const LLVector4a* oe4 = object->mDrawable->getSpatialExtents();
+ object_extents.set( oe4[1][0], oe4[1][1], oe4[1][2] );
+
// make sure they object extents are non-zero
object_extents.clamp(0.001f, F32_MAX);
@@ -551,7 +553,9 @@ BOOL LLAgentCamera::calcCameraMinDistance(F32 &obj_min_distance)
{
BOOL soft_limit = FALSE; // is the bounding box to be treated literally (volumes) or as an approximation (avatars)
- if (!mFocusObject || mFocusObject->isDead())
+ if (!mFocusObject || mFocusObject->isDead() ||
+ mFocusObject->isMesh() ||
+ gSavedSettings.getBOOL("DisableCameraConstraints"))
{
obj_min_distance = 0.f;
return TRUE;
@@ -2038,7 +2042,7 @@ void LLAgentCamera::resetCamera()
//-----------------------------------------------------------------------------
void LLAgentCamera::changeCameraToMouselook(BOOL animate)
{
- if (LLViewerJoystick::getInstance()->getOverrideCamera())
+ if (!gSavedSettings.getBOOL("EnableMouselook") || LLViewerJoystick::getInstance()->getOverrideCamera())
{
return;
}
@@ -2692,6 +2696,9 @@ void LLAgentCamera::lookAtLastChat()
new_camera_pos -= delta_pos * 0.4f;
new_camera_pos += left * 0.3f;
new_camera_pos += up * 0.2f;
+
+ setFocusOnAvatar(FALSE, FALSE);
+
if (chatter_av->mHeadp)
{
setFocusGlobal(gAgent.getPosGlobalFromAgent(chatter_av->mHeadp->getWorldPosition()), gAgent.getLastChatter());
@@ -2702,7 +2709,6 @@ void LLAgentCamera::lookAtLastChat()
setFocusGlobal(chatter->getPositionGlobal(), gAgent.getLastChatter());
mCameraFocusOffsetTarget = gAgent.getPosGlobalFromAgent(new_camera_pos) - chatter->getPositionGlobal();
}
- setFocusOnAvatar(FALSE, TRUE);
}
else
{
@@ -2722,9 +2728,10 @@ void LLAgentCamera::lookAtLastChat()
new_camera_pos += left * 0.3f;
new_camera_pos += up * 0.2f;
+ setFocusOnAvatar(FALSE, FALSE);
+
setFocusGlobal(chatter->getPositionGlobal(), gAgent.getLastChatter());
mCameraFocusOffsetTarget = gAgent.getPosGlobalFromAgent(new_camera_pos) - chatter->getPositionGlobal();
- setFocusOnAvatar(FALSE, TRUE);
}
}
diff --git a/indra/newview/llagentlistener.cpp b/indra/newview/llagentlistener.cpp
index d520debc31..9cea33c7c6 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,21 @@ 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()));
+ add("getGroups",
+ "Send on [\"reply\"], in [\"groups\"], an array describing agent's groups:\n"
+ "[\"id\"]: UUID of group\n"
+ "[\"name\"]: name of group",
+ &LLAgentListener::getGroups,
+ LLSDMap("reply", LLSD()));
}
void LLAgentListener::requestTeleport(LLSD const & event_data) const
@@ -64,7 +81,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 +91,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 +121,46 @@ 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);
+}
+
+void LLAgentListener::getGroups(const LLSD& event) const
+{
+ LLSD reply(LLSD::emptyArray());
+ for (LLDynamicArray<LLGroupData>::const_iterator
+ gi(mAgent.mGroups.begin()), gend(mAgent.mGroups.end());
+ gi != gend; ++gi)
+ {
+ reply.append(LLSDMap
+ ("id", gi->mID)
+ ("name", gi->mName)
+ ("insignia", gi->mInsigniaID)
+ ("notices", bool(gi->mAcceptNotices))
+ ("display", bool(gi->mListInProfile))
+ ("contrib", gi->mContribution));
+ }
+ sendReply(LLSDMap("groups", reply), event);
+}
diff --git a/indra/newview/llagentlistener.h b/indra/newview/llagentlistener.h
index 9b585152f4..5a89a99f6a 100644
--- a/indra/newview/llagentlistener.h
+++ b/indra/newview/llagentlistener.h
@@ -44,6 +44,9 @@ 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;
+ void getGroups(const LLSD& event) const;
private:
LLAgent & mAgent;
diff --git a/indra/newview/llagentpilot.cpp b/indra/newview/llagentpilot.cpp
index 13e1023185..734c502fcf 100644
--- a/indra/newview/llagentpilot.cpp
+++ b/indra/newview/llagentpilot.cpp
@@ -34,12 +34,12 @@
#include "llagent.h"
#include "llappviewer.h"
#include "llviewercontrol.h"
+#include "llviewercamera.h"
+#include "llsdserialize.h"
+#include "llsdutil_math.h"
LLAgentPilot gAgentPilot;
-BOOL LLAgentPilot::sLoop = TRUE;
-BOOL LLAgentPilot::sReplaySession = FALSE;
-
LLAgentPilot::LLAgentPilot() :
mNumRuns(-1),
mQuitAfterRuns(FALSE),
@@ -47,7 +47,10 @@ LLAgentPilot::LLAgentPilot() :
mLastRecordTime(0.f),
mStarted(FALSE),
mPlaying(FALSE),
- mCurrentAction(0)
+ mCurrentAction(0),
+ mOverrideCamera(FALSE),
+ mLoop(TRUE),
+ mReplaySession(FALSE)
{
}
@@ -55,7 +58,26 @@ LLAgentPilot::~LLAgentPilot()
{
}
-void LLAgentPilot::load(const std::string& filename)
+void LLAgentPilot::load()
+{
+ std::string txt_filename = gSavedSettings.getString("StatsPilotFile");
+ std::string xml_filename = gSavedSettings.getString("StatsPilotXMLFile");
+ if (LLFile::isfile(xml_filename))
+ {
+ loadXML(xml_filename);
+ }
+ else if (LLFile::isfile(txt_filename))
+ {
+ loadTxt(txt_filename);
+ }
+ else
+ {
+ lldebugs << "no autopilot file found" << llendl;
+ return;
+ }
+}
+
+void LLAgentPilot::loadTxt(const std::string& filename)
{
if(filename.empty())
{
@@ -75,6 +97,7 @@ void LLAgentPilot::load(const std::string& filename)
llinfos << "Opening pilot file " << filename << llendl;
}
+ mActions.reset();
S32 num_actions;
file >> num_actions;
@@ -89,10 +112,59 @@ void LLAgentPilot::load(const std::string& filename)
mActions.put(new_action);
}
+ mOverrideCamera = false;
+
+ file.close();
+}
+
+void LLAgentPilot::loadXML(const std::string& filename)
+{
+ if(filename.empty())
+ {
+ return;
+ }
+
+ llifstream file(filename);
+
+ if (!file)
+ {
+ lldebugs << "Couldn't open " << filename
+ << ", aborting agentpilot load!" << llendl;
+ return;
+ }
+ else
+ {
+ llinfos << "Opening pilot file " << filename << llendl;
+ }
+
+ mActions.reset();
+ LLSD record;
+ while (!file.eof() && LLSDSerialize::fromXML(record, file))
+ {
+ Action action;
+ action.mTime = record["time"].asReal();
+ action.mType = (EActionType)record["type"].asInteger();
+ action.mCameraView = record["camera_view"].asReal();
+ action.mTarget = ll_vector3d_from_sd(record["target"]);
+ action.mCameraOrigin = ll_vector3_from_sd(record["camera_origin"]);
+ action.mCameraXAxis = ll_vector3_from_sd(record["camera_xaxis"]);
+ action.mCameraYAxis = ll_vector3_from_sd(record["camera_yaxis"]);
+ action.mCameraZAxis = ll_vector3_from_sd(record["camera_zaxis"]);
+ mActions.put(action);
+ }
+ mOverrideCamera = true;
file.close();
}
-void LLAgentPilot::save(const std::string& filename)
+void LLAgentPilot::save()
+{
+ std::string txt_filename = gSavedSettings.getString("StatsPilotFile");
+ std::string xml_filename = gSavedSettings.getString("StatsPilotXMLFile");
+ saveTxt(txt_filename);
+ saveXML(xml_filename);
+}
+
+void LLAgentPilot::saveTxt(const std::string& filename)
{
llofstream file;
file.open(filename);
@@ -108,12 +180,41 @@ void LLAgentPilot::save(const std::string& filename)
for (i = 0; i < mActions.count(); i++)
{
file << mActions[i].mTime << "\t" << mActions[i].mType << "\t";
- file << std::setprecision(32) << mActions[i].mTarget.mdV[VX] << "\t" << mActions[i].mTarget.mdV[VY] << "\t" << mActions[i].mTarget.mdV[VZ] << '\n';
+ file << std::setprecision(32) << mActions[i].mTarget.mdV[VX] << "\t" << mActions[i].mTarget.mdV[VY] << "\t" << mActions[i].mTarget.mdV[VZ];
+ file << '\n';
}
file.close();
}
+void LLAgentPilot::saveXML(const std::string& filename)
+{
+ llofstream file;
+ file.open(filename);
+
+ if (!file)
+ {
+ llinfos << "Couldn't open " << filename << ", aborting agentpilot save!" << llendl;
+ }
+
+ S32 i;
+ for (i = 0; i < mActions.count(); i++)
+ {
+ Action& action = mActions[i];
+ LLSD record;
+ record["time"] = (LLSD::Real)action.mTime;
+ record["type"] = (LLSD::Integer)action.mType;
+ record["camera_view"] = (LLSD::Real)action.mCameraView;
+ record["target"] = ll_sd_from_vector3d(action.mTarget);
+ record["camera_origin"] = ll_sd_from_vector3(action.mCameraOrigin);
+ record["camera_xaxis"] = ll_sd_from_vector3(action.mCameraXAxis);
+ record["camera_yaxis"] = ll_sd_from_vector3(action.mCameraYAxis);
+ record["camera_zaxis"] = ll_sd_from_vector3(action.mCameraZAxis);
+ LLSDSerialize::toXML(record, file);
+ }
+ file.close();
+}
+
void LLAgentPilot::startRecord()
{
mActions.reset();
@@ -125,7 +226,7 @@ void LLAgentPilot::startRecord()
void LLAgentPilot::stopRecord()
{
gAgentPilot.addAction(STRAIGHT);
- gAgentPilot.save(gSavedSettings.getString("StatsPilotFile"));
+ gAgentPilot.save();
mRecording = FALSE;
}
@@ -136,6 +237,12 @@ void LLAgentPilot::addAction(enum EActionType action_type)
action.mType = action_type;
action.mTarget = gAgent.getPositionGlobal();
action.mTime = mTimer.getElapsedTimeF32();
+ LLViewerCamera *cam = LLViewerCamera::getInstance();
+ action.mCameraView = cam->getView();
+ action.mCameraOrigin = cam->getOrigin();
+ action.mCameraXAxis = cam->getXAxis();
+ action.mCameraYAxis = cam->getYAxis();
+ action.mCameraZAxis = cam->getZAxis();
mLastRecordTime = (F32)action.mTime;
mActions.put(action);
}
@@ -152,6 +259,7 @@ void LLAgentPilot::startPlayback()
{
llinfos << "Starting playback, moving to waypoint 0" << llendl;
gAgent.startAutoPilotGlobal(mActions[0].mTarget);
+ moveCamera();
mStarted = FALSE;
}
else
@@ -172,12 +280,53 @@ void LLAgentPilot::stopPlayback()
gAgent.stopAutoPilot();
}
- if (sReplaySession)
+ if (mReplaySession)
{
LLAppViewer::instance()->forceQuit();
}
}
+void LLAgentPilot::moveCamera()
+{
+ if (!getOverrideCamera())
+ return;
+
+ if (mCurrentAction<mActions.count())
+ {
+ S32 start_index = llmax(mCurrentAction-1,0);
+ S32 end_index = mCurrentAction;
+ F32 t = 0.0;
+ F32 timedelta = mActions[end_index].mTime - mActions[start_index].mTime;
+ F32 tickelapsed = mTimer.getElapsedTimeF32()-mActions[start_index].mTime;
+ if (timedelta > 0.0)
+ {
+ t = tickelapsed/timedelta;
+ }
+
+ if ((t<0.0)||(t>1.0))
+ {
+ llwarns << "mCurrentAction is invalid, t = " << t << llendl;
+ return;
+ }
+
+ Action& start = mActions[start_index];
+ Action& end = mActions[end_index];
+
+ F32 view = lerp(start.mCameraView, end.mCameraView, t);
+ LLVector3 origin = lerp(start.mCameraOrigin, end.mCameraOrigin, t);
+ LLQuaternion start_quat(start.mCameraXAxis, start.mCameraYAxis, start.mCameraZAxis);
+ LLQuaternion end_quat(end.mCameraXAxis, end.mCameraYAxis, end.mCameraZAxis);
+ LLQuaternion quat = nlerp(t, start_quat, end_quat);
+ LLMatrix3 mat(quat);
+
+ LLViewerCamera::getInstance()->setView(view);
+ LLViewerCamera::getInstance()->setOrigin(origin);
+ LLViewerCamera::getInstance()->mXAxis = LLVector3(mat.mMatrix[0]);
+ LLViewerCamera::getInstance()->mYAxis = LLVector3(mat.mMatrix[1]);
+ LLViewerCamera::getInstance()->mZAxis = LLVector3(mat.mMatrix[2]);
+ }
+}
+
void LLAgentPilot::updateTarget()
{
if (mPlaying)
@@ -209,12 +358,13 @@ void LLAgentPilot::updateTarget()
if (mCurrentAction < mActions.count())
{
gAgent.startAutoPilotGlobal(mActions[mCurrentAction].mTarget);
+ moveCamera();
}
else
{
stopPlayback();
mNumRuns--;
- if (sLoop)
+ if (mLoop)
{
if ((mNumRuns < 0) || (mNumRuns > 0))
{
@@ -249,29 +399,8 @@ void LLAgentPilot::updateTarget()
}
}
-// static
-void LLAgentPilot::startRecord(void *)
-{
- gAgentPilot.startRecord();
-}
-
-void LLAgentPilot::saveRecord(void *)
+void LLAgentPilot::addWaypoint()
{
- gAgentPilot.stopRecord();
-}
-
-void LLAgentPilot::addWaypoint(void *)
-{
- gAgentPilot.addAction(STRAIGHT);
-}
-
-void LLAgentPilot::startPlayback(void *)
-{
- gAgentPilot.mNumRuns = -1;
- gAgentPilot.startPlayback();
+ addAction(STRAIGHT);
}
-void LLAgentPilot::stopPlayback(void *)
-{
- gAgentPilot.stopPlayback();
-}
diff --git a/indra/newview/llagentpilot.h b/indra/newview/llagentpilot.h
index f3d34246ae..dd1709ec0c 100644
--- a/indra/newview/llagentpilot.h
+++ b/indra/newview/llagentpilot.h
@@ -46,8 +46,12 @@ public:
LLAgentPilot();
virtual ~LLAgentPilot();
- void load(const std::string& filename);
- void save(const std::string& filename);
+ void load();
+ void loadTxt(const std::string& filename);
+ void loadXML(const std::string& filename);
+ void save();
+ void saveTxt(const std::string& filename);
+ void saveXML(const std::string& filename);
void startRecord();
void stopRecord();
@@ -56,19 +60,34 @@ public:
void startPlayback();
void stopPlayback();
+ bool isRecording() { return mRecording; }
+ bool isPlaying() { return mPlaying; }
+ bool getOverrideCamera() { return mOverrideCamera; }
+
void updateTarget();
- static void startRecord(void *);
- static void addWaypoint(void *);
- static void saveRecord(void *);
- static void startPlayback(void *);
- static void stopPlayback(void *);
- static BOOL sLoop;
- static BOOL sReplaySession;
+ void addWaypoint();
+ void moveCamera();
+
+ void setReplaySession(BOOL new_val) { mReplaySession = new_val; }
+ BOOL getReplaySession() { return mReplaySession; }
+
+ void setLoop(BOOL new_val) { mLoop = new_val; }
+ BOOL getLoop() { return mLoop; }
+
+ void setQuitAfterRuns(BOOL quit_val) { mQuitAfterRuns = quit_val; }
+ void setNumRuns(S32 num_runs) { mNumRuns = num_runs; }
+
+private:
+
+
+
+ BOOL mLoop;
+ BOOL mReplaySession;
S32 mNumRuns;
BOOL mQuitAfterRuns;
-private:
+
void setAutopilotTarget(const S32 id);
BOOL mRecording;
@@ -78,6 +97,8 @@ private:
BOOL mPlaying;
S32 mCurrentAction;
+ BOOL mOverrideCamera;
+
class Action
{
public:
@@ -85,10 +106,16 @@ private:
EActionType mType;
LLVector3d mTarget;
F64 mTime;
+ F32 mCameraView;
+ LLVector3 mCameraOrigin;
+ LLVector3 mCameraXAxis;
+ LLVector3 mCameraYAxis;
+ LLVector3 mCameraZAxis;
};
LLDynamicArray<Action> mActions;
LLTimer mTimer;
+
};
extern LLAgentPilot gAgentPilot;
diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp
index 055be4cae2..d426afb17c 100644
--- a/indra/newview/llagentwearables.cpp
+++ b/indra/newview/llagentwearables.cpp
@@ -821,7 +821,7 @@ void LLAgentWearables::popWearable(const LLWearableType::EType type, U32 index)
}
}
-U32 LLAgentWearables::getWearableIndex(LLWearable *wearable)
+U32 LLAgentWearables::getWearableIndex(const LLWearable *wearable) const
{
if (wearable == NULL)
{
@@ -2045,8 +2045,9 @@ void LLAgentWearables::editWearable(const LLUUID& item_id)
return;
}
+ const BOOL disable_camera_switch = LLWearableType::getDisableCameraSwitch(wearable->getType());
LLPanel* panel = LLSideTray::getInstance()->getPanel("sidepanel_appearance");
- LLSidepanelAppearance::editWearable(wearable, panel);
+ LLSidepanelAppearance::editWearable(wearable, panel, disable_camera_switch);
}
// Request editing the item after it gets worn.
diff --git a/indra/newview/llagentwearables.h b/indra/newview/llagentwearables.h
index d7e77a5a5b..3ef50f14da 100644
--- a/indra/newview/llagentwearables.h
+++ b/indra/newview/llagentwearables.h
@@ -124,7 +124,7 @@ public:
void setWearableOutfit(const LLInventoryItem::item_array_t& items, const LLDynamicArray< LLWearable* >& wearables, BOOL remove);
void setWearableName(const LLUUID& item_id, const std::string& new_name);
void addLocalTextureObject(const LLWearableType::EType wearable_type, const LLVOAvatarDefines::ETextureIndex texture_type, U32 wearable_index);
- U32 getWearableIndex(LLWearable *wearable);
+ U32 getWearableIndex(const LLWearable *wearable) const;
protected:
void setWearableFinal(LLInventoryItem* new_item, LLWearable* new_wearable, bool do_append = false);
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index ed5e8ceee3..1388d9aee0 100644
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -110,6 +110,12 @@ public:
{
// support secondlife:///app/appearance/show, but for now we just
// make all secondlife:///app/appearance SLapps behave this way
+ if (!LLUI::sSettingGroups["config"]->getBOOL("EnableAppearance"))
+ {
+ LLNotificationsUtil::add("NoAppearance", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit"));
+ return true;
+ }
+
LLSideTray::getInstance()->showPanel("sidepanel_appearance", LLSD());
return true;
}
@@ -1300,8 +1306,16 @@ bool LLAppearanceMgr::getCanReplaceCOF(const LLUUID& outfit_cat_id)
return false;
}
- // Check whether the outfit contains the full set of body parts (shape+skin+hair+eyes).
- return getCanMakeFolderIntoOutfit(outfit_cat_id);
+ // Check whether the outfit contains any wearables we aren't wearing already (STORM-702).
+ LLInventoryModel::cat_array_t cats;
+ LLInventoryModel::item_array_t items;
+ LLFindWearablesEx is_worn(/*is_worn=*/ false, /*include_body_parts=*/ true);
+ gInventory.collectDescendentsIf(outfit_cat_id,
+ cats,
+ items,
+ LLInventoryModel::EXCLUDE_TRASH,
+ is_worn);
+ return items.size() > 0;
}
void LLAppearanceMgr::purgeBaseOutfitLink(const LLUUID& category)
@@ -2204,12 +2218,11 @@ void LLAppearanceMgr::updateIsDirty()
base_outfit = catp->getUUID();
}
- if(base_outfit.isNull())
- {
- // no outfit link found, display "unsaved outfit"
- mOutfitIsDirty = true;
- }
- else
+ // Set dirty to "false" if no base outfit found to disable "Save"
+ // and leave only "Save As" enabled in My Outfits.
+ mOutfitIsDirty = false;
+
+ if (base_outfit.notNull())
{
LLIsOfAssetType collector = LLIsOfAssetType(LLAssetType::AT_LINK);
@@ -2248,8 +2261,6 @@ void LLAppearanceMgr::updateIsDirty()
return;
}
}
-
- mOutfitIsDirty = false;
}
}
@@ -2440,6 +2451,12 @@ public:
virtual ~LLShowCreatedOutfit()
{
+ if (!LLApp::isRunning())
+ {
+ llwarns << "called during shutdown, skipping" << llendl;
+ return;
+ }
+
LLSD key;
//EXT-7727. For new accounts LLShowCreatedOutfit is created during login process
@@ -2635,6 +2652,7 @@ void LLAppearanceMgr::dumpItemArray(const LLInventoryModel::item_array_t& items,
LLAppearanceMgr::LLAppearanceMgr():
mAttachmentInvLinkEnabled(false),
mOutfitIsDirty(false),
+ mOutfitLocked(false),
mIsInUpdateAppearanceFromCOF(false)
{
LLOutfitObserver& outfit_observer = LLOutfitObserver::instance();
@@ -2755,75 +2773,6 @@ BOOL LLAppearanceMgr::getIsProtectedCOFItem(const LLUUID& obj_id) const
*/
}
-// Shim class to allow arbitrary boost::bind
-// expressions to be run as one-time idle callbacks.
-//
-// TODO: rework idle function spec to take a boost::function in the first place.
-class OnIdleCallbackOneTime
-{
-public:
- OnIdleCallbackOneTime(nullary_func_t callable):
- mCallable(callable)
- {
- }
- static void onIdle(void *data)
- {
- gIdleCallbacks.deleteFunction(onIdle, data);
- OnIdleCallbackOneTime* self = reinterpret_cast<OnIdleCallbackOneTime*>(data);
- self->call();
- delete self;
- }
- void call()
- {
- mCallable();
- }
-private:
- nullary_func_t mCallable;
-};
-
-void doOnIdleOneTime(nullary_func_t callable)
-{
- OnIdleCallbackOneTime* cb_functor = new OnIdleCallbackOneTime(callable);
- gIdleCallbacks.addFunction(&OnIdleCallbackOneTime::onIdle,cb_functor);
-}
-
-// Shim class to allow generic boost functions to be run as
-// recurring idle callbacks. Callable should return true when done,
-// false to continue getting called.
-//
-// TODO: rework idle function spec to take a boost::function in the first place.
-class OnIdleCallbackRepeating
-{
-public:
- OnIdleCallbackRepeating(bool_func_t callable):
- mCallable(callable)
- {
- }
- // Will keep getting called until the callable returns true.
- static void onIdle(void *data)
- {
- OnIdleCallbackRepeating* self = reinterpret_cast<OnIdleCallbackRepeating*>(data);
- bool done = self->call();
- if (done)
- {
- gIdleCallbacks.deleteFunction(onIdle, data);
- delete self;
- }
- }
- bool call()
- {
- return mCallable();
- }
-private:
- bool_func_t mCallable;
-};
-
-void doOnIdleRepeating(bool_func_t callable)
-{
- OnIdleCallbackRepeating* cb_functor = new OnIdleCallbackRepeating(callable);
- gIdleCallbacks.addFunction(&OnIdleCallbackRepeating::onIdle,cb_functor);
-}
-
class CallAfterCategoryFetchStage2: public LLInventoryFetchItemsObserver
{
public:
@@ -2943,3 +2892,35 @@ void wear_multiple(const uuid_vec_t& ids, bool replace)
}
}
+// SLapp for easy-wearing of a stock (library) avatar
+//
+class LLWearFolderHandler : public LLCommandHandler
+{
+public:
+ // not allowed from outside the app
+ LLWearFolderHandler() : LLCommandHandler("wear_folder", UNTRUSTED_BLOCK) { }
+
+ bool handle(const LLSD& tokens, const LLSD& query_map,
+ LLMediaCtrl* web)
+ {
+ LLPointer<LLInventoryCategory> category = new LLInventoryCategory(query_map["folder_id"],
+ LLUUID::null,
+ LLFolderType::FT_CLOTHING,
+ "Quick Appearance");
+ LLSD::UUID folder_uuid = query_map["folder_id"].asUUID();
+ if ( gInventory.getCategory( folder_uuid ) != NULL )
+ {
+ LLAppearanceMgr::getInstance()->wearInventoryCategory(category, true, false);
+
+ // *TODOw: This may not be necessary if initial outfit is chosen already -- josh
+ gAgent.setGenderChosen(TRUE);
+ }
+
+ // release avatar picker keyboard focus
+ gFocusMgr.setKeyboardFocus( NULL );
+
+ return true;
+ }
+};
+
+LLWearFolderHandler gWearFolderHandler;
diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h
index c65d9dc9ee..4b1d95cf25 100644
--- a/indra/newview/llappearancemgr.h
+++ b/indra/newview/llappearancemgr.h
@@ -248,15 +248,6 @@ private:
LLUUID findDescendentCategoryIDByName(const LLUUID& parent_id,const std::string& name);
-typedef boost::function<void ()> nullary_func_t;
-typedef boost::function<bool ()> bool_func_t;
-
-// Call a given callable once in idle loop.
-void doOnIdleOneTime(nullary_func_t callable);
-
-// Repeatedly call a callable in idle loop until it returns true.
-void doOnIdleRepeating(bool_func_t callable);
-
// Invoke a given callable after category contents are fully fetched.
void callAfterCategoryFetch(const LLUUID& cat_id, nullary_func_t cb);
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index ba14c248aa..75b6c18c57 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1,4 +1,4 @@
-/**
+ /**
* @file llappviewer.cpp
* @brief The LLAppViewer class definitions
*
@@ -30,6 +30,7 @@
// Viewer includes
#include "llversioninfo.h"
+#include "llversionviewer.h"
#include "llfeaturemanager.h"
#include "lluictrlfactory.h"
#include "lltexteditor.h"
@@ -43,7 +44,9 @@
#include "llagentwearables.h"
#include "llwindow.h"
#include "llviewerstats.h"
+#include "llviewerstatsrecorder.h"
#include "llmd5.h"
+#include "llmeshrepository.h"
#include "llpumpio.h"
#include "llmimetypes.h"
#include "llslurl.h"
@@ -73,22 +76,28 @@
#include "llteleporthistory.h"
#include "lllocationhistory.h"
#include "llfasttimerview.h"
+#include "llvector4a.h"
+#include "llviewermenufile.h"
#include "llvoicechannel.h"
#include "llvoavatarself.h"
#include "llsidetray.h"
-#include "llfeaturemanager.h"
#include "llurlmatch.h"
#include "lltextutil.h"
-
+#include "lllogininstance.h"
+#include "llprogressview.h"
+#include "llvocache.h"
#include "llweb.h"
#include "llsecondlifeurls.h"
+#include "llupdaterservice.h"
// Linden library includes
#include "llavatarnamecache.h"
+#include "lldiriterator.h"
#include "llimagej2c.h"
#include "llmemory.h"
#include "llprimitive.h"
#include "llurlaction.h"
+#include "llurlentry.h"
#include "llvfile.h"
#include "llvfsthread.h"
#include "llvolumemgr.h"
@@ -127,7 +136,6 @@
#include "lltoolmgr.h"
#include "llassetstorage.h"
#include "llpolymesh.h"
-#include "llcachename.h"
#include "llaudioengine.h"
#include "llstreamingaudio.h"
#include "llviewermenu.h"
@@ -190,10 +198,12 @@
#include "llparcel.h"
#include "llavatariconctrl.h"
#include "llgroupiconctrl.h"
+#include "llviewerassetstats.h"
// Include for security api initialization
#include "llsecapi.h"
#include "llmachineid.h"
+#include "llmainlooprepeater.h"
// *FIX: These extern globals should be cleaned up.
// The globals either represent state/config/resource-storage of either
@@ -328,10 +338,58 @@ void init_default_trans_args()
const char *VFS_DATA_FILE_BASE = "data.db2.x.";
const char *VFS_INDEX_FILE_BASE = "index.db2.x.";
+
+struct SettingsFile : public LLInitParam::Block<SettingsFile>
+{
+ Mandatory<std::string> name;
+ Optional<std::string> file_name;
+ Optional<bool> required,
+ persistent;
+ Optional<std::string> file_name_setting;
+
+ SettingsFile()
+ : name("name"),
+ file_name("file_name"),
+ required("required", false),
+ persistent("persistent", true),
+ file_name_setting("file_name_setting")
+ {}
+};
+
+struct SettingsGroup : public LLInitParam::Block<SettingsGroup>
+{
+ Mandatory<std::string> name;
+ Mandatory<S32> path_index;
+ Multiple<SettingsFile> files;
+
+ SettingsGroup()
+ : name("name"),
+ path_index("path_index"),
+ files("file")
+ {}
+};
+
+struct SettingsFiles : public LLInitParam::Block<SettingsFiles>
+{
+ Multiple<SettingsGroup> groups;
+
+ SettingsFiles()
+ : groups("group")
+ {}
+};
+
static std::string gWindowTitle;
LLAppViewer::LLUpdaterInfo *LLAppViewer::sUpdaterInfo = NULL ;
+//----------------------------------------------------------------------------
+// Metrics logging control constants
+//----------------------------------------------------------------------------
+static const F32 METRICS_INTERVAL_DEFAULT = 600.0;
+static const F32 METRICS_INTERVAL_QA = 30.0;
+static F32 app_metrics_interval = METRICS_INTERVAL_DEFAULT;
+static bool app_metrics_qa_mode = false;
+
void idle_afk_check()
{
// check idle timers
@@ -441,6 +499,7 @@ static void settings_to_globals()
LLVolumeImplFlexible::sUpdateFactor = gSavedSettings.getF32("RenderFlexTimeFactor");
LLVOTree::sTreeFactor = gSavedSettings.getF32("RenderTreeLODFactor");
LLVOAvatar::sLODFactor = gSavedSettings.getF32("RenderAvatarLODFactor");
+ LLVOAvatar::sPhysicsLODFactor = gSavedSettings.getF32("RenderAvatarPhysicsLODFactor");
LLVOAvatar::sMaxVisible = (U32)gSavedSettings.getS32("RenderAvatarMaxVisible");
LLVOAvatar::sVisibleInFirstPerson = gSavedSettings.getBOOL("FirstPersonAvatarVisible");
// clamp auto-open time to some minimum usable value
@@ -449,20 +508,19 @@ static void settings_to_globals()
LLSelectMgr::sRenderHiddenSelections = gSavedSettings.getBOOL("RenderHiddenSelections");
LLSelectMgr::sRenderLightRadius = gSavedSettings.getBOOL("RenderLightRadius");
- gAgentPilot.mNumRuns = gSavedSettings.getS32("StatsNumRuns");
- gAgentPilot.mQuitAfterRuns = gSavedSettings.getBOOL("StatsQuitAfterRuns");
+ gAgentPilot.setNumRuns(gSavedSettings.getS32("StatsNumRuns"));
+ gAgentPilot.setQuitAfterRuns(gSavedSettings.getBOOL("StatsQuitAfterRuns"));
gAgent.setHideGroupTitle(gSavedSettings.getBOOL("RenderHideGroupTitle"));
gDebugWindowProc = gSavedSettings.getBOOL("DebugWindowProc");
gShowObjectUpdates = gSavedSettings.getBOOL("ShowObjectUpdates");
LLWorldMapView::sMapScale = gSavedSettings.getF32("MapScale");
-
- LLCubeMap::sUseCubeMaps = LLFeatureManager::getInstance()->isFeatureAvailable("RenderCubeMap");
}
static void settings_modify()
{
- LLRenderTarget::sUseFBO = gSavedSettings.getBOOL("RenderUseFBO");
+ LLRenderTarget::sUseFBO = gSavedSettings.getBOOL("RenderDeferred");
+ LLPipeline::sRenderDeferred = gSavedSettings.getBOOL("RenderDeferred");
LLVOAvatar::sUseImpostors = gSavedSettings.getBOOL("RenderUseImpostors");
LLVOSurfacePatch::sLODFactor = gSavedSettings.getF32("RenderTerrainLODFactor");
LLVOSurfacePatch::sLODFactor *= LLVOSurfacePatch::sLODFactor; //square lod factor to get exponential range of [1,4]
@@ -501,6 +559,9 @@ static void settings_modify()
gSavedSettings.setBOOL("VectorizeEnable", FALSE );
gSavedSettings.setU32("VectorizeProcessor", 0 );
gSavedSettings.setBOOL("VectorizeSkin", FALSE);
+
+ // disable fullscreen mode, unsupported
+ gSavedSettings.setBOOL("WindowFullScreen", FALSE);
#endif
}
@@ -509,16 +570,10 @@ class LLFastTimerLogThread : public LLThread
public:
std::string mFile;
- LLFastTimerLogThread() : LLThread("fast timer log")
- {
- if(LLFastTimer::sLog)
- {
- mFile = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "performance.slp");
- }
- if(LLFastTimer::sMetricLog)
- {
- mFile = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "metric.slp");
- }
+ LLFastTimerLogThread(std::string& test_name) : LLThread("fast timer log")
+ {
+ std::string file_name = test_name + std::string(".slp");
+ mFile = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, file_name);
}
void run()
@@ -580,7 +635,9 @@ LLAppViewer::LLAppViewer() :
mAgentRegionLastAlive(false),
mRandomizeFramerate(LLCachedControl<bool>(gSavedSettings,"Randomize Framerate", FALSE)),
mPeriodicSlowFrame(LLCachedControl<bool>(gSavedSettings,"Periodic Slow Frame", FALSE)),
- mFastTimerLogThread(NULL)
+ mFastTimerLogThread(NULL),
+ mUpdater(new LLUpdaterService()),
+ mSettingsLocationList(NULL)
{
if(NULL != sInstance)
{
@@ -590,10 +647,16 @@ LLAppViewer::LLAppViewer() :
setupErrorHandling();
sInstance = this;
gLoggedInTime.stop();
+
+ LLLoginInstance::instance().setUpdaterService(mUpdater.get());
}
LLAppViewer::~LLAppViewer()
{
+ delete mSettingsLocationList;
+
+ LLLoginInstance::instance().setUpdaterService(0);
+
destroyMainloopTimeout();
// If we got to this destructor somehow, the app didn't hang.
@@ -611,6 +674,9 @@ bool LLAppViewer::init()
//
LLFastTimer::reset();
+ // initialize SSE options
+ LLVector4a::initClass();
+
// Need to do this initialization before we do anything else, since anything
// that touches files should really go through the lldir API
gDirUtilp->initAppDirs("SecondLife");
@@ -648,18 +714,40 @@ bool LLAppViewer::init()
mAlloc.setProfilingEnabled(gSavedSettings.getBOOL("MemProfiling"));
+#if LL_RECORD_VIEWER_STATS
+ LLViewerStatsRecorder::initClass();
+#endif
+
// *NOTE:Mani - LLCurl::initClass is not thread safe.
// Called before threads are created.
LLCurl::initClass();
LLMachineID::init();
+
+ {
+ // Viewer metrics initialization
+ static LLCachedControl<bool> metrics_submode(gSavedSettings,
+ "QAModeMetrics",
+ false,
+ "Enables QA features (logging, faster cycling) for metrics collector");
+
+ if (metrics_submode)
+ {
+ app_metrics_qa_mode = true;
+ app_metrics_interval = METRICS_INTERVAL_QA;
+ }
+ LLViewerAssetStatsFF::init();
+ }
initThreads();
writeSystemInfo();
- // Build a string representing the current version number.
- gCurrentVersion = llformat("%s %s",
- gSavedSettings.getString("VersionChannelName").c_str(),
- LLVersionInfo::getVersion().c_str());
+ // Initialize updater service (now that we have an io pump)
+ initUpdater();
+ if(isQuitting())
+ {
+ // Early out here because updater set the quitting flag.
+ return true;
+ }
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
@@ -672,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;
@@ -803,12 +891,18 @@ bool LLAppViewer::init()
return 1;
}
+ // Initialize the repeater service.
+ LLMainLoopRepeater::instance().start();
+
//
// Initialize the window
//
gGLActive = TRUE;
initWindow();
+ // initWindow also initializes the Feature List, so now we can initialize this global.
+ LLCubeMap::sUseCubeMaps = LLFeatureManager::getInstance()->isFeatureAvailable("RenderCubeMap");
+
// call all self-registered classes
LLInitClassList::instance().fireCallbacks();
@@ -817,19 +911,25 @@ bool LLAppViewer::init()
gGLManager.getGLInfo(gDebugInfo);
gGLManager.printGLInfoString();
- //load key settings
- bind_keyboard_functions();
-
// Load Default bindings
- if (!gViewerKeyboard.loadBindings(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"keys.ini")))
+ std::string key_bindings_file = gDirUtilp->findFile("keys.xml",
+ gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""),
+ gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
+
+
+ if (!gViewerKeyboard.loadBindingsXML(key_bindings_file))
{
- LL_ERRS("InitInfo") << "Unable to open keys.ini" << LL_ENDL;
+ std::string key_bindings_file = gDirUtilp->findFile("keys.ini",
+ gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""),
+ gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
+ if (!gViewerKeyboard.loadBindings(key_bindings_file))
+ {
+ LL_ERRS("InitInfo") << "Unable to open keys.ini" << LL_ENDL;
+ }
}
- // Load Custom bindings (override defaults)
- gViewerKeyboard.loadBindings(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"custom_keys.ini"));
// 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.
@@ -840,6 +940,18 @@ bool LLAppViewer::init()
return 0;
}
+ // Without SSE2 support we will crash almost immediately, warn here.
+ if (!gSysCPU.hasSSE2())
+ {
+ // can't use an alert here since we're exiting and
+ // all hell breaks lose.
+ OSMessageBox(
+ LLNotifications::instance().getGlobalString("UnsupportedCPUSSE2"),
+ LLStringUtil::null,
+ OSMB_OK);
+ return 0;
+ }
+
// alert the user if they are using unsupported hardware
if(!gSavedSettings.getBOOL("AlertedUnsupportedHardware"))
{
@@ -899,7 +1011,8 @@ bool LLAppViewer::init()
gDebugInfo["GraphicsCard"] = LLFeatureManager::getInstance()->getGPUString();
// Save the current version to the prefs file
- gSavedSettings.setString("LastRunVersion", gCurrentVersion);
+ gSavedSettings.setString("LastRunVersion",
+ LLVersionInfo::getChannelAndVersion());
gSimLastTime = gRenderStartTime.getElapsedTimeF32();
gSimFrames = (F32)gFrameCount;
@@ -943,6 +1056,8 @@ bool LLAppViewer::init()
LLAgentLanguage::init();
+
+
return true;
}
@@ -981,6 +1096,7 @@ bool LLAppViewer::mainLoop()
LLVoiceClient::getInstance()->init(gServicePump);
LLTimer frameTimer,idleTimer;
LLTimer debugTime;
+ LLFrameTimer memCheckTimer;
LLViewerJoystick* joystick(LLViewerJoystick::getInstance());
joystick->setNeedsReset(true);
@@ -991,11 +1107,29 @@ bool LLAppViewer::mainLoop()
// point of posting.
LLSD newFrame;
+ const F32 memory_check_interval = 1.0f ; //second
+
// Handle messages
while (!LLApp::isExiting())
{
LLFastTimer::nextFrame(); // Should be outside of any timer instances
+ //clear call stack records
+ llclearcallstacks;
+
+ //check memory availability information
+ {
+ if(memory_check_interval < memCheckTimer.getElapsedTimeF32())
+ {
+ memCheckTimer.reset() ;
+
+ //update the availability of memory
+ LLMemoryInfo::getAvailableMemoryKB(mAvailPhysicalMemInKB, mAvailVirtualMemInKB) ;
+ }
+ llcallstacks << "Available physical mem(KB): " << mAvailPhysicalMemInKB << llcallstacksendl ;
+ llcallstacks << "Available virtual mem(KB): " << mAvailVirtualMemInKB << llcallstacksendl ;
+ }
+
try
{
pingMainloopTimeout("Main:MiscNativeWindowEvents");
@@ -1097,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;
@@ -1125,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.
@@ -1199,6 +1333,7 @@ bool LLAppViewer::mainLoop()
break;
}
}
+ gMeshRepo.update() ;
if(!total_work_pending) //pause texture fetching threads if nothing to process.
{
@@ -1222,11 +1357,20 @@ bool LLAppViewer::mainLoop()
resumeMainloopTimeout();
pingMainloopTimeout("Main:End");
- }
-
+ }
}
catch(std::bad_alloc)
{
+ {
+ llinfos << "Availabe physical memory(KB) at the beginning of the frame: " << mAvailPhysicalMemInKB << llendl ;
+ llinfos << "Availabe virtual memory(KB) at the beginning of the frame: " << mAvailVirtualMemInKB << llendl ;
+
+ LLMemoryInfo::getAvailableMemoryKB(mAvailPhysicalMemInKB, mAvailVirtualMemInKB) ;
+
+ llinfos << "Current availabe physical memory(KB): " << mAvailPhysicalMemInKB << llendl ;
+ llinfos << "Current availabe virtual memory(KB): " << mAvailVirtualMemInKB << llendl ;
+ }
+
//stop memory leaking simulation
LLFloaterMemLeak* mem_leak_instance =
LLFloaterReg::findTypedInstance<LLFloaterMemLeak>("mem_leaking");
@@ -1275,11 +1419,40 @@ bool LLAppViewer::mainLoop()
return true;
}
+void LLAppViewer::flushVFSIO()
+{
+ while (1)
+ {
+ S32 pending = LLVFSThread::updateClass(0);
+ pending += LLLFSThread::updateClass(0);
+ if (!pending)
+ {
+ break;
+ }
+ llinfos << "Waiting for pending IO to finish: " << pending << llendflush;
+ ms_sleep(100);
+ }
+}
+
bool LLAppViewer::cleanup()
{
// workaround for DEV-35406 crash on shutdown
LLEventPumps::instance().reset();
+ if (LLFastTimerView::sAnalyzePerformance)
+ {
+ llinfos << "Analyzing performance" << llendl;
+ std::string baseline_name = LLFastTimer::sLogName + "_baseline.slp";
+ std::string current_name = LLFastTimer::sLogName + ".slp";
+ std::string report_name = LLFastTimer::sLogName + "_report.csv";
+
+ LLFastTimerView::doAnalysis(
+ gDirUtilp->getExpandedFilename(LL_PATH_LOGS, baseline_name),
+ gDirUtilp->getExpandedFilename(LL_PATH_LOGS, current_name),
+ gDirUtilp->getExpandedFilename(LL_PATH_LOGS, report_name));
+ }
+ LLMetricPerformanceTesterBasic::cleanClass();
+
// remove any old breakpad minidump files from the log directory
if (! isError())
{
@@ -1300,16 +1473,6 @@ bool LLAppViewer::cleanup()
}
mPlugins.clear();
- //----------------------------------------------
- //this test code will be removed after the test
- //test manual call stack tracer
- if(gSavedSettings.getBOOL("QAMode"))
- {
- LLError::LLCallStacks::print() ;
- }
- //end of the test code
- //----------------------------------------------
-
//flag all elements as needing to be destroyed immediately
// to ensure shutdown order
LLMortician::setZealous(TRUE);
@@ -1328,12 +1491,18 @@ bool LLAppViewer::cleanup()
llinfos << "Cleaning Up" << llendflush;
+ // shut down mesh streamer
+ gMeshRepo.shutdown();
+
// Must clean up texture references before viewer window is destroyed.
- LLHUDManager::getInstance()->updateEffects();
- LLHUDObject::updateAll();
- LLHUDManager::getInstance()->cleanupEffects();
- LLHUDObject::cleanupHUDObjects();
- llinfos << "HUD Objects cleaned up" << llendflush;
+ if(LLHUDManager::instanceExists())
+ {
+ LLHUDManager::getInstance()->updateEffects();
+ LLHUDObject::updateAll();
+ LLHUDManager::getInstance()->cleanupEffects();
+ LLHUDObject::cleanupHUDObjects();
+ llinfos << "HUD Objects cleaned up" << llendflush;
+ }
LLKeyframeDataCache::clear();
@@ -1345,8 +1514,10 @@ bool LLAppViewer::cleanup()
// Note: this is where gWorldMap used to be deleted.
// Note: this is where gHUDManager used to be deleted.
- LLHUDManager::getInstance()->shutdownClass();
-
+ if(LLHUDManager::instanceExists())
+ {
+ LLHUDManager::getInstance()->shutdownClass();
+ }
delete gAssetStorage;
gAssetStorage = NULL;
@@ -1409,17 +1580,7 @@ bool LLAppViewer::cleanup()
llinfos << "Cache files removed" << llendflush;
// Wait for any pending VFS IO
- while (1)
- {
- S32 pending = LLVFSThread::updateClass(0);
- pending += LLLFSThread::updateClass(0);
- if (!pending)
- {
- break;
- }
- llinfos << "Waiting for pending IO to finish: " << pending << llendflush;
- ms_sleep(100);
- }
+ flushVFSIO();
llinfos << "Shutting down Views" << llendflush;
// Destroy the UI
@@ -1594,13 +1755,15 @@ bool LLAppViewer::cleanup()
// Delete workers first
// shotdown all worker threads before deleting them in case of co-dependencies
- sTextureCache->shutdown();
sTextureFetch->shutdown();
+ sTextureCache->shutdown();
sImageDecodeThread->shutdown();
sTextureFetch->shutDownTextureCacheThread() ;
sTextureFetch->shutDownImageDecodeThread() ;
+ LLFilePickerThread::cleanupClass();
+
delete sTextureCache;
sTextureCache = NULL;
delete sTextureFetch;
@@ -1614,22 +1777,21 @@ bool LLAppViewer::cleanup()
{
llinfos << "Analyzing performance" << llendl;
- if(LLFastTimer::sLog)
- {
- LLFastTimerView::doAnalysis(
- gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "performance_baseline.slp"),
- gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "performance.slp"),
- gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "performance_report.csv"));
- }
- if(LLFastTimer::sMetricLog)
- {
- LLFastTimerView::doAnalysis(
- gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "metric_baseline.slp"),
- gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "metric.slp"),
- gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "metric_report.csv"));
- }
- }
- LLMetricPerformanceTester::cleanClass() ;
+ std::string baseline_name = LLFastTimer::sLogName + "_baseline.slp";
+ std::string current_name = LLFastTimer::sLogName + ".slp";
+ std::string report_name = LLFastTimer::sLogName + "_report.csv";
+
+ LLFastTimerView::doAnalysis(
+ gDirUtilp->getExpandedFilename(LL_PATH_LOGS, baseline_name),
+ gDirUtilp->getExpandedFilename(LL_PATH_LOGS, current_name),
+ gDirUtilp->getExpandedFilename(LL_PATH_LOGS, report_name));
+ }
+
+ LLMetricPerformanceTesterBasic::cleanClass() ;
+
+#if LL_RECORD_VIEWER_STATS
+ LLViewerStatsRecorder::cleanupClass();
+#endif
llinfos << "Cleaning up Media and Textures" << llendflush;
@@ -1648,7 +1810,10 @@ bool LLAppViewer::cleanup()
#ifndef LL_RELEASE_FOR_DOWNLOAD
llinfos << "Auditing VFS" << llendl;
- gVFS->audit();
+ if(gVFS)
+ {
+ gVFS->audit();
+ }
#endif
llinfos << "Misc Cleanup" << llendflush;
@@ -1666,6 +1831,8 @@ bool LLAppViewer::cleanup()
LLWatchdog::getInstance()->cleanup();
+ LLViewerAssetStatsFF::cleanup();
+
llinfos << "Shutting down message system" << llendflush;
end_messaging_system();
@@ -1689,8 +1856,12 @@ bool LLAppViewer::cleanup()
llinfos << "File launched." << llendflush;
}
+ LLMainLoopRepeater::instance().stop();
+
ll_close_fail_log();
+ MEM_TRACK_RELEASE
+
llinfos << "Goodbye!" << llendflush;
// return 0;
@@ -1730,16 +1901,24 @@ bool LLAppViewer::initThreads()
// Image decoding
LLAppViewer::sImageDecodeThread = new LLImageDecodeThread(enable_threads && true);
LLAppViewer::sTextureCache = new LLTextureCache(enable_threads && true);
- LLAppViewer::sTextureFetch = new LLTextureFetch(LLAppViewer::getTextureCache(), sImageDecodeThread, enable_threads && true);
+ LLAppViewer::sTextureFetch = new LLTextureFetch(LLAppViewer::getTextureCache(),
+ sImageDecodeThread,
+ enable_threads && true,
+ app_metrics_qa_mode);
LLImage::initClass();
if (LLFastTimer::sLog || LLFastTimer::sMetricLog)
{
LLFastTimer::sLogLock = new LLMutex(NULL);
- mFastTimerLogThread = new LLFastTimerLogThread();
+ mFastTimerLogThread = new LLFastTimerLogThread(LLFastTimer::sLogName);
mFastTimerLogThread->start();
}
+ // Mesh streaming and caching
+ gMeshRepo.init();
+
+ LLFilePickerThread::initClass();
+
// *FIX: no error handling here!
return true;
}
@@ -1786,85 +1965,80 @@ bool LLAppViewer::initLogging()
bool LLAppViewer::loadSettingsFromDirectory(const std::string& location_key,
bool set_defaults)
{
- // Find and vet the location key.
- if(!mSettingsLocationList.has(location_key))
+ if (!mSettingsLocationList)
{
- llerrs << "Requested unknown location: " << location_key << llendl;
- return false;
+ llerrs << "Invalid settings location list" << llendl;
}
- LLSD location = mSettingsLocationList.get(location_key);
-
- if(!location.has("PathIndex"))
- {
- llerrs << "Settings location is missing PathIndex value. Settings cannot be loaded." << llendl;
- return false;
- }
- ELLPath path_index = (ELLPath)(location.get("PathIndex").asInteger());
- if(path_index <= LL_PATH_NONE || path_index >= LL_PATH_LAST)
+ LLControlGroup* global_settings = LLControlGroup::getInstance(sGlobalSettingsName);
+ for(LLInitParam::ParamIterator<SettingsGroup>::const_iterator it = mSettingsLocationList->groups.begin(), end_it = mSettingsLocationList->groups.end();
+ it != end_it;
+ ++it)
{
- llerrs << "Out of range path index in app_settings/settings_files.xml" << llendl;
- return false;
- }
-
- // Iterate through the locations list of files.
- LLSD files = location.get("Files");
- for(LLSD::map_iterator itr = files.beginMap(); itr != files.endMap(); ++itr)
- {
- std::string settings_group = (*itr).first;
- llinfos << "Attempting to load settings for the group " << settings_group
- << " - from location " << location_key << llendl;
+ // skip settings groups that aren't the one we requested
+ if (it->name() != location_key) continue;
- if(!LLControlGroup::getInstance(settings_group))
+ ELLPath path_index = (ELLPath)it->path_index();
+ if(path_index <= LL_PATH_NONE || path_index >= LL_PATH_LAST)
{
- llwarns << "No matching settings group for name " << settings_group << llendl;
- continue;
+ llerrs << "Out of range path index in app_settings/settings_files.xml" << llendl;
+ return false;
}
- LLSD file = (*itr).second;
-
- std::string full_settings_path;
- if(file.has("NameFromSetting"))
+ LLInitParam::ParamIterator<SettingsFile>::const_iterator file_it, end_file_it;
+ for (file_it = it->files.begin(), end_file_it = it->files.end();
+ file_it != end_file_it;
+ ++file_it)
{
- std::string custom_name_setting = file.get("NameFromSetting");
- // *NOTE: Regardless of the group currently being lodaed,
- // this setting is always read from the Global settings.
- if(LLControlGroup::getInstance(sGlobalSettingsName)->controlExists(custom_name_setting))
+ llinfos << "Attempting to load settings for the group " << file_it->name()
+ << " - from location " << location_key << llendl;
+
+ LLControlGroup* settings_group = LLControlGroup::getInstance(file_it->name);
+ if(!settings_group)
{
- std::string file_name =
- LLControlGroup::getInstance(sGlobalSettingsName)->getString(custom_name_setting);
- full_settings_path = file_name;
+ llwarns << "No matching settings group for name " << file_it->name() << llendl;
+ continue;
}
- }
- if(full_settings_path.empty())
- {
- std::string file_name = file.get("Name");
- full_settings_path = gDirUtilp->getExpandedFilename(path_index, file_name);
- }
+ std::string full_settings_path;
- int requirement = 0;
- if(file.has("Requirement"))
- {
- requirement = file.get("Requirement").asInteger();
- }
-
- if(!LLControlGroup::getInstance(settings_group)->loadFromFile(full_settings_path, set_defaults))
- {
- if(requirement == 1)
+ if (file_it->file_name_setting.isProvided()
+ && global_settings->controlExists(file_it->file_name_setting))
{
- llwarns << "Error: Cannot load required settings file from: "
- << full_settings_path << llendl;
- return false;
+ // try to find filename stored in file_name_setting control
+ full_settings_path = global_settings->getString(file_it->file_name_setting);
+ if (!gDirUtilp->fileExists(full_settings_path))
+ {
+ // search in default path
+ full_settings_path = gDirUtilp->getExpandedFilename((ELLPath)path_index, full_settings_path);
+ }
}
else
{
- llinfos << "Cannot load " << full_settings_path << " - No settings found." << llendl;
+ // by default, use specified file name
+ full_settings_path = gDirUtilp->getExpandedFilename((ELLPath)path_index, file_it->file_name());
+ }
+
+ if(settings_group->loadFromFile(full_settings_path, set_defaults, file_it->persistent))
+ { // success!
+ llinfos << "Loaded settings file " << full_settings_path << llendl;
+ }
+ else
+ { // failed to load
+ if(file_it->required)
+ {
+ llerrs << "Error: Cannot load required settings file from: " << full_settings_path << llendl;
+ return false;
+ }
+ else
+ {
+ // only complain if we actually have a filename at this point
+ if (!full_settings_path.empty())
+ {
+ llinfos << "Cannot load " << full_settings_path << " - No settings found." << llendl;
+ }
+ }
}
- }
- else
- {
- llinfos << "Loaded settings file " << full_settings_path << llendl;
}
}
@@ -1874,18 +2048,25 @@ bool LLAppViewer::loadSettingsFromDirectory(const std::string& location_key,
std::string LLAppViewer::getSettingsFilename(const std::string& location_key,
const std::string& file)
{
- if(mSettingsLocationList.has(location_key))
+ for(LLInitParam::ParamIterator<SettingsGroup>::const_iterator it = mSettingsLocationList->groups.begin(), end_it = mSettingsLocationList->groups.end();
+ it != end_it;
+ ++it)
{
- LLSD location = mSettingsLocationList.get(location_key);
- if(location.has("Files"))
+ if (it->name() == location_key)
{
- LLSD files = location.get("Files");
- if(files.has(file) && files[file].has("Name"))
+ LLInitParam::ParamIterator<SettingsFile>::const_iterator file_it, end_file_it;
+ for (file_it = it->files.begin(), end_file_it = it->files.end();
+ file_it != end_file_it;
+ ++file_it)
{
- return files.get(file).get("Name").asString();
+ if (file_it->name() == file)
+ {
+ return file_it->file_name;
+ }
}
}
}
+
return std::string();
}
@@ -1898,14 +2079,29 @@ bool LLAppViewer::initConfiguration()
{
//Load settings files list
std::string settings_file_list = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "settings_files.xml");
- LLControlGroup settings_control("SettingsFiles");
- llinfos << "Loading settings file list " << settings_file_list << llendl;
- if (0 == settings_control.loadFromFile(settings_file_list))
+ //LLControlGroup settings_control("SettingsFiles");
+ //llinfos << "Loading settings file list " << settings_file_list << llendl;
+ //if (0 == settings_control.loadFromFile(settings_file_list))
+ //{
+ // llerrs << "Cannot load default configuration file " << settings_file_list << llendl;
+ //}
+
+ LLXMLNodePtr root;
+ BOOL success = LLXMLNode::parseFile(settings_file_list, root, NULL);
+ if (!success)
{
llerrs << "Cannot load default configuration file " << settings_file_list << llendl;
}
- mSettingsLocationList = settings_control.getLLSD("Locations");
+ mSettingsLocationList = new SettingsFiles();
+
+ LLXUIParser parser;
+ parser.readXUI(root, *mSettingsLocationList, settings_file_list);
+
+ if (!mSettingsLocationList->validateBlock())
+ {
+ llerrs << "Invalid settings file list " << settings_file_list << llendl;
+ }
// The settings and command line parsing have a fragile
// order-of-operation:
@@ -2016,9 +2212,44 @@ bool LLAppViewer::initConfiguration()
// - load overrides from user_settings
loadSettingsFromDirectory("User");
+
+ if (gSavedSettings.getBOOL("FirstRunThisInstall"))
+ {
+ gSavedSettings.setString("SessionSettingsFile", "settings_minimal.xml");
+ gSavedSettings.setBOOL("FirstRunThisInstall", FALSE);
+ }
+
+ if (clp.hasOption("sessionsettings"))
+ {
+ std::string session_settings_filename = clp.getOption("sessionsettings")[0];
+ gSavedSettings.setString("SessionSettingsFile", session_settings_filename);
+ llinfos << "Using session settings filename: "
+ << session_settings_filename << llendl;
+ }
+ loadSettingsFromDirectory("Session");
+
+ if (clp.hasOption("usersessionsettings"))
+ {
+ std::string user_session_settings_filename = clp.getOption("usersessionsettings")[0];
+ gSavedSettings.setString("UserSessionSettingsFile", user_session_settings_filename);
+ llinfos << "Using user session settings filename: "
+ << user_session_settings_filename << llendl;
+
+ }
+ loadSettingsFromDirectory("UserSession");
+
// - apply command line settings
clp.notify();
+ // Register the core crash option as soon as we can
+ // if we want gdb post-mortem on cores we need to be up and running
+ // ASAP or we might miss init issue etc.
+ if(clp.hasOption("disablecrashlogger"))
+ {
+ llwarns << "Crashes will be handled by system, stack trace logs and crash logger are both disabled" << llendl;
+ LLAppViewer::instance()->disableCrashlogger();
+ }
+
// Handle initialization from settings.
// Start up the debugging console before handling other options.
if (gSavedSettings.getBOOL("ShowConsoleWindow"))
@@ -2068,6 +2299,10 @@ bool LLAppViewer::initConfiguration()
}
}
+ if(clp.hasOption("channel"))
+ {
+ LLVersionInfo::resetChannel(clp.getOption("channel")[0]);
+ }
// If we have specified crash on startup, set the global so we'll trigger the crash at the right time
if(clp.hasOption("crashonstartup"))
@@ -2078,12 +2313,26 @@ bool LLAppViewer::initConfiguration()
if (clp.hasOption("logperformance"))
{
LLFastTimer::sLog = TRUE;
+ LLFastTimer::sLogName = std::string("performance");
}
- if(clp.hasOption("logmetrics"))
- {
- LLFastTimer::sMetricLog = TRUE ;
- }
+ if (clp.hasOption("logmetrics"))
+ {
+ LLFastTimer::sMetricLog = TRUE ;
+ // '--logmetrics' can be specified with a named test metric argument so the data gathering is done only on that test
+ // In the absence of argument, every metric is gathered (makes for a rather slow run and hard to decipher report...)
+ std::string test_name = clp.getOption("logmetrics")[0];
+ llinfos << "'--logmetrics' argument : " << test_name << llendl;
+ if (test_name == "")
+ {
+ llwarns << "No '--logmetrics' argument given, will output all metrics to " << DEFAULT_METRIC_NAME << llendl;
+ LLFastTimer::sLogName = DEFAULT_METRIC_NAME;
+ }
+ else
+ {
+ LLFastTimer::sLogName = test_name;
+ }
+ }
if (clp.hasOption("graphicslevel"))
{
@@ -2126,12 +2375,12 @@ bool LLAppViewer::initConfiguration()
if (clp.hasOption("replaysession"))
{
- LLAgentPilot::sReplaySession = TRUE;
+ gAgentPilot.setReplaySession(TRUE);
}
if (clp.hasOption("nonotifications"))
{
- gSavedSettings.setBOOL("IgnoreAllNotifications", TRUE);
+ gSavedSettings.getControl("IgnoreAllNotifications")->setValue(true, false);
}
if (clp.hasOption("debugsession"))
@@ -2178,8 +2427,8 @@ bool LLAppViewer::initConfiguration()
if(skinfolder && LLStringUtil::null != skinfolder->getValue().asString())
{
// hack to force the skin to default.
- //gDirUtilp->setSkinFolder(skinfolder->getValue().asString());
- gDirUtilp->setSkinFolder("default");
+ gDirUtilp->setSkinFolder(skinfolder->getValue().asString());
+ //gDirUtilp->setSkinFolder("default");
}
mYieldTime = gSavedSettings.getS32("YieldTime");
@@ -2262,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"))
{
//
@@ -2323,6 +2580,163 @@ bool LLAppViewer::initConfiguration()
return true; // Config was successful.
}
+namespace {
+ // *TODO - decide if there's a better place for these functions.
+ // do we need a file llupdaterui.cpp or something? -brad
+
+ void apply_update_callback(LLSD const & notification, LLSD const & response)
+ {
+ lldebugs << "LLUpdate user response: " << response << llendl;
+ if(response["OK_okcancelbuttons"].asBoolean())
+ {
+ llinfos << "LLUpdate restarting viewer" << llendl;
+ static const bool install_if_ready = true;
+ // *HACK - this lets us launch the installer immediately for now
+ LLUpdaterService().startChecking(install_if_ready);
+ }
+ }
+
+ void apply_update_ok_callback(LLSD const & notification, LLSD const & response)
+ {
+ llinfos << "LLUpdate restarting viewer" << llendl;
+ static const bool install_if_ready = true;
+ // *HACK - this lets us launch the installer immediately for now
+ LLUpdaterService().startChecking(install_if_ready);
+ }
+
+ void on_update_downloaded(LLSD const & data)
+ {
+ std::string notification_name;
+ void (*apply_callback)(LLSD const &, LLSD const &) = NULL;
+
+ if(data["required"].asBoolean())
+ {
+ if(LLStartUp::getStartupState() <= STATE_LOGIN_WAIT)
+ {
+ // The user never saw the progress bar.
+ apply_callback = &apply_update_ok_callback;
+ notification_name = "RequiredUpdateDownloadedVerboseDialog";
+ }
+ else if(LLStartUp::getStartupState() < STATE_WORLD_INIT)
+ {
+ // The user is logging in but blocked.
+ apply_callback = &apply_update_ok_callback;
+ notification_name = "RequiredUpdateDownloadedDialog";
+ }
+ else
+ {
+ // The user is already logged in; treat like an optional update.
+ apply_callback = &apply_update_callback;
+ notification_name = "DownloadBackgroundTip";
+ }
+ }
+ else
+ {
+ apply_callback = &apply_update_callback;
+ if(LLStartUp::getStartupState() < STATE_STARTED)
+ {
+ // CHOP-262 we need to use a different notification
+ // method prior to login.
+ notification_name = "DownloadBackgroundDialog";
+ }
+ else
+ {
+ notification_name = "DownloadBackgroundTip";
+ }
+ }
+
+ LLSD substitutions;
+ substitutions["VERSION"] = data["version"];
+
+ // truncate version at the rightmost '.'
+ std::string version_short(data["version"]);
+ size_t short_length = version_short.rfind('.');
+ if (short_length != std::string::npos)
+ {
+ version_short.resize(short_length);
+ }
+
+ LLUIString relnotes_url("[RELEASE_NOTES_BASE_URL][CHANNEL_URL]/[VERSION_SHORT]");
+ relnotes_url.setArg("[VERSION_SHORT]", version_short);
+
+ // *TODO thread the update service's response through to this point
+ std::string const & channel = LLVersionInfo::getChannel();
+ boost::shared_ptr<char> channel_escaped(curl_escape(channel.c_str(), channel.size()), &curl_free);
+
+ relnotes_url.setArg("[CHANNEL_URL]", channel_escaped.get());
+ relnotes_url.setArg("[RELEASE_NOTES_BASE_URL]", LLTrans::getString("RELEASE_NOTES_BASE_URL"));
+ substitutions["RELEASE_NOTES_FULL_URL"] = relnotes_url.getString();
+
+ LLNotificationsUtil::add(notification_name, substitutions, LLSD(), apply_callback);
+ }
+
+ void install_error_callback(LLSD const & notification, LLSD const & response)
+ {
+ LLAppViewer::instance()->forceQuit();
+ }
+
+ bool notify_update(LLSD const & evt)
+ {
+ std::string notification_name;
+ switch (evt["type"].asInteger())
+ {
+ case LLUpdaterService::DOWNLOAD_COMPLETE:
+ on_update_downloaded(evt);
+ break;
+ case LLUpdaterService::INSTALL_ERROR:
+ if(evt["required"].asBoolean()) {
+ LLNotificationsUtil::add("FailedRequiredUpdateInstall", LLSD(), LLSD(), &install_error_callback);
+ } else {
+ LLNotificationsUtil::add("FailedUpdateInstall");
+ }
+ break;
+ default:
+ break;
+ }
+
+ // let others also handle this event by default
+ return false;
+ }
+
+ bool on_bandwidth_throttle(LLUpdaterService * updater, LLSD const & evt)
+ {
+ updater->setBandwidthLimit(evt.asInteger() * (1024/8));
+ return false; // Let others receive this event.
+ };
+};
+
+void LLAppViewer::initUpdater()
+{
+ // Initialize the updater service.
+ // Generate URL to the udpater service
+ // Get Channel
+ // Get Version
+ std::string url = gSavedSettings.getString("UpdaterServiceURL");
+ std::string channel = LLVersionInfo::getChannel();
+ std::string version = LLVersionInfo::getVersion();
+ std::string protocol_version = gSavedSettings.getString("UpdaterServiceProtocolVersion");
+ std::string service_path = gSavedSettings.getString("UpdaterServicePath");
+ U32 check_period = gSavedSettings.getU32("UpdaterServiceCheckPeriod");
+
+ mUpdater->setAppExitCallback(boost::bind(&LLAppViewer::forceQuit, this));
+ mUpdater->initialize(protocol_version,
+ url,
+ service_path,
+ channel,
+ version);
+ mUpdater->setCheckPeriod(check_period);
+ mUpdater->setBandwidthLimit((int)gSavedSettings.getF32("UpdaterMaximumBandwidth") * (1024/8));
+ gSavedSettings.getControl("UpdaterMaximumBandwidth")->getSignal()->
+ connect(boost::bind(&on_bandwidth_throttle, mUpdater.get(), _2));
+ if(gSavedSettings.getU32("UpdaterServiceSetting"))
+ {
+ bool install_if_ready = true;
+ mUpdater->startChecking(install_if_ready);
+ }
+
+ LLEventPump & updater_pump = LLEventPumps::instance().obtain(LLUpdaterService::pumpName());
+ updater_pump.listen("notify_update", &notify_update);
+}
void LLAppViewer::checkForCrash(void)
{
@@ -2369,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");
@@ -2382,13 +2810,14 @@ bool LLAppViewer::initWindow()
VIEWER_WINDOW_CLASSNAME,
gSavedSettings.getS32("WindowX"), gSavedSettings.getS32("WindowY"),
gSavedSettings.getS32("WindowWidth"), gSavedSettings.getS32("WindowHeight"),
- FALSE, ignorePixelDepth);
+ gSavedSettings.getBOOL("WindowFullScreen"), ignorePixelDepth);
// Need to load feature table before cheking to start watchdog.
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
@@ -2410,28 +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();
- stop_glerror();
- gViewerWindow->initGLDefaults();
+ gPipeline.init();
+
+ 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)
@@ -2439,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
@@ -2473,25 +2915,25 @@ 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
// as we don't track it in callbacks
- BOOL maximized = gViewerWindow->mWindow->getMaximized();
- if (!maximized)
+ if(NULL != gViewerWindow)
{
- LLCoordScreen window_pos;
-
- if (gViewerWindow->mWindow->getPosition(&window_pos))
+ BOOL maximized = gViewerWindow->mWindow->getMaximized();
+ if (!maximized)
{
- gSavedSettings.setS32("WindowX", window_pos.mX);
- gSavedSettings.setS32("WindowY", window_pos.mY);
+ LLCoordScreen window_pos;
+
+ if (gViewerWindow->mWindow->getPosition(&window_pos))
+ {
+ gSavedSettings.setS32("WindowX", window_pos.mX);
+ gSavedSettings.setS32("WindowY", window_pos.mY);
+ }
}
}
@@ -2514,7 +2956,7 @@ void LLAppViewer::writeSystemInfo()
{
gDebugInfo["SLLog"] = LLError::logFileName();
- gDebugInfo["ClientInfo"]["Name"] = gSavedSettings.getString("VersionChannelName");
+ gDebugInfo["ClientInfo"]["Name"] = LLVersionInfo::getChannel();
gDebugInfo["ClientInfo"]["MajorVersion"] = LLVersionInfo::getMajor();
gDebugInfo["ClientInfo"]["MinorVersion"] = LLVersionInfo::getMinor();
gDebugInfo["ClientInfo"]["PatchVersion"] = LLVersionInfo::getPatch();
@@ -2576,6 +3018,8 @@ void LLAppViewer::writeSystemInfo()
LL_INFOS("SystemInfo") << "OS: " << getOSInfo().getOSStringSimple() << LL_ENDL;
LL_INFOS("SystemInfo") << "OS info: " << getOSInfo() << LL_ENDL;
+ LL_INFOS("SystemInfo") << "Timers: " << LLFastTimer::sClockType << LL_ENDL;
+
writeDebugInfo(); // Save out debug_info.log early, in case of crash.
}
@@ -2595,6 +3039,11 @@ void LLAppViewer::handleViewerCrash()
abort();
}
+ if (LLApp::isCrashloggerDisabled())
+ {
+ abort();
+ }
+
// Returns whether a dialog was shown.
// Only do the logic in here once
if (pApp->mReportedCrash)
@@ -2612,7 +3061,7 @@ void LLAppViewer::handleViewerCrash()
//We already do this in writeSystemInfo(), but we do it again here to make /sure/ we have a version
//to check against no matter what
- gDebugInfo["ClientInfo"]["Name"] = gSavedSettings.getString("VersionChannelName");
+ gDebugInfo["ClientInfo"]["Name"] = LLVersionInfo::getChannel();
gDebugInfo["ClientInfo"]["MajorVersion"] = LLVersionInfo::getMajor();
gDebugInfo["ClientInfo"]["MinorVersion"] = LLVersionInfo::getMinor();
@@ -2733,8 +3182,10 @@ void LLAppViewer::handleViewerCrash()
pApp->removeMarkerFile(false);
}
+#if LL_SEND_CRASH_REPORTS
// Call to pure virtual, handled by platform specific llappviewer instance.
pApp->handleCrashReporting();
+#endif
return;
}
@@ -2791,35 +3242,32 @@ void LLAppViewer::initMarkerFile()
std::string llerror_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LLERROR_MARKER_FILE_NAME);
std::string error_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ERROR_MARKER_FILE_NAME);
-
if (LLAPRFile::isExist(mMarkerFileName, NULL, LL_APR_RB) && !anotherInstanceRunning())
{
gLastExecEvent = LAST_EXEC_FROZE;
LL_INFOS("MarkerFile") << "Exec marker found: program froze on previous execution" << LL_ENDL;
}
-
if(LLAPRFile::isExist(logout_marker_file, NULL, LL_APR_RB))
{
- LL_INFOS("MarkerFile") << "Last exec LLError crashed, setting LastExecEvent to " << LAST_EXEC_LLERROR_CRASH << LL_ENDL;
gLastExecEvent = LAST_EXEC_LOGOUT_FROZE;
+ LL_INFOS("MarkerFile") << "Last exec LLError crashed, setting LastExecEvent to " << gLastExecEvent << LL_ENDL;
+ LLAPRFile::remove(logout_marker_file);
}
if(LLAPRFile::isExist(llerror_marker_file, NULL, LL_APR_RB))
{
- llinfos << "Last exec LLError crashed, setting LastExecEvent to " << LAST_EXEC_LLERROR_CRASH << llendl;
if(gLastExecEvent == LAST_EXEC_LOGOUT_FROZE) gLastExecEvent = LAST_EXEC_LOGOUT_CRASH;
else gLastExecEvent = LAST_EXEC_LLERROR_CRASH;
+ LL_INFOS("MarkerFile") << "Last exec LLError crashed, setting LastExecEvent to " << gLastExecEvent << LL_ENDL;
+ LLAPRFile::remove(llerror_marker_file);
}
if(LLAPRFile::isExist(error_marker_file, NULL, LL_APR_RB))
{
- LL_INFOS("MarkerFile") << "Last exec crashed, setting LastExecEvent to " << LAST_EXEC_OTHER_CRASH << LL_ENDL;
if(gLastExecEvent == LAST_EXEC_LOGOUT_FROZE) gLastExecEvent = LAST_EXEC_LOGOUT_CRASH;
else gLastExecEvent = LAST_EXEC_OTHER_CRASH;
+ LL_INFOS("MarkerFile") << "Last exec crashed, setting LastExecEvent to " << gLastExecEvent << LL_ENDL;
+ LLAPRFile::remove(error_marker_file);
}
-
- LLAPRFile::remove(logout_marker_file);
- LLAPRFile::remove(llerror_marker_file);
- LLAPRFile::remove(error_marker_file);
-
+
// No new markers if another instance is running.
if(anotherInstanceRunning())
{
@@ -2869,6 +3317,23 @@ void LLAppViewer::forceQuit()
LLApp::setQuitting();
}
+//TODO: remove
+void LLAppViewer::fastQuit(S32 error_code)
+{
+ // finish pending transfers
+ flushVFSIO();
+ // let sim know we're logging out
+ sendLogoutRequest();
+ // flush network buffers by shutting down messaging system
+ end_messaging_system();
+ // figure out the error code
+ S32 final_error_code = error_code ? error_code : (S32)isError();
+ // this isn't a crash
+ removeMarkerFile();
+ // get outta here
+ _exit(final_error_code);
+}
+
void LLAppViewer::requestQuit()
{
llinfos << "requestQuit" << llendl;
@@ -2877,11 +3342,21 @@ void LLAppViewer::requestQuit()
if( (LLStartUp::getStartupState() < STATE_STARTED) || !region )
{
+ // If we have a region, make some attempt to send a logout request first.
+ // This prevents the halfway-logged-in avatar from hanging around inworld for a couple minutes.
+ if(region)
+ {
+ sendLogoutRequest();
+ }
+
// Quit immediately
forceQuit();
return;
}
+ // Try to send metrics back to the grid
+ metricsSend(!gDisconnected);
+
LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral*)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE);
effectp->setPositionGlobal(gAgent.getPositionGlobal());
effectp->setColor(LLColor4U(gAgent.getEffectColor()));
@@ -2916,9 +3391,23 @@ static bool finish_quit(const LLSD& notification, const LLSD& response)
}
static LLNotificationFunctorRegistration finish_quit_reg("ConfirmQuit", finish_quit);
+static bool switch_standard_skin_and_quit(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+
+ if (option == 0)
+ {
+ gSavedSettings.setString("SessionSettingsFile", "");
+ LLAppViewer::instance()->requestQuit();
+ }
+ return false;
+}
+
+static LLNotificationFunctorRegistration standard_skin_quit_reg("SwitchToStandardSkinAndQuit", switch_standard_skin_and_quit);
+
void LLAppViewer::userQuit()
{
- if (gDisconnected)
+ if (gDisconnected || gViewerWindow->getProgressView()->getVisible())
{
requestQuit();
}
@@ -2941,12 +3430,12 @@ void LLAppViewer::earlyExit(const std::string& name, const LLSD& substitutions)
LLNotificationsUtil::add(name, substitutions, LLSD(), finish_early_exit);
}
-void LLAppViewer::forceExit(S32 arg)
+// case where we need the viewer to exit without any need for notifications
+void LLAppViewer::earlyExitNoNotify()
{
- removeMarkerFile();
-
- // *FIX:Mani - This kind of exit hardly seems appropriate.
- exit(arg);
+ llwarns << "app_early_exit with no notification: " << llendl;
+ gDoDisconnect = TRUE;
+ finish_early_exit( LLSD(), LLSD() );
}
void LLAppViewer::abortQuit()
@@ -2990,7 +3479,9 @@ void LLAppViewer::migrateCacheDirectory()
S32 file_count = 0;
std::string file_name;
std::string mask = delimiter + "*.*";
- while (gDirUtilp->getNextFileInDir(old_cache_dir, mask, file_name, false))
+
+ LLDirIterator iter(old_cache_dir, mask);
+ while (iter.next(file_name))
{
if (file_name == "." || file_name == "..") continue;
std::string source_path = old_cache_dir + delimiter + file_name;
@@ -3089,10 +3580,10 @@ bool LLAppViewer::initCache()
LLAppViewer::getTextureCache()->setReadOnly(read_only) ;
LLVOCache::getInstance()->setReadOnly(read_only);
- BOOL texture_cache_mismatch = FALSE ;
+ bool texture_cache_mismatch = false;
if (gSavedSettings.getS32("LocalCacheVersion") != LLAppViewer::getTextureCacheVersion())
{
- texture_cache_mismatch = TRUE ;
+ texture_cache_mismatch = true;
if(!read_only)
{
gSavedSettings.setS32("LocalCacheVersion", LLAppViewer::getTextureCacheVersion());
@@ -3106,7 +3597,9 @@ bool LLAppViewer::initCache()
gSavedSettings.getBOOL("PurgeCacheOnNextStartup"))
{
gSavedSettings.setBOOL("PurgeCacheOnNextStartup", false);
- mPurgeCache = true;
+ mPurgeCache = true;
+ // STORM-1141 force purgeAllTextures to get called to prevent a crash here. -brad
+ texture_cache_mismatch = true;
}
// We have moved the location of the cache directory over time.
@@ -3209,7 +3702,8 @@ bool LLAppViewer::initCache()
dir = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,"");
std::string found_file;
- if (gDirUtilp->getNextFileInDir(dir, mask, found_file, false))
+ LLDirIterator iter(dir, mask);
+ if (iter.next(found_file))
{
old_vfs_data_file = dir + gDirUtilp->getDirDelimiter() + found_file;
@@ -3411,7 +3905,7 @@ void LLAppViewer::badNetworkHandler()
// is destroyed.
void LLAppViewer::saveFinalSnapshot()
{
- if (!mSavedFinalSnapshot && !gNoRender)
+ if (!mSavedFinalSnapshot)
{
gSavedSettings.setVector3d("FocusPosOnLogout", gAgentCamera.calcFocusPositionTargetGlobal());
gSavedSettings.setVector3d("CameraPosOnLogout", gAgentCamera.calcCameraPositionTargetGlobal());
@@ -3434,6 +3928,7 @@ void LLAppViewer::loadNameCache()
// display names cache
std::string filename =
gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "avatar_name_cache.xml");
+ LL_INFOS("AvNameCache") << filename << LL_ENDL;
llifstream name_cache_stream(filename);
if(name_cache_stream.is_open())
{
@@ -3497,6 +3992,8 @@ static LLFastTimer::DeclareTimer FTM_OBJECTLIST_UPDATE("Update Objectlist");
static LLFastTimer::DeclareTimer FTM_REGION_UPDATE("Update Region");
static LLFastTimer::DeclareTimer FTM_WORLD_UPDATE("Update World");
static LLFastTimer::DeclareTimer FTM_NETWORK("Network");
+static LLFastTimer::DeclareTimer FTM_AGENT_NETWORK("Agent Network");
+static LLFastTimer::DeclareTimer FTM_VLMANAGER("VL Manager");
///////////////////////////////////////////////////////
// idle()
@@ -3517,6 +4014,8 @@ void LLAppViewer::idle()
LLEventTimer::updateClass();
LLCriticalDamp::updateInterpolants();
LLMortician::updateClass();
+ LLFilePickerThread::clearDead(); //calls LLFilePickerThread::notify()
+
F32 dt_raw = idle_timer.getElapsedTimeAndResetF32();
// Cap out-of-control frame times
@@ -3542,6 +4041,18 @@ void LLAppViewer::idle()
}
}
+ // debug setting to quit after N seconds of being AFK - 0 to never do this
+ F32 qas_afk = gSavedSettings.getF32("QuitAfterSecondsOfAFK");
+ if (qas_afk > 0.f)
+ {
+ // idle time is more than setting
+ if ( gAwayTriggerTimer.getElapsedTimeF32() > qas_afk )
+ {
+ // go ahead and just quit gracefully
+ LLAppViewer::instance()->requestQuit();
+ }
+ }
+
// Must wait until both have avatar object and mute list, so poll
// here.
request_initial_instant_messages();
@@ -3647,6 +4158,11 @@ void LLAppViewer::idle()
llinfos << "Unknown object updates: " << gObjectList.mNumUnknownUpdates << llendl;
gObjectList.mNumUnknownUpdates = 0;
}
+
+ // ViewerMetrics FPS piggy-backing on the debug timer.
+ // The 5-second interval is nice for this purpose. If the object debug
+ // bit moves or is disabled, please give this a suitable home.
+ LLViewerAssetStatsFF::record_fps_main(gFPSClamped);
}
}
@@ -3689,6 +4205,18 @@ void LLAppViewer::idle()
gInventory.idleNotifyObservers();
}
+ // Metrics logging (LLViewerAssetStats, etc.)
+ {
+ static LLTimer report_interval;
+
+ // *TODO: Add configuration controls for this
+ if (report_interval.getElapsedTimeF32() >= app_metrics_interval)
+ {
+ metricsSend(! gDisconnected);
+ report_interval.reset();
+ }
+ }
+
if (gDisconnected)
{
return;
@@ -3785,34 +4313,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);
}
//////////////////////////////////////
@@ -3821,16 +4346,17 @@ 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 (LLViewerJoystick::getInstance()->getOverrideCamera())
+ if (gAgentPilot.isPlaying() && gAgentPilot.getOverrideCamera())
{
+ gAgentPilot.moveCamera();
+ }
+ else if (LLViewerJoystick::getInstance()->getOverrideCamera())
+ {
LLViewerJoystick::getInstance()->moveFlycam();
}
else
@@ -3978,7 +4504,10 @@ void LLAppViewer::sendLogoutRequest()
gLogoutMaxTime = LOGOUT_REQUEST_TIME;
mLogoutRequestSent = TRUE;
- LLVoiceClient::getInstance()->leaveChannel();
+ if(LLVoiceClient::instanceExists())
+ {
+ LLVoiceClient::getInstance()->leaveChannel();
+ }
//Set internal status variables and marker files
gLogoutInProgress = TRUE;
@@ -4065,6 +4594,11 @@ static F32 CheckMessagesMaxTime = CHECK_MESSAGES_DEFAULT_MAX_TIME;
#endif
static LLFastTimer::DeclareTimer FTM_IDLE_NETWORK("Idle Network");
+static LLFastTimer::DeclareTimer FTM_MESSAGE_ACKS("Message Acks");
+static LLFastTimer::DeclareTimer FTM_RETRANSMIT("Retransmit");
+static LLFastTimer::DeclareTimer FTM_TIMEOUT_CHECK("Timeout Check");
+static LLFastTimer::DeclareTimer FTM_DYNAMIC_THROTTLE("Dynamic Throttle");
+static LLFastTimer::DeclareTimer FTM_CHECK_REGION_CIRCUIT("Check Region Circuit");
void LLAppViewer::idleNetwork()
{
@@ -4190,12 +4724,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())
@@ -4225,13 +4756,20 @@ void LLAppViewer::disconnectViewer()
// This is where we used to call gObjectList.destroy() and then delete gWorldp.
// Now we just ask the LLWorld singleton to cleanly shut down.
- LLWorld::getInstance()->destroyClass();
+ if(LLWorld::instanceExists())
+ {
+ LLWorld::getInstance()->destroyClass();
+ }
// call all self-registered classes
LLDestroyClassList::instance().fireCallbacks();
cleanup_xfer_manager();
gDisconnected = TRUE;
+
+ // Pass the connection state to LLUrlEntryParcel not to attempt
+ // parcel info requests while disconnected.
+ LLUrlEntryParcel::setDisconnected(gDisconnected);
}
void LLAppViewer::forceErrorLLError()
@@ -4339,7 +4877,7 @@ void LLAppViewer::handleLoginComplete()
initMainloopTimeout("Mainloop Init");
// Store some data to DebugInfo in case of a freeze.
- gDebugInfo["ClientInfo"]["Name"] = gSavedSettings.getString("VersionChannelName");
+ gDebugInfo["ClientInfo"]["Name"] = LLVersionInfo::getChannel();
gDebugInfo["ClientInfo"]["MajorVersion"] = LLVersionInfo::getMajor();
gDebugInfo["ClientInfo"]["MinorVersion"] = LLVersionInfo::getMinor();
@@ -4399,6 +4937,35 @@ void LLAppViewer::loadEventHostModule(S32 listen_port)
return;
}
+ LL_INFOS("eventhost") << "Found lleventhost at '" << dso_path << "'" << LL_ENDL;
+#if ! defined(LL_WINDOWS)
+ {
+ std::string outfile("/tmp/lleventhost.file.out");
+ std::string command("file '" + dso_path + "' > '" + outfile + "' 2>&1");
+ int rc = system(command.c_str());
+ if (rc != 0)
+ {
+ LL_WARNS("eventhost") << command << " ==> " << rc << ':' << LL_ENDL;
+ }
+ else
+ {
+ LL_INFOS("eventhost") << command << ':' << LL_ENDL;
+ }
+ {
+ std::ifstream reader(outfile.c_str());
+ std::string line;
+ while (std::getline(reader, line))
+ {
+ size_t len = line.length();
+ if (len && line[len-1] == '\n')
+ line.erase(len-1);
+ LL_INFOS("eventhost") << line << LL_ENDL;
+ }
+ }
+ remove(outfile.c_str());
+ }
+#endif // LL_WINDOWS
+
apr_dso_handle_t * eventhost_dso_handle = NULL;
apr_pool_t * eventhost_dso_memory_pool = NULL;
@@ -4407,13 +4974,13 @@ void LLAppViewer::loadEventHostModule(S32 listen_port)
apr_status_t rv = apr_dso_load(&eventhost_dso_handle,
dso_path.c_str(),
eventhost_dso_memory_pool);
- ll_apr_assert_status(rv);
+ llassert_always(! ll_apr_warn_status(rv, eventhost_dso_handle));
llassert_always(eventhost_dso_handle != NULL);
int (*ll_plugin_start_func)(LLSD const &) = NULL;
rv = apr_dso_sym((apr_dso_handle_sym_t*)&ll_plugin_start_func, eventhost_dso_handle, "ll_plugin_start");
- ll_apr_assert_status(rv);
+ llassert_always(! ll_apr_warn_status(rv, eventhost_dso_handle));
llassert_always(ll_plugin_start_func != NULL);
LLSD args;
@@ -4445,7 +5012,7 @@ void LLAppViewer::launchUpdater()
// *TODO change userserver to be grid on both viewer and sim, since
// userserver no longer exists.
query_map["userserver"] = LLGridManager::getInstance()->getGridLabel();
- query_map["channel"] = gSavedSettings.getString("VersionChannelName");
+ query_map["channel"] = LLVersionInfo::getChannel();
// *TODO constantize this guy
// *NOTE: This URL is also used in win_setup/lldownloader.cpp
LLURI update_url = LLURI::buildHTTP("secondlife.com", 80, "update.php", query_map);
@@ -4513,6 +5080,8 @@ void LLAppViewer::launchUpdater()
LLAppViewer::sUpdaterInfo->mUpdateExePath += update_url.asString();
LLAppViewer::sUpdaterInfo->mUpdateExePath += "\" -name \"";
LLAppViewer::sUpdaterInfo->mUpdateExePath += LLAppViewer::instance()->getSecondLifeTitle();
+ LLAppViewer::sUpdaterInfo->mUpdateExePath += "\" -bundleid \"";
+ LLAppViewer::sUpdaterInfo->mUpdateExePath += LL_VERSION_BUNDLE_ID;
LLAppViewer::sUpdaterInfo->mUpdateExePath += "\" &";
LL_DEBUGS("AppInit") << "Calling updater: " << LLAppViewer::sUpdaterInfo->mUpdateExePath << LL_ENDL;
@@ -4583,3 +5152,75 @@ bool LLAppViewer::getMasterSystemAudioMute()
{
return gSavedSettings.getBOOL("MuteAudio");
}
+
+//----------------------------------------------------------------------------
+// Metrics-related methods (static and otherwise)
+//----------------------------------------------------------------------------
+
+/**
+ * LLViewerAssetStats collects data on a per-region (as defined by the agent's
+ * location) so we need to tell it about region changes which become a kind of
+ * hidden variable/global state in the collectors. For collectors not running
+ * on the main thread, we need to send a message to move the data over safely
+ * and cheaply (amortized over a run).
+ */
+void LLAppViewer::metricsUpdateRegion(U64 region_handle)
+{
+ if (0 != region_handle)
+ {
+ LLViewerAssetStatsFF::set_region_main(region_handle);
+ if (LLAppViewer::sTextureFetch)
+ {
+ // Send a region update message into 'thread1' to get the new region.
+ LLAppViewer::sTextureFetch->commandSetRegion(region_handle);
+ }
+ else
+ {
+ // No 'thread1', a.k.a. TextureFetch, so update directly
+ LLViewerAssetStatsFF::set_region_thread1(region_handle);
+ }
+ }
+}
+
+
+/**
+ * Attempts to start a multi-threaded metrics report to be sent back to
+ * the grid for consumption.
+ */
+void LLAppViewer::metricsSend(bool enable_reporting)
+{
+ if (! gViewerAssetStatsMain)
+ return;
+
+ if (LLAppViewer::sTextureFetch)
+ {
+ LLViewerRegion * regionp = gAgent.getRegion();
+
+ if (enable_reporting && regionp)
+ {
+ std::string caps_url = regionp->getCapability("ViewerMetrics");
+
+ // Make a copy of the main stats to send into another thread.
+ // Receiving thread takes ownership.
+ LLViewerAssetStats * main_stats(new LLViewerAssetStats(*gViewerAssetStatsMain));
+
+ // Send a report request into 'thread1' to get the rest of the data
+ // and provide some additional parameters while here.
+ LLAppViewer::sTextureFetch->commandSendMetrics(caps_url,
+ gAgentSessionID,
+ gAgentID,
+ main_stats);
+ main_stats = 0; // Ownership transferred
+ }
+ else
+ {
+ LLAppViewer::sTextureFetch->commandDataBreak();
+ }
+ }
+
+ // Reset even if we can't report. Rather than gather up a huge chunk of
+ // data, we'll keep to our sampling interval and retain the data
+ // resolution in time.
+ gViewerAssetStatsMain->reset();
+}
+
diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h
index fdc3b9ef9e..61ee6a7cf1 100644
--- a/indra/newview/llappviewer.h
+++ b/indra/newview/llappviewer.h
@@ -39,7 +39,7 @@ class LLTextureCache;
class LLImageDecodeThread;
class LLTextureFetch;
class LLWatchdogTimeout;
-class LLCommandLineParser;
+class LLUpdaterService;
struct apr_dso_handle_t;
@@ -65,12 +65,14 @@ public:
virtual bool mainLoop(); // Override for the application main loop. Needs to at least gracefully notice the QUITTING state and exit.
// Application control
+ void flushVFSIO(); // waits for vfs transfers to complete
void forceQuit(); // Puts the viewer into 'shutting down without error' mode.
+ void fastQuit(S32 error_code = 0); // Shuts down the viewer immediately after sending a logout message
void requestQuit(); // Request a quit. A kinder, gentler quit.
void userQuit(); // The users asks to quit. Confirm, then requestQuit()
void earlyExit(const std::string& name,
const LLSD& substitutions = LLSD()); // Display an error dialog and forcibly quit.
- void forceExit(S32 arg); // exit() immediately (after some cleanup).
+ void earlyExitNoNotify(); // Do not display error dialog then forcibly quit.
void abortQuit(); // Called to abort a quit request.
bool quitRequested() { return mQuitRequested; }
@@ -167,6 +169,10 @@ public:
// mute/unmute the system's master audio
virtual void setMasterSystemAudioMute(bool mute);
virtual bool getMasterSystemAudioMute();
+
+ // Metrics policy helper statics.
+ static void metricsUpdateRegion(U64 region_handle);
+ static void metricsSend(bool enable_reporting);
protected:
virtual bool initWindow(); // Initialize the viewer's window.
@@ -181,12 +187,13 @@ protected:
virtual std::string generateSerialNumber() = 0; // Platforms specific classes generate this.
+ virtual bool meetsRequirementsForMaximizedStart(); // Used on first login to decide to launch maximized
private:
bool initThreads(); // Initialize viewer threads, return false on failure.
bool initConfiguration(); // Initialize settings from the command line/config file.
-
+ void initUpdater(); // Initialize the updater service.
bool initCache(); // Initialize local client cache.
@@ -247,11 +254,13 @@ private:
bool mQuitRequested; // User wants to quit, may have modified documents open.
bool mLogoutRequestSent; // Disconnect message sent to simulator, no longer safe to send messages to the sim.
S32 mYieldTime;
- LLSD mSettingsLocationList;
+ struct SettingsFiles* mSettingsLocationList;
LLWatchdogTimeout* mMainloopTimeout;
+ // For performance and metric gathering
LLThread* mFastTimerLogThread;
+
// for tracking viewer<->region circuit death
bool mAgentRegionLastAlive;
LLUUID mAgentRegionLastID;
@@ -260,7 +269,16 @@ private:
std::set<struct apr_dso_handle_t*> mPlugins;
+ U32 mAvailPhysicalMemInKB ;
+ U32 mAvailVirtualMemInKB ;
+
+ boost::scoped_ptr<LLUpdaterService> mUpdater;
+
+ //---------------------------------------------
+ //*NOTE: Mani - legacy updater stuff
+ // Still useable?
public:
+
//some information for updater
typedef struct
{
@@ -270,6 +288,7 @@ public:
static LLUpdaterInfo *sUpdaterInfo ;
void launchUpdater();
+ //---------------------------------------------
};
// consts from viewer.h
diff --git a/indra/newview/llappviewerlinux.cpp b/indra/newview/llappviewerlinux.cpp
index 7629265730..714e0e6163 100644
--- a/indra/newview/llappviewerlinux.cpp
+++ b/indra/newview/llappviewerlinux.cpp
@@ -30,6 +30,7 @@
#include "llcommandlineparser.h"
+#include "lldiriterator.h"
#include "llmemtype.h"
#include "llurldispatcher.h" // SLURL from other app instance
#include "llviewernetwork.h"
@@ -233,7 +234,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?
@@ -504,8 +505,9 @@ std::string LLAppViewerLinux::generateSerialNumber()
// trawl /dev/disk/by-uuid looking for a good-looking UUID to grab
std::string this_name;
- BOOL wrap = FALSE;
- while (gDirUtilp->getNextFileInDir(uuiddir, "*", this_name, wrap))
+
+ LLDirIterator iter(uuiddir, "*");
+ while (iter.next(this_name))
{
if (this_name.length() > best.length() ||
(this_name.length() == best.length() &&
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/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp
index d328567a0e..6396ca91ff 100644
--- a/indra/newview/llappviewerwin32.cpp
+++ b/indra/newview/llappviewerwin32.cpp
@@ -26,12 +26,6 @@
#include "llviewerprecompiledheaders.h"
-#if defined(_DEBUG)
-# if _MSC_VER >= 1400 // Visual C++ 2005 or later
-# define WINDOWS_CRT_MEM_CHECKS 1
-# endif
-#endif
-
#include "llappviewerwin32.h"
#include "llmemtype.h"
@@ -440,7 +434,11 @@ bool LLAppViewerWin32::initHardwareTest()
LL_WARNS("AppInit") << " Someone took over my exception handler (post hardware probe)!" << LL_ENDL;
}
- gGLManager.mVRAM = gDXHardware.getVRAM();
+ if (gGLManager.mVRAM == 0)
+ {
+ gGLManager.mVRAM = gDXHardware.getVRAM();
+ }
+
LL_INFOS("AppInit") << "Detected VRAM: " << gGLManager.mVRAM << LL_ENDL;
return true;
diff --git a/indra/newview/llassetuploadresponders.cpp b/indra/newview/llassetuploadresponders.cpp
index f12bc16d4b..c08771c5e7 100644
--- a/indra/newview/llassetuploadresponders.cpp
+++ b/indra/newview/llassetuploadresponders.cpp
@@ -60,6 +60,7 @@
#include "llnotificationsutil.h"
#include "llscrolllistctrl.h"
#include "llsdserialize.h"
+#include "llsdutil.h"
#include "llvfs.h"
// When uploading multiple files, don't display any of them when uploading more than this number.
@@ -67,6 +68,106 @@ static const S32 FILE_COUNT_DISPLAY_THRESHOLD = 5;
void dialog_refresh_all();
+void on_new_single_inventory_upload_complete(
+ LLAssetType::EType asset_type,
+ LLInventoryType::EType inventory_type,
+ const std::string inventory_type_string,
+ const LLUUID& item_folder_id,
+ const std::string& item_name,
+ const std::string& item_description,
+ const LLSD& server_response,
+ S32 upload_price)
+{
+ if ( upload_price > 0 )
+ {
+ // this upload costed us L$, update our balance
+ // and display something saying that it cost L$
+ LLStatusBar::sendMoneyBalanceRequest();
+
+ LLSD args;
+ args["AMOUNT"] = llformat("%d", upload_price);
+ LLNotificationsUtil::add("UploadPayment", args);
+ }
+
+ if( item_folder_id.notNull() )
+ {
+ U32 everyone_perms = PERM_NONE;
+ U32 group_perms = PERM_NONE;
+ U32 next_owner_perms = PERM_ALL;
+ if( server_response.has("new_next_owner_mask") )
+ {
+ // The server provided creation perms so use them.
+ // Do not assume we got the perms we asked for in
+ // since the server may not have granted them all.
+ everyone_perms = server_response["new_everyone_mask"].asInteger();
+ group_perms = server_response["new_group_mask"].asInteger();
+ next_owner_perms = server_response["new_next_owner_mask"].asInteger();
+ }
+ else
+ {
+ // The server doesn't provide creation perms
+ // so use old assumption-based perms.
+ if( inventory_type_string != "snapshot")
+ {
+ next_owner_perms = PERM_MOVE | PERM_TRANSFER;
+ }
+ }
+
+ LLPermissions new_perms;
+ new_perms.init(
+ gAgent.getID(),
+ gAgent.getID(),
+ LLUUID::null,
+ LLUUID::null);
+
+ new_perms.initMasks(
+ PERM_ALL,
+ PERM_ALL,
+ everyone_perms,
+ group_perms,
+ next_owner_perms);
+
+ S32 creation_date_now = time_corrected();
+ LLPointer<LLViewerInventoryItem> item = new LLViewerInventoryItem(
+ server_response["new_inventory_item"].asUUID(),
+ item_folder_id,
+ new_perms,
+ server_response["new_asset"].asUUID(),
+ asset_type,
+ inventory_type,
+ item_name,
+ item_description,
+ LLSaleInfo::DEFAULT,
+ LLInventoryItemFlags::II_FLAGS_NONE,
+ creation_date_now);
+
+ gInventory.updateItem(item);
+ gInventory.notifyObservers();
+
+ // Show the preview panel for textures and sounds to let
+ // user know that the image (or snapshot) arrived intact.
+ LLInventoryPanel* panel = LLInventoryPanel::getActiveInventoryPanel();
+ if ( panel )
+ {
+ LLFocusableElement* focus = gFocusMgr.getKeyboardFocus();
+
+ panel->setSelection(
+ server_response["new_inventory_item"].asUUID(),
+ TAKE_FOCUS_NO);
+
+ // restore keyboard focus
+ gFocusMgr.setKeyboardFocus(focus);
+ }
+ }
+ else
+ {
+ llwarns << "Can't find a folder to put it in" << llendl;
+ }
+
+ // remove the "Uploading..." message
+ LLUploadDialog::modalUploadFinished();
+}
+
LLAssetUploadResponder::LLAssetUploadResponder(const LLSD &post_data,
const LLUUID& vfile_id,
LLAssetType::EType asset_type)
@@ -84,9 +185,10 @@ LLAssetUploadResponder::LLAssetUploadResponder(const LLSD &post_data,
}
}
-LLAssetUploadResponder::LLAssetUploadResponder(const LLSD &post_data,
- const std::string& file_name,
- LLAssetType::EType asset_type)
+LLAssetUploadResponder::LLAssetUploadResponder(
+ const LLSD &post_data,
+ const std::string& file_name,
+ LLAssetType::EType asset_type)
: LLHTTPClient::Responder(),
mPostData(post_data),
mFileName(file_name),
@@ -126,6 +228,7 @@ void LLAssetUploadResponder::error(U32 statusNum, const std::string& reason)
break;
}
LLUploadDialog::modalUploadFinished();
+ LLFilePicker::instance().reset(); // unlock file picker when bulk upload fails
}
//virtual
@@ -134,6 +237,7 @@ void LLAssetUploadResponder::result(const LLSD& content)
lldebugs << "LLAssetUploadResponder::result from capabilities" << llendl;
std::string state = content["state"];
+
if (state == "upload")
{
uploadUpload(content);
@@ -195,16 +299,36 @@ void LLAssetUploadResponder::uploadComplete(const LLSD& content)
{
}
-LLNewAgentInventoryResponder::LLNewAgentInventoryResponder(const LLSD& post_data,
- const LLUUID& vfile_id,
- LLAssetType::EType asset_type)
-: LLAssetUploadResponder(post_data, vfile_id, asset_type)
+LLNewAgentInventoryResponder::LLNewAgentInventoryResponder(
+ const LLSD& post_data,
+ const LLUUID& vfile_id,
+ LLAssetType::EType asset_type)
+ : LLAssetUploadResponder(post_data, vfile_id, asset_type)
{
}
-LLNewAgentInventoryResponder::LLNewAgentInventoryResponder(const LLSD& post_data, const std::string& file_name, LLAssetType::EType asset_type)
-: LLAssetUploadResponder(post_data, file_name, asset_type)
+LLNewAgentInventoryResponder::LLNewAgentInventoryResponder(
+ const LLSD& post_data,
+ const std::string& file_name,
+ LLAssetType::EType asset_type)
+ : LLAssetUploadResponder(post_data, file_name, asset_type)
+{
+}
+
+// virtual
+void LLNewAgentInventoryResponder::error(U32 statusNum, const std::string& reason)
{
+ LLAssetUploadResponder::error(statusNum, reason);
+ //LLImportColladaAssetCache::getInstance()->assetUploaded(mVFileID, LLUUID(), FALSE);
+}
+
+
+//virtual
+void LLNewAgentInventoryResponder::uploadFailure(const LLSD& content)
+{
+ LLAssetUploadResponder::uploadFailure(content);
+
+ //LLImportColladaAssetCache::getInstance()->assetUploaded(mVFileID, content["new_asset"], FALSE);
}
//virtual
@@ -218,95 +342,31 @@ void LLNewAgentInventoryResponder::uploadComplete(const LLSD& content)
LLAssetType::EType asset_type = LLAssetType::lookup(mPostData["asset_type"].asString());
LLInventoryType::EType inventory_type = LLInventoryType::lookup(mPostData["inventory_type"].asString());
- S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload();
+ S32 expected_upload_cost = 0;
// Update L$ and ownership credit information
// since it probably changed on the server
if (asset_type == LLAssetType::AT_TEXTURE ||
asset_type == LLAssetType::AT_SOUND ||
- asset_type == LLAssetType::AT_ANIMATION)
+ asset_type == LLAssetType::AT_ANIMATION ||
+ asset_type == LLAssetType::AT_MESH)
{
- LLStatusBar::sendMoneyBalanceRequest();
-
- LLSD args;
- args["AMOUNT"] = llformat("%d", expected_upload_cost);
- LLNotificationsUtil::add("UploadPayment", args);
+ expected_upload_cost =
+ LLGlobalEconomy::Singleton::getInstance()->getPriceUpload();
}
- // Actually add the upload to viewer inventory
- llinfos << "Adding " << content["new_inventory_item"].asUUID() << " "
- << content["new_asset"].asUUID() << " to inventory." << llendl;
- if(mPostData["folder_id"].asUUID().notNull())
- {
- //std::ostringstream out;
- //LLSDXMLFormatter *formatter = new LLSDXMLFormatter;
- //formatter->format(mPostData, out, LLSDFormatter::OPTIONS_PRETTY);
- //llinfos << "Post Data: " << out.str() << llendl;
+ on_new_single_inventory_upload_complete(
+ asset_type,
+ inventory_type,
+ mPostData["asset_type"].asString(),
+ mPostData["folder_id"].asUUID(),
+ mPostData["name"],
+ mPostData["description"],
+ content,
+ expected_upload_cost);
- U32 everyone_perms = PERM_NONE;
- U32 group_perms = PERM_NONE;
- U32 next_owner_perms = PERM_ALL;
- if(content.has("new_next_owner_mask"))
- {
- // This is a new sim that provides creation perms so use them.
- // Do not assume we got the perms we asked for in mPostData
- // since the sim may not have granted them all.
- everyone_perms = content["new_everyone_mask"].asInteger();
- group_perms = content["new_group_mask"].asInteger();
- next_owner_perms = content["new_next_owner_mask"].asInteger();
- }
- else
- {
- // This old sim doesn't provide creation perms so use old assumption-based perms.
- if(mPostData["inventory_type"].asString() != "snapshot")
- {
- next_owner_perms = PERM_MOVE | PERM_TRANSFER;
- }
- }
- LLPermissions new_perms;
- new_perms.init(gAgent.getID(), gAgent.getID(), LLUUID::null, LLUUID::null);
- new_perms.initMasks(PERM_ALL, PERM_ALL, everyone_perms, group_perms, next_owner_perms);
- S32 creation_date_now = time_corrected();
- LLPointer<LLViewerInventoryItem> item
- = new LLViewerInventoryItem(content["new_inventory_item"].asUUID(),
- mPostData["folder_id"].asUUID(),
- new_perms,
- content["new_asset"].asUUID(),
- asset_type,
- inventory_type,
- mPostData["name"].asString(),
- mPostData["description"].asString(),
- LLSaleInfo::DEFAULT,
- LLInventoryItemFlags::II_FLAGS_NONE,
- creation_date_now);
- gInventory.updateItem(item);
- gInventory.notifyObservers();
-
- // Show the preview panel for textures and sounds to let
- // user know that the image (or snapshot) arrived intact.
- LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel();
- if (active_panel)
- {
- active_panel->setSelection(content["new_inventory_item"].asUUID(), TAKE_FOCUS_NO);
- if((LLAssetType::AT_TEXTURE == asset_type || LLAssetType::AT_SOUND == asset_type)
- && LLFilePicker::instance().getFileCount() <= FILE_COUNT_DISPLAY_THRESHOLD)
- {
- active_panel->openSelected();
- }
- //LLFloaterInventory::dumpSelectionInformation((void*)view);
- // restore keyboard focus
- LLFocusableElement* focus = gFocusMgr.getKeyboardFocus();
- gFocusMgr.setKeyboardFocus(focus);
- }
- }
- else
- {
- llwarns << "Can't find a folder to put it in" << llendl;
- }
+ // continue uploading for bulk uploads
- // remove the "Uploading..." message
- LLUploadDialog::modalUploadFinished();
-
// *FIX: This is a pretty big hack. What this does is check the
// file picker if there are any more pending uploads. If so,
// upload that file.
@@ -323,19 +383,42 @@ void LLNewAgentInventoryResponder::uploadComplete(const LLSD& content)
// Continuing the horrible hack above, we need to extract the originally requested permissions data, if any,
// and use them for each next file to be uploaded. Note the requested perms are not the same as the
- // granted ones found in the given "content" structure but can still be found in mPostData. -MG
- U32 everyone_perms = mPostData.has("everyone_mask") ? mPostData.get("everyone_mask" ).asInteger() : PERM_NONE;
- U32 group_perms = mPostData.has("group_mask") ? mPostData.get("group_mask" ).asInteger() : PERM_NONE;
- U32 next_owner_perms = mPostData.has("next_owner_mask") ? mPostData.get("next_owner_mask").asInteger() : PERM_NONE;
+ U32 everyone_perms =
+ content.has("everyone_mask") ?
+ content["everyone_mask"].asInteger() :
+ PERM_NONE;
+
+ U32 group_perms =
+ content.has("group_mask") ?
+ content["group_mask"].asInteger() :
+ PERM_NONE;
+
+ U32 next_owner_perms =
+ content.has("next_owner_mask") ?
+ content["next_owner_mask"].asInteger() :
+ PERM_NONE;
+
std::string display_name = LLStringUtil::null;
LLAssetStorage::LLStoreAssetCallback callback = NULL;
void *userdata = NULL;
- upload_new_resource(next_file, asset_name, asset_name,
- 0, LLFolderType::FT_NONE, LLInventoryType::IT_NONE,
- next_owner_perms, group_perms,
- everyone_perms, display_name,
- callback, expected_upload_cost, userdata);
+
+ upload_new_resource(
+ next_file,
+ asset_name,
+ asset_name,
+ 0,
+ LLFolderType::FT_NONE,
+ LLInventoryType::IT_NONE,
+ next_owner_perms,
+ group_perms,
+ everyone_perms,
+ display_name,
+ callback,
+ LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(),
+ userdata);
}
+
+ //LLImportColladaAssetCache::getInstance()->assetUploaded(mVFileID, content["new_asset"], TRUE);
}
LLSendTexLayerResponder::LLSendTexLayerResponder(const LLSD& post_data,
@@ -389,17 +472,19 @@ void LLSendTexLayerResponder::error(U32 statusNum, const std::string& reason)
mBakedUploadData = NULL; // deleted in onTextureUploadComplete()
}
-LLUpdateAgentInventoryResponder::LLUpdateAgentInventoryResponder(const LLSD& post_data,
- const LLUUID& vfile_id,
- LLAssetType::EType asset_type)
-: LLAssetUploadResponder(post_data, vfile_id, asset_type)
+LLUpdateAgentInventoryResponder::LLUpdateAgentInventoryResponder(
+ const LLSD& post_data,
+ const LLUUID& vfile_id,
+ LLAssetType::EType asset_type)
+ : LLAssetUploadResponder(post_data, vfile_id, asset_type)
{
}
-LLUpdateAgentInventoryResponder::LLUpdateAgentInventoryResponder(const LLSD& post_data,
- const std::string& file_name,
- LLAssetType::EType asset_type)
-: LLAssetUploadResponder(post_data, file_name, asset_type)
+LLUpdateAgentInventoryResponder::LLUpdateAgentInventoryResponder(
+ const LLSD& post_data,
+ const std::string& file_name,
+ LLAssetType::EType asset_type)
+ : LLAssetUploadResponder(post_data, file_name, asset_type)
{
}
@@ -582,3 +667,474 @@ void LLUpdateTaskInventoryResponder::uploadComplete(const LLSD& content)
break;
}
}
+
+
+/////////////////////////////////////////////////////
+// LLNewAgentInventoryVariablePriceResponder::Impl //
+/////////////////////////////////////////////////////
+class LLNewAgentInventoryVariablePriceResponder::Impl
+{
+public:
+ Impl(
+ const LLUUID& vfile_id,
+ LLAssetType::EType asset_type,
+ const LLSD& inventory_data) :
+ mVFileID(vfile_id),
+ mAssetType(asset_type),
+ mInventoryData(inventory_data),
+ mFileName("")
+ {
+ if (!gVFS->getExists(vfile_id, asset_type))
+ {
+ llwarns
+ << "LLAssetUploadResponder called with nonexistant "
+ << "vfile_id " << vfile_id << llendl;
+ mVFileID.setNull();
+ mAssetType = LLAssetType::AT_NONE;
+ }
+ }
+
+ Impl(
+ const std::string& file_name,
+ LLAssetType::EType asset_type,
+ const LLSD& inventory_data) :
+ mFileName(file_name),
+ mAssetType(asset_type),
+ mInventoryData(inventory_data)
+ {
+ mVFileID.setNull();
+ }
+
+ std::string getFilenameOrIDString() const
+ {
+ return (mFileName.empty() ? mVFileID.asString() : mFileName);
+ }
+
+ LLUUID getVFileID() const
+ {
+ return mVFileID;
+ }
+
+ std::string getFilename() const
+ {
+ return mFileName;
+ }
+
+ LLAssetType::EType getAssetType() const
+ {
+ return mAssetType;
+ }
+
+ LLInventoryType::EType getInventoryType() const
+ {
+ return LLInventoryType::lookup(
+ mInventoryData["inventory_type"].asString());
+ }
+
+ std::string getInventoryTypeString() const
+ {
+ return mInventoryData["inventory_type"].asString();
+ }
+
+ LLUUID getFolderID() const
+ {
+ return mInventoryData["folder_id"].asUUID();
+ }
+
+ std::string getItemName() const
+ {
+ return mInventoryData["name"].asString();
+ }
+
+ std::string getItemDescription() const
+ {
+ return mInventoryData["description"].asString();
+ }
+
+ void displayCannotUploadReason(const std::string& reason)
+ {
+ LLSD args;
+ args["FILE"] = getFilenameOrIDString();
+ args["REASON"] = reason;
+
+
+ LLNotificationsUtil::add("CannotUploadReason", args);
+ LLUploadDialog::modalUploadFinished();
+ }
+
+ void onApplicationLevelError(const LLSD& error)
+ {
+ static const std::string _IDENTIFIER = "identifier";
+
+ static const std::string _INSUFFICIENT_FUNDS =
+ "NewAgentInventory_InsufficientLindenDollarBalance";
+ static const std::string _MISSING_REQUIRED_PARAMETER =
+ "NewAgentInventory_MissingRequiredParamater";
+ static const std::string _INVALID_REQUEST_BODY =
+ "NewAgentInventory_InvalidRequestBody";
+ static const std::string _RESOURCE_COST_DIFFERS =
+ "NewAgentInventory_ResourceCostDiffers";
+
+ static const std::string _MISSING_PARAMETER = "missing_parameter";
+ static const std::string _INVALID_PARAMETER = "invalid_parameter";
+ static const std::string _MISSING_RESOURCE = "missing_resource";
+ static const std::string _INVALID_RESOURCE = "invalid_resource";
+
+ // TODO* Add the other error_identifiers
+
+ std::string error_identifier = error[_IDENTIFIER].asString();
+
+ // TODO*: Pull these user visible strings from an xml file
+ // to be localized
+ if ( _INSUFFICIENT_FUNDS == error_identifier )
+ {
+ displayCannotUploadReason("You do not have a sufficient L$ balance to complete this upload.");
+ }
+ else if ( _MISSING_REQUIRED_PARAMETER == error_identifier )
+ {
+ // Missing parameters
+ if (error.has(_MISSING_PARAMETER) )
+ {
+ std::string message =
+ "Upload request was missing required parameter '[P]'";
+ LLStringUtil::replaceString(
+ message,
+ "[P]",
+ error[_MISSING_PARAMETER].asString());
+
+ displayCannotUploadReason(message);
+ }
+ else
+ {
+ std::string message =
+ "Upload request was missing a required parameter";
+ displayCannotUploadReason(message);
+ }
+ }
+ else if ( _INVALID_REQUEST_BODY == error_identifier )
+ {
+ // Invalid request body, check to see if
+ // a particular parameter was invalid
+ if ( error.has(_INVALID_PARAMETER) )
+ {
+ std::string message = "Upload parameter '[P]' is invalid.";
+ LLStringUtil::replaceString(
+ message,
+ "[P]",
+ error[_INVALID_PARAMETER].asString());
+
+ // See if the server also responds with what resource
+ // is missing.
+ if ( error.has(_MISSING_RESOURCE) )
+ {
+ message += "\nMissing resource '[R]'.";
+
+ LLStringUtil::replaceString(
+ message,
+ "[R]",
+ error[_MISSING_RESOURCE].asString());
+ }
+ else if ( error.has(_INVALID_RESOURCE) )
+ {
+ message += "\nInvalid resource '[R]'.";
+
+ LLStringUtil::replaceString(
+ message,
+ "[R]",
+ error[_INVALID_RESOURCE].asString());
+ }
+
+ displayCannotUploadReason(message);
+ }
+ else
+ {
+ std::string message = "Upload request was malformed";
+ displayCannotUploadReason(message);
+ }
+ }
+ else if ( _RESOURCE_COST_DIFFERS == error_identifier )
+ {
+ displayCannotUploadReason("The resource cost associated with this upload is not consistent with the server.");
+ }
+ else
+ {
+ displayCannotUploadReason("Unknown Error");
+ }
+ }
+
+ void onTransportError()
+ {
+ displayCannotUploadReason(
+ "The server is experiencing unexpected difficulties.");
+ }
+
+ void onTransportError(const LLSD& error)
+ {
+ static const std::string _IDENTIFIER = "identifier";
+
+ static const std::string _SERVER_ERROR_AFTER_CHARGE =
+ "NewAgentInventory_ServerErrorAfterCharge";
+
+ std::string error_identifier = error[_IDENTIFIER].asString();
+
+ // TODO*: Pull the user visible strings from an xml file
+ // to be localized
+
+ if ( _SERVER_ERROR_AFTER_CHARGE == error_identifier )
+ {
+ displayCannotUploadReason(
+ "The server is experiencing unexpected difficulties. You may have been charged for the upload.");
+ }
+ else
+ {
+ displayCannotUploadReason(
+ "The server is experiencing unexpected difficulties.");
+ }
+ }
+
+ bool uploadConfirmationCallback(
+ const LLSD& notification,
+ const LLSD& response,
+ boost::intrusive_ptr<LLNewAgentInventoryVariablePriceResponder> responder)
+ {
+ S32 option;
+ std::string confirmation_url;
+
+ option = LLNotificationsUtil::getSelectedOption(
+ notification,
+ response);
+
+ confirmation_url =
+ notification["payload"]["confirmation_url"].asString();
+
+ // Yay! We are confirming or cancelling our upload
+ switch(option)
+ {
+ case 0:
+ {
+ confirmUpload(confirmation_url, responder);
+ }
+ break;
+ case 1:
+ default:
+ break;
+ }
+
+ return false;
+ }
+
+ void confirmUpload(
+ const std::string& confirmation_url,
+ boost::intrusive_ptr<LLNewAgentInventoryVariablePriceResponder> responder)
+ {
+ if ( getFilename().empty() )
+ {
+ // we have no filename, use virtual file ID instead
+ LLHTTPClient::postFile(
+ confirmation_url,
+ getVFileID(),
+ getAssetType(),
+ responder);
+ }
+ else
+ {
+ LLHTTPClient::postFile(
+ confirmation_url,
+ getFilename(),
+ responder);
+ }
+ }
+
+
+private:
+ std::string mFileName;
+
+ LLSD mInventoryData;
+ LLAssetType::EType mAssetType;
+ LLUUID mVFileID;
+};
+
+///////////////////////////////////////////////
+// LLNewAgentInventoryVariablePriceResponder //
+///////////////////////////////////////////////
+LLNewAgentInventoryVariablePriceResponder::LLNewAgentInventoryVariablePriceResponder(
+ const LLUUID& vfile_id,
+ LLAssetType::EType asset_type,
+ const LLSD& inventory_info)
+{
+ mImpl = new Impl(
+ vfile_id,
+ asset_type,
+ inventory_info);
+}
+
+LLNewAgentInventoryVariablePriceResponder::LLNewAgentInventoryVariablePriceResponder(
+ const std::string& file_name,
+ LLAssetType::EType asset_type,
+ const LLSD& inventory_info)
+{
+ mImpl = new Impl(
+ file_name,
+ asset_type,
+ inventory_info);
+}
+
+LLNewAgentInventoryVariablePriceResponder::~LLNewAgentInventoryVariablePriceResponder()
+{
+ delete mImpl;
+}
+
+void LLNewAgentInventoryVariablePriceResponder::errorWithContent(
+ U32 statusNum,
+ const std::string& reason,
+ const LLSD& content)
+{
+ lldebugs
+ << "LLNewAgentInventoryVariablePrice::error " << statusNum
+ << " reason: " << reason << llendl;
+
+ if ( content.has("error") )
+ {
+ static const std::string _ERROR = "error";
+
+ mImpl->onTransportError(content[_ERROR]);
+ }
+ else
+ {
+ mImpl->onTransportError();
+ }
+}
+
+void LLNewAgentInventoryVariablePriceResponder::result(const LLSD& content)
+{
+ // Parse out application level errors and the appropriate
+ // responses for them
+ static const std::string _ERROR = "error";
+ static const std::string _STATE = "state";
+
+ static const std::string _COMPLETE = "complete";
+ static const std::string _CONFIRM_UPLOAD = "confirm_upload";
+
+ static const std::string _UPLOAD_PRICE = "upload_price";
+ static const std::string _RESOURCE_COST = "resource_cost";
+ static const std::string _RSVP = "rsvp";
+
+ // Check for application level errors
+ if ( content.has(_ERROR) )
+ {
+ onApplicationLevelError(content[_ERROR]);
+ return;
+ }
+
+ std::string state = content[_STATE];
+ LLAssetType::EType asset_type = mImpl->getAssetType();
+
+ if ( _COMPLETE == state )
+ {
+ // rename file in VFS with new asset id
+ if (mImpl->getFilename().empty())
+ {
+ // rename the file in the VFS to the actual asset id
+ // llinfos << "Changing uploaded asset UUID to " << content["new_asset"].asUUID() << llendl;
+ gVFS->renameFile(
+ mImpl->getVFileID(),
+ asset_type,
+ content["new_asset"].asUUID(),
+ asset_type);
+ }
+
+ on_new_single_inventory_upload_complete(
+ asset_type,
+ mImpl->getInventoryType(),
+ mImpl->getInventoryTypeString(),
+ mImpl->getFolderID(),
+ mImpl->getItemName(),
+ mImpl->getItemDescription(),
+ content,
+ content[_UPLOAD_PRICE].asInteger());
+
+ // TODO* Add bulk (serial) uploading or add
+ // a super class of this that does so
+ }
+ else if ( _CONFIRM_UPLOAD == state )
+ {
+ showConfirmationDialog(
+ content[_UPLOAD_PRICE].asInteger(),
+ content[_RESOURCE_COST].asInteger(),
+ content[_RSVP].asString());
+ }
+ else
+ {
+ onApplicationLevelError("");
+ }
+}
+
+void LLNewAgentInventoryVariablePriceResponder::onApplicationLevelError(
+ const LLSD& error)
+{
+ mImpl->onApplicationLevelError(error);
+}
+
+void LLNewAgentInventoryVariablePriceResponder::showConfirmationDialog(
+ S32 upload_price,
+ S32 resource_cost,
+ const std::string& confirmation_url)
+{
+ if ( 0 == upload_price )
+ {
+ // don't show confirmation dialog for free uploads, I mean,
+ // they're free!
+
+ // The creating of a new instrusive_ptr(this)
+ // creates a new boost::intrusive_ptr
+ // which is a copy of this. This code is required because
+ // 'this' is always of type Class* and not the intrusive_ptr,
+ // and thus, a reference to 'this' is not registered
+ // by using just plain 'this'.
+
+ // Since LLNewAgentInventoryVariablePriceResponder is a
+ // reference counted class, it is possible (since the
+ // reference to a plain 'this' would be missed here) that,
+ // when using plain ol' 'this', that this object
+ // would be deleted before the callback is triggered
+ // and cause sadness.
+ mImpl->confirmUpload(
+ confirmation_url,
+ boost::intrusive_ptr<LLNewAgentInventoryVariablePriceResponder>(this));
+ }
+ else
+ {
+ LLSD substitutions;
+ LLSD payload;
+
+ substitutions["PRICE"] = upload_price;
+
+ payload["confirmation_url"] = confirmation_url;
+
+ // The creating of a new instrusive_ptr(this)
+ // creates a new boost::intrusive_ptr
+ // which is a copy of this. This code is required because
+ // 'this' is always of type Class* and not the intrusive_ptr,
+ // and thus, a reference to 'this' is not registered
+ // by using just plain 'this'.
+
+ // Since LLNewAgentInventoryVariablePriceResponder is a
+ // reference counted class, it is possible (since the
+ // reference to a plain 'this' would be missed here) that,
+ // when using plain ol' 'this', that this object
+ // would be deleted before the callback is triggered
+ // and cause sadness.
+ LLNotificationsUtil::add(
+ "UploadCostConfirmation",
+ substitutions,
+ payload,
+ boost::bind(
+ &LLNewAgentInventoryVariablePriceResponder::Impl::uploadConfirmationCallback,
+ mImpl,
+ _1,
+ _2,
+ boost::intrusive_ptr<LLNewAgentInventoryVariablePriceResponder>(this)));
+ }
+}
+
+
diff --git a/indra/newview/llassetuploadresponders.h b/indra/newview/llassetuploadresponders.h
index 752c0dfe45..70871b62e2 100644
--- a/indra/newview/llassetuploadresponders.h
+++ b/indra/newview/llassetuploadresponders.h
@@ -55,15 +55,58 @@ protected:
std::string mFileName;
};
+// TODO*: Remove this once deprecated
class LLNewAgentInventoryResponder : public LLAssetUploadResponder
{
public:
- LLNewAgentInventoryResponder(const LLSD& post_data,
- const LLUUID& vfile_id,
- LLAssetType::EType asset_type);
- LLNewAgentInventoryResponder(const LLSD& post_data, const std::string& file_name,
- LLAssetType::EType asset_type);
+ LLNewAgentInventoryResponder(
+ const LLSD& post_data,
+ const LLUUID& vfile_id,
+ LLAssetType::EType asset_type);
+ LLNewAgentInventoryResponder(
+ const LLSD& post_data,
+ const std::string& file_name,
+ LLAssetType::EType asset_type);
+ virtual void error(U32 statusNum, const std::string& reason);
virtual void uploadComplete(const LLSD& content);
+ virtual void uploadFailure(const LLSD& content);
+};
+
+// A base class which goes through and performs some default
+// actions for variable price uploads. If more specific actions
+// are needed (such as different confirmation messages, etc.)
+// the functions onApplicationLevelError and showConfirmationDialog.
+class LLNewAgentInventoryVariablePriceResponder :
+ public LLHTTPClient::Responder
+{
+public:
+ LLNewAgentInventoryVariablePriceResponder(
+ const LLUUID& vfile_id,
+ LLAssetType::EType asset_type,
+ const LLSD& inventory_info);
+
+ LLNewAgentInventoryVariablePriceResponder(
+ const std::string& file_name,
+ LLAssetType::EType asset_type,
+ const LLSD& inventory_info);
+ virtual ~LLNewAgentInventoryVariablePriceResponder();
+
+ void errorWithContent(
+ U32 statusNum,
+ const std::string& reason,
+ const LLSD& content);
+ void result(const LLSD& content);
+
+ virtual void onApplicationLevelError(
+ const LLSD& error);
+ virtual void showConfirmationDialog(
+ S32 upload_price,
+ S32 resource_cost,
+ const std::string& confirmation_url);
+
+private:
+ class Impl;
+ Impl* mImpl;
};
struct LLBakedUploadData;
diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp
index 066b4d8bc3..cbbdcb2983 100644
--- a/indra/newview/llavataractions.cpp
+++ b/indra/newview/llavataractions.cpp
@@ -47,6 +47,7 @@
#include "llfloatergroups.h"
#include "llfloaterreg.h"
#include "llfloaterpay.h"
+#include "llfloaterwebcontent.h"
#include "llfloaterworldmap.h"
#include "llgiveinventory.h"
#include "llinventorybridge.h"
@@ -56,9 +57,11 @@
#include "llmutelist.h"
#include "llnotificationsutil.h" // for LLNotificationsUtil
#include "llpaneloutfitedit.h"
+#include "llpanelprofile.h"
#include "llrecentpeople.h"
#include "llsidetray.h"
#include "lltrans.h"
+#include "llviewercontrol.h"
#include "llviewerobjectlist.h"
#include "llviewermessage.h" // for handle_lure
#include "llviewerregion.h"
@@ -276,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
@@ -297,25 +300,45 @@ 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)
+{
+ std::string username = av_name.mUsername;
+ if (username.empty())
+ {
+ username = LLCacheName::buildUsername(av_name.mDisplayName);
+ }
+
+ llinfos << "opening web profile for " << username << llendl;
+ std::string url = getProfileURL(username);
+
+ // 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";
+ LLAvatarNameCache::get(id, boost::bind(&on_avatar_name_show_profile, _1, _2));
+ }
+}
- //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);
- }
+//static
+bool LLAvatarActions::profileVisible(const LLUUID& id)
+{
+ LLFloaterWebContent *browser = dynamic_cast<LLFloaterWebContent*> (LLFloaterReg::findInstance("web_content", id.asString()));
+ return browser && browser->isShown();
+}
+
+
+//static
+void LLAvatarActions::hideProfile(const LLUUID& id)
+{
+ LLFloaterWebContent *browser = dynamic_cast<LLFloaterWebContent*> (LLFloaterReg::findInstance("web_content", id.asString()));
+ if (browser)
+ {
+ browser->closeFloater();
}
}
diff --git a/indra/newview/llavataractions.h b/indra/newview/llavataractions.h
index 2db2918eed..956fed7461 100644
--- a/indra/newview/llavataractions.h
+++ b/indra/newview/llavataractions.h
@@ -93,6 +93,8 @@ public:
* Show avatar profile.
*/
static void showProfile(const LLUUID& id);
+ static void hideProfile(const LLUUID& id);
+ static bool profileVisible(const LLUUID& id);
/**
* Show avatar on world map.
diff --git a/indra/newview/llavatarlist.cpp b/indra/newview/llavatarlist.cpp
index ff7dfccc0a..771419f60a 100644
--- a/indra/newview/llavatarlist.cpp
+++ b/indra/newview/llavatarlist.cpp
@@ -240,6 +240,9 @@ void LLAvatarList::addAvalineItem(const LLUUID& item_id, const LLUUID& session_i
LLAvalineListItem* item = new LLAvalineListItem(/*hide_number=*/false);
item->setAvatarId(item_id, session_id, true, false);
item->setName(item_name);
+ item->showLastInteractionTime(mShowLastInteractionTime);
+ item->showSpeakingIndicator(mShowSpeakingIndicator);
+ item->setOnline(false);
addItem(item, item_id);
mIDs.push_back(item_id);
@@ -286,9 +289,18 @@ void LLAvatarList::refresh()
{
// *NOTE: If you change the UI to show a different string,
// be sure to change the filter code below.
- addNewItem(buddy_id,
- av_name.mDisplayName.empty() ? waiting_str : av_name.mDisplayName,
- LLAvatarTracker::instance().isBuddyOnline(buddy_id));
+ if (LLRecentPeople::instance().isAvalineCaller(buddy_id))
+ {
+ const LLSD& call_data = LLRecentPeople::instance().getData(buddy_id);
+ addAvalineItem(buddy_id, call_data["session_id"].asUUID(), call_data["call_number"].asString());
+ }
+ else
+ {
+ addNewItem(buddy_id,
+ av_name.mDisplayName.empty() ? waiting_str : av_name.mDisplayName,
+ LLAvatarTracker::instance().isBuddyOnline(buddy_id));
+ }
+
modified = true;
nadded++;
}
@@ -440,7 +452,7 @@ void LLAvatarList::addNewItem(const LLUUID& id, const std::string& name, BOOL is
BOOL LLAvatarList::handleRightMouseDown(S32 x, S32 y, MASK mask)
{
BOOL handled = LLUICtrl::handleRightMouseDown(x, y, mask);
- if ( mContextMenu )
+ if ( mContextMenu && !isAvalineItemSelected())
{
uuid_vec_t selected_uuids;
getSelectedUUIDs(selected_uuids);
@@ -449,6 +461,21 @@ BOOL LLAvatarList::handleRightMouseDown(S32 x, S32 y, MASK mask)
return handled;
}
+bool LLAvatarList::isAvalineItemSelected()
+{
+ std::vector<LLPanel*> selected_items;
+ getSelectedItems(selected_items);
+ std::vector<LLPanel*>::iterator it = selected_items.begin();
+
+ for(; it != selected_items.end(); ++it)
+ {
+ if (dynamic_cast<LLAvalineListItem*>(*it))
+ return true;
+ }
+
+ return false;
+}
+
void LLAvatarList::setVisible(BOOL visible)
{
if ( visible == FALSE && mContextMenu )
diff --git a/indra/newview/llavatarlist.h b/indra/newview/llavatarlist.h
index cacbcf7244..4814a88a79 100644
--- a/indra/newview/llavatarlist.h
+++ b/indra/newview/llavatarlist.h
@@ -112,6 +112,8 @@ protected:
private:
+ bool isAvalineItemSelected();
+
bool mIgnoreOnlineStatus;
bool mShowLastInteractionTime;
bool mDirty;
diff --git a/indra/newview/llavatarlistitem.cpp b/indra/newview/llavatarlistitem.cpp
index a56dc129d4..30eecfe323 100644
--- a/indra/newview/llavatarlistitem.cpp
+++ b/indra/newview/llavatarlistitem.cpp
@@ -41,7 +41,7 @@
bool LLAvatarListItem::sStaticInitialized = false;
S32 LLAvatarListItem::sLeftPadding = 0;
-S32 LLAvatarListItem::sRightNamePadding = 0;
+S32 LLAvatarListItem::sNameRightPadding = 0;
S32 LLAvatarListItem::sChildrenWidths[LLAvatarListItem::ALIC_COUNT];
static LLWidgetNameRegistry::StaticRegistrar sRegisterAvatarListItemParams(&typeid(LLAvatarListItem::Params), "avatar_list_item");
@@ -52,7 +52,8 @@ LLAvatarListItem::Params::Params()
voice_call_joined_style("voice_call_joined_style"),
voice_call_left_style("voice_call_left_style"),
online_style("online_style"),
- offline_style("offline_style")
+ offline_style("offline_style"),
+ name_right_pad("name_right_pad", 0)
{};
@@ -119,6 +120,9 @@ BOOL LLAvatarListItem::postBuild()
// so that we can hide and show them again later.
initChildrenWidths(this);
+ // Right padding between avatar name text box and nearest visible child.
+ sNameRightPadding = LLUICtrlFactory::getDefaultParams<LLAvatarListItem>().name_right_pad;
+
sStaticInitialized = true;
}
@@ -486,7 +490,6 @@ void LLAvatarListItem::initChildrenWidths(LLAvatarListItem* avatar_item)
S32 icon_width = avatar_item->mAvatarName->getRect().mLeft - avatar_item->mAvatarIcon->getRect().mLeft;
sLeftPadding = avatar_item->mAvatarIcon->getRect().mLeft;
- sRightNamePadding = avatar_item->mLastInteractionTime->getRect().mLeft - avatar_item->mAvatarName->getRect().mRight;
S32 index = ALIC_COUNT;
sChildrenWidths[--index] = icon_width;
@@ -565,7 +568,7 @@ void LLAvatarListItem::updateChildren()
// apply paddings
name_new_width -= sLeftPadding;
- name_new_width -= sRightNamePadding;
+ name_new_width -= sNameRightPadding;
name_view_rect.setLeftTopAndSize(
name_new_left,
diff --git a/indra/newview/llavatarlistitem.h b/indra/newview/llavatarlistitem.h
index a069838ac3..c95ac39696 100644
--- a/indra/newview/llavatarlistitem.h
+++ b/indra/newview/llavatarlistitem.h
@@ -51,6 +51,8 @@ public:
online_style,
offline_style;
+ Optional<S32> name_right_pad;
+
Params();
};
@@ -215,7 +217,7 @@ private:
static bool sStaticInitialized; // this variable is introduced to improve code readability
static S32 sLeftPadding; // padding to first left visible child (icon or name)
- static S32 sRightNamePadding; // right padding from name to next visible child
+ static S32 sNameRightPadding; // right padding from name to next visible child
/**
* Contains widths of each child specified by EAvatarListItemChildIndex
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/llbottomtray.cpp b/indra/newview/llbottomtray.cpp
index 29c2b7565e..f51552aae5 100644
--- a/indra/newview/llbottomtray.cpp
+++ b/indra/newview/llbottomtray.cpp
@@ -38,12 +38,15 @@
#include "lltexteditor.h"
// newview includes
+#include "llagent.h"
#include "llagentcamera.h"
+#include "llavataractions.h"
#include "llchiclet.h"
#include "llfloatercamera.h"
#include "llhints.h"
#include "llimfloater.h" // for LLIMFloater
#include "llnearbychatbar.h"
+#include "llsidetray.h"
#include "llspeakbutton.h"
#include "llsplitbutton.h"
#include "llsyswellwindow.h"
@@ -52,6 +55,7 @@
#include "llviewerwindow.h"
#include "llsdserialize.h"
+#include "llfirstuse.h"
// Distance from mouse down on which drag'n'drop should be started.
#define DRAG_START_DISTANCE 3
@@ -65,31 +69,43 @@ LLDefaultChildRegistry::Register<LLBottomtrayButton> bottomtray_button("bottomtr
// virtual
BOOL LLBottomtrayButton::handleHover(S32 x, S32 y, MASK mask)
{
- S32 screenX, screenY;
- localPointToScreen(x, y, &screenX, &screenY);
- // pass hover to bottomtray
- LLBottomTray::getInstance()->onDraggableButtonHover(screenX, screenY);
- return FALSE;
+ if (mCanDrag)
+ {
+ // pass hover to bottomtray
+ S32 screenX, screenY;
+ localPointToScreen(x, y, &screenX, &screenY);
+ LLBottomTray::getInstance()->onDraggableButtonHover(screenX, screenY);
+
+ return TRUE;
+ }
+ else
+ {
+ return LLButton::handleHover(x, y, mask);
+ }
}
//virtual
BOOL LLBottomtrayButton::handleMouseUp(S32 x, S32 y, MASK mask)
{
+ if (mCanDrag)
+ {
S32 screenX, screenY;
localPointToScreen(x, y, &screenX, &screenY);
// pass mouse up to bottomtray
LLBottomTray::getInstance()->onDraggableButtonMouseUp(this, screenX, screenY);
- LLButton::handleMouseUp(x, y, mask);
- return FALSE;
+ }
+ return LLButton::handleMouseUp(x, y, mask);
}
//virtual
BOOL LLBottomtrayButton::handleMouseDown(S32 x, S32 y, MASK mask)
{
+ if (mCanDrag)
+ {
S32 screenX, screenY;
localPointToScreen(x, y, &screenX, &screenY);
// pass mouse up to bottomtray
LLBottomTray::getInstance()->onDraggableButtonMouseDown(this, screenX, screenY);
- LLButton::handleMouseDown(x, y, mask);
- return FALSE;
+ }
+ return LLButton::handleMouseDown(x, y, mask);
}
static void update_build_button_enable_state()
@@ -150,8 +166,6 @@ public:
{
mFactoryMap["chat_bar"] = LLCallbackMap(LLBottomTray::createNearbyChatBar, NULL);
buildFromFile("panel_bottomtray_lite.xml");
- // Necessary for focus movement among child controls
- setFocusRoot(TRUE);
}
BOOL postBuild()
@@ -191,6 +205,7 @@ LLBottomTray::LLBottomTray(const LLSD&)
mSpeakBtn(NULL),
mNearbyChatBar(NULL),
mChatBarContainer(NULL),
+ mNearbyCharResizeHandlePanel(NULL),
mToolbarStack(NULL),
mMovementButton(NULL),
mResizeState(RS_NORESIZE),
@@ -203,7 +218,7 @@ LLBottomTray::LLBottomTray(const LLSD&)
mLandingTab(NULL),
mCheckForDrag(false)
{
- // Firstly add ourself to IMSession observers, so we catch session events
+ // Firstly add our self to IMSession observers, so we catch session events
// before chiclets do that.
LLIMMgr::getInstance()->addSessionObserver(this);
@@ -218,9 +233,6 @@ LLBottomTray::LLBottomTray(const LLSD&)
//destroyed LLBottomTray requires some subsystems that are long gone
//LLUI::getRootView()->addChild(this);
- // Necessary for focus movement among child controls
- setFocusRoot(TRUE);
-
{
mBottomTrayLite = new LLBottomTrayLite();
mBottomTrayLite->setFollowsAll();
@@ -366,11 +378,17 @@ void LLBottomTray::onChange(EStatusType status, const std::string &channelURI, b
}
// We have to enable/disable right and left parts of speak button separately (EXT-4648)
- mSpeakBtn->setSpeakBtnEnabled(enable);
+ getChild<LLButton>("speak_btn")->setEnabled(enable);
+
// skipped to avoid button blinking
if (status != STATUS_JOINING && status!= STATUS_LEFT_CHANNEL)
{
- mSpeakBtn->setFlyoutBtnEnabled(LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking());
+ bool voice_status = LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking();
+ getChild<LLButton>("speak_flyout_btn")->setEnabled(voice_status);
+ if (voice_status)
+ {
+ LLFirstUse::speak(true);
+ }
}
}
@@ -410,10 +428,6 @@ void LLBottomTray::setVisible(BOOL visible)
{
LLPanel::setVisible(visible);
}
- if(visible)
- gFloaterView->setSnapOffsetBottom(getRect().getHeight());
- else
- gFloaterView->setSnapOffsetBottom(0);
}
S32 LLBottomTray::notifyParent(const LLSD& info)
@@ -479,24 +493,21 @@ void LLBottomTray::updateContextMenu(S32 x, S32 y, MASK mask)
mBottomTrayContextMenu->setItemVisible("NearbyChatBar_Select_All", in_edit_box);
}
-void LLBottomTray::showGestureButton(BOOL visible)
+void LLBottomTray::showSpeakButton(bool visible)
{
- setTrayButtonVisibleIfPossible(RS_BUTTON_GESTURES, visible);
-}
+ // Show/hide the button
+ setTrayButtonVisible(RS_BUTTON_SPEAK, visible);
-void LLBottomTray::showMoveButton(BOOL visible)
-{
- setTrayButtonVisibleIfPossible(RS_BUTTON_MOVEMENT, visible);
-}
-
-void LLBottomTray::showCameraButton(BOOL visible)
-{
- setTrayButtonVisibleIfPossible(RS_BUTTON_CAMERA, visible);
-}
-
-void LLBottomTray::showSnapshotButton(BOOL visible)
-{
- setTrayButtonVisibleIfPossible(RS_BUTTON_SNAPSHOT, visible);
+ // and adjust other panels according to the occupied/freed space.
+ const S32 panel_width = mSpeakPanel->getRect().getWidth();
+ if (visible)
+ {
+ processWidthDecreased(-panel_width);
+ }
+ else
+ {
+ processWidthIncreased(panel_width);
+ }
}
void LLBottomTray::toggleMovementControls()
@@ -513,6 +524,9 @@ void LLBottomTray::toggleCameraControls()
BOOL LLBottomTray::postBuild()
{
+ LLHints::registerHintTarget("bottom_tray", LLView::getHandle());
+ LLHints::registerHintTarget("dest_guide_btn", getChild<LLUICtrl>("destination_btn")->getHandle());
+ LLHints::registerHintTarget("avatar_picker_btn", getChild<LLUICtrl>("avatar_btn")->getHandle());
LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("NearbyChatBar.Action", boost::bind(&LLBottomTray::onContextMenuItemClicked, this, _2));
LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("NearbyChatBar.EnableMenuItem", boost::bind(&LLBottomTray::onContextMenuItemEnabled, this, _2));
@@ -524,6 +538,7 @@ BOOL LLBottomTray::postBuild()
LLHints::registerHintTarget("chat_bar", mNearbyChatBar->LLView::getHandle());
mChatBarContainer = getChild<LLLayoutPanel>("chat_bar_layout_panel");
+ mNearbyCharResizeHandlePanel = getChild<LLPanel>("chat_bar_resize_handle_panel");
mToolbarStack = getChild<LLLayoutStack>("toolbar_stack");
mMovementButton = getChild<LLButton>("movement_btn");
@@ -532,16 +547,27 @@ BOOL LLBottomTray::postBuild()
setRightMouseDownCallback(boost::bind(&LLBottomTray::showBottomTrayContextMenu,this, _2, _3,_4));
mSpeakPanel = getChild<LLPanel>("speak_panel");
- mSpeakBtn = getChild<LLSpeakButton>("talk");
+ mSpeakBtn = findChild<LLSpeakButton>("talk");
+ if (mSpeakBtn)
+ {
+ LLHints::registerHintTarget("speak_btn", mSpeakBtn->getHandle());
+
+ // Localization tool doesn't understand custom buttons like <talk_button>
+ mSpeakBtn->setSpeakToolTip( getString("SpeakBtnToolTip") );
+ mSpeakBtn->setShowToolTip( getString("VoiceControlBtnToolTip") );
+ }
+ else
+ {
+ LLTransientFloaterMgr::getInstance()->addControlView(getChild<LLButton>("speak_btn"));
+ LLTransientFloaterMgr::getInstance()->addControlView(getChild<LLButton>("flyout_btn"));
+ }
+
// Both parts of speak button should be initially disabled because
// it takes some time between logging in to world and connecting to voice channel.
- mSpeakBtn->setSpeakBtnEnabled(false);
- mSpeakBtn->setFlyoutBtnEnabled(false);
+ getChild<LLButton>("speak_btn")->setEnabled(false);
+ getChild<LLButton>("speak_flyout_btn")->setEnabled(false);
- // Localization tool doesn't understand custom buttons like <talk_button>
- mSpeakBtn->setSpeakToolTip( getString("SpeakBtnToolTip") );
- mSpeakBtn->setShowToolTip( getString("VoiceControlBtnToolTip") );
// Registering Chat Bar to receive Voice client status change notifications.
LLVoiceClient::getInstance()->addObserver(this);
@@ -642,12 +668,20 @@ void LLBottomTray::onDraggableButtonHover(S32 x, S32 y)
gViewerWindow->getWindow()->setCursor(UI_CURSOR_NO);
}
}
+ else
+ {
+ // Reset cursor in case you move your mouse from the drag handle to a button.
+ getWindow()->setCursor(UI_CURSOR_ARROW);
+
+ }
}
bool LLBottomTray::isCursorOverDraggableArea(S32 x, S32 y)
{
+ // Draggable area lasts from the nearby chat input resize handle
+ // to the chiclet area (exlusively).
bool result = getRect().pointInRect(x, y);
- result = result && mNearbyChatBar->calcScreenRect().mRight < x;
+ result = result && mNearbyCharResizeHandlePanel->calcScreenRect().mRight < x;
result = result && mChicletPanel->calcScreenRect().mRight > x;
return result;
}
@@ -658,10 +692,7 @@ void LLBottomTray::updateButtonsOrdersAfterDnD()
// (and according to future possible changes in the way button order is saved between sessions).
state_object_map_t::const_iterator it = mStateProcessedObjectMap.begin();
state_object_map_t::const_iterator it_end = mStateProcessedObjectMap.end();
- // Speak button is currently the only draggable button not in mStateProcessedObjectMap,
- // so if dragged_state is not found in that map, it should be RS_BUTTON_SPEAK. Change this code if any other
- // exclusions from mStateProcessedObjectMap will become draggable.
- EResizeState dragged_state = RS_BUTTON_SPEAK;
+ EResizeState dragged_state = RS_NORESIZE;
EResizeState landing_state = RS_NORESIZE;
bool landing_state_found = false;
// Find states for dragged item and landing tab
@@ -677,7 +708,17 @@ void LLBottomTray::updateButtonsOrdersAfterDnD()
landing_state_found = true;
}
}
-
+
+ if (dragged_state == RS_NORESIZE)
+ {
+ llwarns << "Cannot determine what button is being dragged" << llendl;
+ llassert(dragged_state != RS_NORESIZE);
+ return;
+ }
+
+ lldebugs << "Will place " << resizeStateToString(dragged_state)
+ << " before " << resizeStateToString(landing_state) << llendl;
+
// Update order of buttons according to drag'n'drop
mButtonsOrder.erase(std::find(mButtonsOrder.begin(), mButtonsOrder.end(), dragged_state));
if (!landing_state_found && mLandingTab == getChild<LLPanel>(PANEL_CHICLET_NAME))
@@ -686,9 +727,10 @@ void LLBottomTray::updateButtonsOrdersAfterDnD()
}
else
{
- if (!landing_state_found) landing_state = RS_BUTTON_SPEAK;
+ if (!landing_state_found) landing_state = RS_BUTTON_SPEAK; // just a random fallback
mButtonsOrder.insert(std::find(mButtonsOrder.begin(), mButtonsOrder.end(), landing_state), dragged_state);
}
+
// Synchronize button process order with their order
resize_state_vec_t::const_iterator it1 = mButtonsOrder.begin();
const resize_state_vec_t::const_iterator it_end1 = mButtonsOrder.end();
@@ -709,6 +751,8 @@ void LLBottomTray::updateButtonsOrdersAfterDnD()
void LLBottomTray::saveButtonsOrder()
{
+ if (!gSavedSettings.getBOOL("AllowBottomTrayButtonReordering")) return;
+
std::string user_dir = gDirUtilp->getLindenUserDir();
if (user_dir.empty()) return;
@@ -729,6 +773,8 @@ void LLBottomTray::saveButtonsOrder()
void LLBottomTray::loadButtonsOrder()
{
+ if (!gSavedSettings.getBOOL("AllowBottomTrayButtonReordering")) return;
+
// load per-resident sorting information
std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, SORTING_DATA_FILE_NAME);
@@ -765,11 +811,12 @@ void LLBottomTray::loadButtonsOrder()
// placing panels in layout stack according to button order which we loaded in previous for
for (resize_state_vec_t::const_reverse_iterator it = mButtonsOrder.rbegin(); it != it_end; ++it, ++i)
{
- LLPanel* panel_to_move = *it == RS_BUTTON_SPEAK ? mSpeakPanel : mStateProcessedObjectMap[*it];
+ LLPanel* panel_to_move = getButtonPanel(*it);
mToolbarStack->movePanel(panel_to_move, NULL, true); // prepend
}
// Nearbychat is not stored in order settings file, but it must be the first of the panels, so moving it
- // manually here
+ // (along with its drag handle) manually here.
+ mToolbarStack->movePanel(getChild<LLLayoutPanel>("chat_bar_resize_handle_panel"), NULL, true);
mToolbarStack->movePanel(mChatBarContainer, NULL, true);
}
@@ -803,6 +850,28 @@ void LLBottomTray::draw()
LLRect rect = mLandingTab->calcScreenRect();
mImageDragIndication->draw(rect.mLeft - w/2, rect.getHeight(), w, h);
}
+ getChild<LLButton>("show_profile_btn")->setToggleState(LLAvatarActions::profileVisible(gAgent.getID()));
+
+ LLPanel* panel = LLSideTray::getInstance()->getPanel("panel_people");
+ if (panel && panel->isInVisibleChain())
+ {
+ getChild<LLButton>("show_people_button")->setToggleState(true);
+ }
+ else
+ {
+ getChild<LLButton>("show_people_button")->setToggleState(false);
+ }
+
+ LLFloater* help_browser = (LLFloaterReg::findInstance("help_browser"));
+ bool help_floater_visible = (help_browser && help_browser->isInVisibleChain());
+
+ getChild<LLButton>("show_help_btn")->setToggleState(help_floater_visible);
+
+ bool openmic = LLVoiceClient::getInstance()->getUserPTTState();
+ bool voiceenabled = LLVoiceClient::getInstance()->voiceEnabled();
+ getChild<LLButton>("speak_btn")->setToggleState(openmic && voiceenabled);
+ getChild<LLOutputMonitorCtrl>("chat_zone_indicator")->setIsMuted(!voiceenabled);
+
}
bool LLBottomTray::onContextMenuItemEnabled(const LLSD& userdata)
@@ -866,15 +935,14 @@ void LLBottomTray::log(LLView* panel, const std::string& descr)
{
if (NULL == panel) return;
LLView* layout = panel->getParent();
- lldebugs << descr << ": "
+ LL_DEBUGS("Bottom Tray Rects") << descr << ": "
<< "panel: " << panel->getName()
<< ", rect: " << panel->getRect()
- << "layout: " << layout->getName()
+ << " layout: " << layout->getName()
<< ", rect: " << layout->getRect()
- << llendl
- ;
+ << LL_ENDL;
}
void LLBottomTray::reshape(S32 width, S32 height, BOOL called_from_parent)
@@ -894,7 +962,9 @@ void LLBottomTray::reshape(S32 width, S32 height, BOOL called_from_parent)
if (mNearbyChatBar) log(mNearbyChatBar, "before");
if (mChicletPanel) log(mChicletPanel, "before");
- // stores width size on which bottom tray is less than width required by its children. EXT-991
+ // Difference between bottom tray width required to fit its children and the actual width. (see EXT-991)
+ // Positive value means that bottom tray is not wide enough.
+ // Negative value means that there is free space.
static S32 extra_shrink_width = 0;
bool should_be_reshaped = true;
@@ -916,11 +986,9 @@ void LLBottomTray::reshape(S32 width, S32 height, BOOL called_from_parent)
// bottom tray is narrowed
if (delta_width < 0)
{
- if (extra_shrink_width > 0)
+ if (extra_shrink_width > 0) // not enough space
{
- // is world rect was extra shrunk and decreasing again only update this value
- // to delta_width negative
- extra_shrink_width -= delta_width; // use "-=" because delta_width is negative
+ extra_shrink_width += llabs(delta_width);
should_be_reshaped = false;
}
else
@@ -931,13 +999,13 @@ void LLBottomTray::reshape(S32 width, S32 height, BOOL called_from_parent)
width += extra_shrink_width;
}
}
- // bottom tray is widen
+ // bottom tray is widened
else
{
if (extra_shrink_width > delta_width)
{
- // Less than minimum width is more than increasing (delta_width)
- // only reduce it value and make no reshape
+ // Still not enough space.
+ // Only subtract the delta from the required delta and don't reshape.
extra_shrink_width -= delta_width;
should_be_reshaped = false;
}
@@ -977,6 +1045,7 @@ void LLBottomTray::reshape(S32 width, S32 height, BOOL called_from_parent)
{
mDesiredNearbyChatWidth = new_width;
processChatbarCustomization(new_width);
+ lldebugs << "Setting nearby chat bar width to " << new_width << " px" << llendl;
mChatBarContainer->reshape(new_width, mChatBarContainer->getRect().getHeight());
}
needs_restore_custom_state = false;
@@ -988,30 +1057,28 @@ S32 LLBottomTray::processWidthDecreased(S32 delta_width)
{
bool still_should_be_processed = true;
- const S32 chiclet_panel_width = mChicletPanel->getParent()->getRect().getWidth();
- const S32 chiclet_panel_min_width = mChicletPanel->getMinWidth();
+ const S32 chiclet_panel_shrink_headroom = getChicletPanelShrinkHeadroom();
// There are four steps of processing width decrease. If in one of them required width was reached,
// further are not needed.
// 1. Decreasing width of chiclet panel.
- if (chiclet_panel_width > chiclet_panel_min_width)
+ if (chiclet_panel_shrink_headroom > 0)
{
// we have some space to decrease chiclet panel
- S32 panel_delta_min = chiclet_panel_width - chiclet_panel_min_width;
-
- S32 delta_panel = llmin(-delta_width, panel_delta_min);
+ S32 shrink_by = llmin(-delta_width, chiclet_panel_shrink_headroom);
lldebugs << "delta_width: " << delta_width
- << ", panel_delta_min: " << panel_delta_min
- << ", delta_panel: " << delta_panel
+ << ", panel_delta_min: " << chiclet_panel_shrink_headroom
+ << ", shrink_by: " << shrink_by
<< llendl;
- // is chiclet panel width enough to process resizing?
- delta_width += panel_delta_min;
+ // is chiclet panel wide enough to process resizing?
+ delta_width += chiclet_panel_shrink_headroom;
still_should_be_processed = delta_width < 0;
- mChicletPanel->getParent()->reshape(mChicletPanel->getParent()->getRect().getWidth() - delta_panel, mChicletPanel->getParent()->getRect().getHeight());
+ lldebugs << "Shrinking chiclet panel by " << shrink_by << " px" << llendl;
+ mChicletPanel->getParent()->reshape(mChicletPanel->getParent()->getRect().getWidth() - shrink_by, mChicletPanel->getParent()->getRect().getHeight());
log(mChicletPanel, "after processing panel decreasing via chiclet panel");
lldebugs << "RS_CHICLET_PANEL"
@@ -1035,7 +1102,7 @@ S32 LLBottomTray::processWidthDecreased(S32 delta_width)
S32 delta_panel = llmin(-delta_width, panel_delta_min);
- // whether chatbar panel width is enough to process resizing?
+ // is chatbar panel wide enough to process resizing?
delta_width += panel_delta_min;
still_should_be_processed = delta_width < 0;
@@ -1043,6 +1110,7 @@ S32 LLBottomTray::processWidthDecreased(S32 delta_width)
// chatbar should only be shrunk here, not stretched
if(delta_panel > 0)
{
+ lldebugs << "Shrinking nearby chat bar by " << delta_panel << " px " << llendl;
mChatBarContainer->reshape(mNearbyChatBar->getRect().getWidth() - delta_panel, mChatBarContainer->getRect().getHeight());
}
@@ -1074,6 +1142,7 @@ S32 LLBottomTray::processWidthDecreased(S32 delta_width)
{
S32 compensative_width = nearby_needed_width > buttons_freed_width ? buttons_freed_width : nearby_needed_width;
log(mNearbyChatBar, "before applying compensative width");
+ lldebugs << "Extending nearby chat bar by " << compensative_width << " px" << llendl;
mChatBarContainer->reshape(mChatBarContainer->getRect().getWidth() + compensative_width, mChatBarContainer->getRect().getHeight() );
log(mNearbyChatBar, "after applying compensative width");
lldebugs << buttons_freed_width << llendl;
@@ -1088,52 +1157,46 @@ void LLBottomTray::processWidthIncreased(S32 delta_width)
{
if (delta_width <= 0) return;
- const S32 chiclet_panel_width = mChicletPanel->getParent()->getRect().getWidth();
- static const S32 chiclet_panel_min_width = mChicletPanel->getMinWidth();
-
- const S32 available_width_chiclet = chiclet_panel_width - chiclet_panel_min_width;
+ // how much room we have to show hidden buttons
+ S32 available_width = delta_width + getChicletPanelShrinkHeadroom();
- // how many room we have to show hidden buttons
- S32 total_available_width = delta_width + available_width_chiclet;
-
- lldebugs << "Processing extending, available width:"
- << ", chiclets - " << available_width_chiclet
- << ", total - " << total_available_width
- << llendl;
+ lldebugs << "Distributing (" << getChicletPanelShrinkHeadroom()
+ << " + " << delta_width << ") = " << available_width << " px" << llendl;
- S32 available_width = total_available_width;
+ // 1. Try showing buttons that have been auto-hidden.
+ S32 processed_width = processShowButtons(available_width);
+ lldebugs << "processed_width = " << processed_width << ", delta_width = " << delta_width << llendl;
- processShowButtons(available_width);
+ lldebugs << "Available_width after showing buttons: " << available_width << llendl;
- // if we have to show/extend some buttons but resized delta width is not enough...
- S32 processed_width = total_available_width - available_width;
+ // If the newly shown buttons have consumed more than delta_width pixels,
+ // shrink the chiclet panel.
if (processed_width > delta_width)
{
- // ... let's shrink nearby chat & chiclet panels
- S32 required_to_process_width = processed_width;
-
// 1. use delta width of resizing
- required_to_process_width -= delta_width;
+ S32 shrink_by = processed_width - delta_width;
// 2. use width available via decreasing of chiclet panel
- if (required_to_process_width > 0)
+ if (shrink_by > 0)
{
- mChicletPanel->getParent()->reshape(mChicletPanel->getParent()->getRect().getWidth() - required_to_process_width, mChicletPanel->getParent()->getRect().getHeight());
+ lldebugs << "Shrinking chiclet panel by " << shrink_by << " px" << llendl;
+ mChicletPanel->getParent()->reshape(mChicletPanel->getParent()->getRect().getWidth() - shrink_by, mChicletPanel->getParent()->getRect().getHeight());
log(mChicletPanel, "after applying compensative width for chiclets: ");
- lldebugs << required_to_process_width << llendl;
+ lldebugs << shrink_by << llendl;
}
+ // shown buttons take some space, rest should be processed by nearby chatbar & chiclet panels
+ delta_width -= processed_width;
}
- // shown buttons take some space, rest should be processed by nearby chatbar & chiclet panels
- delta_width -= processed_width;
-
-
- // how many space can nearby chatbar take?
- S32 chatbar_panel_width_ = mChatBarContainer->getRect().getWidth();
- if (delta_width > 0 && chatbar_panel_width_ < mDesiredNearbyChatWidth)
+ // 2. Expand the nearby chat bar if needed.
+ S32 chatbar_panel_width = mChatBarContainer->getRect().getWidth();
+ lldebugs << "delta_width = " << delta_width
+ << ", chatbar_panel_width = " << chatbar_panel_width
+ << ", mDesiredNearbyChatWidth = " << mDesiredNearbyChatWidth << llendl;
+ if (delta_width > 0 && chatbar_panel_width < mDesiredNearbyChatWidth)
{
- S32 delta_panel_max = mDesiredNearbyChatWidth - chatbar_panel_width_;
+ S32 delta_panel_max = mDesiredNearbyChatWidth - chatbar_panel_width;
S32 delta_panel = llmin(delta_width, delta_panel_max);
lldebugs << "Unprocesed delta width: " << delta_width
<< ", can be applied to chatbar: " << delta_panel_max
@@ -1141,17 +1204,25 @@ void LLBottomTray::processWidthIncreased(S32 delta_width)
<< llendl;
delta_width -= delta_panel_max;
- mChatBarContainer->reshape(chatbar_panel_width_ + delta_panel, mChatBarContainer->getRect().getHeight());
+ lldebugs << "Extending nearby chat bar by " << delta_panel << " px " << llendl;
+ mChatBarContainer->reshape(chatbar_panel_width + delta_panel, mChatBarContainer->getRect().getHeight());
log(mNearbyChatBar, "applied unprocessed delta width");
}
+
+ // 3. Expand buttons that have been auto-shrunk,
+ // if we haven't yet consumed all the available headroom.
if (delta_width > 0)
{
- processExtendButtons(delta_width);
+ S32 available_width = delta_width + getChicletPanelShrinkHeadroom();
+ processExtendButtons(available_width);
}
}
-void LLBottomTray::processShowButtons(S32& available_width)
+S32 LLBottomTray::processShowButtons(S32& available_width)
{
+ lldebugs << "Distributing " << available_width << " px" << llendl;
+ S32 original_available_width = available_width;
+
// process buttons from left to right
resize_state_vec_t::const_iterator it = mButtonsProcessOrder.begin();
const resize_state_vec_t::const_iterator it_end = mButtonsProcessOrder.end();
@@ -1164,38 +1235,20 @@ void LLBottomTray::processShowButtons(S32& available_width)
// try to show next button
processShowButton(*it, available_width);
}
+
+ return original_available_width - available_width;
}
bool LLBottomTray::processShowButton(EResizeState shown_object_type, S32& available_width)
{
- lldebugs << "Trying to show object type: " << shown_object_type << llendl;
- llassert(mStateProcessedObjectMap[shown_object_type] != NULL);
-
- LLPanel* panel = mStateProcessedObjectMap[shown_object_type];
- if (NULL == panel)
+ // Check if the button was previously auto-hidden (due to lack of space).
+ if (!isAutoHidden(shown_object_type))
{
- lldebugs << "There is no object to process for state: " << shown_object_type << llendl;
return false;
}
- bool can_be_shown = canButtonBeShown(shown_object_type);
- if (can_be_shown)
- {
- //validate if we have enough room to show this button
- const S32 required_width = panel->getRect().getWidth();
- can_be_shown = available_width >= required_width;
- if (can_be_shown)
- {
- available_width -= required_width;
-
- setTrayButtonVisible(shown_object_type, true);
- lldebugs << "processed object type: " << shown_object_type
- << ", rest available width: " << available_width
- << llendl;
- mResizeState &= ~shown_object_type;
- }
- }
- return can_be_shown;
+ // Ok. Try showing the button.
+ return showButton(shown_object_type, available_width);
}
void LLBottomTray::processHideButtons(S32& required_width, S32& buttons_freed_width)
@@ -1217,12 +1270,9 @@ void LLBottomTray::processHideButtons(S32& required_width, S32& buttons_freed_wi
void LLBottomTray::processHideButton(EResizeState processed_object_type, S32& required_width, S32& buttons_freed_width)
{
lldebugs << "Trying to hide object type: " << processed_object_type << llendl;
- llassert(mStateProcessedObjectMap[processed_object_type] != NULL);
-
- LLPanel* panel = mStateProcessedObjectMap[processed_object_type];
+ LLPanel* panel = getButtonPanel(processed_object_type);
if (NULL == panel)
{
- lldebugs << "There is no object to process for state: " << processed_object_type << llendl;
return;
}
@@ -1237,7 +1287,7 @@ void LLBottomTray::processHideButton(EResizeState processed_object_type, S32& re
setTrayButtonVisible(processed_object_type, false);
- mResizeState |= processed_object_type;
+ setAutoHidden(processed_object_type, true);
lldebugs << "processing object type: " << processed_object_type
<< ", buttons_freed_width: " << buttons_freed_width
@@ -1264,7 +1314,6 @@ void LLBottomTray::processShrinkButtons(S32& required_width, S32& buttons_freed_
// then shrink Speak button
if (required_width < 0)
{
-
S32 panel_min_width = 0;
std::string panel_name = mSpeakPanel->getName();
bool success = mToolbarStack->getPanelMinSize(panel_name, &panel_min_width);
@@ -1279,7 +1328,11 @@ void LLBottomTray::processShrinkButtons(S32& required_width, S32& buttons_freed_
if (possible_shrink_width > 0)
{
- mSpeakBtn->setLabelVisible(false);
+ if (mSpeakBtn)
+ {
+ mSpeakBtn->setLabelVisible(false);
+ }
+
mSpeakPanel->reshape(panel_width - possible_shrink_width, mSpeakPanel->getRect().getHeight());
required_width += possible_shrink_width;
@@ -1300,11 +1353,9 @@ void LLBottomTray::processShrinkButtons(S32& required_width, S32& buttons_freed_
void LLBottomTray::processShrinkButton(EResizeState processed_object_type, S32& required_width)
{
- llassert(mStateProcessedObjectMap[processed_object_type] != NULL);
- LLPanel* panel = mStateProcessedObjectMap[processed_object_type];
+ LLPanel* panel = getButtonPanel(processed_object_type);
if (NULL == panel)
{
- lldebugs << "There is no object to process for type: " << processed_object_type << llendl;
return;
}
@@ -1349,133 +1400,168 @@ void LLBottomTray::processShrinkButton(EResizeState processed_object_type, S32&
void LLBottomTray::processExtendButtons(S32& available_width)
{
// do not allow extending any buttons if we have some buttons hidden via resize
- if (mResizeState & RS_BUTTONS_CAN_BE_HIDDEN) return;
+ if (isAutoHidden(RS_BUTTONS_CAN_BE_HIDDEN)) return;
- // process buttons from left to right
- resize_state_vec_t::const_iterator it = mButtonsProcessOrder.begin();
- const resize_state_vec_t::const_iterator it_end = mButtonsProcessOrder.end();
+ lldebugs << "Distributing " << available_width << " px" << llendl;
- // iterate through buttons in the mButtonsProcessOrder first
- for (; it != it_end; ++it)
+ // First try extending the Speak button.
+ if (available_width > 0)
{
- // is there available space?
- if (available_width <= 0) break;
-
- // try to extend next button
- processExtendButton(*it, available_width);
+ if (!processExtendSpeakButton(available_width))
+ {
+ // The Speak button needs extension but lacks some space.
+ // Don't extend other buttons in this case: the Speak button
+ // should consume the available headroom first.
+ return;
+ }
}
- // then try to extend Speak button
+ // Then process the other buttons from left to right.
if (available_width > 0)
{
- S32 panel_max_width = mObjectDefaultWidthMap[RS_BUTTON_SPEAK];
- S32 panel_width = mSpeakPanel->getRect().getWidth();
- S32 possible_extend_width = panel_max_width - panel_width;
- if (possible_extend_width >= 0 && possible_extend_width <= available_width) // HACK: this button doesn't change size so possible_extend_width will be 0
+ resize_state_vec_t::const_iterator it = mButtonsProcessOrder.begin();
+ const resize_state_vec_t::const_iterator it_end = mButtonsProcessOrder.end();
+
+ // iterate through buttons in the mButtonsProcessOrder first
+ for (; it != it_end; ++it)
{
- mSpeakBtn->setLabelVisible(true);
- mSpeakPanel->reshape(panel_max_width, mSpeakPanel->getRect().getHeight());
- log(mSpeakBtn, "speak button is extended");
+ // is there available space?
+ if (available_width <= 0) break;
+
+ // try to extend next button
+ processExtendButton(*it, available_width);
+ }
+ }
+}
- available_width -= possible_extend_width;
+bool LLBottomTray::processExtendSpeakButton(S32& available_width)
+{
+ if (available_width <= 0)
+ {
+ llassert(available_width > 0);
+ return true;
+ }
- lldebugs << "Extending Speak button panel: " << mSpeakPanel->getName()
- << ", extended width: " << possible_extend_width
- << ", rest width to process: " << available_width
- << llendl;
+ const S32 panel_max_width = mObjectDefaultWidthMap[RS_BUTTON_SPEAK];
+ const S32 panel_width = mSpeakPanel->getRect().getWidth();
+ const S32 required_headroom = panel_max_width - panel_width;
+
+ if (panel_width < panel_max_width) // if the button isn't extended already
+ {
+ if (available_width < required_headroom) // not enough space
+ {
+ lldebugs << "Need (" << required_headroom << " - " << available_width << ") = "
+ << (required_headroom - available_width) << " more px"
+ << " to extend the Speak button"<< llendl;
+
+ return false; // Don't extend other buttons until we extend Speak.
}
+
+ // Reshape the Speak button to its maximum width.
+ if (mSpeakBtn) mSpeakBtn->setLabelVisible(true);
+ mSpeakPanel->reshape(panel_max_width, mSpeakPanel->getRect().getHeight());
+
+ available_width -= required_headroom;
+ llassert(available_width >= 0);
+
+ lldebugs << "Extending Speak button panel: " << mSpeakPanel->getName()
+ << ", extended width: " << required_headroom
+ << ", rest width to process: " << available_width
+ << llendl;
}
+
+ return true;
}
void LLBottomTray::processExtendButton(EResizeState processed_object_type, S32& available_width)
{
- llassert(mStateProcessedObjectMap[processed_object_type] != NULL);
- LLPanel* panel = mStateProcessedObjectMap[processed_object_type];
+ llassert(available_width >= 0);
+
+ LLPanel* panel = getButtonPanel(processed_object_type);
if (NULL == panel)
{
- lldebugs << "There is no object to process for type: " << processed_object_type << llendl;
return;
}
if (!panel->getVisible()) return;
+ // Widen the button up to its maximum width, but by not more than <available_width> px.
S32 panel_max_width = mObjectDefaultWidthMap[processed_object_type];
S32 panel_width = panel->getRect().getWidth();
- S32 possible_extend_width = panel_max_width - panel_width;
+ S32 required_headroom = panel_max_width - panel_width;
- if (possible_extend_width > 0)
+ S32 extend_by = llmin(available_width, required_headroom);
+ if (extend_by > 0)
{
- // let calculate real width to extend
+ panel->reshape(panel_width + extend_by, panel->getRect().getHeight());
- // 1. apply all possible width
- available_width -= possible_extend_width;
-
- // 2. it it is too much...
- if (available_width < 0)
- {
- // reduce applied extended width to the excessive value.
- possible_extend_width += available_width;
- available_width = 0;
- }
- panel->reshape(panel_width + possible_extend_width, panel->getRect().getHeight());
+ // Decrease amount of headroom available for other panels.
+ available_width -= extend_by;
- lldebugs << "Extending panel: " << panel->getName()
- << ", extended width: " << possible_extend_width
- << ", rest width to process: " << available_width
+ lldebugs << "Extending " << panel->getName()
+ << " by " << extend_by
+ << " px; remaining available width: " << available_width
<< llendl;
}
}
bool LLBottomTray::canButtonBeShown(EResizeState processed_object_type) const
{
- // 0. Check if passed button was previously hidden on resize
- bool can_be_shown = mResizeState & processed_object_type;
- if (can_be_shown)
- {
- // Yes, it was. Lets now check that all buttons before it (that can be hidden on resize)
- // are already shown
-
- // process buttons in direct order (from left to right)
- resize_state_vec_t::const_iterator it = mButtonsProcessOrder.begin();
- const resize_state_vec_t::const_iterator it_end = mButtonsProcessOrder.end();
+ // Check that all buttons (that can be hidden on resize)
+ // to the left of the given one are already shown.
- // 1. Find and accumulate all buttons types before one passed into the method.
- MASK buttons_before_mask = RS_NORESIZE;
- for (; it != it_end; ++it)
- {
- const EResizeState button_type = *it;
- if (button_type == processed_object_type) break;
+ // process buttons in direct order (from left to right)
+ resize_state_vec_t::const_iterator it = mButtonsProcessOrder.begin();
+ const resize_state_vec_t::const_iterator it_end = mButtonsProcessOrder.end();
- buttons_before_mask |= button_type;
- }
+ MASK buttons_before_mask = RS_NORESIZE;
+ for (; it != it_end; ++it)
+ {
+ const EResizeState button_type = *it;
+ if (button_type == processed_object_type) break;
- // 2. Check if some previous buttons are still hidden on resize
- can_be_shown = !(buttons_before_mask & mResizeState);
+ buttons_before_mask |= button_type;
}
- return can_be_shown;
+
+ return !isAutoHidden(buttons_before_mask);
}
void LLBottomTray::initResizeStateContainers()
{
// init map with objects should be processed for each type
+ mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_SPEAK, getChild<LLPanel>("speak_panel")));
mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_GESTURES, getChild<LLPanel>("gesture_panel")));
mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_MOVEMENT, getChild<LLPanel>("movement_panel")));
mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_CAMERA, getChild<LLPanel>("cam_panel")));
+ mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_DESTINATIONS, getChild<LLPanel>("destinations_panel")));
+ mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_AVATARS, getChild<LLPanel>("avatar_panel")));
mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_SNAPSHOT, getChild<LLPanel>("snapshot_panel")));
mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_BUILD, getChild<LLPanel>("build_btn_panel")));
mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_SEARCH, getChild<LLPanel>("search_btn_panel")));
mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_WORLD_MAP, getChild<LLPanel>("world_map_btn_panel")));
mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_MINI_MAP, getChild<LLPanel>("mini_map_btn_panel")));
+ mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_SPLITTER_1, getChild<LLPanel>("splitter_panel_1")));
+ mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_PEOPLE, getChild<LLPanel>("people_panel")));
+ mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_PROFILE, getChild<LLPanel>("profile_panel")));
+ mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_SPLITTER_2, getChild<LLPanel>("splitter_panel_2")));
+ mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_HOWTO, getChild<LLPanel>("howto_panel")));
// init an order of processed buttons
- mButtonsProcessOrder.push_back(RS_BUTTON_GESTURES);
- mButtonsProcessOrder.push_back(RS_BUTTON_MOVEMENT);
- mButtonsProcessOrder.push_back(RS_BUTTON_CAMERA);
+ mButtonsProcessOrder.push_back(RS_BUTTON_DESTINATIONS);
+ mButtonsProcessOrder.push_back(RS_BUTTON_AVATARS);
mButtonsProcessOrder.push_back(RS_BUTTON_SNAPSHOT);
mButtonsProcessOrder.push_back(RS_BUTTON_BUILD);
mButtonsProcessOrder.push_back(RS_BUTTON_SEARCH);
mButtonsProcessOrder.push_back(RS_BUTTON_WORLD_MAP);
mButtonsProcessOrder.push_back(RS_BUTTON_MINI_MAP);
+ mButtonsProcessOrder.push_back(RS_BUTTON_SPLITTER_1);
+ mButtonsProcessOrder.push_back(RS_BUTTON_PEOPLE);
+ mButtonsProcessOrder.push_back(RS_BUTTON_PROFILE);
+ mButtonsProcessOrder.push_back(RS_BUTTON_SPLITTER_2);
+ mButtonsProcessOrder.push_back(RS_BUTTON_HOWTO);
+ mButtonsProcessOrder.push_back(RS_BUTTON_MOVEMENT);
+ mButtonsProcessOrder.push_back(RS_BUTTON_CAMERA);
+ mButtonsProcessOrder.push_back(RS_BUTTON_GESTURES);
mButtonsOrder.push_back(RS_BUTTON_SPEAK);
mButtonsOrder.insert(mButtonsOrder.end(), mButtonsProcessOrder.begin(), mButtonsProcessOrder.end());
@@ -1490,22 +1576,22 @@ void LLBottomTray::initResizeStateContainers()
{
const EResizeState button_type = *it;
// is there an appropriate object?
- llassert(mStateProcessedObjectMap.count(button_type) > 0);
- if (0 == mStateProcessedObjectMap.count(button_type)) continue;
+ LLPanel* button_panel = getButtonPanel(button_type);
+ if (!button_panel) continue;
// set default width for it.
- mObjectDefaultWidthMap[button_type] = mStateProcessedObjectMap[button_type]->getRect().getWidth();
+ mObjectDefaultWidthMap[button_type] = button_panel->getRect().getWidth();
}
// ... and add Speak button because it also can be shrunk.
mObjectDefaultWidthMap[RS_BUTTON_SPEAK] = mSpeakPanel->getRect().getWidth();
-
}
// this method must be called before restoring of the chat entry field on startup
// because it resets chatbar's width according to resize logic.
void LLBottomTray::initButtonsVisibility()
{
+ setVisibleAndFitWidths(RS_BUTTON_SPEAK, gSavedSettings.getBOOL("EnableVoiceChat") || !mSpeakBtn );
setVisibleAndFitWidths(RS_BUTTON_GESTURES, gSavedSettings.getBOOL("ShowGestureButton"));
setVisibleAndFitWidths(RS_BUTTON_MOVEMENT, gSavedSettings.getBOOL("ShowMoveButton"));
setVisibleAndFitWidths(RS_BUTTON_CAMERA, gSavedSettings.getBOOL("ShowCameraButton"));
@@ -1514,10 +1600,17 @@ void LLBottomTray::initButtonsVisibility()
setVisibleAndFitWidths(RS_BUTTON_SEARCH, gSavedSettings.getBOOL("ShowSearchButton"));
setVisibleAndFitWidths(RS_BUTTON_WORLD_MAP, gSavedSettings.getBOOL("ShowWorldMapButton"));
setVisibleAndFitWidths(RS_BUTTON_MINI_MAP, gSavedSettings.getBOOL("ShowMiniMapButton"));
+ lldebugs << "mResizeState = " << resizeStateMaskToString(mResizeState) << llendl;
}
void LLBottomTray::setButtonsControlsAndListeners()
{
+ // always show the speak panel if using the basic skin
+ if (mSpeakBtn)
+ {
+ gSavedSettings.getControl("EnableVoiceChat")->getSignal()->connect(boost::bind(&LLBottomTray::toggleShowButton, RS_BUTTON_SPEAK, _2));
+ }
+
gSavedSettings.getControl("ShowGestureButton")->getSignal()->connect(boost::bind(&LLBottomTray::toggleShowButton, RS_BUTTON_GESTURES, _2));
gSavedSettings.getControl("ShowMoveButton")->getSignal()->connect(boost::bind(&LLBottomTray::toggleShowButton, RS_BUTTON_MOVEMENT, _2));
gSavedSettings.getControl("ShowCameraButton")->getSignal()->connect(boost::bind(&LLBottomTray::toggleShowButton, RS_BUTTON_CAMERA, _2));
@@ -1544,13 +1637,53 @@ bool LLBottomTray::toggleShowButton(LLBottomTray::EResizeState button_type, cons
return true;
}
+bool LLBottomTray::showButton(EResizeState button_type, S32& available_width)
+{
+ LLPanel* panel = getButtonPanel(button_type);
+ if (NULL == panel)
+ {
+ return false;
+ }
+
+ if (panel->getVisible())
+ {
+ return false;
+ }
+
+ // Check if none of the buttons to the left of the given one was auto-hidden.
+ // (we auto-show the buttons left to right).
+ if (!canButtonBeShown(button_type))
+ {
+ return false;
+ }
+
+ // Make sure we have enough room to show this button.
+ const S32 required_width = panel->getRect().getWidth();
+ if (available_width < required_width)
+ {
+ lldebugs << "Need " << (required_width - available_width) << " more px to show " << resizeStateToString(button_type) << llendl;
+ return false;
+ }
+
+ // All good. Show the button.
+ setTrayButtonVisible(button_type, true);
+
+ // Let the caller know that there is now less available space.
+ available_width -= required_width;
+
+ lldebugs << "Showing button " << resizeStateToString(button_type)
+ << ", remaining available width: " << available_width
+ << llendl;
+ setAutoHidden(button_type, false);
+
+ return true;
+}
+
void LLBottomTray::setTrayButtonVisible(EResizeState shown_object_type, bool visible)
{
- llassert(mStateProcessedObjectMap[shown_object_type] != NULL);
- LLPanel* panel = mStateProcessedObjectMap[shown_object_type];
+ LLPanel* panel = getButtonPanel(shown_object_type);
if (NULL == panel)
{
- lldebugs << "There is no object to show for state: " << shown_object_type << llendl;
return;
}
@@ -1570,10 +1703,17 @@ void LLBottomTray::setTrayButtonVisibleIfPossible(EResizeState shown_object_type
bool LLBottomTray::setVisibleAndFitWidths(EResizeState object_type, bool visible)
{
- LLPanel* cur_panel = mStateProcessedObjectMap[object_type];
+ // The Speak button is treated specially: if voice is enabled,
+ // the button should be displayed no matter how much space we've got.
+ if (object_type == RS_BUTTON_SPEAK)
+ {
+ showSpeakButton(visible);
+ return true;
+ }
+
+ LLPanel* cur_panel = getButtonPanel(object_type);
if (NULL == cur_panel)
{
- lldebugs << "There is no object to process for state: " << object_type << llendl;
return false;
}
@@ -1582,17 +1722,13 @@ bool LLBottomTray::setVisibleAndFitWidths(EResizeState object_type, bool visible
if (visible)
{
// Assume that only chiclet panel can be auto-resized
- const S32 available_width =
- mChicletPanel->getParent()->getRect().getWidth() - mChicletPanel->getMinWidth();
+ const S32 available_width = getChicletPanelShrinkHeadroom();
S32 preferred_width = mObjectDefaultWidthMap[object_type];
S32 current_width = cur_panel->getRect().getWidth();
S32 result_width = 0;
bool decrease_width = false;
- // Mark this button to be shown
- mResizeState |= object_type;
-
if (preferred_width > 0 && available_width >= preferred_width)
{
result_width = preferred_width;
@@ -1615,7 +1751,7 @@ bool LLBottomTray::setVisibleAndFitWidths(EResizeState object_type, bool visible
for (; it != it_end; ++it)
{
- LLPanel * cur_panel = mStateProcessedObjectMap[*it];
+ LLPanel* cur_panel = getButtonPanel(*it);
sum_of_min_widths += get_panel_min_width(mToolbarStack, cur_panel);
sum_of_curr_widths += get_curr_width(cur_panel);
}
@@ -1636,7 +1772,11 @@ bool LLBottomTray::setVisibleAndFitWidths(EResizeState object_type, bool visible
}
else
{
- // Nothing can be done, give up...
+ lldebugs << "Need " << (minimal_width - available_width - possible_shrunk_width)
+ << " more px to show " << resizeStateToString(object_type) << llendl;
+
+ // Make the button uppear when we have more available space.
+ setAutoHidden(object_type, true);
return false;
}
}
@@ -1647,7 +1787,7 @@ bool LLBottomTray::setVisibleAndFitWidths(EResizeState object_type, bool visible
current_width = result_width;
}
- is_set = processShowButton(object_type, current_width);
+ is_set = showButton(object_type, current_width);
// Shrink buttons if needed
if (is_set && decrease_width)
@@ -1662,7 +1802,8 @@ bool LLBottomTray::setVisibleAndFitWidths(EResizeState object_type, bool visible
setTrayButtonVisible(object_type, false);
// Mark button NOT to show while future bottom tray extending
- mResizeState &= ~object_type;
+ lldebugs << "Removing " << resizeStateToString(object_type) << " from mResizeState" << llendl;
+ setAutoHidden(object_type, false);
// Extend other buttons if need
if (delta_width)
@@ -1673,6 +1814,19 @@ bool LLBottomTray::setVisibleAndFitWidths(EResizeState object_type, bool visible
return is_set;
}
+LLPanel* LLBottomTray::getButtonPanel(EResizeState button_type)
+{
+ // Don't use the operator[] because it inserts a NULL value if the key is not found.
+ if (mStateProcessedObjectMap.count(button_type) == 0)
+ {
+ llwarns << "Cannot find a panel for " << resizeStateToString(button_type) << llendl;
+ llassert(mStateProcessedObjectMap.count(button_type) == 1);
+ return NULL;
+ }
+
+ return mStateProcessedObjectMap[button_type];
+}
+
void LLBottomTray::showWellButton(EResizeState object_type, bool visible)
{
llassert( ((RS_NOTIFICATION_WELL | RS_IM_WELL) & object_type) == object_type );
@@ -1706,12 +1860,14 @@ void LLBottomTray::processChatbarCustomization(S32 new_width)
if (delta_width == 0) return;
+ {
+ static unsigned dbg_cnt = 0;
+ lldebugs << llformat("*** (%03d) ************************************* %d", delta_width, ++dbg_cnt) << llendl;
+ }
+
mDesiredNearbyChatWidth = new_width;
- LLView * chiclet_layout_panel = mChicletPanel->getParent();
- const S32 chiclet_min_width = get_panel_min_width(mToolbarStack, chiclet_layout_panel);
- const S32 chiclet_panel_width = chiclet_layout_panel->getRect().getWidth();
- const S32 available_chiclet_shrink_width = chiclet_panel_width - chiclet_min_width;
+ const S32 available_chiclet_shrink_width = getChicletPanelShrinkHeadroom();
llassert(available_chiclet_shrink_width >= 0);
if (delta_width > 0) // panel gets narrowly
@@ -1730,4 +1886,99 @@ void LLBottomTray::processChatbarCustomization(S32 new_width)
}
}
+S32 LLBottomTray::getChicletPanelShrinkHeadroom() const
+{
+ static const S32 min_width = mChicletPanel->getMinWidth();
+ const S32 cur_width = mChicletPanel->getParent()->getRect().getWidth();
+
+ S32 shrink_headroom = cur_width - min_width;
+ llassert(shrink_headroom >= 0); // the panel cannot get narrower than the minimum
+ return shrink_headroom;
+}
+
+// static
+std::string LLBottomTray::resizeStateToString(EResizeState state)
+{
+ const char *rs_string = "UNKNOWN_BUTTON";
+
+ switch (state)
+ {
+ case RS_NORESIZE: rs_string = "RS_NORESIZE"; break;
+ case RS_CHICLET_PANEL: rs_string = "RS_CHICLET_PANEL"; break;
+ case RS_CHATBAR_INPUT: rs_string = "RS_CHATBAR_INPUT"; break;
+ case RS_BUTTON_SNAPSHOT: rs_string = "RS_BUTTON_SNAPSHOT"; break;
+ case RS_BUTTON_CAMERA: rs_string = "RS_BUTTON_CAMERA"; break;
+ case RS_BUTTON_MOVEMENT: rs_string = "RS_BUTTON_MOVEMENT"; break;
+ case RS_BUTTON_GESTURES: rs_string = "RS_BUTTON_GESTURES"; break;
+ case RS_BUTTON_SPEAK: rs_string = "RS_BUTTON_SPEAK"; break;
+ case RS_IM_WELL: rs_string = "RS_IM_WELL"; break;
+ case RS_NOTIFICATION_WELL: rs_string = "RS_NOTIFICATION_WELL"; break;
+ case RS_BUTTON_BUILD: rs_string = "RS_BUTTON_BUILD"; break;
+ case RS_BUTTON_SEARCH: rs_string = "RS_BUTTON_SEARCH"; break;
+ case RS_BUTTON_WORLD_MAP: rs_string = "RS_BUTTON_WORLD_MAP"; break;
+ case RS_BUTTON_MINI_MAP: rs_string = "RS_BUTTON_MINI_MAP"; break;
+ case RS_BUTTON_DESTINATIONS: rs_string = "RS_BUTTON_DESTINATIONS"; break;
+ case RS_BUTTON_AVATARS: rs_string = "RS_BUTTON_AVATARS"; break;
+ case RS_BUTTON_PEOPLE: rs_string = "RS_BUTTON_PEOPLE"; break;
+ case RS_BUTTON_PROFILE: rs_string = "RS_BUTTON_PROFILE"; break;
+ case RS_BUTTON_HOWTO: rs_string = "RS_BUTTON_HOWTO"; break;
+ case RS_BUTTON_SPLITTER_1: rs_string = "RS_BUTTON_SPLITTER_1"; break;
+ case RS_BUTTON_SPLITTER_2: rs_string = "RS_BUTTON_SPLITTER_2"; break;
+ case RS_BUTTONS_CAN_BE_HIDDEN: rs_string = "RS_BUTTONS_CAN_BE_HIDDEN"; break;
+ // No default to track additions.
+ }
+
+ return rs_string;
+}
+
+// static
+std::string LLBottomTray::resizeStateMaskToString(MASK mask)
+{
+ std::string res;
+
+ bool add_delimiter = false;
+ for (U32 i = 0; i < 16; i++)
+ {
+ EResizeState state = (EResizeState) (1 << i);
+ if (mask & state)
+ {
+ if (!add_delimiter)
+ {
+ add_delimiter = true;
+ }
+ else
+ {
+ res += ", ";
+ }
+
+ res += resizeStateToString(state);
+ }
+ }
+
+ if (res.empty())
+ {
+ res = resizeStateToString(RS_NORESIZE);
+ }
+
+ res += llformat(" (0x%X)", mask);
+ return res;
+}
+
+bool LLBottomTray::isAutoHidden(MASK button_types) const
+{
+ return (mResizeState & button_types) != 0;
+}
+
+void LLBottomTray::setAutoHidden(MASK button_types, bool hide)
+{
+ if (hide)
+ {
+ mResizeState |= button_types;
+ }
+ else
+ {
+ mResizeState &= ~button_types;
+ }
+}
+
//EOF
diff --git a/indra/newview/llbottomtray.h b/indra/newview/llbottomtray.h
index 8d8a42c553..d9c95d82e5 100644
--- a/indra/newview/llbottomtray.h
+++ b/indra/newview/llbottomtray.h
@@ -54,7 +54,9 @@ class LLBottomtrayButton : public LLButton
public:
struct Params : public LLInitParam::Block<Params, LLButton::Params>
{
- Params(){}
+ Optional<bool> can_drag;
+ Params()
+ : can_drag("can_drag", true){}
};
/*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask);
/*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask);
@@ -62,11 +64,14 @@ public:
protected:
LLBottomtrayButton(const Params& p)
- : LLButton(p)
+ : LLButton(p),
+ mCanDrag(p.can_drag)
{
}
friend class LLUICtrlFactory;
+
+ bool mCanDrag;
};
class LLBottomTray
@@ -107,10 +112,7 @@ public:
void showBottomTrayContextMenu(S32 x, S32 y, MASK mask);
- void showGestureButton(BOOL visible);
- void showMoveButton(BOOL visible);
- void showCameraButton(BOOL visible);
- void showSnapshotButton(BOOL visible);
+ void showSpeakButton(bool visible);
void toggleMovementControls();
void toggleCameraControls();
@@ -138,22 +140,29 @@ public:
private:
- typedef enum e_resize_status_type
+ typedef enum e_resize_state
{
- RS_NORESIZE = 0x0000
- , RS_CHICLET_PANEL = 0x0001
- , RS_CHATBAR_INPUT = 0x0002
- , RS_BUTTON_SNAPSHOT = 0x0004
- , RS_BUTTON_CAMERA = 0x0008
- , RS_BUTTON_MOVEMENT = 0x0010
- , RS_BUTTON_GESTURES = 0x0020
- , RS_BUTTON_SPEAK = 0x0040
- , RS_IM_WELL = 0x0080
- , RS_NOTIFICATION_WELL = 0x0100
- , RS_BUTTON_BUILD = 0x0200
- , RS_BUTTON_SEARCH = 0x0400
- , RS_BUTTON_WORLD_MAP = 0x0800
- , RS_BUTTON_MINI_MAP = 0x1000
+ RS_NORESIZE = 0x0000,
+ RS_CHICLET_PANEL = 0x0001,
+ RS_CHATBAR_INPUT = 0x0002,
+ RS_BUTTON_SNAPSHOT = 0x0004,
+ RS_BUTTON_CAMERA = 0x0008,
+ RS_BUTTON_MOVEMENT = 0x0010,
+ RS_BUTTON_GESTURES = 0x0020,
+ RS_BUTTON_SPEAK = 0x0040,
+ RS_IM_WELL = 0x0080,
+ RS_NOTIFICATION_WELL = 0x0100,
+ RS_BUTTON_BUILD = 0x0200,
+ RS_BUTTON_SEARCH = 0x0400,
+ RS_BUTTON_WORLD_MAP = 0x0800,
+ RS_BUTTON_MINI_MAP = 0x1000,
+ RS_BUTTON_DESTINATIONS = 0x2000,
+ RS_BUTTON_AVATARS = 0x4000,
+ RS_BUTTON_PEOPLE = 0x8000,
+ RS_BUTTON_PROFILE = 0x10000,
+ RS_BUTTON_HOWTO = 0x20000,
+ RS_BUTTON_SPLITTER_1 = 0x40000,
+ RS_BUTTON_SPLITTER_2 = 0x80000,
/*
Once new button that can be hidden on resize is added don't forget to update related places:
@@ -164,10 +173,11 @@ private:
/**
* Specifies buttons which can be hidden when bottom tray is shrunk.
* They are: Gestures, Movement (Move), Camera (View), Snapshot
- * new: Build, Search, Map, World Map, Mini-Map.
+ * new: Build, Search, Map, World Map, Mini-Map, destinations, avatars
*/
- , RS_BUTTONS_CAN_BE_HIDDEN = RS_BUTTON_SNAPSHOT | RS_BUTTON_CAMERA | RS_BUTTON_MOVEMENT | RS_BUTTON_GESTURES
+ RS_BUTTONS_CAN_BE_HIDDEN = RS_BUTTON_SNAPSHOT | RS_BUTTON_CAMERA | RS_BUTTON_MOVEMENT | RS_BUTTON_GESTURES
| RS_BUTTON_BUILD | RS_BUTTON_SEARCH | RS_BUTTON_WORLD_MAP | RS_BUTTON_MINI_MAP
+ | RS_BUTTON_DESTINATIONS | RS_BUTTON_AVATARS
}EResizeState;
// Below are three methods that were introduced to handle drag'n'drop
@@ -234,8 +244,9 @@ private:
*
* @params[in, out] available_width - reference to available width to be used to show buttons.
* @see processShowButton()
+ * @return consumed pixels (difference in available width).
*/
- void processShowButtons(S32& available_width);
+ S32 processShowButtons(S32& available_width);
/**
* Tries to show panel with specified button using available width.
@@ -311,6 +322,20 @@ private:
void processExtendButtons(S32& available_width);
/**
+ * Extends the Speak button if there is anough headroom.
+ *
+ * Unlike other buttons, the Speak buttons has only two possible widths:
+ * the minimal one (without label) and the maximal (default) one.
+ *
+ * If the button is at its minimum width there is not enough headroom to
+ * reshape it to the maximum width, the method does nothing.
+ *
+ * @param available_width Available headroom.
+ * @return false if the button requires extension but there's not enough headroom, true otherwise.
+ */
+ bool processExtendSpeakButton(S32& available_width);
+
+ /**
* Extends shown button to increase total taken space.
*
* @params[in] processed_object_type - type of button to be extended.
@@ -359,6 +384,16 @@ private:
static bool toggleShowButton(EResizeState button_type, const LLSD& new_visibility);
/**
+ * Show the button if there is enough space.
+ *
+ * @param[in] button_type - type of button to be shown.
+ * @param[in, out] available_width amount of available space on the bottom bar.
+ *
+ * @return true if button was shown, false that's not possible (not enough space, etc)
+ */
+ bool showButton(EResizeState button_type, S32& available_width);
+
+ /**
* Sets passed visibility to object specified by resize type.
*/
void setTrayButtonVisible(EResizeState shown_object_type, bool visible);
@@ -386,6 +421,13 @@ private:
bool setVisibleAndFitWidths(EResizeState object_type, bool visible);
/**
+ * Get panel containing the given button.
+ *
+ * @see mStateProcessedObjectMap
+ */
+ LLPanel* getButtonPanel(EResizeState button_type);
+
+ /**
* Shows/hides panel with specified well button (IM or Notification)
*
* @param[in] object_type - type of well button to be processed.
@@ -404,12 +446,39 @@ private:
*/
void processChatbarCustomization(S32 new_width);
+ /**
+ * @return difference between current chiclet panel width and the minimum.
+ */
+ S32 getChicletPanelShrinkHeadroom() const;
+
+ /// Get button name for debugging.
+ static std::string resizeStateToString(EResizeState state);
+
+ /// Dump a mask for debugging
+ static std::string resizeStateMaskToString(MASK mask);
+ /// @return true if any of the the passed buttons have been auto-hidden due to lack of available space.
+ bool isAutoHidden(MASK button_types) const;
+
+ /**
+ * (Un)Mark the buttons as hidden.
+ *
+ * Auto-hidden buttons are those that re-appear as soon as we have enough available space.
+ */
+ void setAutoHidden(MASK button_types, bool hide);
+
+ /// Buttons automatically hidden due to lack of space.
MASK mResizeState;
+ /**
+ * Mapping of button types to the layout panels the buttons are wrapped in.
+ *
+ * Used by getButtonPanel().
+ */
typedef std::map<EResizeState, LLPanel*> state_object_map_t;
state_object_map_t mStateProcessedObjectMap;
+ /// Default (maximum) widths of the layout panels.
typedef std::map<EResizeState, S32> state_object_width_map_t;
state_object_width_map_t mObjectDefaultWidthMap;
@@ -419,6 +488,7 @@ private:
* Contains order in which child buttons should be processed in show/hide, extend/shrink methods.
*/
resize_state_vec_t mButtonsProcessOrder;
+
/**
* Contains order in which child buttons are shown.
* It traces order of all bottomtray buttons that may change place via drag'n'drop and should
@@ -446,6 +516,7 @@ protected:
LLSpeakButton* mSpeakBtn;
LLNearbyChatBar* mNearbyChatBar;
LLLayoutPanel* mChatBarContainer;
+ LLPanel* mNearbyCharResizeHandlePanel;
LLLayoutStack* mToolbarStack;
LLMenuGL* mBottomTrayContextMenu;
LLButton* mCamButton;
diff --git a/indra/newview/llbreastmotion.cpp b/indra/newview/llbreastmotion.cpp
new file mode 100644
index 0000000000..9a8cd5ceae
--- /dev/null
+++ b/indra/newview/llbreastmotion.cpp
@@ -0,0 +1,396 @@
+/**
+ * @file llbreastmotion.cpp
+ * @brief Implementation of LLBreastMotion 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 "llbreastmotion.h"
+#include "llcharacter.h"
+#include "llviewercontrol.h"
+#include "llviewervisualparam.h"
+#include "llvoavatarself.h"
+
+#define MIN_REQUIRED_PIXEL_AREA_BREAST_MOTION 0.f;
+
+#define N_PARAMS 2
+
+// User-set params
+static const std::string breast_param_names_user[N_PARAMS] =
+{
+ "Breast_Female_Cleavage_Driver",
+ "Breast_Gravity_Driver"
+};
+
+// Params driven by this algorithm
+static const std::string breast_param_names_driven[N_PARAMS] =
+{
+ "Breast_Female_Cleavage",
+ "Breast_Gravity"
+};
+
+
+
+LLBreastMotion::LLBreastMotion(const LLUUID &id) :
+ LLMotion(id),
+ mCharacter(NULL)
+{
+ mName = "breast_motion";
+ mChestState = new LLJointState;
+
+ mBreastMassParam = (F32)1.0;
+ mBreastDragParam = LLVector3((F32)0.1, (F32)0.1, (F32)0.1);
+ mBreastSmoothingParam = (U32)2;
+ mBreastGravityParam = (F32)0.0;
+
+ mBreastSpringParam = LLVector3((F32)3.0, (F32)0.0, (F32)3.0);
+ mBreastGainParam = LLVector3((F32)50.0, (F32)0.0, (F32)50.0);
+ mBreastDampingParam = LLVector3((F32)0.3, (F32)0.0, (F32)0.3);
+ mBreastMaxVelocityParam = LLVector3((F32)10.0, (F32)0.0, (F32)10.0);
+
+ mBreastParamsUser[0] = mBreastParamsUser[1] = mBreastParamsUser[2] = NULL;
+ mBreastParamsDriven[0] = mBreastParamsDriven[1] = mBreastParamsDriven[2] = NULL;
+
+ mCharLastPosition_world_pt = LLVector3(0,0,0);
+ mCharLastVelocity_local_vec = LLVector3(0,0,0);
+ mCharLastAcceleration_local_vec = LLVector3(0,0,0);
+ mBreastLastPosition_local_pt = LLVector3(0,0,0);
+ mBreastLastUpdatePosition_local_pt = LLVector3(0,0,0);
+ mBreastVelocity_local_vec = LLVector3(0,0,0);
+}
+
+LLBreastMotion::~LLBreastMotion()
+{
+}
+
+BOOL LLBreastMotion::onActivate()
+{
+ return TRUE;
+}
+
+void LLBreastMotion::onDeactivate()
+{
+}
+
+LLMotion::LLMotionInitStatus LLBreastMotion::onInitialize(LLCharacter *character)
+{
+ mCharacter = character;
+
+ if (!mChestState->setJoint(character->getJoint("mChest")))
+ {
+ return STATUS_FAILURE;
+ }
+
+ mChestState->setUsage(LLJointState::ROT);
+ addJointState( mChestState );
+
+ for (U32 i=0; i < N_PARAMS; i++)
+ {
+ mBreastParamsUser[i] = NULL;
+ mBreastParamsDriven[i] = NULL;
+ mBreastParamsMin[i] = 0;
+ mBreastParamsMax[i] = 0;
+ if (breast_param_names_user[i] != "" && breast_param_names_driven[i] != "")
+ {
+ mBreastParamsUser[i] = (LLViewerVisualParam*)mCharacter->getVisualParam(breast_param_names_user[i].c_str());
+ mBreastParamsDriven[i] = (LLViewerVisualParam*)mCharacter->getVisualParam(breast_param_names_driven[i].c_str());
+ if (mBreastParamsDriven[i])
+ {
+ mBreastParamsMin[i] = mBreastParamsDriven[i]->getMinWeight();
+ mBreastParamsMax[i] = mBreastParamsDriven[i]->getMaxWeight();
+ }
+ }
+ }
+
+ mTimer.reset();
+ return STATUS_SUCCESS;
+}
+
+F32 LLBreastMotion::getMinPixelArea()
+{
+ return MIN_REQUIRED_PIXEL_AREA_BREAST_MOTION;
+}
+
+
+F32 LLBreastMotion::calculateTimeDelta()
+{
+ const F32 time = mTimer.getElapsedTimeF32();
+ const F32 time_delta = time - mLastTime;
+ mLastTime = time;
+ return time_delta;
+}
+
+// Local space means "parameter space".
+LLVector3 LLBreastMotion::toLocal(const LLVector3 &world_vector)
+{
+ LLVector3 local_vec(0,0,0);
+
+ LLJoint *chest_joint = mChestState->getJoint();
+ const LLQuaternion world_rot = chest_joint->getWorldRotation();
+
+ // Cleavage
+ LLVector3 breast_dir_world_vec = LLVector3(-1,0,0) * world_rot; // -1 b/c cleavage param changes opposite to direction
+ breast_dir_world_vec.normalize();
+ local_vec[0] = world_vector * breast_dir_world_vec;
+
+ // Up-Down Bounce
+ LLVector3 breast_up_dir_world_vec = LLVector3(0,0,1) * world_rot;
+ breast_up_dir_world_vec.normalize();
+ local_vec[1] = world_vector * breast_up_dir_world_vec;
+
+ return local_vec;
+}
+
+LLVector3 LLBreastMotion::calculateVelocity_local(const F32 time_delta)
+{
+ LLJoint *chest_joint = mChestState->getJoint();
+ const LLVector3 world_pos_pt = chest_joint->getWorldPosition();
+ const LLQuaternion world_rot = chest_joint->getWorldRotation();
+ const LLVector3 last_world_pos_pt = mCharLastPosition_world_pt;
+ const LLVector3 char_velocity_world_vec = (world_pos_pt-last_world_pos_pt) / time_delta;
+ const LLVector3 char_velocity_local_vec = toLocal(char_velocity_world_vec);
+
+ return char_velocity_local_vec;
+}
+
+LLVector3 LLBreastMotion::calculateAcceleration_local(const LLVector3 &new_char_velocity_local_vec,
+ const F32 time_delta)
+{
+ LLVector3 char_acceleration_local_vec = new_char_velocity_local_vec - mCharLastVelocity_local_vec;
+
+ char_acceleration_local_vec =
+ char_acceleration_local_vec * 1.0/mBreastSmoothingParam +
+ mCharLastAcceleration_local_vec * (mBreastSmoothingParam-1.0)/mBreastSmoothingParam;
+
+ mCharLastAcceleration_local_vec = char_acceleration_local_vec;
+
+ return char_acceleration_local_vec;
+}
+
+BOOL LLBreastMotion::onUpdate(F32 time, U8* joint_mask)
+{
+ // Skip if disabled globally.
+ if (!gSavedSettings.getBOOL("AvatarPhysics"))
+ {
+ return TRUE;
+ }
+
+ // 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;
+ }
+
+ if (mCharacter->getSex() != SEX_FEMALE) return TRUE;
+ const F32 time_delta = calculateTimeDelta();
+ if (time_delta < .01 || time_delta > 10.0) return TRUE;
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Get all parameters and settings
+ //
+
+ mBreastMassParam = mCharacter->getVisualParamWeight("Breast_Physics_Mass");
+ mBreastSmoothingParam = (U32)(mCharacter->getVisualParamWeight("Breast_Physics_Smoothing"));
+ mBreastGravityParam = mCharacter->getVisualParamWeight("Breast_Physics_Gravity");
+
+ mBreastSpringParam[0] = mCharacter->getVisualParamWeight("Breast_Physics_Side_Spring");
+ mBreastGainParam[0] = mCharacter->getVisualParamWeight("Breast_Physics_Side_Gain");
+ mBreastDampingParam[0] = mCharacter->getVisualParamWeight("Breast_Physics_Side_Damping");
+ mBreastMaxVelocityParam[0] = mCharacter->getVisualParamWeight("Breast_Physics_Side_Max_Velocity");
+ mBreastDragParam[0] = mCharacter->getVisualParamWeight("Breast_Physics_Side_Drag");
+
+ mBreastSpringParam[1] = mCharacter->getVisualParamWeight("Breast_Physics_UpDown_Spring");
+ mBreastGainParam[1] = mCharacter->getVisualParamWeight("Breast_Physics_UpDown_Gain");
+ mBreastDampingParam[1] = mCharacter->getVisualParamWeight("Breast_Physics_UpDown_Damping");
+ mBreastMaxVelocityParam[1] = mCharacter->getVisualParamWeight("Breast_Physics_UpDown_Max_Velocity");
+ mBreastDragParam[1] = mCharacter->getVisualParamWeight("Breast_Physics_UpDown_Drag");
+
+
+ // Get the current morph parameters.
+ LLVector3 breast_user_local_pt(0,0,0);
+ for (U32 i=0; i < N_PARAMS; i++)
+ {
+ if (mBreastParamsUser[i] != NULL)
+ {
+ breast_user_local_pt[i] = mBreastParamsUser[i]->getWeight();
+ }
+ }
+
+ LLVector3 breast_current_local_pt = mBreastLastPosition_local_pt;
+
+ //
+ // End parameters and settings
+ ////////////////////////////////////////////////////////////////////////////////
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Calculate velocity and acceleration in parameter space.
+ //
+
+ const LLVector3 char_velocity_local_vec = calculateVelocity_local(time_delta);
+ const LLVector3 char_acceleration_local_vec = calculateAcceleration_local(char_velocity_local_vec, time_delta);
+ mCharLastVelocity_local_vec = char_velocity_local_vec;
+
+ LLJoint *chest_joint = mChestState->getJoint();
+ mCharLastPosition_world_pt = chest_joint->getWorldPosition();
+
+ //
+ // End velocity and acceleration
+ ////////////////////////////////////////////////////////////////////////////////
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Calculate the total force
+ //
+
+ // Spring force is a restoring force towards the original user-set breast position.
+ // F = kx
+ const LLVector3 spring_length_local = breast_current_local_pt-breast_user_local_pt;
+ LLVector3 force_spring_local_vec = -spring_length_local; force_spring_local_vec *= mBreastSpringParam;
+
+ // Acceleration is the force that comes from the change in velocity of the torso.
+ // F = ma + mg
+ LLVector3 force_accel_local_vec = char_acceleration_local_vec * mBreastMassParam;
+ const LLVector3 force_gravity_local_vec = toLocal(LLVector3(0,0,1))* mBreastGravityParam * mBreastMassParam;
+ force_accel_local_vec += force_gravity_local_vec;
+ force_accel_local_vec *= mBreastGainParam;
+
+ // Damping is a restoring force that opposes the current velocity.
+ // F = -kv
+ LLVector3 force_damping_local_vec = -mBreastDampingParam;
+ force_damping_local_vec *= mBreastVelocity_local_vec;
+
+ // Drag is a force imparted by velocity, intuitively it is similar to wind resistance.
+ // F = .5v*v
+ LLVector3 force_drag_local_vec = .5*char_velocity_local_vec;
+ force_drag_local_vec *= char_velocity_local_vec;
+ force_drag_local_vec *= mBreastDragParam[0];
+
+ LLVector3 force_net_local_vec =
+ force_accel_local_vec +
+ force_gravity_local_vec +
+ force_spring_local_vec +
+ force_damping_local_vec +
+ force_drag_local_vec;
+
+ //
+ // End total force
+ ////////////////////////////////////////////////////////////////////////////////
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Calculate new params
+ //
+
+ // Calculate the new acceleration based on the net force.
+ // a = F/m
+ LLVector3 acceleration_local_vec = force_net_local_vec / mBreastMassParam;
+ mBreastVelocity_local_vec += acceleration_local_vec;
+ mBreastVelocity_local_vec.clamp(-mBreastMaxVelocityParam*100.0, mBreastMaxVelocityParam*100.0);
+
+ // Temporary debugging setting to cause all avatars to move, for profiling purposes.
+ if (gSavedSettings.getBOOL("AvatarPhysicsTest"))
+ {
+ mBreastVelocity_local_vec[0] = sin(mTimer.getElapsedTimeF32()*4.0)*5.0;
+ mBreastVelocity_local_vec[1] = sin(mTimer.getElapsedTimeF32()*3.0)*5.0;
+ }
+ // Calculate the new parameters and clamp them to the min/max ranges.
+ LLVector3 new_local_pt = breast_current_local_pt + mBreastVelocity_local_vec*time_delta;
+ new_local_pt.clamp(mBreastParamsMin,mBreastParamsMax);
+
+ // Set the new parameters.
+ for (U32 i=0; i < 3; i++)
+ {
+ // If the param is disabled, just set the param to the user value.
+ if (mBreastMaxVelocityParam[i] == 0)
+ {
+ new_local_pt[i] = breast_user_local_pt[i];
+ }
+ if (mBreastParamsDriven[i])
+ {
+ mCharacter->setVisualParamWeight(mBreastParamsDriven[i],
+ new_local_pt[i],
+ FALSE);
+ }
+ }
+
+ mBreastLastPosition_local_pt = new_local_pt;
+
+ //
+ // 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.
+
+ // For non-self, if the avatar is small enough visually, then don't update.
+ const BOOL is_self = (dynamic_cast<LLVOAvatarSelf *>(this) != NULL);
+ if (!is_self)
+ {
+ 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 = fsqrtf(mCharacter->getPixelArea());
+ if (pixel_area < area_for_this_setting)
+ {
+ return TRUE;
+ }
+ }
+
+ // If the parameter hasn't changed enough, then don't update.
+ LLVector3 position_diff = mBreastLastUpdatePosition_local_pt-new_local_pt;
+ for (U32 i=0; i < 3; i++)
+ {
+ const F32 min_delta = (1.0-lod_factor)*(mBreastParamsMax[i]-mBreastParamsMin[i])/2.0;
+ if (llabs(position_diff[i]) > min_delta)
+ {
+ mCharacter->updateVisualParams();
+ mBreastLastUpdatePosition_local_pt = new_local_pt;
+ return TRUE;
+ }
+ }
+
+ //
+ // End update visual params
+ ////////////////////////////////////////////////////////////////////////////////
+
+ return TRUE;
+}
diff --git a/indra/newview/llbreastmotion.h b/indra/newview/llbreastmotion.h
new file mode 100644
index 0000000000..aa0fdf9f8b
--- /dev/null
+++ b/indra/newview/llbreastmotion.h
@@ -0,0 +1,154 @@
+/**
+ * @file llbreastmotion.h
+ * @brief Implementation of LLBreastMotion 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_LLBREASTMOTION_H
+#define LL_LLBREASTMOTION_H
+
+//-----------------------------------------------------------------------------
+// Header files
+//-----------------------------------------------------------------------------
+#include "llmotion.h"
+#include "llframetimer.h"
+
+#define BREAST_MOTION_FADEIN_TIME 1.0f
+#define BREAST_MOTION_FADEOUT_TIME 1.0f
+
+class LLViewerVisualParam;
+
+//-----------------------------------------------------------------------------
+// class LLBreastMotion
+//-----------------------------------------------------------------------------
+class LLBreastMotion :
+ public LLMotion
+{
+public:
+ // Constructor
+ LLBreastMotion(const LLUUID &id);
+
+ // Destructor
+ virtual ~LLBreastMotion();
+
+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 LLBreastMotion(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 BREAST_MOTION_FADEIN_TIME; }
+
+ // motions must report their "ease out" duration.
+ virtual F32 getEaseOutDuration() { return BREAST_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();
+
+protected:
+ LLVector3 toLocal(const LLVector3 &world_vector);
+ LLVector3 calculateVelocity_local(const F32 time_delta);
+ LLVector3 calculateAcceleration_local(const LLVector3 &new_char_velocity_local_vec,
+ const F32 time_delta);
+ F32 calculateTimeDelta();
+private:
+ //-------------------------------------------------------------------------
+ // joint states to be animated
+ //-------------------------------------------------------------------------
+ LLPointer<LLJointState> mChestState;
+ LLCharacter* mCharacter;
+
+
+ //-------------------------------------------------------------------------
+ // miscellaneous parameters
+ //-------------------------------------------------------------------------
+ LLViewerVisualParam *mBreastParamsUser[3];
+ LLViewerVisualParam *mBreastParamsDriven[3];
+ LLVector3 mBreastParamsMin;
+ LLVector3 mBreastParamsMax;
+
+ LLVector3 mCharLastPosition_world_pt; // Last position of the avatar
+ LLVector3 mCharLastVelocity_local_vec; // How fast the character is moving
+ LLVector3 mCharLastAcceleration_local_vec; // Change in character velocity
+
+ LLVector3 mBreastLastPosition_local_pt; // Last parameters for breast
+ LLVector3 mBreastVelocity_local_vec; // How fast the breast params are moving
+ LLVector3 mBreastLastUpdatePosition_local_pt; // Last parameters when visual update was sent
+
+
+ F32 mBreastMassParam;
+ F32 mBreastGravityParam;
+ U32 mBreastSmoothingParam;
+
+ LLVector3 mBreastSpringParam;
+ LLVector3 mBreastDampingParam;
+ LLVector3 mBreastGainParam;
+ LLVector3 mBreastMaxVelocityParam;
+ LLVector3 mBreastDragParam;
+
+ LLFrameTimer mTimer;
+ F32 mLastTime;
+
+ U32 mFileTicks;
+};
+
+#endif // LL_LLBREASTMOTION_H
+
diff --git a/indra/newview/llbrowsernotification.cpp b/indra/newview/llbrowsernotification.cpp
index d6a813d608..6e77d1e336 100644
--- a/indra/newview/llbrowsernotification.cpp
+++ b/indra/newview/llbrowsernotification.cpp
@@ -29,8 +29,9 @@
#include "llnotificationhandler.h"
#include "llnotifications.h"
-#include "llfloaterreg.h"
#include "llmediactrl.h"
+#include "llviewermedia.h"
+#include "llviewermediafocus.h"
using namespace LLNotificationsUI;
@@ -39,10 +40,19 @@ bool LLBrowserNotification::processNotification(const LLSD& notify)
LLNotificationPtr notification = LLNotifications::instance().find(notify["id"].asUUID());
if (!notification) return false;
- LLMediaCtrl* media_instance = LLMediaCtrl::getInstance(notification->getPayload()["media_id"].asUUID());
+ LLUUID media_id = notification->getPayload()["media_id"].asUUID();
+ LLMediaCtrl* media_instance = LLMediaCtrl::getInstance(media_id);
if (media_instance)
{
media_instance->showNotification(notification);
}
+ else if (LLViewerMediaFocus::instance().getControlsMediaID() == media_id)
+ {
+ LLViewerMediaImpl* impl = LLViewerMedia::getMediaImplFromTextureID(media_id);
+ if (impl)
+ {
+ impl->showNotification(notification);
+ }
+ }
return false;
}
diff --git a/indra/newview/llbuycurrencyhtml.cpp b/indra/newview/llbuycurrencyhtml.cpp
index d35c9ed853..e5a9be0203 100644
--- a/indra/newview/llbuycurrencyhtml.cpp
+++ b/indra/newview/llbuycurrencyhtml.cpp
@@ -33,6 +33,7 @@
#include "llfloaterreg.h"
#include "llcommandhandler.h"
#include "llviewercontrol.h"
+#include "llstatusbar.h"
// support for secondlife:///app/buycurrencyhtml/{ACTION}/{NEXT_ACTION}/{RETURN_CODE} SLapps
class LLBuyCurrencyHTMLHandler :
@@ -156,4 +157,7 @@ void LLBuyCurrencyHTML::closeDialog()
{
buy_currency_floater->closeFloater();
};
+
+ // Update L$ balance in the status bar in case L$ were purchased
+ LLStatusBar::sendMoneyBalanceRequest();
}
diff --git a/indra/newview/llcallbacklist.cpp b/indra/newview/llcallbacklist.cpp
index a54c77b4a0..357a6582d1 100644
--- a/indra/newview/llcallbacklist.cpp
+++ b/indra/newview/llcallbacklist.cpp
@@ -115,6 +115,71 @@ void LLCallbackList::callFunctions()
}
}
+// Shim class to allow arbitrary boost::bind
+// expressions to be run as one-time idle callbacks.
+class OnIdleCallbackOneTime
+{
+public:
+ OnIdleCallbackOneTime(nullary_func_t callable):
+ mCallable(callable)
+ {
+ }
+ static void onIdle(void *data)
+ {
+ gIdleCallbacks.deleteFunction(onIdle, data);
+ OnIdleCallbackOneTime* self = reinterpret_cast<OnIdleCallbackOneTime*>(data);
+ self->call();
+ delete self;
+ }
+ void call()
+ {
+ mCallable();
+ }
+private:
+ nullary_func_t mCallable;
+};
+
+void doOnIdleOneTime(nullary_func_t callable)
+{
+ OnIdleCallbackOneTime* cb_functor = new OnIdleCallbackOneTime(callable);
+ gIdleCallbacks.addFunction(&OnIdleCallbackOneTime::onIdle,cb_functor);
+}
+
+// Shim class to allow generic boost functions to be run as
+// recurring idle callbacks. Callable should return true when done,
+// false to continue getting called.
+class OnIdleCallbackRepeating
+{
+public:
+ OnIdleCallbackRepeating(bool_func_t callable):
+ mCallable(callable)
+ {
+ }
+ // Will keep getting called until the callable returns true.
+ static void onIdle(void *data)
+ {
+ OnIdleCallbackRepeating* self = reinterpret_cast<OnIdleCallbackRepeating*>(data);
+ bool done = self->call();
+ if (done)
+ {
+ gIdleCallbacks.deleteFunction(onIdle, data);
+ delete self;
+ }
+ }
+ bool call()
+ {
+ return mCallable();
+ }
+private:
+ bool_func_t mCallable;
+};
+
+void doOnIdleRepeating(bool_func_t callable)
+{
+ OnIdleCallbackRepeating* cb_functor = new OnIdleCallbackRepeating(callable);
+ gIdleCallbacks.addFunction(&OnIdleCallbackRepeating::onIdle,cb_functor);
+}
+
#ifdef _DEBUG
void test1(void *data)
diff --git a/indra/newview/llcallbacklist.h b/indra/newview/llcallbacklist.h
index 07ac21f5e9..97f3bfd9ee 100644
--- a/indra/newview/llcallbacklist.h
+++ b/indra/newview/llcallbacklist.h
@@ -52,6 +52,15 @@ protected:
callback_list_t mCallbackList;
};
+typedef boost::function<void ()> nullary_func_t;
+typedef boost::function<bool ()> bool_func_t;
+
+// Call a given callable once in idle loop.
+void doOnIdleOneTime(nullary_func_t callable);
+
+// Repeatedly call a callable in idle loop until it returns true.
+void doOnIdleRepeating(bool_func_t callable);
+
extern LLCallbackList gIdleCallbacks;
#endif
diff --git a/indra/newview/llcallfloater.cpp b/indra/newview/llcallfloater.cpp
index 078bd73379..945a760d05 100644
--- a/indra/newview/llcallfloater.cpp
+++ b/indra/newview/llcallfloater.cpp
@@ -45,10 +45,12 @@
#include "llspeakers.h"
#include "lltextutil.h"
#include "lltransientfloatermgr.h"
+#include "llviewercontrol.h"
#include "llviewerdisplayname.h"
#include "llviewerwindow.h"
#include "llvoicechannel.h"
#include "llviewerparcelmgr.h"
+#include "llfirstuse.h"
static void get_voice_participants_uuids(uuid_vec_t& speakers_uuids);
void reshape_floater(LLCallFloater* floater, S32 delta_height);
@@ -166,15 +168,16 @@ BOOL LLCallFloater::postBuild()
//chrome="true" hides floater caption
if (mDragHandle)
mDragHandle->setTitleVisible(TRUE);
+ updateTransparency(TT_ACTIVE); // force using active floater transparency (STORM-730)
updateSession();
-
return TRUE;
}
// virtual
void LLCallFloater::onOpen(const LLSD& /*key*/)
{
+ LLFirstUse::speak(false);
}
// virtual
@@ -205,6 +208,17 @@ void LLCallFloater::draw()
}
// virtual
+void LLCallFloater::setFocus( BOOL b )
+{
+ LLTransientDockableFloater::setFocus(b);
+
+ // Force using active floater transparency (STORM-730).
+ // We have to override setFocus() for LLCallFloater because selecting an item
+ // of the voice morphing combobox causes the floater to lose focus and thus become transparent.
+ updateTransparency(TT_ACTIVE);
+}
+
+// virtual
void LLCallFloater::onParticipantsChanged()
{
if (NULL == mParticipants) return;
@@ -335,8 +349,9 @@ void LLCallFloater::refreshParticipantList()
{
mParticipants = new LLParticipantList(mSpeakerManager, mAvatarList, true, mVoiceType != VC_GROUP_CHAT && mVoiceType != VC_AD_HOC_CHAT, false);
mParticipants->setValidateSpeakerCallback(boost::bind(&LLCallFloater::validateSpeaker, this, _1));
- mParticipants->setSortOrder(LLParticipantList::E_SORT_BY_RECENT_SPEAKERS);
-
+ const U32 speaker_sort_order = gSavedSettings.getU32("SpeakerParticipantDefaultOrder");
+ mParticipants->setSortOrder(LLParticipantList::EParticipantSortOrder(speaker_sort_order));
+
if (LLLocalSpeakerMgr::getInstance() == mSpeakerManager)
{
mAvatarList->setNoItemsCommentText(getString("no_one_near"));
diff --git a/indra/newview/llcallfloater.h b/indra/newview/llcallfloater.h
index 3bc7043353..00a3f76e56 100644
--- a/indra/newview/llcallfloater.h
+++ b/indra/newview/llcallfloater.h
@@ -64,6 +64,7 @@ public:
/*virtual*/ BOOL postBuild();
/*virtual*/ void onOpen(const LLSD& key);
/*virtual*/ void draw();
+ /*virtual*/ void setFocus( BOOL b );
/**
* Is called by LLVoiceClient::notifyParticipantObservers when voice participant list is changed.
diff --git a/indra/newview/llcapabilityprovider.h b/indra/newview/llcapabilityprovider.h
index a6e743f625..9d91245597 100644
--- a/indra/newview/llcapabilityprovider.h
+++ b/indra/newview/llcapabilityprovider.h
@@ -46,7 +46,7 @@ public:
/**
* Get host to which to send that capability request.
*/
- virtual LLHost getHost() const = 0;
+ virtual const LLHost& getHost() const = 0;
/**
* Describe this LLCapabilityProvider for logging etc.
*/
diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp
index 9153f7325f..c0c9ea1451 100644
--- a/indra/newview/llchathistory.cpp
+++ b/indra/newview/llchathistory.cpp
@@ -138,10 +138,7 @@ public:
if (level == "profile")
{
- LLSD params;
- params["object_id"] = getAvatarId();
-
- LLFloaterReg::showInstance("inspect_object", params);
+ LLFloaterReg::showInstance("inspect_remote_object", mObjectData);
}
else if (level == "block")
{
@@ -229,7 +226,7 @@ public:
if (mSourceType == CHAT_SOURCE_OBJECT)
{
- LLFloaterReg::showInstance("inspect_object", LLSD().with("object_id", mAvatarID));
+ LLFloaterReg::showInstance("inspect_remote_object", mObjectData);
}
else if (mSourceType == CHAT_SOURCE_AGENT)
{
@@ -251,7 +248,7 @@ public:
const LLUUID& getAvatarId () const { return mAvatarID;}
- void setup(const LLChat& chat,const LLStyle::Params& style_params)
+ void setup(const LLChat& chat, const LLStyle::Params& style_params, const LLSD& args)
{
mAvatarID = chat.mFromID;
mSessionID = chat.mSessionID;
@@ -332,7 +329,8 @@ public:
setTimeField(chat);
-
+
+ // Set up the icon.
LLAvatarIconCtrl* icon = getChild<LLAvatarIconCtrl>("avatar_icon");
if(mSourceType != CHAT_SOURCE_AGENT || mAvatarID.isNull())
@@ -352,6 +350,30 @@ public:
case CHAT_SOURCE_UNKNOWN:
icon->setValue(LLSD("Unknown_Icon"));
}
+
+ // In case the message came from an object, save the object info
+ // to be able properly show its profile.
+ if ( chat.mSourceType == CHAT_SOURCE_OBJECT)
+ {
+ std::string slurl = args["slurl"].asString();
+ if (slurl.empty())
+ {
+ LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosAgent(chat.mPosAgent);
+ if(region)
+ {
+ LLSLURL region_slurl(region->getName(), chat.mPosAgent);
+ slurl = region_slurl.getLocationString();
+ }
+ }
+
+ LLSD payload;
+ payload["object_id"] = chat.mFromID;
+ payload["name"] = chat.mFromName;
+ payload["owner_id"] = chat.mOwnerID;
+ payload["slurl"] = LLWeb::escapeURL(slurl);
+
+ mObjectData = payload;
+ }
}
/*virtual*/ void draw()
@@ -540,6 +562,7 @@ protected:
static LLUICtrl* sInfoCtrl;
LLUUID mAvatarID;
+ LLSD mObjectData;
EChatSourceType mSourceType;
std::string mFrom;
LLUUID mSessionID;
@@ -586,7 +609,7 @@ void LLChatHistory::initFromParams(const LLChatHistory::Params& p)
LLLayoutStack::Params layout_p;
layout_p.rect = stack_rect;
layout_p.follows.flags = FOLLOWS_ALL;
- layout_p.orientation = "vertical";
+ layout_p.orientation = LLLayoutStack::VERTICAL;
layout_p.mouse_opaque = false;
LLLayoutStack* stackp = LLUICtrlFactory::create<LLLayoutStack>(layout_p, this);
@@ -649,10 +672,10 @@ LLView* LLChatHistory::getSeparator()
return separator;
}
-LLView* LLChatHistory::getHeader(const LLChat& chat,const LLStyle::Params& style_params)
+LLView* LLChatHistory::getHeader(const LLChat& chat,const LLStyle::Params& style_params, const LLSD& args)
{
LLChatHistoryHeader* header = LLChatHistoryHeader::createInstance(mMessageHeaderFilename);
- header->setup(chat,style_params);
+ header->setup(chat, style_params, args);
return header;
}
@@ -770,41 +793,31 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL
if ( chat.mSourceType == CHAT_SOURCE_OBJECT && chat.mFromID.notNull())
{
// for object IMs, create a secondlife:///app/objectim SLapp
- std::string url = LLSLURL("objectim", chat.mFromID, "").getSLURLString();
- url += "?name=" + chat.mFromName;
- url += "&owner=" + chat.mOwnerID.asString();
-
- std::string slurl = args["slurl"].asString();
- if (slurl.empty())
- {
- LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosAgent(chat.mPosAgent);
- if(region)
- {
- LLSLURL region_slurl(region->getName(), chat.mPosAgent);
- slurl = region_slurl.getLocationString();
- }
- }
- url += "&slurl=" + LLURI::escape(slurl);
+ std::string url = LLViewerChat::getSenderSLURL(chat, args);
// set the link for the object name to be the objectim SLapp
// (don't let object names with hyperlinks override our objectim Url)
LLStyle::Params link_params(style_params);
- link_params.color.control = "HTMLLinkColor";
+ LLColor4 link_color = LLUIColorTable::instance().getColor("HTMLLinkColor");
+ link_params.color = link_color;
+ link_params.readonly_color = link_color;
+ link_params.is_link = true;
link_params.link_href = url;
- mEditor->appendText("<nolink>" + chat.mFromName + "</nolink>" + delimiter,
+
+ mEditor->appendText(chat.mFromName + delimiter,
false, link_params);
}
else if ( chat.mFromName != SYSTEM_FROM && chat.mFromID.notNull() && !message_from_log)
{
LLStyle::Params link_params(style_params);
link_params.overwriteFrom(LLStyleMap::instance().lookupAgent(chat.mFromID));
+
// Add link to avatar's inspector and delimiter to message.
- mEditor->appendText(link_params.link_href, false, style_params);
- mEditor->appendText(delimiter, false, style_params);
+ mEditor->appendText(std::string(link_params.link_href) + delimiter, false, link_params);
}
else
{
- mEditor->appendText(chat.mFromName + delimiter, false, style_params);
+ mEditor->appendText("<nolink>" + chat.mFromName + "</nolink>" + delimiter, false, style_params);
}
}
}
@@ -830,7 +843,7 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL
}
else
{
- view = getHeader(chat, style_params);
+ view = getHeader(chat, style_params, args);
if (mEditor->getText().size() == 0)
p.top_pad = 0;
else
@@ -895,31 +908,14 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL
}
}
- LLTextEditor* text_editor = notify_box->getChild<LLTextEditor>("text_editor_box", TRUE);
- S32 text_heigth = 0;
- if(text_editor != NULL)
- {
- text_heigth = text_editor->getTextBoundingRect().getHeight();
- }
-
//Prepare the rect for the view
LLRect target_rect = mEditor->getDocumentView()->getRect();
// squeeze down the widget by subtracting padding off left and right
target_rect.mLeft += mLeftWidgetPad + mEditor->getHPad();
target_rect.mRight -= mRightWidgetPad;
- notify_box->reshape(target_rect.getWidth(),
- notify_box->getRect().getHeight());
+ notify_box->reshape(target_rect.getWidth(), notify_box->getRect().getHeight());
notify_box->setOrigin(target_rect.mLeft, notify_box->getRect().mBottom);
- if (text_editor != NULL)
- {
- S32 text_heigth_delta =
- text_editor->getTextBoundingRect().getHeight()
- - text_heigth;
- notify_box->reshape(target_rect.getWidth(),
- notify_box->getRect().getHeight() + text_heigth_delta);
- }
-
LLInlineViewSegment::Params params;
params.view = notify_box;
params.left_pad = mLeftWidgetPad;
diff --git a/indra/newview/llchathistory.h b/indra/newview/llchathistory.h
index ac48d7bf29..28344e6a10 100644
--- a/indra/newview/llchathistory.h
+++ b/indra/newview/llchathistory.h
@@ -94,7 +94,7 @@ class LLChatHistory : public LLUICtrl
* Builds a message header.
* @return pointer to LLView header object.
*/
- LLView* getHeader(const LLChat& chat,const LLStyle::Params& style_params);
+ LLView* getHeader(const LLChat& chat,const LLStyle::Params& style_params, const LLSD& args);
void onClickMoreText();
diff --git a/indra/newview/llchatitemscontainerctrl.cpp b/indra/newview/llchatitemscontainerctrl.cpp
index ababa71348..8584885bc9 100644
--- a/indra/newview/llchatitemscontainerctrl.cpp
+++ b/indra/newview/llchatitemscontainerctrl.cpp
@@ -31,6 +31,7 @@
#include "llchatmsgbox.h"
#include "llavatariconctrl.h"
+#include "llcommandhandler.h"
#include "llfloaterreg.h"
#include "lllocalcliprect.h"
#include "lltrans.h"
@@ -45,6 +46,40 @@ static const S32 msg_right_offset = 10;
static const S32 msg_height_pad = 5;
//*******************************************************************************************************************
+// LLObjectHandler
+//*******************************************************************************************************************
+
+// handle secondlife:///app/object/<ID>/inspect SLURLs
+class LLObjectHandler : public LLCommandHandler
+{
+public:
+ LLObjectHandler() : LLCommandHandler("object", UNTRUSTED_BLOCK) { }
+
+ bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web)
+ {
+ if (params.size() < 2) return false;
+
+ LLUUID object_id;
+ if (!object_id.set(params[0], FALSE))
+ {
+ return false;
+ }
+
+ const std::string verb = params[1].asString();
+
+ if (verb == "inspect")
+ {
+ LLFloaterReg::showInstance("inspect_object", LLSD().with("object_id", object_id));
+ return true;
+ }
+
+ return false;
+ }
+};
+
+LLObjectHandler gObjectHandler;
+
+//*******************************************************************************************************************
//LLNearbyChatToastPanel
//*******************************************************************************************************************
@@ -169,30 +204,33 @@ void LLNearbyChatToastPanel::init(LLSD& notification)
{
std::string str_sender;
- str_sender = "<nolink>"; // disable parsing URLs in object names (STORM-358)
- str_sender += fromName;
- str_sender += "</nolink>";
+ str_sender = fromName;
str_sender+=" ";
- //append user name
+ //append sender name
+ if (mSourceType == CHAT_SOURCE_AGENT || mSourceType == CHAT_SOURCE_OBJECT)
{
LLStyle::Params style_params_name;
- LLColor4 userNameColor = LLUIColorTable::instance().getColor("ChatToastAgentNameColor");
-
- style_params_name.color(userNameColor);
+ LLColor4 user_name_color = LLUIColorTable::instance().getColor("HTMLLinkColor");
+ style_params_name.color(user_name_color);
std::string font_name = LLFontGL::nameFromFont(messageFont);
std::string font_style_size = LLFontGL::sizeFromFont(messageFont);
style_params_name.font.name(font_name);
style_params_name.font.size(font_style_size);
- style_params_name.link_href = LLSLURL("agent",mFromID,"about").getSLURLString();
+ style_params_name.link_href = notification["sender_slurl"].asString();
+ style_params_name.is_link = true;
msg_text->appendText(str_sender, FALSE, style_params_name);
}
+ else
+ {
+ msg_text->appendText(str_sender, false);
+ }
}
//append text
diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp
index 8f385160e9..3000209aad 100644
--- a/indra/newview/llchiclet.cpp
+++ b/indra/newview/llchiclet.cpp
@@ -483,8 +483,9 @@ void LLIMChiclet::setShowSpeaker(bool show)
if(needs_resize)
{
mShowSpeaker = show;
- toggleSpeakerControl();
}
+
+ toggleSpeakerControl();
}
void LLIMChiclet::enableCounterControl(bool enable)
@@ -1092,9 +1093,11 @@ LLChicletPanel::LLChicletPanel(const Params&p)
LLChicletPanel::~LLChicletPanel()
{
- LLTransientFloaterMgr::getInstance()->removeControlView(mLeftScrollButton);
- LLTransientFloaterMgr::getInstance()->removeControlView(mRightScrollButton);
-
+ if(LLTransientFloaterMgr::instanceExists())
+ {
+ LLTransientFloaterMgr::getInstance()->removeControlView(mLeftScrollButton);
+ LLTransientFloaterMgr::getInstance()->removeControlView(mRightScrollButton);
+ }
}
void im_chiclet_callback(LLChicletPanel* panel, const LLSD& data){
@@ -1181,6 +1184,10 @@ void LLChicletPanel::onCurrentVoiceChannelChanged(const LLUUID& session_id)
if(chiclet)
{
chiclet->setShowSpeaker(true);
+ if (gSavedSettings.getBOOL("OpenIMOnVoice"))
+ {
+ LLIMFloater::show(chiclet->getSessionId());
+ }
}
}
diff --git a/indra/newview/llcolorswatch.cpp b/indra/newview/llcolorswatch.cpp
index c9a526a3be..d77ebc5367 100644
--- a/indra/newview/llcolorswatch.cpp
+++ b/indra/newview/llcolorswatch.cpp
@@ -53,6 +53,7 @@ LLColorSwatchCtrl::Params::Params()
alpha_background_image("alpha_background_image"),
border_color("border_color"),
label_width("label_width", -1),
+ label_height("label_height", -1),
caption_text("caption_text"),
border("border")
{
@@ -68,17 +69,20 @@ LLColorSwatchCtrl::LLColorSwatchCtrl(const Params& p)
mOnCancelCallback(p.cancel_callback()),
mOnSelectCallback(p.select_callback()),
mBorderColor(p.border_color()),
- mLabelWidth(p.label_width)
+ mLabelWidth(p.label_width),
+ mLabelHeight(p.label_height)
{
LLTextBox::Params tp = p.caption_text;
+ // use custom label height if it is provided
+ mLabelHeight = mLabelHeight != -1 ? mLabelHeight : BTN_HEIGHT_SMALL;
// label_width is specified, not -1
if(mLabelWidth!= -1)
{
- tp.rect(LLRect( 0, BTN_HEIGHT_SMALL, mLabelWidth, 0 ));
+ tp.rect(LLRect( 0, mLabelHeight, mLabelWidth, 0 ));
}
else
{
- tp.rect(LLRect( 0, BTN_HEIGHT_SMALL, getRect().getWidth(), 0 ));
+ tp.rect(LLRect( 0, mLabelHeight, getRect().getWidth(), 0 ));
}
tp.initial_value(p.label());
@@ -88,7 +92,7 @@ LLColorSwatchCtrl::LLColorSwatchCtrl(const Params& p)
LLRect border_rect = getLocalRect();
border_rect.mTop -= 1;
border_rect.mRight -=1;
- border_rect.mBottom += BTN_HEIGHT_SMALL;
+ border_rect.mBottom += mLabelHeight;
LLViewBorder::Params params = p.border;
params.rect(border_rect);
@@ -181,6 +185,10 @@ BOOL LLColorSwatchCtrl::handleMouseUp(S32 x, S32 y, MASK mask)
llassert(getEnabled());
llassert(getVisible());
+ // Focus the widget now in order to return the focus
+ // after the color picker is closed.
+ setFocus(TRUE);
+
showPicker(FALSE);
}
}
@@ -191,10 +199,12 @@ BOOL LLColorSwatchCtrl::handleMouseUp(S32 x, S32 y, MASK mask)
// assumes GL state is set for 2D
void LLColorSwatchCtrl::draw()
{
- F32 alpha = getDrawContext().mAlpha;
+ // If we're in a focused floater, don't apply the floater's alpha to the color swatch (STORM-676).
+ F32 alpha = getTransparencyType() == TT_ACTIVE ? 1.0f : getCurrentTransparency();
+
mBorder->setKeyboardFocusHighlight(hasFocus());
// Draw border
- LLRect border( 0, getRect().getHeight(), getRect().getWidth(), BTN_HEIGHT_SMALL );
+ LLRect border( 0, getRect().getHeight(), getRect().getWidth(), mLabelHeight );
gl_rect_2d( border, mBorderColor.get(), FALSE );
LLRect interior = border;
@@ -203,19 +213,29 @@ void LLColorSwatchCtrl::draw()
// Check state
if ( mValid )
{
+ if (!mColor.isOpaque())
+ {
+ // Draw checker board.
+ gl_rect_2d_checkerboard(interior, alpha);
+ }
+
// Draw the color swatch
- gl_rect_2d_checkerboard( interior );
- gl_rect_2d(interior, mColor, TRUE);
- LLColor4 opaque_color = mColor;
- opaque_color.mV[VALPHA] = 1.f;
- gGL.color4fv(opaque_color.mV);
- if (mAlphaGradientImage.notNull())
+ gl_rect_2d(interior, mColor % alpha, TRUE);
+
+ if (!mColor.isOpaque())
{
- gGL.pushMatrix();
+ // Draw semi-transparent center area in filled with mColor.
+ LLColor4 opaque_color = mColor;
+ opaque_color.mV[VALPHA] = alpha;
+ gGL.color4fv(opaque_color.mV);
+ if (mAlphaGradientImage.notNull())
{
- mAlphaGradientImage->draw(interior, mColor);
+ gGL.pushMatrix();
+ {
+ mAlphaGradientImage->draw(interior, mColor % alpha);
+ }
+ gGL.popMatrix();
}
- gGL.popMatrix();
}
}
else
@@ -303,7 +323,7 @@ void LLColorSwatchCtrl::onColorChanged ( void* data, EColorPickOp pick_op )
// This is called when the main floatercustomize panel is closed.
// Since this class has pointers up to its parents, we need to cleanup
// this class first in order to avoid a crash.
-void LLColorSwatchCtrl::onParentFloaterClosed()
+void LLColorSwatchCtrl::closeFloaterColorPicker()
{
LLFloaterColorPicker* pickerp = (LLFloaterColorPicker*)mPickerHandle.get();
if (pickerp)
diff --git a/indra/newview/llcolorswatch.h b/indra/newview/llcolorswatch.h
index a4ce1ca099..5bdd1712d2 100644
--- a/indra/newview/llcolorswatch.h
+++ b/indra/newview/llcolorswatch.h
@@ -61,6 +61,7 @@ public:
Optional<commit_callback_t> select_callback;
Optional<LLUIColor> border_color;
Optional<S32> label_width;
+ Optional<S32> label_height;
Optional<LLTextBox::Params> caption_text;
Optional<LLViewBorder::Params> border;
@@ -99,7 +100,7 @@ public:
/*virtual*/ void setEnabled( BOOL enabled );
static void onColorChanged ( void* data, EColorPickOp pick_op = COLOR_CHANGE );
- void onParentFloaterClosed();
+ void closeFloaterColorPicker();
protected:
BOOL mValid;
@@ -112,6 +113,7 @@ protected:
commit_callback_t mOnCancelCallback;
commit_callback_t mOnSelectCallback;
S32 mLabelWidth;
+ S32 mLabelHeight;
LLPointer<LLUIImage> mAlphaGradientImage;
std::string mFallbackImageName;
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 360ba080ac..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 15 // 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/llcommandlineparser.cpp b/indra/newview/llcommandlineparser.cpp
index ee8646aad0..65c61c4a8b 100644
--- a/indra/newview/llcommandlineparser.cpp
+++ b/indra/newview/llcommandlineparser.cpp
@@ -267,7 +267,11 @@ bool LLCommandLineParser::parseAndStoreResults(po::command_line_parser& clp)
{
clp.options(gOptionsDesc);
clp.positional(gPositionalOptions);
- clp.style(po::command_line_style::default_style
+ // SNOW-626: Boost 1.42 erroneously added allow_guessing to the default style
+ // (see http://groups.google.com/group/boost-list/browse_thread/thread/545d7bf98ff9bb16?fwc=2&pli=1)
+ // Remove allow_guessing from the default style, because that is not allowed
+ // when we have options that are a prefix of other options (aka, --help and --helperuri).
+ clp.style((po::command_line_style::default_style & ~po::command_line_style::allow_guessing)
| po::command_line_style::allow_long_disguise);
if(mExtraParser)
{
@@ -341,7 +345,10 @@ bool LLCommandLineParser::parseCommandLine(int argc, char **argv)
bool LLCommandLineParser::parseCommandLineString(const std::string& str)
{
// Split the string content into tokens
- boost::escaped_list_separator<char> sep("\\", "\r\n ", "\"'");
+ const char* escape_chars = "\\";
+ const char* separator_chars = "\r\n ";
+ const char* quote_chars = "\"'";
+ boost::escaped_list_separator<char> sep(escape_chars, separator_chars, quote_chars);
boost::tokenizer< boost::escaped_list_separator<char> > tok(str, sep);
std::vector<std::string> tokens;
// std::copy(tok.begin(), tok.end(), std::back_inserter(tokens));
diff --git a/indra/newview/llcurrencyuimanager.cpp b/indra/newview/llcurrencyuimanager.cpp
index 2b92b228b3..b4a1457f47 100644
--- a/indra/newview/llcurrencyuimanager.cpp
+++ b/indra/newview/llcurrencyuimanager.cpp
@@ -166,7 +166,7 @@ void LLCurrencyUIManager::Impl::updateCurrencyInfo()
gAgent.getSecureSessionID().asString());
keywordArgs.appendString("language", LLUI::getLanguage());
keywordArgs.appendInt("currencyBuy", mUserCurrencyBuy);
- keywordArgs.appendString("viewerChannel", gSavedSettings.getString("VersionChannelName"));
+ keywordArgs.appendString("viewerChannel", LLVersionInfo::getChannel());
keywordArgs.appendInt("viewerMajorVersion", LLVersionInfo::getMajor());
keywordArgs.appendInt("viewerMinorVersion", LLVersionInfo::getMinor());
keywordArgs.appendInt("viewerPatchVersion", LLVersionInfo::getPatch());
@@ -241,7 +241,7 @@ void LLCurrencyUIManager::Impl::startCurrencyBuy(const std::string& password)
{
keywordArgs.appendString("password", password);
}
- keywordArgs.appendString("viewerChannel", gSavedSettings.getString("VersionChannelName"));
+ keywordArgs.appendString("viewerChannel", LLVersionInfo::getChannel());
keywordArgs.appendInt("viewerMajorVersion", LLVersionInfo::getMajor());
keywordArgs.appendInt("viewerMinorVersion", LLVersionInfo::getMinor());
keywordArgs.appendInt("viewerPatchVersion", LLVersionInfo::getPatch());
diff --git a/indra/newview/lldateutil.cpp b/indra/newview/lldateutil.cpp
index fcc73a07bc..18ae6107e7 100644
--- a/indra/newview/lldateutil.cpp
+++ b/indra/newview/lldateutil.cpp
@@ -32,9 +32,9 @@
#include "llui.h"
static S32 DAYS_PER_MONTH_NOLEAP[] =
- { 31, 28, 21, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+ { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
static S32 DAYS_PER_MONTH_LEAP[] =
- { 31, 29, 21, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+ { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
static S32 days_from_month(S32 year, S32 month)
{
diff --git a/indra/newview/lldebugview.cpp b/indra/newview/lldebugview.cpp
index 0876c3fd99..b6d67899f8 100644
--- a/indra/newview/lldebugview.cpp
+++ b/indra/newview/lldebugview.cpp
@@ -39,7 +39,9 @@
#include "llviewerwindow.h"
#include "llappviewer.h"
#include "llmemoryview.h"
+#include "llsceneview.h"
#include "llviewertexture.h"
+
//
// Globals
//
@@ -83,6 +85,13 @@ void LLDebugView::init()
addChild(mFastTimerView);
mFastTimerView->setRect(rect);
+ gSceneView = new LLSceneView(r);
+ gSceneView->setFollowsTop();
+ gSceneView->setFollowsLeft();
+ gSceneView->setVisible(FALSE);
+ addChild(gSceneView);
+ gSceneView->setRect(rect);
+
r.setLeftTopAndSize(25, rect.getHeight() - 50, (S32) (gViewerWindow->getWindowRectScaled().getWidth() * 0.75f),
(S32) (gViewerWindow->getWindowRectScaled().getHeight() * 0.75f));
LLMemoryView::Params mp;
@@ -103,6 +112,9 @@ void LLDebugView::init()
addChild(gTextureView);
//gTextureView->reshape(r.getWidth(), r.getHeight(), TRUE);
+
+
+
if(gAuditTexture)
{
r.set(150, rect.getHeight() - 50, 900 + LLImageGL::sTextureLoadedCounter.size() * 30, 100);
@@ -133,6 +145,7 @@ LLDebugView::~LLDebugView()
// These have already been deleted. Fix the globals appropriately.
gDebugView = NULL;
gTextureView = NULL;
+ gSceneView = NULL;
gTextureSizeView = NULL;
gTextureCategoryView = NULL;
}
diff --git a/indra/newview/lldirpicker.cpp b/indra/newview/lldirpicker.cpp
index 53101f0ce2..dd243397a1 100644
--- a/indra/newview/lldirpicker.cpp
+++ b/indra/newview/lldirpicker.cpp
@@ -35,6 +35,7 @@
#include "llframetimer.h"
#include "lltrans.h"
#include "llwindow.h" // beforeDialog()
+#include "llviewercontrol.h"
#if LL_LINUX || LL_SOLARIS
# include "llfilepicker.h"
@@ -53,6 +54,23 @@ LLDirPicker LLDirPicker::sInstance;
//
// Implementation
//
+
+// utility function to check if access to local file system via file browser
+// is enabled and if not, tidy up and indicate we're not allowed to do this.
+bool LLDirPicker::check_local_file_access_enabled()
+{
+ // if local file browsing is turned off, return without opening dialog
+ bool local_file_system_browsing_enabled = gSavedSettings.getBOOL("LocalFileSystemBrowsingEnabled");
+ if ( ! local_file_system_browsing_enabled )
+ {
+ mDir.clear(); // Windows
+ mFileName = NULL; // Mac/Linux
+ return false;
+ }
+
+ return true;
+}
+
#if LL_WINDOWS
LLDirPicker::LLDirPicker() :
@@ -72,6 +90,13 @@ BOOL LLDirPicker::getDir(std::string* filename)
{
return FALSE;
}
+
+ // if local file browsing is turned off, return without opening dialog
+ if ( check_local_file_access_enabled() == false )
+ {
+ return FALSE;
+ }
+
BOOL success = FALSE;
// Modal, so pause agent
@@ -231,7 +256,13 @@ BOOL LLDirPicker::getDir(std::string* filename)
if( mLocked ) return FALSE;
BOOL success = FALSE;
OSStatus error = noErr;
-
+
+ // if local file browsing is turned off, return without opening dialog
+ if ( check_local_file_access_enabled() == false )
+ {
+ return FALSE;
+ }
+
mFileName = filename;
// mNavOptions.saveFileName
@@ -289,6 +320,13 @@ void LLDirPicker::reset()
BOOL LLDirPicker::getDir(std::string* filename)
{
reset();
+
+ // if local file browsing is turned off, return without opening dialog
+ if ( check_local_file_access_enabled() == false )
+ {
+ return FALSE;
+ }
+
if (mFilePicker)
{
GtkWindow* picker = mFilePicker->buildFilePicker(false, true,
diff --git a/indra/newview/lldirpicker.h b/indra/newview/lldirpicker.h
index a360293fff..2188b7edd0 100644
--- a/indra/newview/lldirpicker.h
+++ b/indra/newview/lldirpicker.h
@@ -75,6 +75,7 @@ private:
};
void buildDirname( void );
+ bool check_local_file_access_enabled();
#if LL_DARWIN
NavDialogCreationOptions mNavOptions;
diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp
index 583bb54160..bdc12ec0e3 100644
--- a/indra/newview/lldrawable.cpp
+++ b/indra/newview/lldrawable.cpp
@@ -35,6 +35,7 @@
#include "llcriticaldamp.h"
#include "llface.h"
#include "lllightconstants.h"
+#include "llmatrix4a.h"
#include "llsky.h"
#include "llsurfacepatch.h"
#include "llviewercamera.h"
@@ -85,6 +86,7 @@ void LLDrawable::incrementVisible()
sCurVisible++;
sCurPixelAngle = (F32) gViewerWindow->getWindowHeightRaw()/LLViewerCamera::getInstance()->getView();
}
+
void LLDrawable::init()
{
// mXform
@@ -115,6 +117,11 @@ void LLDrawable::initClass()
void LLDrawable::destroy()
{
+ if (gDebugGL)
+ {
+ gPipeline.checkReferences(this);
+ }
+
if (isDead())
{
sNumZombieDrawables--;
@@ -133,6 +140,7 @@ void LLDrawable::destroy()
{
llinfos << "- Zombie drawables: " << sNumZombieDrawables << llendl;
}*/
+
}
void LLDrawable::markDead()
@@ -170,6 +178,11 @@ LLVOVolume* LLDrawable::getVOVolume() const
}
}
+const LLMatrix4& LLDrawable::getRenderMatrix() const
+{
+ return isRoot() ? getWorldMatrix() : getParent()->getWorldMatrix();
+}
+
BOOL LLDrawable::isLight() const
{
LLViewerObject* objectp = mVObjp;
@@ -183,20 +196,30 @@ BOOL LLDrawable::isLight() const
}
}
+static LLFastTimer::DeclareTimer FTM_CLEANUP_DRAWABLE("Cleanup Drawable");
+static LLFastTimer::DeclareTimer FTM_DEREF_DRAWABLE("Deref");
+static LLFastTimer::DeclareTimer FTM_DELETE_FACES("Faces");
+
void LLDrawable::cleanupReferences()
{
- LLFastTimer t(FTM_PIPELINE);
+ LLFastTimer t(FTM_CLEANUP_DRAWABLE);
- std::for_each(mFaces.begin(), mFaces.end(), DeletePointer());
- mFaces.clear();
+ {
+ LLFastTimer t(FTM_DELETE_FACES);
+ std::for_each(mFaces.begin(), mFaces.end(), DeletePointer());
+ mFaces.clear();
+ }
gObjectList.removeDrawable(this);
gPipeline.unlinkDrawable(this);
- // Cleanup references to other objects
- mVObjp = NULL;
- mParent = NULL;
+ {
+ LLFastTimer t(FTM_DEREF_DRAWABLE);
+ // Cleanup references to other objects
+ mVObjp = NULL;
+ mParent = NULL;
+ }
}
void LLDrawable::cleanupDeadDrawables()
@@ -358,6 +381,7 @@ void LLDrawable::makeActive()
{
U32 pcode = mVObjp->getPCode();
if (pcode == LLViewerObject::LL_VO_WATER ||
+ pcode == LLViewerObject::LL_VO_VOID_WATER ||
pcode == LLViewerObject::LL_VO_SURFACE_PATCH ||
pcode == LLViewerObject::LL_VO_PART_GROUP ||
pcode == LLViewerObject::LL_VO_HUD_PART_GROUP ||
@@ -684,13 +708,15 @@ void LLDrawable::updateDistance(LLCamera& camera, bool force_update)
LLVOVolume* volume = getVOVolume();
if (volume)
{
- volume->updateRelativeXform();
- pos = volume->getRelativeXform().getTranslation();
- if (isStatic())
+ if (getSpatialGroup())
{
- pos += volume->getRegion()->getOriginAgent();
+ pos.set(getPositionGroup().getF32ptr());
}
-
+ else
+ {
+ pos = getPositionAgent();
+ }
+
if (isState(LLDrawable::HAS_ALPHA))
{
for (S32 i = 0; i < getNumFaces(); i++)
@@ -698,21 +724,23 @@ void LLDrawable::updateDistance(LLCamera& camera, bool force_update)
LLFace* facep = getFace(i);
if (force_update || facep->getPoolType() == LLDrawPool::POOL_ALPHA)
{
- LLVector3 box = (facep->mExtents[1] - facep->mExtents[0]) * 0.25f;
+ LLVector4a box;
+ box.setSub(facep->mExtents[1], facep->mExtents[0]);
+ box.mul(0.25f);
LLVector3 v = (facep->mCenterLocal-camera.getOrigin());
const LLVector3& at = camera.getAtAxis();
for (U32 j = 0; j < 3; j++)
{
- v.mV[j] -= box.mV[j] * at.mV[j];
+ v.mV[j] -= box[j] * at.mV[j];
}
facep->mDistance = v * camera.getAtAxis();
}
}
- }
+ }
}
else
{
- pos = LLVector3(getPositionGroup());
+ pos = LLVector3(getPositionGroup().getF32ptr());
}
pos -= camera.getOrigin();
@@ -738,7 +766,7 @@ void LLDrawable::updateTexture()
if (getVOVolume())
{
- if (isActive())
+ /*if (isActive())
{
if (isRoot())
{
@@ -748,7 +776,7 @@ void LLDrawable::updateTexture()
{
getParent()->mQuietCount = 0;
}
- }
+ }*/
gPipeline.markRebuild(this, LLDrawable::REBUILD_MATERIAL, TRUE);
}
@@ -761,7 +789,7 @@ BOOL LLDrawable::updateGeometry(BOOL priority)
return res;
}
-void LLDrawable::shiftPos(const LLVector3 &shift_vector)
+void LLDrawable::shiftPos(const LLVector4a &shift_vector)
{
if (isDead())
{
@@ -793,20 +821,19 @@ void LLDrawable::shiftPos(const LLVector3 &shift_vector)
for (S32 i = 0; i < getNumFaces(); i++)
{
LLFace *facep = getFace(i);
- facep->mCenterAgent += shift_vector;
- facep->mExtents[0] += shift_vector;
- facep->mExtents[1] += shift_vector;
+ facep->mCenterAgent += LLVector3(shift_vector.getF32ptr());
+ facep->mExtents[0].add(shift_vector);
+ facep->mExtents[1].add(shift_vector);
if (!volume && facep->hasGeometry())
{
- facep->mVertexBuffer = NULL;
- facep->mLastVertexBuffer = NULL;
+ facep->clearVertexBuffer();
}
}
- mExtents[0] += shift_vector;
- mExtents[1] += shift_vector;
- mPositionGroup += LLVector3d(shift_vector);
+ mExtents[0].add(shift_vector);
+ mExtents[1].add(shift_vector);
+ mPositionGroup.add(shift_vector);
}
else if (mSpatialBridge)
{
@@ -814,9 +841,9 @@ void LLDrawable::shiftPos(const LLVector3 &shift_vector)
}
else if (isAvatar())
{
- mExtents[0] += shift_vector;
- mExtents[1] += shift_vector;
- mPositionGroup += LLVector3d(shift_vector);
+ mExtents[0].add(shift_vector);
+ mExtents[1].add(shift_vector);
+ mPositionGroup.add(shift_vector);
}
mVObjp->onShift(shift_vector);
@@ -828,21 +855,26 @@ const LLVector3& LLDrawable::getBounds(LLVector3& min, LLVector3& max) const
return mXform.getPositionW();
}
-const LLVector3* LLDrawable::getSpatialExtents() const
+const LLVector4a* LLDrawable::getSpatialExtents() const
{
return mExtents;
}
-void LLDrawable::setSpatialExtents(LLVector3 min, LLVector3 max)
+void LLDrawable::setSpatialExtents(const LLVector3& min, const LLVector3& max)
+{
+ mExtents[0].load3(min.mV);
+ mExtents[1].load3(max.mV);
+}
+
+void LLDrawable::setSpatialExtents(const LLVector4a& min, const LLVector4a& max)
{
- LLVector3 size = max - min;
mExtents[0] = min;
- mExtents[1] = max;
+ mExtents[1] = max;
}
-void LLDrawable::setPositionGroup(const LLVector3d& pos)
+void LLDrawable::setPositionGroup(const LLVector4a& pos)
{
- mPositionGroup.setVec(pos);
+ mPositionGroup = pos;
}
void LLDrawable::updateSpatialExtents()
@@ -856,7 +888,7 @@ void LLDrawable::updateSpatialExtents()
if (mSpatialBridge.notNull())
{
- mPositionGroup.setVec(0,0,0);
+ mPositionGroup.splat(0.f);
}
}
@@ -909,6 +941,18 @@ void LLDrawable::setSpatialGroup(LLSpatialGroup *groupp)
{
mSpatialGroupp->setState(LLSpatialGroup::GEOM_DIRTY);
}*/
+
+ if (mSpatialGroupp != groupp && getVOVolume())
+ { //NULL out vertex buffer references for volumes on spatial group change to maintain
+ //requirement that every face vertex buffer is either NULL or points to a vertex buffer
+ //contained by its drawable's spatial group
+ for (S32 i = 0; i < getNumFaces(); ++i)
+ {
+ LLFace* facep = getFace(i);
+ facep->clearVertexBuffer();
+ }
+ }
+
mSpatialGroupp = groupp;
}
@@ -1026,7 +1070,7 @@ BOOL LLDrawable::isVisible() const
//=======================================
LLSpatialBridge::LLSpatialBridge(LLDrawable* root, BOOL render_by_group, U32 data_mask)
-: LLSpatialPartition(data_mask, render_by_group, FALSE)
+: LLSpatialPartition(data_mask, render_by_group, GL_STREAM_DRAW_ARB)
{
mDrawable = root;
root->setSpatialBridge(this);
@@ -1067,59 +1111,72 @@ void LLSpatialBridge::updateSpatialExtents()
root->rebound();
}
- LLXformMatrix* mat = mDrawable->getXform();
-
- LLVector3 offset = root->mBounds[0];
- LLVector3 size = root->mBounds[1];
+ LLVector4a offset;
+ LLVector4a size = root->mBounds[1];
- LLVector3 center = LLVector3(0,0,0) * mat->getWorldMatrix();
- LLQuaternion rotation = LLQuaternion(mat->getWorldMatrix());
+ //VECTORIZE THIS
+ LLMatrix4a mat;
+ mat.loadu(mDrawable->getXform()->getWorldMatrix());
+
+ LLVector4a t;
+ t.splat(0.f);
+
+ LLVector4a center;
+ mat.affineTransform(t, center);
- offset *= rotation;
- center += offset;
+ mat.rotate(root->mBounds[0], offset);
+ center.add(offset);
- LLVector3 v[4];
+ LLVector4a v[4];
+
//get 4 corners of bounding box
- v[0] = (size * rotation);
- v[1] = (LLVector3(-size.mV[0], -size.mV[1], size.mV[2]) * rotation);
- v[2] = (LLVector3(size.mV[0], -size.mV[1], -size.mV[2]) * rotation);
- v[3] = (LLVector3(-size.mV[0], size.mV[1], -size.mV[2]) * rotation);
+ mat.rotate(size,v[0]);
- LLVector3& newMin = mExtents[0];
- LLVector3& newMax = mExtents[1];
+ LLVector4a scale;
+
+ scale.set(-1.f, -1.f, 1.f);
+ scale.mul(size);
+ mat.rotate(scale, v[1]);
+
+ scale.set(1.f, -1.f, -1.f);
+ scale.mul(size);
+ mat.rotate(scale, v[2]);
+
+ scale.set(-1.f, 1.f, -1.f);
+ scale.mul(size);
+ mat.rotate(scale, v[3]);
+
+
+ LLVector4a& newMin = mExtents[0];
+ LLVector4a& newMax = mExtents[1];
newMin = newMax = center;
for (U32 i = 0; i < 4; i++)
{
- for (U32 j = 0; j < 3; j++)
- {
- F32 delta = fabsf(v[i].mV[j]);
- F32 min = center.mV[j] - delta;
- F32 max = center.mV[j] + delta;
-
- if (min < newMin.mV[j])
- {
- newMin.mV[j] = min;
- }
-
- if (max > newMax.mV[j])
- {
- newMax.mV[j] = max;
- }
- }
- }
+ LLVector4a delta;
+ delta.setAbs(v[i]);
+ LLVector4a min;
+ min.setSub(center, delta);
+ LLVector4a max;
+ max.setAdd(center, delta);
- LLVector3 diagonal = newMax - newMin;
- mRadius = diagonal.magVec() * 0.5f;
+ newMin.setMin(newMin, min);
+ newMax.setMax(newMax, max);
+ }
+
+ LLVector4a diagonal;
+ diagonal.setSub(newMax, newMin);
+ mRadius = diagonal.getLength3().getF32() * 0.5f;
- mPositionGroup.setVec((newMin + newMax) * 0.5f);
+ mPositionGroup.setAdd(newMin,newMax);
+ mPositionGroup.mul(0.5f);
updateBinRadius();
}
void LLSpatialBridge::updateBinRadius()
{
- mBinRadius = llmin((F32) mOctree->getSize().mdV[0]*0.5f, 256.f);
+ mBinRadius = llmin( mOctree->getSize()[0]*0.5f, 256.f);
}
LLCamera LLSpatialBridge::transformCamera(LLCamera& camera)
@@ -1260,8 +1317,12 @@ void LLSpatialBridge::setVisible(LLCamera& camera_in, std::vector<LLDrawable*>*
LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0);
group->rebound();
- LLVector3 center = (mExtents[0] + mExtents[1]) * 0.5f;
- LLVector3 size = (mExtents[1]-mExtents[0]) * 0.5f;
+ LLVector4a center;
+ center.setAdd(mExtents[0], mExtents[1]);
+ center.mul(0.5f);
+ LLVector4a size;
+ size.setSub(mExtents[1], mExtents[0]);
+ size.mul(0.5f);
if ((LLPipeline::sShadowRender && camera_in.AABBInFrustum(center, size)) ||
LLPipeline::sImpostorRender ||
@@ -1374,11 +1435,11 @@ BOOL LLSpatialBridge::updateMove()
return TRUE;
}
-void LLSpatialBridge::shiftPos(const LLVector3& vec)
+void LLSpatialBridge::shiftPos(const LLVector4a& vec)
{
- mExtents[0] += vec;
- mExtents[1] += vec;
- mPositionGroup += LLVector3d(vec);
+ mExtents[0].add(vec);
+ mExtents[1].add(vec);
+ mPositionGroup.add(vec);
}
void LLSpatialBridge::cleanupReferences()
@@ -1496,7 +1557,7 @@ F32 LLHUDBridge::calcPixelArea(LLSpatialGroup* group, LLCamera& camera)
}
-void LLHUDBridge::shiftPos(const LLVector3& vec)
+void LLHUDBridge::shiftPos(const LLVector4a& vec)
{
//don't shift hud bridges on region crossing
}
diff --git a/indra/newview/lldrawable.h b/indra/newview/lldrawable.h
index 2cea41df0a..9ebe1a45b4 100644
--- a/indra/newview/lldrawable.h
+++ b/indra/newview/lldrawable.h
@@ -35,6 +35,7 @@
#include "v4math.h"
#include "m4math.h"
#include "v4coloru.h"
+#include "llvector4a.h"
#include "llquaternion.h"
#include "xform.h"
#include "llmemtype.h"
@@ -61,6 +62,17 @@ const U32 SILHOUETTE_HIGHLIGHT = 0;
class LLDrawable : public LLRefCount
{
public:
+ LLDrawable(const LLDrawable& rhs)
+ {
+ *this = rhs;
+ }
+
+ const LLDrawable& operator=(const LLDrawable& rhs)
+ {
+ llerrs << "Illegal operation!" << llendl;
+ return *this;
+ }
+
static void initClass();
LLDrawable() { init(); }
@@ -84,19 +96,19 @@ public:
LLVOVolume* getVOVolume() const; // cast mVObjp tp LLVOVolume if OK
const LLMatrix4& getWorldMatrix() const { return mXform.getWorldMatrix(); }
- const LLMatrix4& getRenderMatrix() const { return isRoot() ? getWorldMatrix() : getParent()->getWorldMatrix(); }
+ const LLMatrix4& getRenderMatrix() const;
void setPosition(LLVector3 v) const { }
const LLVector3& getPosition() const { return mXform.getPosition(); }
const LLVector3& getWorldPosition() const { return mXform.getPositionW(); }
const LLVector3 getPositionAgent() const;
- const LLVector3d& getPositionGroup() const { return mPositionGroup; }
+ const LLVector4a& getPositionGroup() const { return mPositionGroup; }
const LLVector3& getScale() const { return mCurrentScale; }
void setScale(const LLVector3& scale) { mCurrentScale = scale; }
const LLQuaternion& getWorldRotation() const { return mXform.getWorldRotation(); }
const LLQuaternion& getRotation() const { return mXform.getRotation(); }
F32 getIntensity() const { return llmin(mXform.getScale().mV[0], 4.f); }
S32 getLOD() const { return mVObjp ? mVObjp->getLOD() : 1; }
- F64 getBinRadius() const { return mBinRadius; }
+ F32 getBinRadius() const { return mBinRadius; }
void getMinMax(LLVector3& min,LLVector3& max) const { mXform.getMinMax(min,max); }
LLXformMatrix* getXform() { return &mXform; }
@@ -150,7 +162,7 @@ public:
void updateSpecialHoverCursor(BOOL enabled);
- virtual void shiftPos(const LLVector3 &shift_vector);
+ virtual void shiftPos(const LLVector4a &shift_vector);
S32 getGeneration() const { return mGeneration; }
@@ -168,11 +180,12 @@ public:
const LLVector3& getBounds(LLVector3& min, LLVector3& max) const;
virtual void updateSpatialExtents();
virtual void updateBinRadius();
- const LLVector3* getSpatialExtents() const;
- void setSpatialExtents(LLVector3 min, LLVector3 max);
- void setPositionGroup(const LLVector3d& pos);
- void setPositionGroup(const LLVector3& pos) { setPositionGroup(LLVector3d(pos)); }
+ const LLVector4a* getSpatialExtents() const;
+ void setSpatialExtents(const LLVector3& min, const LLVector3& max);
+ void setSpatialExtents(const LLVector4a& min, const LLVector4a& max);
+ void setPositionGroup(const LLVector4a& pos);
+
void setRenderType(S32 type) { mRenderType = type; }
BOOL isRenderType(S32 type) { return mRenderType == type; }
S32 getRenderType() { return mRenderType; }
@@ -232,37 +245,44 @@ public:
typedef enum e_drawable_flags
{
- IN_REBUILD_Q1 = 0x00000002,
- IN_REBUILD_Q2 = 0x00000004,
- IN_LIGHT_Q = 0x00000008,
- EARLY_MOVE = 0x00000010,
- MOVE_UNDAMPED = 0x00000020,
- ON_MOVE_LIST = 0x00000040,
- USE_BACKLIGHT = 0x00000080,
- UV = 0x00000100,
- UNLIT = 0x00000200,
- LIGHT = 0x00000400,
- LIGHTING_BUILT = 0x00000800,
- REBUILD_VOLUME = 0x00001000, //volume changed LOD or parameters, or vertex buffer changed
- REBUILD_TCOORD = 0x00002000, //texture coordinates changed
- REBUILD_COLOR = 0x00004000, //color changed
- REBUILD_POSITION= 0x00010000, //vertex positions/normals changed
+ IN_REBUILD_Q1 = 0x00000001,
+ IN_REBUILD_Q2 = 0x00000002,
+ IN_LIGHT_Q = 0x00000004,
+ EARLY_MOVE = 0x00000008,
+ MOVE_UNDAMPED = 0x00000010,
+ ON_MOVE_LIST = 0x00000020,
+ USE_BACKLIGHT = 0x00000040,
+ UV = 0x00000080,
+ UNLIT = 0x00000100,
+ LIGHT = 0x00000200,
+ LIGHTING_BUILT = 0x00000400,
+ REBUILD_VOLUME = 0x00000800, //volume changed LOD or parameters, or vertex buffer changed
+ REBUILD_TCOORD = 0x00001000, //texture coordinates changed
+ REBUILD_COLOR = 0x00002000, //color changed
+ REBUILD_POSITION= 0x00004000, //vertex positions/normals changed
REBUILD_GEOMETRY= REBUILD_POSITION|REBUILD_TCOORD|REBUILD_COLOR,
REBUILD_MATERIAL= REBUILD_TCOORD|REBUILD_COLOR,
REBUILD_ALL = REBUILD_GEOMETRY|REBUILD_VOLUME,
- ON_SHIFT_LIST = 0x00100000,
- BLOCKER = 0x00400000,
- ACTIVE = 0x00800000,
- DEAD = 0x01000000,
- INVISIBLE = 0x02000000, // stay invisible until flag is cleared
- NEARBY_LIGHT = 0x04000000, // In gPipeline.mNearbyLightSet
- BUILT = 0x08000000,
- FORCE_INVISIBLE = 0x10000000, // stay invis until CLEAR_INVISIBLE is set (set of orphaned)
- CLEAR_INVISIBLE = 0x20000000, // clear FORCE_INVISIBLE next draw frame
- REBUILD_SHADOW = 0x40000000,
- HAS_ALPHA = 0x80000000,
+ REBUILD_RIGGED = 0x00008000,
+ ON_SHIFT_LIST = 0x00010000,
+ BLOCKER = 0x00020000,
+ ACTIVE = 0x00040000,
+ DEAD = 0x00080000,
+ INVISIBLE = 0x00100000, // stay invisible until flag is cleared
+ NEARBY_LIGHT = 0x00200000, // In gPipeline.mNearbyLightSet
+ BUILT = 0x00400000,
+ FORCE_INVISIBLE = 0x00800000, // stay invis until CLEAR_INVISIBLE is set (set of orphaned)
+ CLEAR_INVISIBLE = 0x01000000, // clear FORCE_INVISIBLE next draw frame
+ REBUILD_SHADOW = 0x02000000,
+ HAS_ALPHA = 0x04000000,
+ RIGGED = 0x08000000,
} EDrawableFlags;
+private: //aligned members
+ LLVector4a mExtents[2];
+ LLVector4a mPositionGroup;
+
+public:
LLXformMatrix mXform;
// vis data
@@ -292,9 +312,7 @@ private:
mutable U32 mVisible;
F32 mRadius;
- LLVector3 mExtents[2];
- LLVector3d mPositionGroup;
- F64 mBinRadius;
+ F32 mBinRadius;
S32 mGeneration;
LLVector3 mCurrentScale;
diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp
index cb651f9d3a..25e4bc847c 100644
--- a/indra/newview/lldrawpool.cpp
+++ b/indra/newview/lldrawpool.cpp
@@ -89,6 +89,7 @@ LLDrawPool *LLDrawPool::createPool(const U32 type, LLViewerTexture *tex0)
case POOL_SKY:
poolp = new LLDrawPoolSky();
break;
+ case POOL_VOIDWATER:
case POOL_WATER:
poolp = new LLDrawPoolWater();
break;
@@ -242,11 +243,6 @@ void LLFacePool::dirtyTextures(const std::set<LLViewerFetchedTexture*>& textures
{
}
-BOOL LLFacePool::moveFace(LLFace *face, LLDrawPool *poolp, BOOL copy_data)
-{
- return TRUE;
-}
-
// static
S32 LLFacePool::drawLoop(face_array_t& face_list)
{
diff --git a/indra/newview/lldrawpool.h b/indra/newview/lldrawpool.h
index 221f81ec25..d3fd9ead0d 100644
--- a/indra/newview/lldrawpool.h
+++ b/indra/newview/lldrawpool.h
@@ -47,16 +47,17 @@ public:
{
// Correspond to LLPipeline render type
POOL_SIMPLE = 1,
+ POOL_GROUND,
+ POOL_FULLBRIGHT,
+ POOL_BUMP,
POOL_TERRAIN,
- POOL_TREE,
POOL_SKY,
POOL_WL_SKY,
- POOL_GROUND,
+ POOL_TREE,
POOL_GRASS,
- POOL_FULLBRIGHT,
- POOL_BUMP,
POOL_INVISIBLE, // see below *
POOL_AVATAR,
+ POOL_VOIDWATER,
POOL_WATER,
POOL_GLOW,
POOL_ALPHA,
@@ -167,7 +168,6 @@ public:
LLFacePool(const U32 type);
virtual ~LLFacePool();
- virtual void renderForSelect() = 0;
BOOL isDead() { return mReferences.empty(); }
virtual LLViewerTexture *getTexture();
@@ -182,8 +182,6 @@ public:
virtual void resetDrawOrders();
void resetAll();
- BOOL moveFace(LLFace *face, LLDrawPool *poolp, BOOL copy_data = FALSE);
-
void destroy();
void buildEdges();
diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp
index a2428d2de0..8b5a2ce781 100644
--- a/indra/newview/lldrawpoolalpha.cpp
+++ b/indra/newview/lldrawpoolalpha.cpp
@@ -103,16 +103,40 @@ void LLDrawPoolAlpha::renderDeferred(S32 pass)
S32 LLDrawPoolAlpha::getNumPostDeferredPasses()
{
- return 1;
+ if (LLPipeline::sImpostorRender)
+ { //skip depth buffer filling pass when rendering impostors
+ return 1;
+ }
+ else if (gSavedSettings.getBOOL("RenderDepthOfField"))
+ {
+ return 2;
+ }
+ else
+ {
+ return 1;
+ }
}
void LLDrawPoolAlpha::beginPostDeferredPass(S32 pass)
{
LLFastTimer t(FTM_RENDER_ALPHA);
- simple_shader = &gDeferredAlphaProgram;
- fullbright_shader = &gDeferredFullbrightProgram;
-
+ if (pass == 0)
+ {
+ simple_shader = &gDeferredAlphaProgram;
+ fullbright_shader = &gDeferredFullbrightProgram;
+ }
+ else
+ {
+ //update depth buffer sampler
+ gPipeline.mScreen.flush();
+ gPipeline.mDeferredDepth.copyContents(gPipeline.mDeferredScreen, 0, 0, gPipeline.mDeferredScreen.getWidth(), gPipeline.mDeferredScreen.getHeight(),
+ 0, 0, gPipeline.mDeferredDepth.getWidth(), gPipeline.mDeferredDepth.getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST);
+ gPipeline.mDeferredDepth.bindTarget();
+ simple_shader = NULL;
+ fullbright_shader = NULL;
+ }
+
deferred_render = TRUE;
if (mVertexShaderLevel > 0)
{
@@ -124,6 +148,13 @@ void LLDrawPoolAlpha::beginPostDeferredPass(S32 pass)
void LLDrawPoolAlpha::endPostDeferredPass(S32 pass)
{
+
+ if (pass == 1)
+ {
+ gPipeline.mDeferredDepth.flush();
+ gPipeline.mScreen.bindTarget();
+ }
+
deferred_render = FALSE;
endRenderPass(pass);
}
@@ -174,9 +205,16 @@ void LLDrawPoolAlpha::render(S32 pass)
LLGLSPipelineAlpha gls_pipeline_alpha;
- gGL.setColorMask(true, true);
+ if (deferred_render && pass == 1)
+ { //depth only
+ gGL.setColorMask(false, false);
+ }
+ else
+ {
+ gGL.setColorMask(true, true);
+ }
- if (LLPipeline::sAutoMaskAlphaNonDeferred && !deferred_render)
+ if (LLPipeline::sAutoMaskAlphaNonDeferred)
{
mColorSFactor = LLRender::BF_ONE; // }
mColorDFactor = LLRender::BF_ZERO; // } these are like disabling blend on the color channels, but we're still blending on the alpha channel so that we can suppress glow
@@ -192,7 +230,10 @@ void LLDrawPoolAlpha::render(S32 pass)
simple_shader->bind();
pushBatches(LLRenderPass::PASS_ALPHA_MASK, getVertexDataMask());
}
- fullbright_shader->bind();
+ if (fullbright_shader)
+ {
+ fullbright_shader->bind();
+ }
pushBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, getVertexDataMask());
LLGLSLShader::bindNoShader();
}
@@ -206,18 +247,42 @@ void LLDrawPoolAlpha::render(S32 pass)
gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
}
- LLGLDepthTest depth(GL_TRUE, LLDrawPoolWater::sSkipScreenCopy ? GL_TRUE : GL_FALSE);
+ LLGLDepthTest depth(GL_TRUE, LLDrawPoolWater::sSkipScreenCopy ||
+ (deferred_render && pass == 1) ? GL_TRUE : GL_FALSE);
- mColorSFactor = LLRender::BF_SOURCE_ALPHA; // } regular alpha blend
- mColorDFactor = LLRender::BF_ONE_MINUS_SOURCE_ALPHA; // }
- mAlphaSFactor = LLRender::BF_ZERO; // } glow suppression
- mAlphaDFactor = LLRender::BF_ONE_MINUS_SOURCE_ALPHA; // }
- gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor);
+ if (deferred_render && pass == 1)
+ {
+ gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.33f);
+ gGL.blendFunc(LLRender::BF_SOURCE_ALPHA, LLRender::BF_ONE_MINUS_SOURCE_ALPHA);
+ }
+ else
+ {
+ mColorSFactor = LLRender::BF_SOURCE_ALPHA; // } regular alpha blend
+ mColorDFactor = LLRender::BF_ONE_MINUS_SOURCE_ALPHA; // }
+ mAlphaSFactor = LLRender::BF_ZERO; // } glow suppression
+ mAlphaDFactor = LLRender::BF_ONE_MINUS_SOURCE_ALPHA; // }
+ gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor);
+
+ if (LLPipeline::sImpostorRender)
+ {
+ gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f);
+ }
+ else
+ {
+ gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
+ }
+ }
renderAlpha(getVertexDataMask());
gGL.setColorMask(true, false);
+ if (deferred_render && pass == 1)
+ {
+ gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
+ gGL.setSceneBlendType(LLRender::BT_ALPHA);
+ }
+
if (deferred_render && current_shader != NULL)
{
gPipeline.unbindDeferredShader(*current_shader);
@@ -276,22 +341,10 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask)
BOOL light_enabled = TRUE;
S32 diffuse_channel = 0;
- //BOOL is_particle = FALSE;
BOOL use_shaders = (LLPipeline::sUnderWaterRender && gPipeline.canUseVertexShaders())
|| gPipeline.canUseWindLightShadersOnObjects();
- // check to see if it's a particle and if it's "close"
- {
- if (LLPipeline::sImpostorRender)
- {
- gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f);
- }
- else
- {
- gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
- }
- }
-
+
for (LLCullResult::sg_list_t::iterator i = gPipeline.beginAlphaGroups(); i != gPipeline.endAlphaGroups(); ++i)
{
LLSpatialGroup* group = *i;
diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp
index 8cf4dc1b95..645c7ebcae 100644
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -31,15 +31,21 @@
#include "llvoavatar.h"
#include "m3math.h"
+#include "llmatrix4a.h"
+#include "llagent.h" //for gAgent.needsRenderAvatar()
#include "lldrawable.h"
+#include "lldrawpoolbump.h"
#include "llface.h"
+#include "llmeshrepository.h"
#include "llsky.h"
#include "llviewercamera.h"
#include "llviewerregion.h"
#include "noise.h"
#include "pipeline.h"
#include "llviewershadermgr.h"
+#include "llvovolume.h"
+#include "llvolume.h"
#include "llappviewer.h"
#include "llrendersphere.h"
#include "llviewerpartsim.h"
@@ -47,10 +53,15 @@
static U32 sDataMask = LLDrawPoolAvatar::VERTEX_DATA_MASK;
static U32 sBufferUsage = GL_STREAM_DRAW_ARB;
static U32 sShaderLevel = 0;
-static LLGLSLShader* sVertexProgram = NULL;
+
+LLGLSLShader* LLDrawPoolAvatar::sVertexProgram = NULL;
BOOL LLDrawPoolAvatar::sSkipOpaque = FALSE;
BOOL LLDrawPoolAvatar::sSkipTransparent = FALSE;
+S32 LLDrawPoolAvatar::sDiffuseChannel = 0;
+
+
+static bool is_deferred_render = false;
extern BOOL gUseGLPick;
@@ -86,7 +97,7 @@ BOOL gAvatarEmbossBumpMap = FALSE;
static BOOL sRenderingSkinned = FALSE;
S32 normal_channel = -1;
S32 specular_channel = -1;
-S32 diffuse_channel = -1;
+S32 cube_channel = -1;
static LLFastTimer::DeclareTimer FTM_SHADOW_AVATAR("Avatar Shadow");
@@ -142,21 +153,17 @@ LLMatrix4& LLDrawPoolAvatar::getModelView()
//-----------------------------------------------------------------------------
-S32 LLDrawPoolAvatar::getNumDeferredPasses()
-{
- return getNumPasses();
-}
void LLDrawPoolAvatar::beginDeferredPass(S32 pass)
{
LLFastTimer t(FTM_RENDER_CHARACTERS);
sSkipTransparent = TRUE;
-
+ is_deferred_render = true;
+
if (LLPipeline::sImpostorRender)
- {
- beginDeferredSkinned();
- return;
+ { //impostor pass does not have rigid or impostor rendering
+ pass += 2;
}
switch (pass)
@@ -170,6 +177,12 @@ void LLDrawPoolAvatar::beginDeferredPass(S32 pass)
case 2:
beginDeferredSkinned();
break;
+ case 3:
+ beginDeferredRiggedSimple();
+ break;
+ case 4:
+ beginDeferredRiggedBump();
+ break;
}
}
@@ -178,11 +191,11 @@ void LLDrawPoolAvatar::endDeferredPass(S32 pass)
LLFastTimer t(FTM_RENDER_CHARACTERS);
sSkipTransparent = FALSE;
+ is_deferred_render = false;
if (LLPipeline::sImpostorRender)
{
- endDeferredSkinned();
- return;
+ pass += 2;
}
switch (pass)
@@ -196,6 +209,12 @@ void LLDrawPoolAvatar::endDeferredPass(S32 pass)
case 2:
endDeferredSkinned();
break;
+ case 3:
+ endDeferredRiggedSimple();
+ break;
+ case 4:
+ endDeferredRiggedBump();
+ break;
}
}
@@ -206,11 +225,36 @@ void LLDrawPoolAvatar::renderDeferred(S32 pass)
S32 LLDrawPoolAvatar::getNumPostDeferredPasses()
{
- return 1;
+ return 6;
}
void LLDrawPoolAvatar::beginPostDeferredPass(S32 pass)
{
+ switch (pass)
+ {
+ case 0:
+ beginPostDeferredAlpha();
+ break;
+ case 1:
+ beginRiggedFullbright();
+ break;
+ case 2:
+ beginRiggedFullbrightShiny();
+ break;
+ case 3:
+ beginDeferredRiggedAlpha();
+ break;
+ case 4:
+ beginRiggedFullbrightAlpha();
+ break;
+ case 5:
+ beginRiggedGlow();
+ break;
+ }
+}
+
+void LLDrawPoolAvatar::beginPostDeferredAlpha()
+{
sSkipOpaque = TRUE;
sShaderLevel = mVertexShaderLevel;
sVertexProgram = &gDeferredAvatarAlphaProgram;
@@ -219,64 +263,143 @@ void LLDrawPoolAvatar::beginPostDeferredPass(S32 pass)
gPipeline.bindDeferredShader(*sVertexProgram);
+ sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
enable_vertex_weighting(sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_WEIGHT]);
}
+void LLDrawPoolAvatar::beginDeferredRiggedAlpha()
+{
+ sVertexProgram = &gDeferredSkinnedAlphaProgram;
+ gPipeline.bindDeferredShader(*sVertexProgram);
+ sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+ LLVertexBuffer::sWeight4Loc = sVertexProgram->getAttribLocation(LLViewerShaderMgr::OBJECT_WEIGHT);
+ gPipeline.enableLightsDynamic();
+}
+
+void LLDrawPoolAvatar::endDeferredRiggedAlpha()
+{
+ LLVertexBuffer::unbind();
+ gPipeline.unbindDeferredShader(*sVertexProgram);
+ sDiffuseChannel = 0;
+ LLVertexBuffer::sWeight4Loc = -1;
+ sVertexProgram = NULL;
+}
+
void LLDrawPoolAvatar::endPostDeferredPass(S32 pass)
{
+ switch (pass)
+ {
+ case 0:
+ endPostDeferredAlpha();
+ break;
+ case 1:
+ endRiggedFullbright();
+ break;
+ case 2:
+ endRiggedFullbrightShiny();
+ break;
+ case 3:
+ endDeferredRiggedAlpha();
+ break;
+ case 4:
+ endRiggedFullbrightAlpha();
+ break;
+ case 5:
+ endRiggedGlow();
+ break;
+ }
+}
+
+void LLDrawPoolAvatar::endPostDeferredAlpha()
+{
// if we're in software-blending, remember to set the fence _after_ we draw so we wait till this rendering is done
sRenderingSkinned = FALSE;
sSkipOpaque = FALSE;
disable_vertex_weighting(sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_WEIGHT]);
gPipeline.unbindDeferredShader(*sVertexProgram);
-
+ sDiffuseChannel = 0;
sShaderLevel = mVertexShaderLevel;
}
void LLDrawPoolAvatar::renderPostDeferred(S32 pass)
{
- render(2); //pass 2 = skinned
+ const S32 actual_pass[] =
+ { //map post deferred pass numbers to what render() expects
+ 2, //skinned
+ 4, // rigged fullbright
+ 6, //rigged fullbright shiny
+ 7, //rigged alpha
+ 8, //rigged fullbright alpha
+ 9, //rigged glow
+ };
+
+ pass = actual_pass[pass];
+
+ if (LLPipeline::sImpostorRender)
+ { //HACK for impostors so actual pass ends up being proper pass
+ pass -= 2;
+ }
+
+ render(pass);
}
S32 LLDrawPoolAvatar::getNumShadowPasses()
{
- return 1;
+ return 2;
}
void LLDrawPoolAvatar::beginShadowPass(S32 pass)
{
LLFastTimer t(FTM_SHADOW_AVATAR);
- sVertexProgram = &gDeferredAvatarShadowProgram;
- if (sShaderLevel > 0)
+
+ if (pass == 0)
{
- gAvatarMatrixParam = sVertexProgram->mUniform[LLViewerShaderMgr::AVATAR_MATRIX];
- }
- gGL.setAlphaRejectSettings(LLRender::CF_GREATER_EQUAL, 0.2f);
-
- glColor4f(1,1,1,1);
+ sVertexProgram = &gDeferredAvatarShadowProgram;
+ if (sShaderLevel > 0)
+ {
+ gAvatarMatrixParam = sVertexProgram->mUniform[LLViewerShaderMgr::AVATAR_MATRIX];
+ }
+ gGL.setAlphaRejectSettings(LLRender::CF_GREATER_EQUAL, 0.2f);
+
+ glColor4f(1,1,1,1);
- if ((sShaderLevel > 0)) // for hardware blending
+ if ((sShaderLevel > 0)) // for hardware blending
+ {
+ sRenderingSkinned = TRUE;
+ sVertexProgram->bind();
+ enable_vertex_weighting(sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_WEIGHT]);
+ }
+ }
+ else
{
- sRenderingSkinned = TRUE;
+ sVertexProgram = &gDeferredAttachmentShadowProgram;
+ sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
sVertexProgram->bind();
- enable_vertex_weighting(sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_WEIGHT]);
+ LLVertexBuffer::sWeight4Loc = sVertexProgram->getAttribLocation(LLViewerShaderMgr::OBJECT_WEIGHT);
}
-
}
void LLDrawPoolAvatar::endShadowPass(S32 pass)
{
LLFastTimer t(FTM_SHADOW_AVATAR);
- if (sShaderLevel > 0)
+ if (pass == 0)
{
- sRenderingSkinned = FALSE;
+ if (sShaderLevel > 0)
+ {
+ sRenderingSkinned = FALSE;
+ sVertexProgram->unbind();
+ disable_vertex_weighting(sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_WEIGHT]);
+ }
+ }
+ else
+ {
+ LLVertexBuffer::unbind();
sVertexProgram->unbind();
- disable_vertex_weighting(sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_WEIGHT]);
+ LLVertexBuffer::sWeight4Loc = -1;
+ sVertexProgram = NULL;
}
-
- gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
}
void LLDrawPoolAvatar::renderShadow(S32 pass)
@@ -306,26 +429,66 @@ void LLDrawPoolAvatar::renderShadow(S32 pass)
return;
}
- if (sShaderLevel > 0)
+ if (pass == 0)
{
- gAvatarMatrixParam = sVertexProgram->mUniform[LLViewerShaderMgr::AVATAR_MATRIX];
- }
-
- avatarp->renderSkinned(AVATAR_RENDER_PASS_SINGLE);
+ if (sShaderLevel > 0)
+ {
+ gAvatarMatrixParam = sVertexProgram->mUniform[LLViewerShaderMgr::AVATAR_MATRIX];
+ }
+ avatarp->renderSkinned(AVATAR_RENDER_PASS_SINGLE);
+ }
+ else
+ {
+ renderRigged(avatarp, RIGGED_SIMPLE);
+ renderRigged(avatarp, RIGGED_ALPHA);
+ renderRigged(avatarp, RIGGED_FULLBRIGHT);
+ renderRigged(avatarp, RIGGED_FULLBRIGHT_SHINY);
+ renderRigged(avatarp, RIGGED_SHINY);
+ renderRigged(avatarp, RIGGED_FULLBRIGHT_ALPHA);
+ }
}
S32 LLDrawPoolAvatar::getNumPasses()
{
- return LLPipeline::sImpostorRender ? 1 : 3;
+ if (LLPipeline::sImpostorRender)
+ {
+ return 8;
+ }
+ else
+ {
+ return 10;
+ }
+ if (LLPipeline::sImpostorRender)
+ {
+ return 1;
+ }
+ else
+ {
+ return 3;
+ }
+}
+
+
+S32 LLDrawPoolAvatar::getNumDeferredPasses()
+{
+ if (LLPipeline::sImpostorRender)
+ {
+ return 3;
+ }
+ else
+ {
+ return 5;
+ }
}
+
void LLDrawPoolAvatar::render(S32 pass)
{
LLFastTimer t(FTM_RENDER_CHARACTERS);
if (LLPipeline::sImpostorRender)
{
- renderAvatars(NULL, 2);
+ renderAvatars(NULL, pass+2);
return;
}
@@ -338,10 +501,14 @@ void LLDrawPoolAvatar::beginRenderPass(S32 pass)
//reset vertex buffer mappings
LLVertexBuffer::unbind();
+ if (pass == 0)
+ { //make sure no stale colors are left over from a previous render
+ glColor4f(1,1,1,1);
+ }
+
if (LLPipeline::sImpostorRender)
- {
- beginSkinned();
- return;
+ { //impostor render does not have impostors or rigid rendering
+ pass += 2;
}
switch (pass)
@@ -355,6 +522,27 @@ void LLDrawPoolAvatar::beginRenderPass(S32 pass)
case 2:
beginSkinned();
break;
+ case 3:
+ beginRiggedSimple();
+ break;
+ case 4:
+ beginRiggedFullbright();
+ break;
+ case 5:
+ beginRiggedShinySimple();
+ break;
+ case 6:
+ beginRiggedFullbrightShiny();
+ break;
+ case 7:
+ beginRiggedAlpha();
+ break;
+ case 8:
+ beginRiggedFullbrightAlpha();
+ break;
+ case 9:
+ beginRiggedGlow();
+ break;
}
}
@@ -364,8 +552,7 @@ void LLDrawPoolAvatar::endRenderPass(S32 pass)
if (LLPipeline::sImpostorRender)
{
- endSkinned();
- return;
+ pass += 2;
}
switch (pass)
@@ -378,6 +565,28 @@ void LLDrawPoolAvatar::endRenderPass(S32 pass)
break;
case 2:
endSkinned();
+ break;
+ case 3:
+ endRiggedSimple();
+ break;
+ case 4:
+ endRiggedFullbright();
+ break;
+ case 5:
+ endRiggedShinySimple();
+ break;
+ case 6:
+ endRiggedFullbrightShiny();
+ break;
+ case 7:
+ endRiggedAlpha();
+ break;
+ case 8:
+ endRiggedFullbrightAlpha();
+ break;
+ case 9:
+ endRiggedGlow();
+ break;
}
}
@@ -390,7 +599,7 @@ void LLDrawPoolAvatar::beginImpostor()
}
gPipeline.enableLightsFullbright(LLColor4(1,1,1,1));
- diffuse_channel = 0;
+ sDiffuseChannel = 0;
}
void LLDrawPoolAvatar::endImpostor()
@@ -441,9 +650,9 @@ void LLDrawPoolAvatar::beginDeferredImpostor()
sVertexProgram = &gDeferredImpostorProgram;
- normal_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::DEFERRED_NORMAL);
specular_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::SPECULAR_MAP);
- diffuse_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+ normal_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::DEFERRED_NORMAL);
+ sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
sVertexProgram->bind();
}
@@ -563,6 +772,254 @@ void LLDrawPoolAvatar::endSkinned()
gGL.getTexUnit(0)->activate();
}
+void LLDrawPoolAvatar::beginRiggedSimple()
+{
+ if (sShaderLevel > 0)
+ {
+ if (LLPipeline::sUnderWaterRender)
+ {
+ sVertexProgram = &gSkinnedObjectSimpleWaterProgram;
+ }
+ else
+ {
+ sVertexProgram = &gSkinnedObjectSimpleProgram;
+ }
+ }
+ else
+ {
+ if (LLPipeline::sUnderWaterRender)
+ {
+ sVertexProgram = &gObjectSimpleWaterProgram;
+ }
+ else
+ {
+ sVertexProgram = &gObjectSimpleProgram;
+ }
+ }
+
+ if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
+ {
+ sDiffuseChannel = 0;
+ sVertexProgram->bind();
+ LLVertexBuffer::sWeight4Loc = sVertexProgram->getAttribLocation(LLViewerShaderMgr::OBJECT_WEIGHT);
+ }
+}
+
+void LLDrawPoolAvatar::endRiggedSimple()
+{
+ LLVertexBuffer::unbind();
+ if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
+ {
+ sVertexProgram->unbind();
+ sVertexProgram = NULL;
+ LLVertexBuffer::sWeight4Loc = -1;
+ }
+}
+
+void LLDrawPoolAvatar::beginRiggedAlpha()
+{
+ beginRiggedSimple();
+}
+
+void LLDrawPoolAvatar::endRiggedAlpha()
+{
+ endRiggedSimple();
+}
+
+
+void LLDrawPoolAvatar::beginRiggedFullbrightAlpha()
+{
+ beginRiggedFullbright();
+}
+
+void LLDrawPoolAvatar::endRiggedFullbrightAlpha()
+{
+ endRiggedFullbright();
+}
+
+void LLDrawPoolAvatar::beginRiggedGlow()
+{
+ beginRiggedFullbright();
+}
+
+void LLDrawPoolAvatar::endRiggedGlow()
+{
+ endRiggedFullbright();
+}
+
+void LLDrawPoolAvatar::beginRiggedFullbright()
+{
+ if (sShaderLevel > 0)
+ {
+ if (LLPipeline::sUnderWaterRender)
+ {
+ sVertexProgram = &gSkinnedObjectFullbrightWaterProgram;
+ }
+ else
+ {
+ sVertexProgram = &gSkinnedObjectFullbrightProgram;
+ }
+ }
+ else
+ {
+ if (LLPipeline::sUnderWaterRender)
+ {
+ sVertexProgram = &gObjectFullbrightWaterProgram;
+ }
+ else
+ {
+ sVertexProgram = &gObjectFullbrightProgram;
+ }
+ }
+
+ if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
+ {
+ sDiffuseChannel = 0;
+ sVertexProgram->bind();
+ LLVertexBuffer::sWeight4Loc = sVertexProgram->getAttribLocation(LLViewerShaderMgr::OBJECT_WEIGHT);
+ }
+}
+
+void LLDrawPoolAvatar::endRiggedFullbright()
+{
+ LLVertexBuffer::unbind();
+ if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
+ {
+ sVertexProgram->unbind();
+ sVertexProgram = NULL;
+ LLVertexBuffer::sWeight4Loc = -1;
+ }
+}
+
+void LLDrawPoolAvatar::beginRiggedShinySimple()
+{
+ if (sShaderLevel > 0)
+ {
+ if (LLPipeline::sUnderWaterRender)
+ {
+ sVertexProgram = &gSkinnedObjectShinySimpleWaterProgram;
+ }
+ else
+ {
+ sVertexProgram = &gSkinnedObjectShinySimpleProgram;
+ }
+ }
+ else
+ {
+ if (LLPipeline::sUnderWaterRender)
+ {
+ sVertexProgram = &gObjectShinyWaterProgram;
+ }
+ else
+ {
+ sVertexProgram = &gObjectShinyProgram;
+ }
+ }
+
+ if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
+ {
+ sVertexProgram->bind();
+ LLDrawPoolBump::bindCubeMap(sVertexProgram, 2, sDiffuseChannel, cube_channel, false);
+ LLVertexBuffer::sWeight4Loc = sVertexProgram->getAttribLocation(LLViewerShaderMgr::OBJECT_WEIGHT);
+ }
+}
+
+void LLDrawPoolAvatar::endRiggedShinySimple()
+{
+ LLVertexBuffer::unbind();
+ if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
+ {
+ LLDrawPoolBump::unbindCubeMap(sVertexProgram, 2, sDiffuseChannel, cube_channel, false);
+ sVertexProgram->unbind();
+ sVertexProgram = NULL;
+ LLVertexBuffer::sWeight4Loc = -1;
+ }
+}
+
+void LLDrawPoolAvatar::beginRiggedFullbrightShiny()
+{
+ if (sShaderLevel > 0)
+ {
+ if (LLPipeline::sUnderWaterRender)
+ {
+ sVertexProgram = &gSkinnedObjectFullbrightShinyWaterProgram;
+ }
+ else
+ {
+ sVertexProgram = &gSkinnedObjectFullbrightShinyProgram;
+ }
+ }
+ else
+ {
+ if (LLPipeline::sUnderWaterRender)
+ {
+ sVertexProgram = &gObjectFullbrightShinyWaterProgram;
+ }
+ else
+ {
+ sVertexProgram = &gObjectFullbrightShinyProgram;
+ }
+ }
+
+
+ if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
+ {
+ sVertexProgram->bind();
+ LLDrawPoolBump::bindCubeMap(sVertexProgram, 2, sDiffuseChannel, cube_channel, false);
+ LLVertexBuffer::sWeight4Loc = sVertexProgram->getAttribLocation(LLViewerShaderMgr::OBJECT_WEIGHT);
+ }
+}
+
+void LLDrawPoolAvatar::endRiggedFullbrightShiny()
+{
+ LLVertexBuffer::unbind();
+ if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
+ {
+ LLDrawPoolBump::unbindCubeMap(sVertexProgram, 2, sDiffuseChannel, cube_channel, false);
+ sVertexProgram->unbind();
+ sVertexProgram = NULL;
+ LLVertexBuffer::sWeight4Loc = -1;
+ }
+}
+
+
+void LLDrawPoolAvatar::beginDeferredRiggedSimple()
+{
+ sVertexProgram = &gDeferredSkinnedDiffuseProgram;
+ sDiffuseChannel = 0;
+ sVertexProgram->bind();
+ LLVertexBuffer::sWeight4Loc = sVertexProgram->getAttribLocation(LLViewerShaderMgr::OBJECT_WEIGHT);
+}
+
+void LLDrawPoolAvatar::endDeferredRiggedSimple()
+{
+ LLVertexBuffer::unbind();
+ sVertexProgram->unbind();
+ LLVertexBuffer::sWeight4Loc = -1;
+ sVertexProgram = NULL;
+}
+
+void LLDrawPoolAvatar::beginDeferredRiggedBump()
+{
+ sVertexProgram = &gDeferredSkinnedBumpProgram;
+ sVertexProgram->bind();
+ normal_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::BUMP_MAP);
+ sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+ LLVertexBuffer::sWeight4Loc = sVertexProgram->getAttribLocation(LLViewerShaderMgr::OBJECT_WEIGHT);
+}
+
+void LLDrawPoolAvatar::endDeferredRiggedBump()
+{
+ LLVertexBuffer::unbind();
+ sVertexProgram->disableTexture(LLViewerShaderMgr::BUMP_MAP);
+ sVertexProgram->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+ sVertexProgram->unbind();
+ LLVertexBuffer::sWeight4Loc = -1;
+ normal_channel = -1;
+ sDiffuseChannel = 0;
+ sVertexProgram = NULL;
+}
+
void LLDrawPoolAvatar::beginDeferredSkinned()
{
sShaderLevel = mVertexShaderLevel;
@@ -572,6 +1029,7 @@ void LLDrawPoolAvatar::beginDeferredSkinned()
sVertexProgram->bind();
+ sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
enable_vertex_weighting(sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_WEIGHT]);
gGL.getTexUnit(0)->activate();
@@ -584,6 +1042,8 @@ void LLDrawPoolAvatar::endDeferredSkinned()
disable_vertex_weighting(sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_WEIGHT]);
sVertexProgram->unbind();
+ sVertexProgram->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+
sShaderLevel = mVertexShaderLevel;
gGL.getTexUnit(0)->activate();
@@ -668,8 +1128,6 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass)
return;
}
- LLOverrideFaceColor color(this, 1.0f, 1.0f, 1.0f, 1.0f);
-
if (pass == 0)
{
if (!LLPipeline::sReflectionRender)
@@ -679,7 +1137,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass)
if (impostor)
{
- if (LLPipeline::sRenderDeferred && avatarp->mImpostor.isComplete())
+ if (LLPipeline::sRenderDeferred && !LLPipeline::sReflectionRender && avatarp->mImpostor.isComplete())
{
if (normal_channel > -1)
{
@@ -690,7 +1148,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass)
avatarp->mImpostor.bindTexture(1, specular_channel);
}
}
- avatarp->renderImpostor(LLColor4U(255,255,255,255), diffuse_channel);
+ avatarp->renderImpostor(LLColor4U(255,255,255,255), sDiffuseChannel);
}
return;
}
@@ -706,6 +1164,88 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass)
avatarp->renderRigid();
return;
}
+
+ if (pass == 3)
+ {
+ if (is_deferred_render)
+ {
+ renderDeferredRiggedSimple(avatarp);
+ }
+ else
+ {
+ renderRiggedSimple(avatarp);
+ }
+ return;
+ }
+
+ if (pass == 4)
+ {
+ if (is_deferred_render)
+ {
+ renderDeferredRiggedBump(avatarp);
+ }
+ else
+ {
+ renderRiggedFullbright(avatarp);
+ }
+
+ return;
+ }
+
+ if (pass == 5)
+ {
+ renderRiggedShinySimple(avatarp);
+ return;
+ }
+
+ if (pass == 6)
+ {
+ renderRiggedFullbrightShiny(avatarp);
+ return;
+ }
+
+ if (pass >= 7 && pass < 9)
+ {
+ LLGLEnable blend(GL_BLEND);
+
+ gGL.setColorMask(true, true);
+ gGL.blendFunc(LLRender::BF_SOURCE_ALPHA,
+ LLRender::BF_ONE_MINUS_SOURCE_ALPHA,
+ LLRender::BF_ZERO,
+ LLRender::BF_ONE_MINUS_SOURCE_ALPHA);
+
+
+ if (pass == 7)
+ {
+ renderRiggedAlpha(avatarp);
+ return;
+ }
+
+ if (pass == 8)
+ {
+ renderRiggedFullbrightAlpha(avatarp);
+ return;
+ }
+ }
+
+ if (pass == 9)
+ {
+ LLGLEnable blend(GL_BLEND);
+ LLGLDisable test(GL_ALPHA_TEST);
+ gGL.flush();
+
+ LLGLEnable polyOffset(GL_POLYGON_OFFSET_FILL);
+ glPolygonOffset(-1.0f, -1.0f);
+ gGL.setSceneBlendType(LLRender::BT_ADD);
+
+ LLGLDepthTest depth(GL_TRUE, GL_FALSE);
+ gGL.setColorMask(false, true);
+
+ renderRiggedGlow(avatarp);
+ gGL.setColorMask(true, false);
+ gGL.setSceneBlendType(LLRender::BT_ALPHA);
+ return;
+ }
if (sShaderLevel > 0)
{
@@ -743,80 +1283,308 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass)
}
}
-//-----------------------------------------------------------------------------
-// renderForSelect()
-//-----------------------------------------------------------------------------
-void LLDrawPoolAvatar::renderForSelect()
+void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace* face, const LLMeshSkinInfo* skin, LLVolume* volume, const LLVolumeFace& vol_face)
{
-
-
- if (mDrawFace.empty())
+ LLVector4a* weight = vol_face.mWeights;
+ if (!weight)
{
return;
}
- const LLFace *facep = mDrawFace[0];
- if (!facep->getDrawable())
- {
- return;
- }
- LLVOAvatar *avatarp = (LLVOAvatar *)facep->getDrawable()->getVObj().get();
+ LLVertexBuffer* buffer = face->getVertexBuffer();
- if (avatarp->isDead() || avatarp->mIsDummy || avatarp->mDrawable.isNull())
+ U32 data_mask = face->getRiggedVertexBufferDataMask();
+
+ if (!buffer ||
+ buffer->getTypeMask() != data_mask ||
+ buffer->getRequestedVerts() != vol_face.mNumVertices)
{
- return;
+ face->setGeomIndex(0);
+ face->setIndicesIndex(0);
+ face->setSize(vol_face.mNumVertices, vol_face.mNumIndices, true);
+
+
+ if (sShaderLevel > 0)
+ {
+ buffer = new LLVertexBuffer(data_mask, GL_DYNAMIC_DRAW_ARB);
+ }
+ else
+ {
+ buffer = new LLVertexBuffer(data_mask, GL_STREAM_DRAW_ARB);
+ }
+
+ buffer->allocateBuffer(face->getGeomCount(), face->getIndicesCount(), true);
+
+ face->setVertexBuffer(buffer);
+
+ U16 offset = 0;
+
+ LLMatrix4 mat_vert = skin->mBindShapeMatrix;
+ glh::matrix4f m((F32*) mat_vert.mMatrix);
+ m = m.inverse().transpose();
+
+ F32 mat3[] =
+ { m.m[0], m.m[1], m.m[2],
+ m.m[4], m.m[5], m.m[6],
+ m.m[8], m.m[9], m.m[10] };
+
+ LLMatrix3 mat_normal(mat3);
+
+ face->getGeometryVolume(*volume, face->getTEOffset(), mat_vert, mat_normal, offset, true);
}
- S32 curr_shader_level = getVertexShaderLevel();
- S32 name = avatarp->mDrawable->getVObj()->mGLName;
- LLColor4U color((U8)(name >> 16), (U8)(name >> 8), (U8)name);
+ if (sShaderLevel <= 0 && face->mLastSkinTime < avatar->getLastSkinTime())
+ { //perform software vertex skinning for this face
+ LLStrider<LLVector3> position;
+ LLStrider<LLVector3> normal;
- BOOL impostor = avatarp->isImpostor();
- if (impostor)
- {
- gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_VERT_COLOR);
- gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_ALPHA, LLTexUnit::TBS_VERT_ALPHA);
+ bool has_normal = buffer->hasDataType(LLVertexBuffer::TYPE_NORMAL);
+ buffer->getVertexStrider(position);
- avatarp->renderImpostor(color);
+ if (has_normal)
+ {
+ buffer->getNormalStrider(normal);
+ }
- gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
- return;
+ LLVector4a* pos = (LLVector4a*) position.get();
+
+ LLVector4a* norm = has_normal ? (LLVector4a*) normal.get() : NULL;
+
+ //build matrix palette
+ LLMatrix4a mp[64];
+ LLMatrix4* mat = (LLMatrix4*) mp;
+
+ for (U32 j = 0; j < skin->mJointNames.size(); ++j)
+ {
+ LLJoint* joint = avatar->getJoint(skin->mJointNames[j]);
+ if (joint)
+ {
+ mat[j] = skin->mInvBindMatrix[j];
+ mat[j] *= joint->getWorldMatrix();
+ }
+ }
+
+ LLMatrix4a bind_shape_matrix;
+ bind_shape_matrix.loadu(skin->mBindShapeMatrix);
+
+ for (U32 j = 0; j < buffer->getRequestedVerts(); ++j)
+ {
+ LLMatrix4a final_mat;
+ final_mat.clear();
+
+ S32 idx[4];
+
+ LLVector4 wght;
+
+ F32 scale = 0.f;
+ for (U32 k = 0; k < 4; k++)
+ {
+ F32 w = weight[j][k];
+
+ idx[k] = llclamp((S32) floorf(w), 0, 63);
+ wght[k] = w - floorf(w);
+ scale += wght[k];
+ }
+
+ wght *= 1.f/scale;
+
+ for (U32 k = 0; k < 4; k++)
+ {
+ F32 w = wght[k];
+
+ LLMatrix4a src;
+ src.setMul(mp[idx[k]], w);
+
+ final_mat.add(src);
+ }
+
+
+ LLVector4a& v = vol_face.mPositions[j];
+ LLVector4a t;
+ LLVector4a dst;
+ bind_shape_matrix.affineTransform(v, t);
+ final_mat.affineTransform(t, dst);
+ pos[j] = dst;
+
+ if (norm)
+ {
+ LLVector4a& n = vol_face.mNormals[j];
+ bind_shape_matrix.rotate(n, t);
+ final_mat.rotate(t, dst);
+ norm[j] = dst;
+ }
+ }
}
+}
- sVertexProgram = &gAvatarPickProgram;
- if (curr_shader_level > 0)
+void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow)
+{
+ if (avatar->isSelf() && !gAgent.needsRenderAvatar())
{
- gAvatarMatrixParam = sVertexProgram->mUniform[LLViewerShaderMgr::AVATAR_MATRIX];
+ return;
}
- gGL.setAlphaRejectSettings(LLRender::CF_GREATER_EQUAL, 0.2f);
- gGL.setSceneBlendType(LLRender::BT_REPLACE);
- glColor4ubv(color.mV);
+ stop_glerror();
- if (curr_shader_level > 0) // for hardware blending
+ for (U32 i = 0; i < mRiggedFace[type].size(); ++i)
{
- sRenderingSkinned = TRUE;
- sVertexProgram->bind();
- enable_vertex_weighting(sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_WEIGHT]);
+ LLFace* face = mRiggedFace[type][i];
+ LLDrawable* drawable = face->getDrawable();
+ if (!drawable)
+ {
+ continue;
+ }
+
+ LLVOVolume* vobj = drawable->getVOVolume();
+
+ if (!vobj)
+ {
+ continue;
+ }
+
+ LLVolume* volume = vobj->getVolume();
+ S32 te = face->getTEOffset();
+
+ if (!volume || volume->getNumVolumeFaces() <= te)
+ {
+ continue;
+ }
+
+ LLUUID mesh_id = volume->getParams().getSculptID();
+ if (mesh_id.isNull())
+ {
+ continue;
+ }
+
+ const LLMeshSkinInfo* skin = gMeshRepo.getSkinInfo(mesh_id);
+ if (!skin)
+ {
+ continue;
+ }
+
+ stop_glerror();
+
+ const LLVolumeFace& vol_face = volume->getVolumeFace(te);
+ updateRiggedFaceVertexBuffer(avatar, face, skin, volume, vol_face);
+
+ stop_glerror();
+
+ U32 data_mask = LLFace::getRiggedDataMask(type);
+
+ LLVertexBuffer* buff = face->getVertexBuffer();
+
+ if (buff)
+ {
+ if (sShaderLevel > 0)
+ { //upload matrix palette to shader
+ LLMatrix4 mat[64];
+
+ for (U32 i = 0; i < skin->mJointNames.size(); ++i)
+ {
+ LLJoint* joint = avatar->getJoint(skin->mJointNames[i]);
+ if (joint)
+ {
+ mat[i] = skin->mInvBindMatrix[i];
+ mat[i] *= joint->getWorldMatrix();
+ }
+ }
+
+ stop_glerror();
+
+ LLDrawPoolAvatar::sVertexProgram->uniformMatrix4fv("matrixPalette",
+ skin->mJointNames.size(),
+ FALSE,
+ (GLfloat*) mat[0].mMatrix);
+
+ stop_glerror();
+ }
+ else
+ {
+ data_mask &= ~LLVertexBuffer::MAP_WEIGHT4;
+ }
+
+ buff->setBuffer(data_mask);
+
+ U16 start = face->getGeomStart();
+ U16 end = start + face->getGeomCount()-1;
+ S32 offset = face->getIndicesStart();
+ U32 count = face->getIndicesCount();
+
+ if (glow)
+ {
+ glColor4f(0,0,0,face->getTextureEntry()->getGlow());
+ }
+
+ gGL.getTexUnit(sDiffuseChannel)->bind(face->getTexture());
+ if (normal_channel > -1)
+ {
+ LLDrawPoolBump::bindBumpMap(face, normal_channel);
+ }
+
+ if (face->mTextureMatrix)
+ {
+ glMatrixMode(GL_TEXTURE);
+ glLoadMatrixf((F32*) face->mTextureMatrix->mMatrix);
+ buff->drawRange(LLRender::TRIANGLES, start, end, count, offset);
+ glLoadIdentity();
+ glMatrixMode(GL_MODELVIEW);
+ }
+ else
+ {
+ buff->drawRange(LLRender::TRIANGLES, start, end, count, offset);
+ }
+ }
}
+}
+
+void LLDrawPoolAvatar::renderDeferredRiggedSimple(LLVOAvatar* avatar)
+{
+ renderRigged(avatar, RIGGED_DEFERRED_SIMPLE);
+}
+
+void LLDrawPoolAvatar::renderDeferredRiggedBump(LLVOAvatar* avatar)
+{
+ renderRigged(avatar, RIGGED_DEFERRED_BUMP);
+}
+
+void LLDrawPoolAvatar::renderRiggedSimple(LLVOAvatar* avatar)
+{
+ renderRigged(avatar, RIGGED_SIMPLE);
+}
+
+void LLDrawPoolAvatar::renderRiggedFullbright(LLVOAvatar* avatar)
+{
+ renderRigged(avatar, RIGGED_FULLBRIGHT);
+}
+
- avatarp->renderSkinned(AVATAR_RENDER_PASS_SINGLE);
+void LLDrawPoolAvatar::renderRiggedShinySimple(LLVOAvatar* avatar)
+{
+ renderRigged(avatar, RIGGED_SHINY);
+}
- // if we're in software-blending, remember to set the fence _after_ we draw so we wait till this rendering is done
- if (curr_shader_level > 0)
- {
- sRenderingSkinned = FALSE;
- sVertexProgram->unbind();
- disable_vertex_weighting(sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_WEIGHT]);
- }
+void LLDrawPoolAvatar::renderRiggedFullbrightShiny(LLVOAvatar* avatar)
+{
+ renderRigged(avatar, RIGGED_FULLBRIGHT_SHINY);
+}
- gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
- gGL.setSceneBlendType(LLRender::BT_ALPHA);
+void LLDrawPoolAvatar::renderRiggedAlpha(LLVOAvatar* avatar)
+{
+ renderRigged(avatar, RIGGED_ALPHA);
+}
- // restore texture mode
- gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
+void LLDrawPoolAvatar::renderRiggedFullbrightAlpha(LLVOAvatar* avatar)
+{
+ renderRigged(avatar, RIGGED_FULLBRIGHT_ALPHA);
+}
+
+void LLDrawPoolAvatar::renderRiggedGlow(LLVOAvatar* avatar)
+{
+ renderRigged(avatar, RIGGED_GLOW, true);
}
+
+
//-----------------------------------------------------------------------------
// getDebugTexture()
//-----------------------------------------------------------------------------
@@ -843,6 +1611,50 @@ LLColor3 LLDrawPoolAvatar::getDebugColor() const
return LLColor3(0.f, 1.f, 0.f);
}
+void LLDrawPoolAvatar::addRiggedFace(LLFace* facep, U32 type)
+{
+ if (type >= NUM_RIGGED_PASSES)
+ {
+ llerrs << "Invalid rigged face type." << llendl;
+ }
+
+ if (facep->getRiggedIndex(type) != -1)
+ {
+ llerrs << "Tried to add a rigged face that's referenced elsewhere." << llendl;
+ }
+
+ facep->setRiggedIndex(type, mRiggedFace[type].size());
+ facep->setPool(this);
+ mRiggedFace[type].push_back(facep);
+}
+
+void LLDrawPoolAvatar::removeRiggedFace(LLFace* facep)
+{
+ facep->setPool(NULL);
+
+ for (U32 i = 0; i < NUM_RIGGED_PASSES; ++i)
+ {
+ S32 index = facep->getRiggedIndex(i);
+
+ if (index > -1)
+ {
+ if (mRiggedFace[i].size() > index && mRiggedFace[i][index] == facep)
+ {
+ facep->setRiggedIndex(i,-1);
+ mRiggedFace[i].erase(mRiggedFace[i].begin()+index);
+ for (U32 j = index; j < mRiggedFace[i].size(); ++j)
+ { //bump indexes down for faces referenced after erased face
+ mRiggedFace[i][j]->setRiggedIndex(i, j);
+ }
+ }
+ else
+ {
+ llerrs << "Face reference data corrupt for rigged type " << i << llendl;
+ }
+ }
+ }
+}
+
LLVertexBufferAvatar::LLVertexBufferAvatar()
: LLVertexBuffer(sDataMask,
GL_STREAM_DRAW_ARB) //avatars are always stream draw due to morph targets
@@ -855,22 +1667,25 @@ void LLVertexBufferAvatar::setupVertexBuffer(U32 data_mask) const
{
if (sRenderingSkinned)
{
- U8* base = useVBOs() ? NULL : mMappedData;
+ U8* base = useVBOs() ? (U8*) mAlignedOffset : mMappedData;
- glVertexPointer(3,GL_FLOAT, mStride, (void*)(base + 0));
- glNormalPointer(GL_FLOAT, mStride, (void*)(base + mOffsets[TYPE_NORMAL]));
- glTexCoordPointer(2,GL_FLOAT, mStride, (void*)(base + mOffsets[TYPE_TEXCOORD0]));
+ glVertexPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_VERTEX], (void*)(base + 0));
+ glNormalPointer(GL_FLOAT, LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_NORMAL], (void*)(base + mOffsets[TYPE_NORMAL]));
+ glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_TEXCOORD0], (void*)(base + mOffsets[TYPE_TEXCOORD0]));
- set_vertex_weights(sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_WEIGHT], mStride, (F32*)(base + mOffsets[TYPE_WEIGHT]));
+ set_vertex_weights(LLDrawPoolAvatar::sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_WEIGHT],
+ LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_WEIGHT], (F32*)(base + mOffsets[TYPE_WEIGHT]));
if (sShaderLevel >= LLDrawPoolAvatar::SHADER_LEVEL_BUMP)
{
- set_binormals(sVertexProgram->mAttribute[LLViewerShaderMgr::BINORMAL], mStride, (LLVector3*)(base + mOffsets[TYPE_BINORMAL]));
+ set_binormals(LLDrawPoolAvatar::sVertexProgram->mAttribute[LLViewerShaderMgr::BINORMAL],
+ LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_BINORMAL], (LLVector3*)(base + mOffsets[TYPE_BINORMAL]));
}
if (sShaderLevel >= LLDrawPoolAvatar::SHADER_LEVEL_CLOTH)
{
- set_vertex_clothing_weights(sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_CLOTHING], mStride, (LLVector4*)(base + mOffsets[TYPE_CLOTHWEIGHT]));
+ set_vertex_clothing_weights(LLDrawPoolAvatar::sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_CLOTHING],
+ LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_CLOTHWEIGHT], (LLVector4*)(base + mOffsets[TYPE_CLOTHWEIGHT]));
}
}
else
diff --git a/indra/newview/lldrawpoolavatar.h b/indra/newview/lldrawpoolavatar.h
index c46fed824e..fcd8294af5 100644
--- a/indra/newview/lldrawpoolavatar.h
+++ b/indra/newview/lldrawpoolavatar.h
@@ -1,4 +1,4 @@
-/**
+ /**
* @file lldrawpoolavatar.h
* @brief LLDrawPoolAvatar class definition
*
@@ -30,6 +30,12 @@
#include "lldrawpool.h"
class LLVOAvatar;
+class LLGLSLShader;
+class LLFace;
+class LLMeshSkinInfo;
+class LLVolume;
+class LLVolumeFace;
+
class LLDrawPoolAvatar : public LLFacePool
{
@@ -64,7 +70,6 @@ public:
/*virtual*/ void endRenderPass(S32 pass);
/*virtual*/ void prerender();
/*virtual*/ void render(S32 pass = 0);
- /*virtual*/ void renderForSelect();
/*virtual*/ S32 getNumDeferredPasses();
/*virtual*/ void beginDeferredPass(S32 pass);
@@ -84,7 +89,7 @@ public:
void beginRigid();
void beginImpostor();
void beginSkinned();
-
+
void endRigid();
void endImpostor();
void endSkinned();
@@ -96,14 +101,113 @@ public:
void endDeferredImpostor();
void endDeferredRigid();
void endDeferredSkinned();
+
+ void beginPostDeferredAlpha();
+ void endPostDeferredAlpha();
+
+ void beginRiggedSimple();
+ void beginRiggedFullbright();
+ void beginRiggedFullbrightShiny();
+ void beginRiggedShinySimple();
+ void beginRiggedAlpha();
+ void beginRiggedFullbrightAlpha();
+ void beginRiggedGlow();
+ void beginDeferredRiggedAlpha();
+
+ void endRiggedSimple();
+ void endRiggedFullbright();
+ void endRiggedFullbrightShiny();
+ void endRiggedShinySimple();
+ void endRiggedAlpha();
+ void endRiggedFullbrightAlpha();
+ void endRiggedGlow();
+ void endDeferredRiggedAlpha();
+
+ void beginDeferredRiggedSimple();
+ void beginDeferredRiggedBump();
+
+ void endDeferredRiggedSimple();
+ void endDeferredRiggedBump();
+ void updateRiggedFaceVertexBuffer(LLVOAvatar* avatar,
+ LLFace* facep,
+ const LLMeshSkinInfo* skin,
+ LLVolume* volume,
+ const LLVolumeFace& vol_face);
+
+ void renderRigged(LLVOAvatar* avatar, U32 type, bool glow = false);
+ void renderRiggedSimple(LLVOAvatar* avatar);
+ void renderRiggedAlpha(LLVOAvatar* avatar);
+ void renderRiggedFullbrightAlpha(LLVOAvatar* avatar);
+ void renderRiggedFullbright(LLVOAvatar* avatar);
+ void renderRiggedShinySimple(LLVOAvatar* avatar);
+ void renderRiggedFullbrightShiny(LLVOAvatar* avatar);
+ void renderRiggedGlow(LLVOAvatar* avatar);
+ void renderDeferredRiggedSimple(LLVOAvatar* avatar);
+ void renderDeferredRiggedBump(LLVOAvatar* avatar);
+
+ typedef enum
+ {
+ RIGGED_SIMPLE = 0,
+ RIGGED_FULLBRIGHT,
+ RIGGED_SHINY,
+ RIGGED_FULLBRIGHT_SHINY,
+ RIGGED_GLOW,
+ RIGGED_ALPHA,
+ RIGGED_FULLBRIGHT_ALPHA,
+ RIGGED_DEFERRED_BUMP,
+ RIGGED_DEFERRED_SIMPLE,
+ NUM_RIGGED_PASSES,
+ RIGGED_UNKNOWN,
+ } eRiggedPass;
+
+ typedef enum
+ {
+ RIGGED_SIMPLE_MASK = LLVertexBuffer::MAP_VERTEX |
+ LLVertexBuffer::MAP_NORMAL |
+ LLVertexBuffer::MAP_TEXCOORD0 |
+ LLVertexBuffer::MAP_COLOR |
+ LLVertexBuffer::MAP_WEIGHT4,
+ RIGGED_FULLBRIGHT_MASK = LLVertexBuffer::MAP_VERTEX |
+ LLVertexBuffer::MAP_TEXCOORD0 |
+ LLVertexBuffer::MAP_COLOR |
+ LLVertexBuffer::MAP_WEIGHT4,
+ RIGGED_SHINY_MASK = RIGGED_SIMPLE_MASK,
+ RIGGED_FULLBRIGHT_SHINY_MASK = RIGGED_SIMPLE_MASK,
+ RIGGED_GLOW_MASK = LLVertexBuffer::MAP_VERTEX |
+ LLVertexBuffer::MAP_TEXCOORD0 |
+ LLVertexBuffer::MAP_WEIGHT4,
+ RIGGED_ALPHA_MASK = RIGGED_SIMPLE_MASK,
+ RIGGED_FULLBRIGHT_ALPHA_MASK = RIGGED_FULLBRIGHT_MASK,
+ RIGGED_DEFERRED_BUMP_MASK = LLVertexBuffer::MAP_VERTEX |
+ LLVertexBuffer::MAP_NORMAL |
+ LLVertexBuffer::MAP_TEXCOORD0 |
+ LLVertexBuffer::MAP_BINORMAL |
+ LLVertexBuffer::MAP_COLOR |
+ LLVertexBuffer::MAP_WEIGHT4,
+ RIGGED_DEFERRED_SIMPLE_MASK = LLVertexBuffer::MAP_VERTEX |
+ LLVertexBuffer::MAP_NORMAL |
+ LLVertexBuffer::MAP_TEXCOORD0 |
+ LLVertexBuffer::MAP_COLOR |
+ LLVertexBuffer::MAP_WEIGHT4,
+ } eRiggedDataMask;
+
+ void addRiggedFace(LLFace* facep, U32 type);
+ void removeRiggedFace(LLFace* facep);
+
+ std::vector<LLFace*> mRiggedFace[NUM_RIGGED_PASSES];
+
/*virtual*/ LLViewerTexture *getDebugTexture();
/*virtual*/ LLColor3 getDebugColor() const; // For AGP debug display
void renderAvatars(LLVOAvatar *single_avatar, S32 pass = -1); // renders only one avatar if single_avatar is not null.
+
static BOOL sSkipOpaque;
static BOOL sSkipTransparent;
+ static S32 sDiffuseChannel;
+
+ static LLGLSLShader* sVertexProgram;
};
class LLVertexBufferAvatar : public LLVertexBuffer
diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp
index 223e4a438c..29b50761d8 100644
--- a/indra/newview/lldrawpoolbump.cpp
+++ b/indra/newview/lldrawpoolbump.cpp
@@ -145,12 +145,7 @@ void LLStandardBumpmap::addstandard()
// llinfos << "Loading bumpmap: " << bump_image_id << " from viewerart" << llendl;
gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mLabel = label;
gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mImage =
- LLViewerTextureManager::getFetchedTexture(LLUUID(bump_image_id),
- TRUE,
- LLViewerTexture::BOOST_NONE,
- LLViewerTexture::LOD_TEXTURE,
- 0,
- 0);
+ LLViewerTextureManager::getFetchedTexture(LLUUID(bump_image_id));
gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mImage->setBoostLevel(LLViewerTexture::BOOST_BUMP) ;
gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mImage->setLoadedCallback(LLBumpImageList::onSourceStandardLoaded, 0, TRUE, FALSE, NULL, NULL );
LLStandardBumpmap::sStandardBumpmapCount++;
@@ -334,30 +329,43 @@ void LLDrawPoolBump::beginShiny(bool invisible)
sVertexMask = VERTEX_MASK_SHINY | LLVertexBuffer::MAP_TEXCOORD0;
}
- if (LLPipeline::sUnderWaterRender)
+ if (getVertexShaderLevel() > 0)
{
- shader = &gObjectShinyWaterProgram;
+ if (LLPipeline::sUnderWaterRender)
+ {
+ shader = &gObjectShinyWaterProgram;
+ }
+ else
+ {
+ shader = &gObjectShinyProgram;
+ }
+ shader->bind();
}
else
{
- shader = &gObjectShinyProgram;
+ shader = NULL;
}
+ bindCubeMap(shader, mVertexShaderLevel, diffuse_channel, cube_channel, invisible);
+}
+
+//static
+void LLDrawPoolBump::bindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel, bool invisible)
+{
LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
if( cube_map )
{
- if (!invisible && LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 0 )
+ if (!invisible && shader )
{
LLMatrix4 mat;
mat.initRows(LLVector4(gGLModelView+0),
LLVector4(gGLModelView+4),
LLVector4(gGLModelView+8),
LLVector4(gGLModelView+12));
- shader->bind();
LLVector3 vec = LLVector3(gShinyOrigin) * mat;
LLVector4 vec4(vec, gShinyOrigin.mV[3]);
shader->uniform4fv(LLViewerShaderMgr::SHINY_ORIGIN, 1, vec4.mV);
- if (mVertexShaderLevel > 1)
+ if (shader_level > 1)
{
cube_map->setMatrix(1);
// Make sure that texture coord generation happens for tex unit 1, as that's the one we use for
@@ -419,22 +427,16 @@ void LLDrawPoolBump::renderShiny(bool invisible)
}
}
-void LLDrawPoolBump::endShiny(bool invisible)
+//static
+void LLDrawPoolBump::unbindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel, bool invisible)
{
- LLFastTimer t(FTM_RENDER_SHINY);
- if ((!invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_SHINY))||
- (invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY)))
- {
- return;
- }
-
LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
if( cube_map )
{
cube_map->disable();
cube_map->restoreMatrix();
- if (!invisible && mVertexShaderLevel > 1)
+ if (!invisible && shader_level > 1)
{
shader->disableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP);
@@ -445,7 +447,6 @@ void LLDrawPoolBump::endShiny(bool invisible)
shader->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
}
}
- shader->unbind();
}
}
gGL.getTexUnit(diffuse_channel)->disable();
@@ -453,6 +454,22 @@ void LLDrawPoolBump::endShiny(bool invisible)
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
+}
+
+void LLDrawPoolBump::endShiny(bool invisible)
+{
+ LLFastTimer t(FTM_RENDER_SHINY);
+ if ((!invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_SHINY))||
+ (invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY)))
+ {
+ return;
+ }
+
+ unbindCubeMap(shader, mVertexShaderLevel, diffuse_channel, cube_channel, invisible);
+ if (shader)
+ {
+ shader->unbind();
+ }
diffuse_channel = -1;
cube_channel = 0;
@@ -473,7 +490,7 @@ void LLDrawPoolBump::beginFullbrightShiny()
if (LLPipeline::sUnderWaterRender)
{
- shader = &gObjectShinyWaterProgram;
+ shader = &gObjectFullbrightShinyWaterProgram;
}
else
{
@@ -580,18 +597,37 @@ void LLDrawPoolBump::renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL
// static
BOOL LLDrawPoolBump::bindBumpMap(LLDrawInfo& params, S32 channel)
{
- LLViewerTexture* bump = NULL;
-
U8 bump_code = params.mBump;
+ return bindBumpMap(bump_code, params.mTexture, params.mVSize, channel);
+}
+
+//static
+BOOL LLDrawPoolBump::bindBumpMap(LLFace* face, S32 channel)
+{
+ const LLTextureEntry* te = face->getTextureEntry();
+ if (te)
+ {
+ U8 bump_code = te->getBumpmap();
+ return bindBumpMap(bump_code, face->getTexture(), face->getVirtualSize(), channel);
+ }
+
+ return FALSE;
+}
+
+//static
+BOOL LLDrawPoolBump::bindBumpMap(U8 bump_code, LLViewerTexture* texture, F32 vsize, S32 channel)
+{
//Note: texture atlas does not support bump texture now.
- LLViewerFetchedTexture* tex = LLViewerTextureManager::staticCastToFetchedTexture(params.mTexture) ;
+ LLViewerFetchedTexture* tex = LLViewerTextureManager::staticCastToFetchedTexture(texture) ;
if(!tex)
{
//if the texture is not a fetched texture
return FALSE;
}
+ LLViewerTexture* bump = NULL;
+
switch( bump_code )
{
case BE_NO_BUMP:
@@ -605,7 +641,7 @@ BOOL LLDrawPoolBump::bindBumpMap(LLDrawInfo& params, S32 channel)
if( bump_code < LLStandardBumpmap::sStandardBumpmapCount )
{
bump = gStandardBumpmapList[bump_code].mImage;
- gBumpImageList.addTextureStats(bump_code, tex->getID(), params.mVSize);
+ gBumpImageList.addTextureStats(bump_code, tex->getID(), vsize);
}
break;
}
@@ -624,7 +660,7 @@ BOOL LLDrawPoolBump::bindBumpMap(LLDrawInfo& params, S32 channel)
return TRUE;
}
-
+
return FALSE;
}
@@ -853,6 +889,11 @@ void LLBumpImageList::destroyGL()
void LLBumpImageList::restoreGL()
{
+ if(!gTextureList.isInitialized())
+ {
+ return ;
+ }
+
LLStandardBumpmap::restoreGL();
// Images will be recreated as they are needed.
}
@@ -964,25 +1005,28 @@ LLViewerTexture* LLBumpImageList::getBrightnessDarknessImage(LLViewerFetchedText
}
bump_image_map_t::iterator iter = entries_list->find(src_image->getID());
- if (iter != entries_list->end())
+ if (iter != entries_list->end() && iter->second.notNull())
{
bump = iter->second;
}
else
{
LLPointer<LLImageRaw> raw = new LLImageRaw(1,1,1);
- raw->clear(0x77, 0x77, 0x77, 0xFF);
+ raw->clear(0x77, 0x77, 0xFF, 0xFF);
(*entries_list)[src_image->getID()] = LLViewerTextureManager::getLocalTexture( raw.get(), TRUE);
- (*entries_list)[src_image->getID()]->setExplicitFormat(GL_ALPHA8, GL_ALPHA);
-
- // Note: this may create an LLImageGL immediately
- src_image->setBoostLevel(LLViewerTexture::BOOST_BUMP) ;
- src_image->setLoadedCallback( callback_func, 0, TRUE, FALSE, new LLUUID(src_image->getID()), NULL );
bump = (*entries_list)[src_image->getID()]; // In case callback was called immediately and replaced the image
+ }
-// bump_total++;
-// llinfos << "*** Creating " << (void*)bump << " " << bump_total << llendl;
+ if (!src_image->hasCallbacks())
+ { //if image has no callbacks but resolutions don't match, trigger raw image loaded callback again
+ if (src_image->getWidth() != bump->getWidth() ||
+ src_image->getHeight() != bump->getHeight() ||
+ (LLPipeline::sRenderDeferred && bump->getComponents() != 4))
+ {
+ src_image->setBoostLevel(LLViewerTexture::BOOST_BUMP) ;
+ src_image->setLoadedCallback( callback_func, 0, TRUE, FALSE, new LLUUID(src_image->getID()), NULL );
+ }
}
}
@@ -1085,7 +1129,21 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI
{
bump_image_map_t& entries_list(bump_code == BE_BRIGHTNESS ? gBumpImageList.mBrightnessEntries : gBumpImageList.mDarknessEntries );
bump_image_map_t::iterator iter = entries_list.find(source_asset_id);
- if (iter != entries_list.end()) // bump not cached yet
+
+ if (iter == entries_list.end() ||
+ iter->second.isNull() ||
+ iter->second->getWidth() != src->getWidth() ||
+ iter->second->getHeight() != src->getHeight()) // bump not cached yet or has changed resolution
+ { //make sure an entry exists for this image
+ LLPointer<LLImageRaw> raw = new LLImageRaw(1,1,1);
+ raw->clear(0x77, 0x77, 0xFF, 0xFF);
+
+ entries_list[src_vi->getID()] = LLViewerTextureManager::getLocalTexture( raw.get(), TRUE);
+ iter = entries_list.find(src_vi->getID());
+ }
+
+ //if (iter->second->getWidth() != src->getWidth() ||
+ // iter->second->getHeight() != src->getHeight()) // bump not cached yet or has changed resolution
{
LLPointer<LLImageRaw> dst_image = new LLImageRaw(src->getWidth(), src->getHeight(), 1);
U8* dst_data = dst_image->getData();
@@ -1211,18 +1269,10 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI
bump->setExplicitFormat(GL_RGBA, GL_RGBA);
bump->createGLTexture(0, nrm_image);
}
-
-
+
iter->second = bump; // derefs (and deletes) old image
//---------------------------------------------------
}
- else
- {
- // entry should have been added in LLBumpImageList::getImage().
-
- // Not a legit assertion - the bump texture could have been flushed by the bump image manager
- //llassert(0);
- }
}
}
diff --git a/indra/newview/lldrawpoolbump.h b/indra/newview/lldrawpoolbump.h
index 65a813ab94..f4702bf61d 100644
--- a/indra/newview/lldrawpoolbump.h
+++ b/indra/newview/lldrawpoolbump.h
@@ -35,6 +35,7 @@
class LLImageRaw;
class LLSpatialGroup;
class LLDrawInfo;
+class LLGLSLShader;
class LLViewerFetchedTexture;
class LLDrawPoolBump : public LLRenderPass
@@ -73,6 +74,9 @@ public:
void renderBump(U32 pass = LLRenderPass::PASS_BUMP);
void endBump(U32 pass = LLRenderPass::PASS_BUMP);
+ static void bindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel, bool invisible);
+ static void unbindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel, bool invisible);
+
virtual S32 getNumDeferredPasses();
/*virtual*/ void beginDeferredPass(S32 pass);
/*virtual*/ void endDeferredPass(S32 pass);
@@ -83,7 +87,12 @@ public:
/*virtual*/ void endPostDeferredPass(S32 pass);
/*virtual*/ void renderPostDeferred(S32 pass);
- BOOL bindBumpMap(LLDrawInfo& params, S32 channel = -2);
+ static BOOL bindBumpMap(LLDrawInfo& params, S32 channel = -2);
+ static BOOL bindBumpMap(LLFace* face, S32 channel = -2);
+
+private:
+ static BOOL bindBumpMap(U8 bump_code, LLViewerTexture* tex, F32 vsize, S32 channel);
+
};
enum EBumpEffect
diff --git a/indra/newview/lldrawpoolclouds.cpp b/indra/newview/lldrawpoolclouds.cpp
index f7da144671..5db1d8cfed 100644
--- a/indra/newview/lldrawpoolclouds.cpp
+++ b/indra/newview/lldrawpoolclouds.cpp
@@ -95,6 +95,3 @@ void LLDrawPoolClouds::render(S32 pass)
}
-void LLDrawPoolClouds::renderForSelect()
-{
-}
diff --git a/indra/newview/lldrawpoolclouds.h b/indra/newview/lldrawpoolclouds.h
index 548720ed9c..019f11a795 100644
--- a/indra/newview/lldrawpoolclouds.h
+++ b/indra/newview/lldrawpoolclouds.h
@@ -49,7 +49,6 @@ public:
/*virtual*/ void enqueue(LLFace *face);
/*virtual*/ void beginRenderPass(S32 pass);
/*virtual*/ void render(S32 pass = 0);
- /*virtual*/ void renderForSelect();
};
#endif // LL_LLDRAWPOOLSKY_H
diff --git a/indra/newview/lldrawpoolground.cpp b/indra/newview/lldrawpoolground.cpp
index e950fbfa82..ce07e62122 100644
--- a/indra/newview/lldrawpoolground.cpp
+++ b/indra/newview/lldrawpoolground.cpp
@@ -68,7 +68,7 @@ void LLDrawPoolGround::render(S32 pass)
LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
- LLGLClampToFarClip far_clip(glh_get_current_projection());
+ LLGLSquashToFarClip far_clip(glh_get_current_projection());
F32 water_height = gAgent.getRegion()->getWaterHeight();
glPushMatrix();
@@ -85,7 +85,3 @@ void LLDrawPoolGround::render(S32 pass)
glPopMatrix();
}
-void LLDrawPoolGround::renderForSelect()
-{
-}
-
diff --git a/indra/newview/lldrawpoolground.h b/indra/newview/lldrawpoolground.h
index c6c7cbf964..a4f8a3fcf5 100644
--- a/indra/newview/lldrawpoolground.h
+++ b/indra/newview/lldrawpoolground.h
@@ -47,7 +47,6 @@ public:
/*virtual*/ void prerender();
/*virtual*/ void render(S32 pass = 0);
- /*virtual*/ void renderForSelect();
};
#endif // LL_LLDRAWPOOLGROUND_H
diff --git a/indra/newview/lldrawpoolsky.cpp b/indra/newview/lldrawpoolsky.cpp
index d811ab8c54..030d6e1110 100644
--- a/indra/newview/lldrawpoolsky.cpp
+++ b/indra/newview/lldrawpoolsky.cpp
@@ -63,6 +63,8 @@ void LLDrawPoolSky::prerender()
void LLDrawPoolSky::render(S32 pass)
{
+ gGL.flush();
+
if (mDrawFace.empty())
{
return;
@@ -97,7 +99,7 @@ void LLDrawPoolSky::render(S32 pass)
LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
- LLGLClampToFarClip far_clip(glh_get_current_projection());
+ LLGLSquashToFarClip far_clip(glh_get_current_projection());
LLGLEnable fog_enable( (mVertexShaderLevel < 1 && LLViewerCamera::getInstance()->cameraUnderWater()) ? GL_FOG : 0);
@@ -111,13 +113,14 @@ void LLDrawPoolSky::render(S32 pass)
S32 face_count = (S32)mDrawFace.size();
+ LLVertexBuffer::unbind();
+ glColor4f(1,1,1,1);
+
for (S32 i = 0; i < llmin(6, face_count); ++i)
{
renderSkyCubeFace(i);
}
- LLGLEnable blend(GL_BLEND);
-
glPopMatrix();
}
@@ -143,10 +146,6 @@ void LLDrawPoolSky::renderSkyCubeFace(U8 side)
}
}
-void LLDrawPoolSky::renderForSelect()
-{
-}
-
void LLDrawPoolSky::endRenderPass( S32 pass )
{
}
diff --git a/indra/newview/lldrawpoolsky.h b/indra/newview/lldrawpoolsky.h
index 15d643c886..098bd2134a 100644
--- a/indra/newview/lldrawpoolsky.h
+++ b/indra/newview/lldrawpoolsky.h
@@ -58,7 +58,6 @@ public:
/*virtual*/ void prerender();
/*virtual*/ void render(S32 pass = 0);
- /*virtual*/ void renderForSelect();
/*virtual*/ void endRenderPass(S32 pass);
void setSkyTex(LLSkyTex* const st) { mSkyTex = st; }
diff --git a/indra/newview/lldrawpoolterrain.cpp b/indra/newview/lldrawpoolterrain.cpp
index 3dede9d8fc..84eeace9c6 100644
--- a/indra/newview/lldrawpoolterrain.cpp
+++ b/indra/newview/lldrawpoolterrain.cpp
@@ -899,27 +899,6 @@ void LLDrawPoolTerrain::renderOwnership()
}
-void LLDrawPoolTerrain::renderForSelect()
-{
- if (mDrawFace.empty())
- {
- return;
- }
-
-
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-
- for (std::vector<LLFace*>::iterator iter = mDrawFace.begin();
- iter != mDrawFace.end(); iter++)
- {
- LLFace *facep = *iter;
- if (!facep->getDrawable()->isDead() && (facep->getDrawable()->getVObj()->mGLName))
- {
- facep->renderForSelect(LLVertexBuffer::MAP_VERTEX);
- }
- }
-}
-
void LLDrawPoolTerrain::dirtyTextures(const std::set<LLViewerFetchedTexture*>& textures)
{
LLViewerFetchedTexture* tex = LLViewerTextureManager::staticCastToFetchedTexture(mTexturep) ;
diff --git a/indra/newview/lldrawpoolterrain.h b/indra/newview/lldrawpoolterrain.h
index 730298609d..3056da44d5 100644
--- a/indra/newview/lldrawpoolterrain.h
+++ b/indra/newview/lldrawpoolterrain.h
@@ -66,7 +66,6 @@ public:
/*virtual*/ void prerender();
/*virtual*/ void beginRenderPass( S32 pass );
/*virtual*/ void endRenderPass( S32 pass );
- /*virtual*/ void renderForSelect();
/*virtual*/ void dirtyTextures(const std::set<LLViewerFetchedTexture*>& textures);
/*virtual*/ LLViewerTexture *getTexture();
/*virtual*/ LLViewerTexture *getDebugTexture();
diff --git a/indra/newview/lldrawpooltree.cpp b/indra/newview/lldrawpooltree.cpp
index 09cca8b73c..195ee60a2e 100644
--- a/indra/newview/lldrawpooltree.cpp
+++ b/indra/newview/lldrawpooltree.cpp
@@ -107,11 +107,12 @@ void LLDrawPoolTree::render(S32 pass)
iter != mDrawFace.end(); iter++)
{
LLFace *face = *iter;
- if(face->mVertexBuffer.notNull())
+ LLVertexBuffer* buff = face->getVertexBuffer();
+ if(buff)
{
- face->mVertexBuffer->setBuffer(LLDrawPoolTree::VERTEX_DATA_MASK);
- face->mVertexBuffer->drawRange(LLRender::TRIANGLES, 0, face->mVertexBuffer->getRequestedVerts()-1, face->mVertexBuffer->getRequestedIndices(), 0);
- gPipeline.addTrianglesDrawn(face->mVertexBuffer->getRequestedIndices());
+ buff->setBuffer(LLDrawPoolTree::VERTEX_DATA_MASK);
+ buff->drawRange(LLRender::TRIANGLES, 0, buff->getRequestedVerts()-1, buff->getRequestedIndices(), 0);
+ gPipeline.addTrianglesDrawn(buff->getRequestedIndices());
}
}
}
@@ -183,68 +184,6 @@ void LLDrawPoolTree::endShadowPass(S32 pass)
}
-void LLDrawPoolTree::renderForSelect()
-{
- if (mDrawFace.empty())
- {
- return;
- }
-
- LLOverrideFaceColor color(this, 1.f, 1.f, 1.f, 1.f);
-
- LLGLSObjectSelectAlpha gls_alpha;
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-
- gGL.setSceneBlendType(LLRender::BT_REPLACE);
- gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f);
-
- gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_COLOR);
- gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_ALPHA, LLTexUnit::TBS_VERT_ALPHA);
-
- if (gSavedSettings.getBOOL("RenderAnimateTrees"))
- {
- renderTree(TRUE);
- }
- else
- {
- gGL.getTexUnit(sDiffTex)->bind(mTexturep);
-
- for (std::vector<LLFace*>::iterator iter = mDrawFace.begin();
- iter != mDrawFace.end(); iter++)
- {
- LLFace *face = *iter;
- LLDrawable *drawablep = face->getDrawable();
-
- if (drawablep->isDead() || face->mVertexBuffer.isNull())
- {
- continue;
- }
-
- // Render each of the trees
- LLVOTree *treep = (LLVOTree *)drawablep->getVObj().get();
-
- LLColor4U color(255,255,255,255);
-
- if (treep->mGLName != 0)
- {
- S32 name = treep->mGLName;
- color = LLColor4U((U8)(name >> 16), (U8)(name >> 8), (U8)name, 255);
-
- LLFacePool::LLOverrideFaceColor col(this, color);
-
- face->mVertexBuffer->setBuffer(LLDrawPoolTree::VERTEX_DATA_MASK);
- face->mVertexBuffer->drawRange(LLRender::TRIANGLES, 0, face->mVertexBuffer->getRequestedVerts()-1, face->mVertexBuffer->getRequestedIndices(), 0);
- gPipeline.addTrianglesDrawn(face->mVertexBuffer->getRequestedIndices());
- }
- }
- }
-
- gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
- gGL.setSceneBlendType(LLRender::BT_ALPHA);
-
- gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
-}
-
void LLDrawPoolTree::renderTree(BOOL selecting)
{
LLGLState normalize(GL_NORMALIZE, TRUE);
@@ -262,13 +201,13 @@ void LLDrawPoolTree::renderTree(BOOL selecting)
LLFace *face = *iter;
LLDrawable *drawablep = face->getDrawable();
- if (drawablep->isDead() || face->mVertexBuffer.isNull())
+ if (drawablep->isDead() || !face->getVertexBuffer())
{
continue;
}
- face->mVertexBuffer->setBuffer(LLDrawPoolTree::VERTEX_DATA_MASK);
- U16* indicesp = (U16*) face->mVertexBuffer->getIndicesPointer();
+ face->getVertexBuffer()->setBuffer(LLDrawPoolTree::VERTEX_DATA_MASK);
+ U16* indicesp = (U16*) face->getVertexBuffer()->getIndicesPointer();
// Render each of the trees
LLVOTree *treep = (LLVOTree *)drawablep->getVObj().get();
diff --git a/indra/newview/lldrawpooltree.h b/indra/newview/lldrawpooltree.h
index cebe41f75f..ddb259bb82 100644
--- a/indra/newview/lldrawpooltree.h
+++ b/indra/newview/lldrawpooltree.h
@@ -62,7 +62,6 @@ public:
/*virtual*/ void render(S32 pass = 0);
/*virtual*/ void endRenderPass( S32 pass );
/*virtual*/ S32 getNumPasses() { return 1; }
- /*virtual*/ void renderForSelect();
/*virtual*/ BOOL verify() const;
/*virtual*/ LLViewerTexture *getTexture();
/*virtual*/ LLViewerTexture *getDebugTexture();
diff --git a/indra/newview/lldrawpoolwater.cpp b/indra/newview/lldrawpoolwater.cpp
index ce1b899d55..dc94924da4 100644
--- a/indra/newview/lldrawpoolwater.cpp
+++ b/indra/newview/lldrawpoolwater.cpp
@@ -48,7 +48,8 @@
#include "llviewershadermgr.h"
#include "llwaterparammanager.h"
-const LLUUID WATER_TEST("2bfd3884-7e27-69b9-ba3a-3e673f680004");
+const LLUUID TRANSPARENT_WATER_TEXTURE("2bfd3884-7e27-69b9-ba3a-3e673f680004");
+const LLUUID OPAQUE_WATER_TEXTURE("43c32285-d658-1793-c123-bf86315de055");
static float sTime;
@@ -71,10 +72,14 @@ LLDrawPoolWater::LLDrawPoolWater() :
gGL.getTexUnit(0)->bind(mHBTex[1]);
mHBTex[1]->setAddressMode(LLTexUnit::TAM_CLAMP);
- mWaterImagep = LLViewerTextureManager::getFetchedTexture(WATER_TEST);
- mWaterImagep->setNoDelete() ;
+
+ mWaterImagep = LLViewerTextureManager::getFetchedTexture(TRANSPARENT_WATER_TEXTURE);
+ llassert(mWaterImagep);
+ mWaterImagep->setNoDelete();
+ mOpaqueWaterImagep = LLViewerTextureManager::getFetchedTexture(OPAQUE_WATER_TEXTURE);
+ llassert(mOpaqueWaterImagep);
mWaterNormp = LLViewerTextureManager::getFetchedTexture(DEFAULT_WATER_NORMAL);
- mWaterNormp->setNoDelete() ;
+ mWaterNormp->setNoDelete();
restoreGL();
}
@@ -161,6 +166,14 @@ void LLDrawPoolWater::render(S32 pass)
std::sort(mDrawFace.begin(), mDrawFace.end(), LLFace::CompareDistanceGreater());
+ // See if we are rendering water as opaque or not
+ if (!gSavedSettings.getBOOL("RenderTransparentWater"))
+ {
+ // render water for low end hardware
+ renderOpaqueLegacyWater();
+ return;
+ }
+
LLGLEnable blend(GL_BLEND);
if ((mVertexShaderLevel > 0) && !sSkipScreenCopy)
@@ -314,6 +327,87 @@ void LLDrawPoolWater::render(S32 pass)
gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
}
+// for low end hardware
+void LLDrawPoolWater::renderOpaqueLegacyWater()
+{
+ LLVOSky *voskyp = gSky.mVOSkyp;
+
+ stop_glerror();
+
+ // Depth sorting and write to depth buffer
+ // since this is opaque, we should see nothing
+ // behind the water. No blending because
+ // of no transparency. And no face culling so
+ // that the underside of the water is also opaque.
+ LLGLDepthTest gls_depth(GL_TRUE, GL_TRUE);
+ LLGLDisable no_cull(GL_CULL_FACE);
+ LLGLDisable no_blend(GL_BLEND);
+
+ gPipeline.disableLights();
+
+ mOpaqueWaterImagep->addTextureStats(1024.f*1024.f);
+
+ // Activate the texture binding and bind one
+ // texture since all images will have the same texture
+ gGL.getTexUnit(0)->activate();
+ gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
+ gGL.getTexUnit(0)->bind(mOpaqueWaterImagep);
+
+ // Automatically generate texture coords for water texture
+ glEnable(GL_TEXTURE_GEN_S); //texture unit 0
+ glEnable(GL_TEXTURE_GEN_T); //texture unit 0
+ glTexGenf(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
+ glTexGenf(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
+
+ // Use the fact that we know all water faces are the same size
+ // to save some computation
+
+ // Slowly move texture coordinates over time so the watter appears
+ // to be moving.
+ F32 movement_period_secs = 50.f;
+
+ F32 offset = fmod(gFrameTimeSeconds, movement_period_secs);
+
+ if (movement_period_secs != 0)
+ {
+ offset /= movement_period_secs;
+ }
+ else
+ {
+ offset = 0;
+ }
+
+ F32 tp0[4] = { 16.f / 256.f, 0.0f, 0.0f, offset };
+ F32 tp1[4] = { 0.0f, 16.f / 256.f, 0.0f, offset };
+
+ glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0);
+ glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1);
+
+ glColor3f(1.f, 1.f, 1.f);
+
+ for (std::vector<LLFace*>::iterator iter = mDrawFace.begin();
+ iter != mDrawFace.end(); iter++)
+ {
+ LLFace *face = *iter;
+ if (voskyp->isReflFace(face))
+ {
+ continue;
+ }
+
+ face->renderIndexed();
+ }
+
+ stop_glerror();
+
+ // Reset the settings back to expected values
+ glDisable(GL_TEXTURE_GEN_S); //texture unit 0
+ glDisable(GL_TEXTURE_GEN_T); //texture unit 0
+
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
+}
+
+
void LLDrawPoolWater::renderReflection(LLFace* face)
{
LLVOSky *voskyp = gSky.mVOSkyp;
@@ -532,6 +626,7 @@ void LLDrawPoolWater::shade()
glColor4fv(water_color.mV);
{
+ LLGLEnable depth_clamp(gGLManager.mHasDepthClamp ? GL_DEPTH_CLAMP : 0);
LLGLDisable cullface(GL_CULL_FACE);
for (std::vector<LLFace*>::iterator iter = mDrawFace.begin();
iter != mDrawFace.end(); iter++)
@@ -548,30 +643,19 @@ void LLDrawPoolWater::shade()
sNeedsReflectionUpdate = TRUE;
- if (water->getUseTexture())
+ if (water->getUseTexture() || !water->getIsEdgePatch())
{
sNeedsDistortionUpdate = TRUE;
face->renderIndexed();
}
+ else if (gGLManager.mHasDepthClamp || deferred_render)
+ {
+ face->renderIndexed();
+ }
else
- { //smash background faces to far clip plane
- if (water->getIsEdgePatch())
- {
- if (deferred_render)
- {
- face->renderIndexed();
- }
- else
- {
- LLGLClampToFarClip far_clip(glh_get_current_projection());
- face->renderIndexed();
- }
- }
- else
- {
- sNeedsDistortionUpdate = TRUE;
- face->renderIndexed();
- }
+ {
+ LLGLSquashToFarClip far_clip(glh_get_current_projection());
+ face->renderIndexed();
}
}
}
@@ -601,12 +685,6 @@ void LLDrawPoolWater::shade()
}
-void LLDrawPoolWater::renderForSelect()
-{
- // Can't select water!
- return;
-}
-
LLViewerTexture *LLDrawPoolWater::getDebugTexture()
{
return LLViewerFetchedTexture::sSmokeImagep;
diff --git a/indra/newview/lldrawpoolwater.h b/indra/newview/lldrawpoolwater.h
index 3ab4bc5e2c..99b541ca5a 100644
--- a/indra/newview/lldrawpoolwater.h
+++ b/indra/newview/lldrawpoolwater.h
@@ -39,6 +39,7 @@ class LLDrawPoolWater: public LLFacePool
protected:
LLPointer<LLViewerTexture> mHBTex[2];
LLPointer<LLViewerTexture> mWaterImagep;
+ LLPointer<LLViewerTexture> mOpaqueWaterImagep;
LLPointer<LLViewerTexture> mWaterNormp;
public:
@@ -74,13 +75,15 @@ public:
/*virtual*/ S32 getNumPasses();
/*virtual*/ void render(S32 pass = 0);
/*virtual*/ void prerender();
- /*virtual*/ void renderForSelect();
/*virtual*/ LLViewerTexture *getDebugTexture();
/*virtual*/ LLColor3 getDebugColor() const; // For AGP debug display
void renderReflection(LLFace* face);
void shade();
+
+protected:
+ void renderOpaqueLegacyWater();
};
void cgErrorCallback();
diff --git a/indra/newview/lldrawpoolwlsky.cpp b/indra/newview/lldrawpoolwlsky.cpp
index 41a299151e..696c2d1abd 100644
--- a/indra/newview/lldrawpoolwlsky.cpp
+++ b/indra/newview/lldrawpoolwlsky.cpp
@@ -192,7 +192,7 @@ void LLDrawPoolWLSky::renderSkyClouds(F32 camHeightLocal) const
&gWLCloudProgram;
LLGLEnable blend(GL_BLEND);
- LLGLSBlendFunc blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ gGL.setSceneBlendType(LLRender::BT_ALPHA);
gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
gGL.getTexUnit(0)->bind(sCloudNoiseTexture);
@@ -260,7 +260,7 @@ void LLDrawPoolWLSky::render(S32 pass)
LLGLDepthTest depth(GL_TRUE, GL_FALSE);
LLGLDisable clip(GL_CLIP_PLANE0);
- LLGLClampToFarClip far_clip(glh_get_current_projection());
+ LLGLSquashToFarClip far_clip(glh_get_current_projection());
renderSkyHaze(camHeightLocal);
diff --git a/indra/newview/lldriverparam.h b/indra/newview/lldriverparam.h
index a0e45cf5e5..fb1b44458c 100644
--- a/indra/newview/lldriverparam.h
+++ b/indra/newview/lldriverparam.h
@@ -30,6 +30,7 @@
#include "llviewervisualparam.h"
#include "llwearabletype.h"
+class LLPhysicsMotion;
class LLVOAvatar;
class LLWearable;
@@ -76,6 +77,7 @@ protected:
class LLDriverParam : public LLViewerVisualParam
{
+ friend class LLPhysicsMotion; // physics motion needs to access driven params directly.
public:
LLDriverParam(LLVOAvatar *avatarp);
LLDriverParam(LLWearable *wearablep);
diff --git a/indra/newview/lldynamictexture.cpp b/indra/newview/lldynamictexture.cpp
index a3d2941114..f781d5f3ff 100644
--- a/indra/newview/lldynamictexture.cpp
+++ b/indra/newview/lldynamictexture.cpp
@@ -177,10 +177,6 @@ void LLViewerDynamicTexture::postRender(BOOL success)
generateGLTexture() ;
}
- if(gGLManager.mDebugGPU)
- {
- LLGLState::dumpStates() ;
- }
success = mGLTexturep->setSubImageFromFrameBuffer(0, 0, mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight);
}
}
@@ -220,12 +216,6 @@ BOOL LLViewerDynamicTexture::updateAllInstances()
LLViewerDynamicTexture *dynamicTexture = *iter;
if (dynamicTexture->needsRender())
{
- if(gGLManager.mDebugGPU)
- {
- llinfos << "class type: " << (S32)dynamicTexture->getType() << llendl;
- LLGLState::dumpStates() ;
- }
-
glClear(GL_DEPTH_BUFFER_BIT);
gDepthDirty = TRUE;
diff --git a/indra/newview/lleventnotifier.h b/indra/newview/lleventnotifier.h
index 697a708762..3fee46c2f6 100644
--- a/indra/newview/lleventnotifier.h
+++ b/indra/newview/lleventnotifier.h
@@ -31,6 +31,7 @@
#include "v3dmath.h"
class LLEventNotification;
+class LLMessageSystem;
class LLEventNotifier
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/llexternaleditor.cpp b/indra/newview/llexternaleditor.cpp
new file mode 100644
index 0000000000..ed1d7e860a
--- /dev/null
+++ b/indra/newview/llexternaleditor.cpp
@@ -0,0 +1,208 @@
+/**
+ * @file llexternaleditor.cpp
+ * @brief A convenient class to run external editor.
+ *
+ * $LicenseInfo:firstyear=2010&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 "llexternaleditor.h"
+
+#include "lltrans.h"
+#include "llui.h"
+
+// static
+const std::string LLExternalEditor::sFilenameMarker = "%s";
+
+// static
+const std::string LLExternalEditor::sSetting = "ExternalEditor";
+
+LLExternalEditor::EErrorCode LLExternalEditor::setCommand(const std::string& env_var, const std::string& override)
+{
+ std::string cmd = findCommand(env_var, override);
+ if (cmd.empty())
+ {
+ llwarns << "Editor command is empty or not set" << llendl;
+ return EC_NOT_SPECIFIED;
+ }
+
+ // Add the filename marker if missing.
+ if (cmd.find(sFilenameMarker) == std::string::npos)
+ {
+ cmd += " \"" + sFilenameMarker + "\"";
+ llinfos << "Adding the filename marker (" << sFilenameMarker << ")" << llendl;
+ }
+
+ string_vec_t tokens;
+ if (tokenize(tokens, cmd) < 2) // 2 = bin + at least one arg (%s)
+ {
+ llwarns << "Error parsing editor command" << llendl;
+ return EC_PARSE_ERROR;
+ }
+
+ // Check executable for existence.
+ std::string bin_path = tokens[0];
+ if (!LLFile::isfile(bin_path))
+ {
+ llwarns << "Editor binary [" << bin_path << "] not found" << llendl;
+ return EC_BINARY_NOT_FOUND;
+ }
+
+ // Save command.
+ mProcess.setExecutable(bin_path);
+ mArgs.clear();
+ for (size_t i = 1; i < tokens.size(); ++i)
+ {
+ if (i > 1) mArgs += " ";
+ mArgs += "\"" + tokens[i] + "\"";
+ }
+ llinfos << "Setting command [" << bin_path << " " << mArgs << "]" << llendl;
+
+ return EC_SUCCESS;
+}
+
+LLExternalEditor::EErrorCode LLExternalEditor::run(const std::string& file_path)
+{
+ std::string args = mArgs;
+ if (mProcess.getExecutable().empty() || args.empty())
+ {
+ llwarns << "Editor command not set" << llendl;
+ return EC_NOT_SPECIFIED;
+ }
+
+ // Substitute the filename marker in the command with the actual passed file name.
+ LLStringUtil::replaceString(args, sFilenameMarker, file_path);
+
+ // Split command into separate tokens.
+ string_vec_t tokens;
+ tokenize(tokens, args);
+
+ // Set process arguments taken from the command.
+ mProcess.clearArguments();
+ for (string_vec_t::const_iterator arg_it = tokens.begin(); arg_it != tokens.end(); ++arg_it)
+ {
+ mProcess.addArgument(*arg_it);
+ }
+
+ // Run the editor.
+ llinfos << "Running editor command [" << mProcess.getExecutable() + " " + args << "]" << llendl;
+ int result = mProcess.launch();
+ if (result == 0)
+ {
+ // Prevent killing the process in destructor (will add it to the zombies list).
+ mProcess.orphan();
+ }
+
+ return result == 0 ? EC_SUCCESS : EC_FAILED_TO_RUN;
+}
+
+// static
+std::string LLExternalEditor::getErrorMessage(EErrorCode code)
+{
+ switch (code)
+ {
+ case EC_SUCCESS: return LLTrans::getString("ok");
+ case EC_NOT_SPECIFIED: return LLTrans::getString("ExternalEditorNotSet");
+ case EC_PARSE_ERROR: return LLTrans::getString("ExternalEditorCommandParseError");
+ case EC_BINARY_NOT_FOUND: return LLTrans::getString("ExternalEditorNotFound");
+ case EC_FAILED_TO_RUN: return LLTrans::getString("ExternalEditorFailedToRun");
+ }
+
+ return LLTrans::getString("Unknown");
+}
+
+// static
+size_t LLExternalEditor::tokenize(string_vec_t& tokens, const std::string& str)
+{
+ tokens.clear();
+
+ // Split the argument string into separate strings for each argument
+ typedef boost::tokenizer< boost::char_separator<char> > tokenizer;
+ boost::char_separator<char> sep("", "\" ", boost::drop_empty_tokens);
+
+ tokenizer tokens_list(str, sep);
+ tokenizer::iterator token_iter;
+ BOOL inside_quotes = FALSE;
+ BOOL last_was_space = FALSE;
+ for (token_iter = tokens_list.begin(); token_iter != tokens_list.end(); ++token_iter)
+ {
+ if (!strncmp("\"",(*token_iter).c_str(),2))
+ {
+ inside_quotes = !inside_quotes;
+ }
+ else if (!strncmp(" ",(*token_iter).c_str(),2))
+ {
+ if(inside_quotes)
+ {
+ tokens.back().append(std::string(" "));
+ last_was_space = TRUE;
+ }
+ }
+ else
+ {
+ std::string to_push = *token_iter;
+ if (last_was_space)
+ {
+ tokens.back().append(to_push);
+ last_was_space = FALSE;
+ }
+ else
+ {
+ tokens.push_back(to_push);
+ }
+ }
+ }
+
+ return tokens.size();
+}
+
+// static
+std::string LLExternalEditor::findCommand(
+ const std::string& env_var,
+ const std::string& override)
+{
+ std::string cmd;
+
+ // Get executable path.
+ if (!override.empty()) // try the supplied override first
+ {
+ cmd = override;
+ llinfos << "Using override" << llendl;
+ }
+ else if (!LLUI::sSettingGroups["config"]->getString(sSetting).empty())
+ {
+ cmd = LLUI::sSettingGroups["config"]->getString(sSetting);
+ llinfos << "Using setting" << llendl;
+ }
+ else // otherwise use the path specified by the environment variable
+ {
+ char* env_var_val = getenv(env_var.c_str());
+ if (env_var_val)
+ {
+ cmd = env_var_val;
+ llinfos << "Using env var " << env_var << llendl;
+ }
+ }
+
+ llinfos << "Found command [" << cmd << "]" << llendl;
+ return cmd;
+}
diff --git a/indra/newview/llexternaleditor.h b/indra/newview/llexternaleditor.h
new file mode 100644
index 0000000000..ef5db56c6e
--- /dev/null
+++ b/indra/newview/llexternaleditor.h
@@ -0,0 +1,105 @@
+/**
+ * @file llexternaleditor.h
+ * @brief A convenient class to run external editor.
+ *
+ * $LicenseInfo:firstyear=2010&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_LLEXTERNALEDITOR_H
+#define LL_LLEXTERNALEDITOR_H
+
+#include <llprocesslauncher.h>
+
+/**
+ * Usage:
+ * LLExternalEditor ed;
+ * ed.setCommand("MY_EXTERNAL_EDITOR_VAR");
+ * ed.run("/path/to/file1");
+ * ed.run("/other/path/to/file2");
+ */
+class LLExternalEditor
+{
+ typedef std::vector<std::string> string_vec_t;
+
+public:
+
+ typedef enum e_error_code {
+ EC_SUCCESS, /// No error.
+ EC_NOT_SPECIFIED, /// Editor path not specified.
+ EC_PARSE_ERROR, /// Editor command parsing error.
+ EC_BINARY_NOT_FOUND, /// Could find the editor binary (missing or not quoted).
+ EC_FAILED_TO_RUN, /// Could not execute the editor binary.
+ } EErrorCode;
+
+ /**
+ * Set editor command.
+ *
+ * @param env_var Environment variable of the same purpose.
+ * @param override Optional override.
+ *
+ * First tries the override, then a predefined setting (sSetting),
+ * then the environment variable.
+ *
+ * @return EC_SUCCESS if command is valid and refers to an existing executable,
+ * EC_NOT_SPECIFIED or EC_FAILED_TO_RUNan on error.
+ *
+ * @see sSetting
+ */
+ EErrorCode setCommand(const std::string& env_var, const std::string& override = LLStringUtil::null);
+
+ /**
+ * Run the editor with the given file.
+ *
+ * @param file_path File to edit.
+ * @return EC_SUCCESS on success, error code on error.
+ */
+ EErrorCode run(const std::string& file_path);
+
+ /**
+ * Get a meaningful error message for the given status code.
+ */
+ static std::string getErrorMessage(EErrorCode code);
+
+private:
+
+ static std::string findCommand(
+ const std::string& env_var,
+ const std::string& override);
+
+ static size_t tokenize(string_vec_t& tokens, const std::string& str);
+
+ /**
+ * Filename placeholder that gets replaced with an actual file name.
+ */
+ static const std::string sFilenameMarker;
+
+ /**
+ * Setting that can specify the editor command.
+ */
+ static const std::string sSetting;
+
+
+ std::string mArgs;
+ LLProcessLauncher mProcess;
+};
+
+#endif // LL_LLEXTERNALEDITOR_H
diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp
index d22950cad3..5398c13c44 100644
--- a/indra/newview/llface.cpp
+++ b/indra/newview/llface.cpp
@@ -33,8 +33,10 @@
#include "llviewercontrol.h"
#include "llvolume.h"
#include "m3math.h"
+#include "llmatrix4a.h"
#include "v3color.h"
+#include "lldrawpoolavatar.h"
#include "lldrawpoolbump.h"
#include "llgl.h"
#include "llrender.h"
@@ -67,35 +69,43 @@ The resulting texture coordinate <u,v> is:
u = 2(B dot P)
v = 2(T dot P)
*/
-void planarProjection(LLVector2 &tc, const LLVector3& normal,
- const LLVector3 &mCenter, const LLVector3& vec)
-{ //DONE!
- LLVector3 binormal;
- float d = normal * LLVector3(1,0,0);
+void planarProjection(LLVector2 &tc, const LLVector4a& normal,
+ const LLVector4a &center, const LLVector4a& vec)
+{
+ LLVector4a binormal;
+ F32 d = normal[0];
+
if (d >= 0.5f || d <= -0.5f)
{
- binormal = LLVector3(0,1,0);
- if (normal.mV[0] < 0)
+ if (d < 0)
{
- binormal = -binormal;
+ binormal.set(0,-1,0);
+ }
+ else
+ {
+ binormal.set(0, 1, 0);
}
}
else
{
- binormal = LLVector3(1,0,0);
- if (normal.mV[1] > 0)
+ if (normal[1] > 0)
{
- binormal = -binormal;
+ binormal.set(-1,0,0);
+ }
+ else
+ {
+ binormal.set(1,0,0);
}
}
- LLVector3 tangent = binormal % normal;
+ LLVector4a tangent;
+ tangent.setCross3(binormal,normal);
- tc.mV[1] = -((tangent*vec)*2 - 0.5f);
- tc.mV[0] = 1.0f+((binormal*vec)*2 - 0.5f);
+ tc.mV[1] = -((tangent.dot3(vec).getF32())*2 - 0.5f);
+ tc.mV[0] = 1.0f+((binormal.dot3(vec).getF32())*2 - 0.5f);
}
-void sphericalProjection(LLVector2 &tc, const LLVector3& normal,
- const LLVector3 &mCenter, const LLVector3& vec)
+void sphericalProjection(LLVector2 &tc, const LLVector4a& normal,
+ const LLVector4a &mCenter, const LLVector4a& vec)
{ //BROKEN
/*tc.mV[0] = acosf(vd.mNormal * LLVector3(1,0,0))/3.14159f;
@@ -106,7 +116,7 @@ void sphericalProjection(LLVector2 &tc, const LLVector3& normal,
}*/
}
-void cylindricalProjection(LLVector2 &tc, const LLVector3& normal, const LLVector3 &mCenter, const LLVector3& vec)
+void cylindricalProjection(LLVector2 &tc, const LLVector4a& normal, const LLVector4a &mCenter, const LLVector4a& vec)
{ //BROKEN
/*LLVector3 binormal;
float d = vd.mNormal * LLVector3(1,0,0);
@@ -138,6 +148,7 @@ void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp)
{
mLastUpdateTime = gFrameTimeSeconds;
mLastMoveTime = 0.f;
+ mLastSkinTime = gFrameTimeSeconds;
mVSize = 0.f;
mPixelArea = 16.f;
mState = GLOBAL;
@@ -179,9 +190,13 @@ void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp)
mHasMedia = FALSE ;
}
-
void LLFace::destroy()
{
+ if (gDebugGL)
+ {
+ gPipeline.checkReferences(this);
+ }
+
if(mTexture.notNull())
{
mTexture->removeFace(this) ;
@@ -189,7 +204,15 @@ void LLFace::destroy()
if (mDrawPoolp)
{
- mDrawPoolp->removeFace(this);
+ if (this->isState(LLFace::RIGGED) && mDrawPoolp->getType() == LLDrawPool::POOL_AVATAR)
+ {
+ ((LLDrawPoolAvatar*) mDrawPoolp)->removeRiggedFace(this);
+ }
+ else
+ {
+ mDrawPoolp->removeFace(this);
+ }
+
mDrawPoolp = NULL;
}
@@ -210,8 +233,8 @@ void LLFace::destroy()
}
setDrawInfo(NULL);
-
removeAtlas();
+
mDrawablep = NULL;
mVObjp = NULL;
}
@@ -227,6 +250,11 @@ void LLFace::setWorldMatrix(const LLMatrix4 &mat)
llerrs << "Faces on this drawable are not independently modifiable\n" << llendl;
}
+void LLFace::setPool(LLFacePool* pool)
+{
+ mDrawPoolp = pool;
+}
+
void LLFace::setPool(LLFacePool* new_pool, LLViewerTexture *texturep)
{
LLMemType mt1(LLMemType::MTYPE_DRAWABLE);
@@ -329,8 +357,21 @@ void LLFace::setDrawable(LLDrawable *drawable)
mXform = &drawable->mXform;
}
-void LLFace::setSize(const S32 num_vertices, const S32 num_indices)
+void LLFace::setSize(S32 num_vertices, S32 num_indices, bool align)
{
+ if (align)
+ {
+ //allocate vertices in blocks of 4 for alignment
+ num_vertices = (num_vertices + 0x3) & ~0x3;
+ }
+ else
+ {
+ if (mDrawablep->getVOVolume())
+ {
+ llerrs << "WTF?" << llendl;
+ }
+ }
+
if (mGeomCount != num_vertices ||
mIndicesCount != num_indices)
{
@@ -339,8 +380,28 @@ void LLFace::setSize(const S32 num_vertices, const S32 num_indices)
mVertexBuffer = NULL;
mLastVertexBuffer = NULL;
}
+
+ llassert(verify());
+}
+
+void LLFace::setGeomIndex(U16 idx)
+{
+ if (mGeomIndex != idx)
+ {
+ mGeomIndex = idx;
+ mVertexBuffer = NULL;
+ }
}
+void LLFace::setIndicesIndex(S32 idx)
+{
+ if (mIndicesIndex != idx)
+ {
+ mIndicesIndex = idx;
+ mVertexBuffer = NULL;
+ }
+}
+
//============================================================================
U16 LLFace::getGeometryAvatar(
@@ -399,84 +460,6 @@ void LLFace::updateCenterAgent()
}
}
-void LLFace::renderForSelect(U32 data_mask)
-{
- if(mDrawablep.isNull() || mVertexBuffer.isNull())
- {
- return;
- }
-
- LLSpatialGroup* group = mDrawablep->getSpatialGroup();
- if (!group || group->isState(LLSpatialGroup::GEOM_DIRTY))
- {
- return;
- }
-
- if (mVObjp->mGLName)
- {
- S32 name = mVObjp->mGLName;
-
- LLColor4U color((U8)(name >> 16), (U8)(name >> 8), (U8)name);
-#if 0 // *FIX: Postponing this fix until we have texcoord pick info...
- if (mTEOffset != -1)
- {
- color.mV[VALPHA] = (U8)(getTextureEntry()->getColor().mV[VALPHA] * 255.f);
- }
-#endif
- glColor4ubv(color.mV);
-
- if (!getPool())
- {
- switch (getPoolType())
- {
- case LLDrawPool::POOL_ALPHA:
- gGL.getTexUnit(0)->bind(getTexture());
- break;
- default:
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- break;
- }
- }
-
- mVertexBuffer->setBuffer(data_mask);
-#if !LL_RELEASE_FOR_DOWNLOAD
- LLGLState::checkClientArrays("", data_mask);
-#endif
- if (mTEOffset != -1)
- {
- // mask off high 4 bits (16 total possible faces)
- color.mV[0] &= 0x0f;
- color.mV[0] |= (mTEOffset & 0x0f) << 4;
- glColor4ubv(color.mV);
- }
-
- if (mIndicesCount)
- {
- if (isState(GLOBAL))
- {
- if (mDrawablep->getVOVolume())
- {
- glPushMatrix();
- glMultMatrixf((float*) mDrawablep->getRegion()->mRenderMatrix.mMatrix);
- mVertexBuffer->draw(LLRender::TRIANGLES, mIndicesCount, mIndicesIndex);
- glPopMatrix();
- }
- else
- {
- mVertexBuffer->draw(LLRender::TRIANGLES, mIndicesCount, mIndicesIndex);
- }
- }
- else
- {
- glPushMatrix();
- glMultMatrixf((float*)getRenderMatrix().mMatrix);
- mVertexBuffer->draw(LLRender::TRIANGLES, mIndicesCount, mIndicesIndex);
- glPopMatrix();
- }
- }
- }
-}
-
void LLFace::renderSelected(LLViewerTexture *imagep, const LLColor4& color)
{
if (mDrawablep->getSpatialGroup() == NULL)
@@ -507,8 +490,36 @@ void LLFace::renderSelected(LLViewerTexture *imagep, const LLColor4& color)
}
glColor4fv(color.mV);
- mVertexBuffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0);
- mVertexBuffer->draw(LLRender::TRIANGLES, mIndicesCount, mIndicesIndex);
+
+ if (mDrawablep->isState(LLDrawable::RIGGED))
+ {
+ LLVOVolume* volume = mDrawablep->getVOVolume();
+ if (volume)
+ {
+ LLRiggedVolume* rigged = volume->getRiggedVolume();
+ if (rigged)
+ {
+ LLGLEnable offset(GL_POLYGON_OFFSET_FILL);
+ glPolygonOffset(-1.f, -1.f);
+ glMultMatrixf((F32*) volume->getRelativeXform().mMatrix);
+ const LLVolumeFace& vol_face = rigged->getVolumeFace(getTEOffset());
+ LLVertexBuffer::unbind();
+ glVertexPointer(3, GL_FLOAT, 16, vol_face.mPositions);
+ if (vol_face.mTexCoords)
+ {
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glTexCoordPointer(2, GL_FLOAT, 8, vol_face.mTexCoords);
+ }
+ glDrawElements(GL_TRIANGLES, vol_face.mNumIndices, GL_UNSIGNED_SHORT, vol_face.mIndices);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ }
+ }
+ }
+ else
+ {
+ mVertexBuffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0);
+ mVertexBuffer->draw(LLRender::TRIANGLES, mIndicesCount, mIndicesIndex);
+ }
gGL.popMatrix();
}
@@ -593,23 +604,26 @@ void LLFace::printDebugInfo() const
llinfos << "II: " << mIndicesIndex << " Count:" << mIndicesCount << llendl;
llinfos << llendl;
- poolp->printDebugInfo();
-
- S32 pool_references = 0;
- for (std::vector<LLFace*>::iterator iter = poolp->mReferences.begin();
- iter != poolp->mReferences.end(); iter++)
+ if (poolp)
{
- LLFace *facep = *iter;
- if (facep == this)
+ poolp->printDebugInfo();
+
+ S32 pool_references = 0;
+ for (std::vector<LLFace*>::iterator iter = poolp->mReferences.begin();
+ iter != poolp->mReferences.end(); iter++)
{
- llinfos << "Pool reference: " << pool_references << llendl;
- pool_references++;
+ LLFace *facep = *iter;
+ if (facep == this)
+ {
+ llinfos << "Pool reference: " << pool_references << llendl;
+ pool_references++;
+ }
}
- }
- if (pool_references != 1)
- {
- llinfos << "Incorrect number of pool references!" << llendl;
+ if (pool_references != 1)
+ {
+ llinfos << "Incorrect number of pool references!" << llendl;
+ }
}
#if 0
@@ -666,95 +680,116 @@ static void xform(LLVector2 &tex_coord, F32 cosAng, F32 sinAng, F32 offS, F32 of
BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f,
- const LLMatrix4& mat_vert, const LLMatrix3& mat_normal, BOOL global_volume)
+ const LLMatrix4& mat_vert_in, const LLMatrix3& mat_normal_in, BOOL global_volume)
{
LLMemType mt1(LLMemType::MTYPE_DRAWABLE);
//get bounding box
- if (mDrawablep->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION))
+ if (mDrawablep->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION | LLDrawable::REBUILD_RIGGED))
{
+ //VECTORIZE THIS
+ LLMatrix4a mat_vert;
+ mat_vert.loadu(mat_vert_in);
+
+ LLMatrix4a mat_normal;
+ mat_normal.loadu(mat_normal_in);
+
//if (mDrawablep->isState(LLDrawable::REBUILD_VOLUME))
//{ //vertex buffer no longer valid
// mVertexBuffer = NULL;
// mLastVertexBuffer = NULL;
//}
- LLVector3 min,max;
+ //VECTORIZE THIS
+ LLVector4a min,max;
if (f >= volume.getNumVolumeFaces())
{
- min = LLVector3(-1,-1,-1);
- max = LLVector3(1,1,1);
- }
- else
- {
- const LLVolumeFace &face = volume.getVolumeFace(f);
- min = face.mExtents[0];
- max = face.mExtents[1];
+ llwarns << "Generating bounding box for invalid face index!" << llendl;
+ f = 0;
}
+ const LLVolumeFace &face = volume.getVolumeFace(f);
+ min = face.mExtents[0];
+ max = face.mExtents[1];
+
+
//min, max are in volume space, convert to drawable render space
- LLVector3 center = ((min + max) * 0.5f)*mat_vert;
- LLVector3 size = ((max-min) * 0.5f);
+ LLVector4a center;
+ LLVector4a t;
+ t.setAdd(min, max);
+ t.mul(0.5f);
+ mat_vert.affineTransform(t, center);
+ LLVector4a size;
+ size.setSub(max, min);
+ size.mul(0.5f);
+
if (!global_volume)
{
- size.scaleVec(mDrawablep->getVObj()->getScale());
+ //VECTORIZE THIS
+ LLVector4a scale;
+ scale.load3(mDrawablep->getVObj()->getScale().mV);
+ size.mul(scale);
}
- LLMatrix3 mat = mat_normal;
- LLVector3 x = mat.getFwdRow();
- LLVector3 y = mat.getLeftRow();
- LLVector3 z = mat.getUpRow();
- x.normVec();
- y.normVec();
- z.normVec();
+ mat_normal.mMatrix[0].normalize3fast();
+ mat_normal.mMatrix[1].normalize3fast();
+ mat_normal.mMatrix[2].normalize3fast();
+
+ LLVector4a v[4];
- mat.setRows(x,y,z);
+ //get 4 corners of bounding box
+ mat_normal.rotate(size,v[0]);
- LLQuaternion rotation = LLQuaternion(mat);
+ //VECTORIZE THIS
+ LLVector4a scale;
- LLVector3 v[4];
- //get 4 corners of bounding box
- v[0] = (size * rotation);
- v[1] = (LLVector3(-size.mV[0], -size.mV[1], size.mV[2]) * rotation);
- v[2] = (LLVector3(size.mV[0], -size.mV[1], -size.mV[2]) * rotation);
- v[3] = (LLVector3(-size.mV[0], size.mV[1], -size.mV[2]) * rotation);
+ scale.set(-1.f, -1.f, 1.f);
+ scale.mul(size);
+ mat_normal.rotate(scale, v[1]);
+
+ scale.set(1.f, -1.f, -1.f);
+ scale.mul(size);
+ mat_normal.rotate(scale, v[2]);
+
+ scale.set(-1.f, 1.f, -1.f);
+ scale.mul(size);
+ mat_normal.rotate(scale, v[3]);
- LLVector3& newMin = mExtents[0];
- LLVector3& newMax = mExtents[1];
+ LLVector4a& newMin = mExtents[0];
+ LLVector4a& newMax = mExtents[1];
newMin = newMax = center;
for (U32 i = 0; i < 4; i++)
{
- for (U32 j = 0; j < 3; j++)
- {
- F32 delta = fabsf(v[i].mV[j]);
- F32 min = center.mV[j] - delta;
- F32 max = center.mV[j] + delta;
-
- if (min < newMin.mV[j])
- {
- newMin.mV[j] = min;
- }
-
- if (max > newMax.mV[j])
- {
- newMax.mV[j] = max;
- }
- }
+ LLVector4a delta;
+ delta.setAbs(v[i]);
+ LLVector4a min;
+ min.setSub(center, delta);
+ LLVector4a max;
+ max.setAdd(center, delta);
+
+ newMin.setMin(newMin,min);
+ newMax.setMax(newMax,max);
}
if (!mDrawablep->isActive())
{
- LLVector3 offset = mDrawablep->getRegion()->getOriginAgent();
- newMin += offset;
- newMax += offset;
+ LLVector4a offset;
+ offset.load3(mDrawablep->getRegion()->getOriginAgent().mV);
+ newMin.add(offset);
+ newMax.add(offset);
}
- mCenterLocal = (newMin+newMax)*0.5f;
- LLVector3 tmp = (newMin - newMax) ;
- mBoundingSphereRadius = tmp.length() * 0.5f ;
+ t.setAdd(newMin, newMax);
+ t.mul(0.5f);
+
+ //VECTORIZE THIS
+ mCenterLocal.set(t.getF32ptr());
+
+ t.setSub(newMax,newMin);
+ mBoundingSphereRadius = t.getLength3().getF32()*0.5f;
updateCenterAgent();
}
@@ -781,18 +816,26 @@ LLVector2 LLFace::surfaceToTexture(LLVector2 surface_coord, LLVector3 position,
return surface_coord;
}
+ //VECTORIZE THIS
// see if we have a non-default mapping
U8 texgen = getTextureEntry()->getTexGen();
if (texgen != LLTextureEntry::TEX_GEN_DEFAULT)
{
- LLVector3 center = mDrawablep->getVOVolume()->getVolume()->getVolumeFace(mTEOffset).mCenter;
+ LLVector4a& center = *(mDrawablep->getVOVolume()->getVolume()->getVolumeFace(mTEOffset).mCenter);
+
+ LLVector4a volume_position;
+ volume_position.load3(mDrawablep->getVOVolume()->agentPositionToVolume(position).mV);
- LLVector3 scale = (mDrawablep->getVOVolume()->isVolumeGlobal()) ? LLVector3(1,1,1) : mVObjp->getScale();
- LLVector3 volume_position = mDrawablep->getVOVolume()->agentPositionToVolume(position);
- volume_position.scaleVec(scale);
+ if (!mDrawablep->getVOVolume()->isVolumeGlobal())
+ {
+ LLVector4a scale;
+ scale.load3(mVObjp->getScale().mV);
+ volume_position.mul(scale);
+ }
- LLVector3 volume_normal = mDrawablep->getVOVolume()->agentDirectionToVolume(normal);
- volume_normal.normalize();
+ LLVector4a volume_normal;
+ volume_normal.load3(mDrawablep->getVOVolume()->agentDirectionToVolume(normal).mV);
+ volume_normal.normalize3fast();
switch (texgen)
{
@@ -833,10 +876,10 @@ void LLFace::getPlanarProjectedParams(LLQuaternion* face_rot, LLVector3* face_po
{
const LLMatrix4& vol_mat = getWorldMatrix();
const LLVolumeFace& vf = getViewerObject()->getVolume()->getVolumeFace(mTEOffset);
- LLVector3 normal = vf.mVertices[0].mNormal;
- LLVector3 binormal = vf.mVertices[0].mBinormal;
+ const LLVector4a& normal4a = vf.mNormals[0];
+ const LLVector4a& binormal4a = vf.mBinormals[0];
LLVector2 projected_binormal;
- planarProjection(projected_binormal, normal, vf.mCenter, binormal);
+ planarProjection(projected_binormal, normal4a, *vf.mCenter, binormal4a);
projected_binormal -= LLVector2(0.5f, 0.5f); // this normally happens in xform()
*scale = projected_binormal.length();
// rotate binormal to match what planarProjection() thinks it is,
@@ -844,6 +887,10 @@ void LLFace::getPlanarProjectedParams(LLQuaternion* face_rot, LLVector3* face_po
projected_binormal.normalize();
F32 ang = acos(projected_binormal.mV[VY]);
ang = (projected_binormal.mV[VX] < 0.f) ? -ang : ang;
+
+ //VECTORIZE THIS
+ LLVector3 binormal(binormal4a.getF32ptr());
+ LLVector3 normal(normal4a.getF32ptr());
binormal.rotVec(ang, normal);
LLQuaternion local_rot( binormal % normal, binormal, normal );
*face_rot = local_rot * vol_mat.quaternion();
@@ -926,20 +973,35 @@ void LLFace::updateRebuildFlags()
bool LLFace::canRenderAsMask()
{
+ if (LLPipeline::sNoAlpha)
+ {
+ return true;
+ }
+
const LLTextureEntry* te = getTextureEntry();
- return (
- (
- (LLPipeline::sRenderDeferred && LLPipeline::sAutoMaskAlphaDeferred) ||
-
- (!LLPipeline::sRenderDeferred && LLPipeline::sAutoMaskAlphaNonDeferred)
- ) // do we want masks at all?
- &&
- (te->getColor().mV[3] == 1.0f) && // can't treat as mask if we have face alpha
- !(LLPipeline::sRenderDeferred && te->getFullbright()) && // hack: alpha masking renders fullbright faces invisible in deferred rendering mode, need to figure out why - for now, avoid
+
+ if ((te->getColor().mV[3] == 1.0f) && // can't treat as mask if we have face alpha
(te->getGlow() == 0.f) && // glowing masks are hard to implement - don't mask
+ getTexture()->getIsAlphaMask()) // texture actually qualifies for masking (lazily recalculated but expensive)
+ {
+ if (LLPipeline::sRenderDeferred)
+ {
+ if (getViewerObject()->isHUDAttachment() || te->getFullbright())
+ { //hud attachments and fullbright objects are NOT subject to the deferred rendering pipe
+ return LLPipeline::sAutoMaskAlphaNonDeferred;
+ }
+ else
+ {
+ return LLPipeline::sAutoMaskAlphaDeferred;
+ }
+ }
+ else
+ {
+ return LLPipeline::sAutoMaskAlphaNonDeferred;
+ }
+ }
- getTexture()->getIsAlphaMask() // texture actually qualifies for masking (lazily recalculated but expensive)
- );
+ return false;
}
@@ -947,13 +1009,15 @@ static LLFastTimer::DeclareTimer FTM_FACE_GET_GEOM("Face Geom");
BOOL LLFace::getGeometryVolume(const LLVolume& volume,
const S32 &f,
- const LLMatrix4& mat_vert, const LLMatrix3& mat_normal,
- const U16 &index_offset)
+ const LLMatrix4& mat_vert_in, const LLMatrix3& mat_norm_in,
+ const U16 &index_offset,
+ bool force_rebuild)
{
LLFastTimer t(FTM_FACE_GET_GEOM);
+ llassert(verify());
const LLVolumeFace &vf = volume.getVolumeFace(f);
- S32 num_vertices = (S32)vf.mVertices.size();
- S32 num_indices = LLPipeline::sUseTriStrips ? (S32)vf.mTriStrip.size() : (S32) vf.mIndices.size();
+ S32 num_vertices = (S32)vf.mNumVertices;
+ S32 num_indices = (S32) vf.mNumIndices;
if (mVertexBuffer.notNull())
{
@@ -978,15 +1042,20 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
}
}
- LLStrider<LLVector3> vertices;
+ LLStrider<LLVector3> vert;
+ LLVector4a* vertices = NULL;
LLStrider<LLVector2> tex_coords;
LLStrider<LLVector2> tex_coords2;
- LLStrider<LLVector3> normals;
+ LLVector4a* normals = NULL;
+ LLStrider<LLVector3> norm;
LLStrider<LLColor4U> colors;
- LLStrider<LLVector3> binormals;
+ LLVector4a* binormals = NULL;
+ LLStrider<LLVector3> binorm;
LLStrider<U16> indicesp;
+ LLVector4a* weights = NULL;
+ LLStrider<LLVector4> wght;
- BOOL full_rebuild = mDrawablep->isState(LLDrawable::REBUILD_VOLUME);
+ BOOL full_rebuild = force_rebuild || mDrawablep->isState(LLDrawable::REBUILD_VOLUME);
BOOL global_volume = mDrawablep->getVOVolume()->isVolumeGlobal();
LLVector3 scale;
@@ -999,28 +1068,37 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
scale = mVObjp->getScale();
}
- BOOL rebuild_pos = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_POSITION);
- BOOL rebuild_color = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_COLOR);
- BOOL rebuild_tcoord = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_TCOORD);
- BOOL rebuild_normal = rebuild_pos && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_NORMAL);
- BOOL rebuild_binormal = rebuild_pos && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_BINORMAL);
+ bool rebuild_pos = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_POSITION);
+ bool rebuild_color = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_COLOR);
+ bool rebuild_tcoord = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_TCOORD);
+ bool rebuild_normal = rebuild_pos && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_NORMAL);
+ bool rebuild_binormal = rebuild_pos && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_BINORMAL);
+ bool rebuild_weights = rebuild_pos && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_WEIGHT4);
const LLTextureEntry *tep = mVObjp->getTE(f);
- U8 bump_code = tep ? tep->getBumpmap() : 0;
+ const U8 bump_code = tep ? tep->getBumpmap() : 0;
if (rebuild_pos)
{
- mVertexBuffer->getVertexStrider(vertices, mGeomIndex);
+ mVertexBuffer->getVertexStrider(vert, mGeomIndex);
+ vertices = (LLVector4a*) vert.get();
}
if (rebuild_normal)
{
- mVertexBuffer->getNormalStrider(normals, mGeomIndex);
+ mVertexBuffer->getNormalStrider(norm, mGeomIndex);
+ normals = (LLVector4a*) norm.get();
}
if (rebuild_binormal)
{
- mVertexBuffer->getBinormalStrider(binormals, mGeomIndex);
+ mVertexBuffer->getBinormalStrider(binorm, mGeomIndex);
+ binormals = (LLVector4a*) binorm.get();
}
-
+ if (rebuild_weights)
+ {
+ mVertexBuffer->getWeight4Strider(wght, mGeomIndex);
+ weights = (LLVector4a*) wght.get();
+ }
+
F32 tcoord_xoffset = 0.f ;
F32 tcoord_yoffset = 0.f ;
F32 tcoord_xscale = 1.f ;
@@ -1052,8 +1130,6 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
mVertexBuffer->getColorStrider(colors, mGeomIndex);
}
- F32 r = 0, os = 0, ot = 0, ms = 0, mt = 0, cos_ang = 0, sin_ang = 0;
-
BOOL is_static = mDrawablep->isStatic();
BOOL is_global = is_static;
@@ -1068,59 +1144,6 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
clearState(GLOBAL);
}
- LLVector2 tmin, tmax;
-
-
-
- if (rebuild_tcoord)
- {
- if (tep)
- {
- r = tep->getRotation();
- os = tep->mOffsetS;
- ot = tep->mOffsetT;
- ms = tep->mScaleS;
- mt = tep->mScaleT;
- cos_ang = cos(r);
- sin_ang = sin(r);
- }
- else
- {
- cos_ang = 1.0f;
- sin_ang = 0.0f;
- os = 0.0f;
- ot = 0.0f;
- ms = 1.0f;
- mt = 1.0f;
- }
- }
-
- U8 tex_mode = 0;
-
- if (isState(TEXTURE_ANIM))
- {
- LLVOVolume* vobj = (LLVOVolume*) (LLViewerObject*) mVObjp;
- tex_mode = vobj->mTexAnimMode;
-
- if (!tex_mode)
- {
- clearState(TEXTURE_ANIM);
- }
- else
- {
- os = ot = 0.f;
- r = 0.f;
- cos_ang = 1.f;
- sin_ang = 0.f;
- ms = mt = 1.f;
- }
-
- if (getVirtualSize() >= MIN_TEX_ANIM_SIZE)
- { //don't override texture transform during tc bake
- tex_mode = 0;
- }
- }
-
LLColor4U color = tep->getColor();
if (rebuild_color)
@@ -1142,265 +1165,469 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
}
}
- // INDICES
+ // INDICES
if (full_rebuild)
{
mVertexBuffer->getIndexStrider(indicesp, mIndicesIndex);
- if (LLPipeline::sUseTriStrips)
+ __m128i* dst = (__m128i*) indicesp.get();
+ __m128i* src = (__m128i*) vf.mIndices;
+ __m128i offset = _mm_set1_epi16(index_offset);
+
+ S32 end = num_indices/8;
+
+ for (S32 i = 0; i < end; i++)
{
- for (U32 i = 0; i < (U32) num_indices; i++)
- {
- *indicesp++ = vf.mTriStrip[i] + index_offset;
- }
+ __m128i res = _mm_add_epi16(src[i], offset);
+ _mm_storeu_si128(dst+i, res);
}
- else
+
+ for (S32 i = end*8; i < num_indices; ++i)
{
- for (U32 i = 0; i < (U32) num_indices; i++)
- {
- *indicesp++ = vf.mIndices[i] + index_offset;
- }
+ indicesp[i] = vf.mIndices[i]+index_offset;
}
}
+ LLMatrix4a mat_normal;
+ mat_normal.loadu(mat_norm_in);
- //bump setup
- LLVector3 binormal_dir( -sin_ang, cos_ang, 0 );
- LLVector3 bump_s_primary_light_ray;
- LLVector3 bump_t_primary_light_ray;
+ //if it's not fullbright and has no normals, bake sunlight based on face normal
+ //bool bake_sunlight = !getTextureEntry()->getFullbright() &&
+ // !mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_NORMAL);
- LLQuaternion bump_quat;
- if (mDrawablep->isActive())
- {
- bump_quat = LLQuaternion(mDrawablep->getRenderMatrix());
- }
-
- if (bump_code)
+ F32 r = 0, os = 0, ot = 0, ms = 0, mt = 0, cos_ang = 0, sin_ang = 0;
+
+ if (rebuild_tcoord)
{
- mVObjp->getVolume()->genBinormals(f);
- F32 offset_multiple;
- switch( bump_code )
+ bool do_xform;
+
+ if (tep)
{
- case BE_NO_BUMP:
- offset_multiple = 0.f;
- break;
- case BE_BRIGHTNESS:
- case BE_DARKNESS:
- if( mTexture.notNull() && mTexture->hasGLTexture())
+ r = tep->getRotation();
+ os = tep->mOffsetS;
+ ot = tep->mOffsetT;
+ ms = tep->mScaleS;
+ mt = tep->mScaleT;
+ cos_ang = cos(r);
+ sin_ang = sin(r);
+
+ if (cos_ang != 1.f ||
+ sin_ang != 0.f ||
+ os != 0.f ||
+ ot != 0.f ||
+ ms != 1.f ||
+ mt != 1.f)
{
- // Offset by approximately one texel
- S32 cur_discard = mTexture->getDiscardLevel();
- S32 max_size = llmax( mTexture->getWidth(), mTexture->getHeight() );
- max_size <<= cur_discard;
- const F32 ARTIFICIAL_OFFSET = 2.f;
- offset_multiple = ARTIFICIAL_OFFSET / (F32)max_size;
+ do_xform = true;
}
else
{
- offset_multiple = 1.f/256;
- }
- break;
-
- default: // Standard bumpmap textures. Assumed to be 256x256
- offset_multiple = 1.f / 256;
- break;
+ do_xform = false;
+ }
}
-
- F32 s_scale = 1.f;
- F32 t_scale = 1.f;
- if( tep )
+ else
{
- tep->getScale( &s_scale, &t_scale );
+ do_xform = false;
}
- // Use the nudged south when coming from above sun angle, such
- // that emboss mapping always shows up on the upward faces of cubes when
- // it's noon (since a lot of builders build with the sun forced to noon).
- LLVector3 sun_ray = gSky.mVOSkyp->mBumpSunDir;
- LLVector3 moon_ray = gSky.getMoonDirection();
- LLVector3& primary_light_ray = (sun_ray.mV[VZ] > 0) ? sun_ray : moon_ray;
+
+ //bump setup
+ LLVector4a binormal_dir( -sin_ang, cos_ang, 0.f );
+ LLVector4a bump_s_primary_light_ray(0.f, 0.f, 0.f);
+ LLVector4a bump_t_primary_light_ray(0.f, 0.f, 0.f);
- bump_s_primary_light_ray = offset_multiple * s_scale * primary_light_ray;
- bump_t_primary_light_ray = offset_multiple * t_scale * primary_light_ray;
- }
-
- U8 texgen = getTextureEntry()->getTexGen();
- if (rebuild_tcoord && texgen != LLTextureEntry::TEX_GEN_DEFAULT)
- { //planar texgen needs binormals
- mVObjp->getVolume()->genBinormals(f);
- }
-
- for (S32 i = 0; i < num_vertices; i++)
- {
- if (rebuild_tcoord)
+ LLQuaternion bump_quat;
+ if (mDrawablep->isActive())
{
- LLVector2 tc = vf.mVertices[i].mTexCoord;
+ bump_quat = LLQuaternion(mDrawablep->getRenderMatrix());
+ }
- if (texgen != LLTextureEntry::TEX_GEN_DEFAULT)
+ if (bump_code)
+ {
+ mVObjp->getVolume()->genBinormals(f);
+ F32 offset_multiple;
+ switch( bump_code )
{
- LLVector3 vec = vf.mVertices[i].mPosition;
-
- vec.scaleVec(scale);
-
- switch (texgen)
+ case BE_NO_BUMP:
+ offset_multiple = 0.f;
+ break;
+ case BE_BRIGHTNESS:
+ case BE_DARKNESS:
+ if( mTexture.notNull() && mTexture->hasGLTexture())
{
- case LLTextureEntry::TEX_GEN_PLANAR:
- planarProjection(tc, vf.mVertices[i].mNormal, vf.mCenter, vec);
- break;
- case LLTextureEntry::TEX_GEN_SPHERICAL:
- sphericalProjection(tc, vf.mVertices[i].mNormal, vf.mCenter, vec);
- break;
- case LLTextureEntry::TEX_GEN_CYLINDRICAL:
- cylindricalProjection(tc, vf.mVertices[i].mNormal, vf.mCenter, vec);
- break;
- default:
- break;
- }
+ // Offset by approximately one texel
+ S32 cur_discard = mTexture->getDiscardLevel();
+ S32 max_size = llmax( mTexture->getWidth(), mTexture->getHeight() );
+ max_size <<= cur_discard;
+ const F32 ARTIFICIAL_OFFSET = 2.f;
+ offset_multiple = ARTIFICIAL_OFFSET / (F32)max_size;
+ }
+ else
+ {
+ offset_multiple = 1.f/256;
+ }
+ break;
+
+ default: // Standard bumpmap textures. Assumed to be 256x256
+ offset_multiple = 1.f / 256;
+ break;
+ }
+
+ F32 s_scale = 1.f;
+ F32 t_scale = 1.f;
+ if( tep )
+ {
+ tep->getScale( &s_scale, &t_scale );
}
+ // Use the nudged south when coming from above sun angle, such
+ // that emboss mapping always shows up on the upward faces of cubes when
+ // it's noon (since a lot of builders build with the sun forced to noon).
+ LLVector3 sun_ray = gSky.mVOSkyp->mBumpSunDir;
+ LLVector3 moon_ray = gSky.getMoonDirection();
+ LLVector3& primary_light_ray = (sun_ray.mV[VZ] > 0) ? sun_ray : moon_ray;
+
+ bump_s_primary_light_ray.load3((offset_multiple * s_scale * primary_light_ray).mV);
+ bump_t_primary_light_ray.load3((offset_multiple * t_scale * primary_light_ray).mV);
+ }
+
+ U8 texgen = getTextureEntry()->getTexGen();
+ if (rebuild_tcoord && texgen != LLTextureEntry::TEX_GEN_DEFAULT)
+ { //planar texgen needs binormals
+ mVObjp->getVolume()->genBinormals(f);
+ }
+
+ U8 tex_mode = 0;
+
+ if (isState(TEXTURE_ANIM))
+ {
+ LLVOVolume* vobj = (LLVOVolume*) (LLViewerObject*) mVObjp;
+ tex_mode = vobj->mTexAnimMode;
- if (tex_mode && mTextureMatrix)
+ if (!tex_mode)
{
- LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f);
- tmp = tmp * *mTextureMatrix;
- tc.mV[0] = tmp.mV[0];
- tc.mV[1] = tmp.mV[1];
+ clearState(TEXTURE_ANIM);
}
else
{
- xform(tc, cos_ang, sin_ang, os, ot, ms, mt);
+ os = ot = 0.f;
+ r = 0.f;
+ cos_ang = 1.f;
+ sin_ang = 0.f;
+ ms = mt = 1.f;
+
+ do_xform = false;
}
- if(in_atlas)
- {
- //
- //manually calculate tex-coord per vertex for varying address modes.
- //should be removed if shader can handle this.
- //
+ if (getVirtualSize() >= MIN_TEX_ANIM_SIZE)
+ { //don't override texture transform during tc bake
+ tex_mode = 0;
+ }
+ }
- S32 int_part = 0 ;
- switch(mTexture->getAddressMode())
- {
- case LLTexUnit::TAM_CLAMP:
- if(tc.mV[0] < 0.f)
- {
- tc.mV[0] = 0.f ;
- }
- else if(tc.mV[0] > 1.f)
- {
- tc.mV[0] = 1.f;
- }
+ LLVector4a scalea;
+ scalea.load3(scale.mV);
- if(tc.mV[1] < 0.f)
- {
- tc.mV[1] = 0.f ;
- }
- else if(tc.mV[1] > 1.f)
- {
- tc.mV[1] = 1.f;
- }
- break;
- case LLTexUnit::TAM_MIRROR:
- if(tc.mV[0] < 0.f)
- {
- tc.mV[0] = -tc.mV[0] ;
- }
- int_part = (S32)tc.mV[0] ;
- if(int_part & 1) //odd number
- {
- tc.mV[0] = int_part + 1 - tc.mV[0] ;
- }
- else //even number
- {
- tc.mV[0] -= int_part ;
- }
+ bool do_bump = bump_code && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1);
+ bool do_tex_mat = tex_mode && mTextureMatrix;
- if(tc.mV[1] < 0.f)
+ if (!in_atlas && !do_bump)
+ { //not in atlas or not bump mapped, might be able to do a cheap update
+ if (texgen != LLTextureEntry::TEX_GEN_PLANAR)
+ {
+ if (!do_tex_mat)
+ {
+ if (!do_xform)
{
- tc.mV[1] = -tc.mV[1] ;
+ LLVector4a::memcpyNonAliased16((F32*) tex_coords.get(), (F32*) vf.mTexCoords, num_vertices*2*sizeof(F32));
}
- int_part = (S32)tc.mV[1] ;
- if(int_part & 1) //odd number
+ else
{
- tc.mV[1] = int_part + 1 - tc.mV[1] ;
+ for (S32 i = 0; i < num_vertices; i++)
+ {
+ LLVector2 tc(vf.mTexCoords[i]);
+ xform(tc, cos_ang, sin_ang, os, ot, ms, mt);
+ *tex_coords++ = tc;
+ }
}
- else //even number
- {
- tc.mV[1] -= int_part ;
+ }
+ else
+ { //do tex mat, no texgen, no atlas, no bump
+ for (S32 i = 0; i < num_vertices; i++)
+ {
+ LLVector2 tc(vf.mTexCoords[i]);
+ //LLVector4a& norm = vf.mNormals[i];
+ //LLVector4a& center = *(vf.mCenter);
+
+ LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f);
+ tmp = tmp * *mTextureMatrix;
+ tc.mV[0] = tmp.mV[0];
+ tc.mV[1] = tmp.mV[1];
+ *tex_coords++ = tc;
}
- break;
- case LLTexUnit::TAM_WRAP:
- if(tc.mV[0] > 1.f)
- tc.mV[0] -= (S32)(tc.mV[0] - 0.00001f) ;
- else if(tc.mV[0] < -1.f)
- tc.mV[0] -= (S32)(tc.mV[0] + 0.00001f) ;
-
- if(tc.mV[1] > 1.f)
- tc.mV[1] -= (S32)(tc.mV[1] - 0.00001f) ;
- else if(tc.mV[1] < -1.f)
- tc.mV[1] -= (S32)(tc.mV[1] + 0.00001f) ;
-
- if(tc.mV[0] < 0.f)
- {
- tc.mV[0] = 1.0f + tc.mV[0] ;
+ }
+ }
+ else
+ { //no bump, no atlas, tex gen planar
+ if (do_tex_mat)
+ {
+ for (S32 i = 0; i < num_vertices; i++)
+ {
+ LLVector2 tc(vf.mTexCoords[i]);
+ LLVector4a& norm = vf.mNormals[i];
+ LLVector4a& center = *(vf.mCenter);
+ LLVector4a vec = vf.mPositions[i];
+ vec.mul(scalea);
+ planarProjection(tc, norm, center, vec);
+
+ LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f);
+ tmp = tmp * *mTextureMatrix;
+ tc.mV[0] = tmp.mV[0];
+ tc.mV[1] = tmp.mV[1];
+
+ *tex_coords++ = tc;
}
- if(tc.mV[1] < 0.f)
- {
- tc.mV[1] = 1.0f + tc.mV[1] ;
+ }
+ else
+ {
+ for (S32 i = 0; i < num_vertices; i++)
+ {
+ LLVector2 tc(vf.mTexCoords[i]);
+ LLVector4a& norm = vf.mNormals[i];
+ LLVector4a& center = *(vf.mCenter);
+ LLVector4a vec = vf.mPositions[i];
+ vec.mul(scalea);
+ planarProjection(tc, norm, center, vec);
+
+ xform(tc, cos_ang, sin_ang, os, ot, ms, mt);
+
+ *tex_coords++ = tc;
}
- break;
- default:
- break;
}
-
- tc.mV[0] = tcoord_xoffset + tcoord_xscale * tc.mV[0] ;
- tc.mV[1] = tcoord_yoffset + tcoord_yscale * tc.mV[1] ;
}
+ }
+ else
+ { //either bump mapped or in atlas, just do the whole expensive loop
+ for (S32 i = 0; i < num_vertices; i++)
+ {
+ LLVector2 tc(vf.mTexCoords[i]);
+ LLVector4a& norm = vf.mNormals[i];
+
+ LLVector4a& center = *(vf.mCenter);
+
+ if (texgen != LLTextureEntry::TEX_GEN_DEFAULT)
+ {
+ LLVector4a vec = vf.mPositions[i];
+
+ vec.mul(scalea);
- *tex_coords++ = tc;
-
- if (bump_code && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1))
- {
- LLVector3 tangent = vf.mVertices[i].mBinormal % vf.mVertices[i].mNormal;
+ switch (texgen)
+ {
+ case LLTextureEntry::TEX_GEN_PLANAR:
+ planarProjection(tc, norm, center, vec);
+ break;
+ case LLTextureEntry::TEX_GEN_SPHERICAL:
+ sphericalProjection(tc, norm, center, vec);
+ break;
+ case LLTextureEntry::TEX_GEN_CYLINDRICAL:
+ cylindricalProjection(tc, norm, center, vec);
+ break;
+ default:
+ break;
+ }
+ }
- LLMatrix3 tangent_to_object;
- tangent_to_object.setRows(tangent, vf.mVertices[i].mBinormal, vf.mVertices[i].mNormal);
- LLVector3 binormal = binormal_dir * tangent_to_object;
- binormal = binormal * mat_normal;
-
- if (mDrawablep->isActive())
+ if (tex_mode && mTextureMatrix)
{
- binormal *= bump_quat;
+ LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f);
+ tmp = tmp * *mTextureMatrix;
+ tc.mV[0] = tmp.mV[0];
+ tc.mV[1] = tmp.mV[1];
+ }
+ else
+ {
+ xform(tc, cos_ang, sin_ang, os, ot, ms, mt);
}
- binormal.normVec();
- tc += LLVector2( bump_s_primary_light_ray * tangent, bump_t_primary_light_ray * binormal );
+ if(in_atlas)
+ {
+ //
+ //manually calculate tex-coord per vertex for varying address modes.
+ //should be removed if shader can handle this.
+ //
+
+ S32 int_part = 0 ;
+ switch(mTexture->getAddressMode())
+ {
+ case LLTexUnit::TAM_CLAMP:
+ if(tc.mV[0] < 0.f)
+ {
+ tc.mV[0] = 0.f ;
+ }
+ else if(tc.mV[0] > 1.f)
+ {
+ tc.mV[0] = 1.f;
+ }
+
+ if(tc.mV[1] < 0.f)
+ {
+ tc.mV[1] = 0.f ;
+ }
+ else if(tc.mV[1] > 1.f)
+ {
+ tc.mV[1] = 1.f;
+ }
+ break;
+ case LLTexUnit::TAM_MIRROR:
+ if(tc.mV[0] < 0.f)
+ {
+ tc.mV[0] = -tc.mV[0] ;
+ }
+ int_part = (S32)tc.mV[0] ;
+ if(int_part & 1) //odd number
+ {
+ tc.mV[0] = int_part + 1 - tc.mV[0] ;
+ }
+ else //even number
+ {
+ tc.mV[0] -= int_part ;
+ }
+
+ if(tc.mV[1] < 0.f)
+ {
+ tc.mV[1] = -tc.mV[1] ;
+ }
+ int_part = (S32)tc.mV[1] ;
+ if(int_part & 1) //odd number
+ {
+ tc.mV[1] = int_part + 1 - tc.mV[1] ;
+ }
+ else //even number
+ {
+ tc.mV[1] -= int_part ;
+ }
+ break;
+ case LLTexUnit::TAM_WRAP:
+ if(tc.mV[0] > 1.f)
+ tc.mV[0] -= (S32)(tc.mV[0] - 0.00001f) ;
+ else if(tc.mV[0] < -1.f)
+ tc.mV[0] -= (S32)(tc.mV[0] + 0.00001f) ;
+
+ if(tc.mV[1] > 1.f)
+ tc.mV[1] -= (S32)(tc.mV[1] - 0.00001f) ;
+ else if(tc.mV[1] < -1.f)
+ tc.mV[1] -= (S32)(tc.mV[1] + 0.00001f) ;
+
+ if(tc.mV[0] < 0.f)
+ {
+ tc.mV[0] = 1.0f + tc.mV[0] ;
+ }
+ if(tc.mV[1] < 0.f)
+ {
+ tc.mV[1] = 1.0f + tc.mV[1] ;
+ }
+ break;
+ default:
+ break;
+ }
- *tex_coords2++ = tc;
- }
+ tc.mV[0] = tcoord_xoffset + tcoord_xscale * tc.mV[0] ;
+ tc.mV[1] = tcoord_yoffset + tcoord_yscale * tc.mV[1] ;
+ }
+
+
+ *tex_coords++ = tc;
+
+ if (bump_code && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1))
+ {
+ LLVector4a tangent;
+ tangent.setCross3(vf.mBinormals[i], vf.mNormals[i]);
+
+ LLMatrix4a tangent_to_object;
+ tangent_to_object.setRows(tangent, vf.mBinormals[i], vf.mNormals[i]);
+ LLVector4a t;
+ tangent_to_object.rotate(binormal_dir, t);
+ LLVector4a binormal;
+ mat_normal.rotate(t, binormal);
+
+ //VECTORIZE THIS
+ if (mDrawablep->isActive())
+ {
+ LLVector3 t;
+ t.set(binormal.getF32ptr());
+ t *= bump_quat;
+ binormal.load3(t.mV);
+ }
+
+ binormal.normalize3fast();
+ tc += LLVector2( bump_s_primary_light_ray.dot3(tangent).getF32(), bump_t_primary_light_ray.dot3(binormal).getF32() );
+
+ *tex_coords2++ = tc;
+ }
+ }
}
-
- if (rebuild_pos)
- {
- *vertices++ = vf.mVertices[i].mPosition * mat_vert;
+ }
+
+ if (rebuild_pos)
+ {
+ LLMatrix4a mat_vert;
+ mat_vert.loadu(mat_vert_in);
+
+ LLVector4a* src = vf.mPositions;
+ LLVector4a* dst = vertices;
+
+ LLVector4a* end = dst+num_vertices;
+ do
+ {
+ mat_vert.affineTransform(*src++, *dst++);
}
+ while(dst < end);
+ }
- if (rebuild_normal)
- {
- LLVector3 normal = vf.mVertices[i].mNormal * mat_normal;
- normal.normVec();
-
- *normals++ = normal;
+ if (rebuild_normal)
+ {
+ for (S32 i = 0; i < num_vertices; i++)
+ {
+ LLVector4a normal;
+ mat_normal.rotate(vf.mNormals[i], normal);
+ normal.normalize3fast();
+ normals[i] = normal;
}
+ }
- if (rebuild_binormal)
- {
- LLVector3 binormal = vf.mVertices[i].mBinormal * mat_normal;
- binormal.normVec();
- *binormals++ = binormal;
+ if (rebuild_binormal)
+ {
+ for (S32 i = 0; i < num_vertices; i++)
+ {
+ LLVector4a binormal;
+ mat_normal.rotate(vf.mBinormals[i], binormal);
+ binormal.normalize3fast();
+ binormals[i] = binormal;
}
+ }
+
+ if (rebuild_weights && vf.mWeights)
+ {
+ LLVector4a::memcpyNonAliased16((F32*) weights, (F32*) vf.mWeights, num_vertices*4*sizeof(F32));
+ }
+
+ if (rebuild_color)
+ {
+ LLVector4a src;
+
+ U32 vec[4];
+ vec[0] = vec[1] = vec[2] = vec[3] = color.mAll;
- if (rebuild_color)
+ src.loadua((F32*) vec);
+
+ LLVector4a* dst = (LLVector4a*) colors.get();
+ S32 num_vecs = num_vertices/4;
+ if (num_vertices%4 > 0)
{
- *colors++ = color;
+ ++num_vecs;
+ }
+
+ for (S32 i = 0; i < num_vecs; i++)
+ {
+ dst[i] = src;
}
}
@@ -1409,7 +1636,14 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
mTexExtents[0].setVec(0,0);
mTexExtents[1].setVec(1,1);
xform(mTexExtents[0], cos_ang, sin_ang, os, ot, ms, mt);
- xform(mTexExtents[1], cos_ang, sin_ang, os, ot, ms, mt);
+ xform(mTexExtents[1], cos_ang, sin_ang, os, ot, ms, mt);
+
+ F32 es = vf.mTexCoordExtents[1].mV[0] - vf.mTexCoordExtents[0].mV[0] ;
+ F32 et = vf.mTexCoordExtents[1].mV[1] - vf.mTexCoordExtents[0].mV[1] ;
+ mTexExtents[0][0] *= es ;
+ mTexExtents[1][0] *= es ;
+ mTexExtents[0][1] *= et ;
+ mTexExtents[1][1] *= et ;
}
mLastVertexBuffer = mVertexBuffer;
@@ -1489,20 +1723,32 @@ F32 LLFace::getTextureVirtualSize()
BOOL LLFace::calcPixelArea(F32& cos_angle_to_view_dir, F32& radius)
{
+ //VECTORIZE THIS
//get area of circle around face
- LLVector3 center = getPositionAgent();
- LLVector3 size = (mExtents[1] - mExtents[0]) * 0.5f;
+ LLVector4a center;
+ center.load3(getPositionAgent().mV);
+ LLVector4a size;
+ size.setSub(mExtents[1], mExtents[0]);
+ size.mul(0.5f);
+
LLViewerCamera* camera = LLViewerCamera::getInstance();
- F32 size_squared = size.lengthSquared() ;
- LLVector3 lookAt = center - camera->getOrigin();
- F32 dist = lookAt.normVec() ;
+ F32 size_squared = size.dot3(size).getF32();
+ LLVector4a lookAt;
+ LLVector4a t;
+ t.load3(camera->getOrigin().mV);
+ lookAt.setSub(center, t);
+ F32 dist = lookAt.getLength3().getF32();
+ dist = llmax(dist-size.getLength3().getF32(), 0.f);
+ lookAt.normalize3fast() ;
//get area of circle around node
- F32 app_angle = atanf(fsqrtf(size_squared) / dist);
+ F32 app_angle = atanf((F32) sqrt(size_squared) / dist);
radius = app_angle*LLDrawable::sCurPixelAngle;
mPixelArea = radius*radius * 3.14159f;
- cos_angle_to_view_dir = lookAt * camera->getXAxis() ;
+ LLVector4a x_axis;
+ x_axis.load3(camera->getXAxis().mV);
+ cos_angle_to_view_dir = lookAt.dot3(x_axis).getF32();
//if has media, check if the face is out of the view frustum.
if(hasMedia())
@@ -1518,7 +1764,10 @@ BOOL LLFace::calcPixelArea(F32& cos_angle_to_view_dir, F32& radius)
}
else
{
- if(dist * dist * (lookAt - camera->getXAxis()).lengthSquared() < size_squared)
+ LLVector4a d;
+ d.setSub(lookAt, x_axis);
+
+ if(dist * dist * d.dot3(d) < size_squared)
{
cos_angle_to_view_dir = 1.0f ;
}
@@ -1633,24 +1882,15 @@ BOOL LLFace::verify(const U32* indices_array) const
BOOL ok = TRUE;
if( mVertexBuffer.isNull() )
- {
- if( mGeomCount )
- {
- // This happens before teleports as faces are torn down.
- // Stop the crash in DEV-31893 with a null pointer check,
- // but present this info.
- // To clean up the log, the geometry could be cleared, or the
- // face could otherwise be marked for no ::verify.
- llinfos << "Face with no vertex buffer and " << mGeomCount << " mGeomCount" << llendl;
- }
+ { //no vertex buffer, face is implicitly valid
return TRUE;
}
// First, check whether the face data fits within the pool's range.
- if ((mGeomIndex + mGeomCount) > mVertexBuffer->getNumVerts())
+ if ((mGeomIndex + mGeomCount) > mVertexBuffer->getRequestedVerts())
{
ok = FALSE;
- llinfos << "Face not within pool range!" << llendl;
+ llinfos << "Face references invalid vertices!" << llendl;
}
S32 indices_count = (S32)getIndicesCount();
@@ -1666,6 +1906,12 @@ BOOL LLFace::verify(const U32* indices_array) const
llinfos << "Face has bogus indices count" << llendl;
}
+ if (mIndicesIndex + mIndicesCount > mVertexBuffer->getRequestedIndices())
+ {
+ ok = FALSE;
+ llinfos << "Face references invalid indices!" << llendl;
+ }
+
#if 0
S32 geom_start = getGeomStart();
S32 geom_count = mGeomCount;
@@ -1974,3 +2220,78 @@ BOOL LLFace::switchTexture()
return mUsingAtlas ;
}
+
+void LLFace::setVertexBuffer(LLVertexBuffer* buffer)
+{
+ mVertexBuffer = buffer;
+ llassert(verify());
+}
+
+void LLFace::clearVertexBuffer()
+{
+ mVertexBuffer = NULL;
+ mLastVertexBuffer = NULL;
+}
+
+//static
+U32 LLFace::getRiggedDataMask(U32 type)
+{
+ static const U32 rigged_data_mask[] = {
+ LLDrawPoolAvatar::RIGGED_SIMPLE_MASK,
+ LLDrawPoolAvatar::RIGGED_FULLBRIGHT_MASK,
+ LLDrawPoolAvatar::RIGGED_SHINY_MASK,
+ LLDrawPoolAvatar::RIGGED_FULLBRIGHT_SHINY_MASK,
+ LLDrawPoolAvatar::RIGGED_GLOW_MASK,
+ LLDrawPoolAvatar::RIGGED_ALPHA_MASK,
+ LLDrawPoolAvatar::RIGGED_FULLBRIGHT_ALPHA_MASK,
+ LLDrawPoolAvatar::RIGGED_DEFERRED_BUMP_MASK,
+ LLDrawPoolAvatar::RIGGED_DEFERRED_SIMPLE_MASK,
+ };
+
+ llassert(type < sizeof(rigged_data_mask)/sizeof(U32));
+
+ return rigged_data_mask[type];
+}
+
+U32 LLFace::getRiggedVertexBufferDataMask() const
+{
+ U32 data_mask = 0;
+ for (U32 i = 0; i < mRiggedIndex.size(); ++i)
+ {
+ if (mRiggedIndex[i] > -1)
+ {
+ data_mask |= LLFace::getRiggedDataMask(i);
+ }
+ }
+
+ return data_mask;
+}
+
+S32 LLFace::getRiggedIndex(U32 type) const
+{
+ if (mRiggedIndex.empty())
+ {
+ return -1;
+ }
+
+ llassert(type < mRiggedIndex.size());
+
+ return mRiggedIndex[type];
+}
+
+void LLFace::setRiggedIndex(U32 type, S32 index)
+{
+ if (mRiggedIndex.empty())
+ {
+ mRiggedIndex.resize(LLDrawPoolAvatar::NUM_RIGGED_PASSES);
+ for (U32 i = 0; i < mRiggedIndex.size(); ++i)
+ {
+ mRiggedIndex[i] = -1;
+ }
+ }
+
+ llassert(type < mRiggedIndex.size());
+
+ mRiggedIndex[type] = index;
+}
+
diff --git a/indra/newview/llface.h b/indra/newview/llface.h
index 0166e45bee..b2170c4cf3 100644
--- a/indra/newview/llface.h
+++ b/indra/newview/llface.h
@@ -59,6 +59,17 @@ class LLFace
{
public:
+ LLFace(const LLFace& rhs)
+ {
+ *this = rhs;
+ }
+
+ const LLFace& operator=(const LLFace& rhs)
+ {
+ llerrs << "Illegal operation!" << llendl;
+ return *this;
+ }
+
enum EMasks
{
LIGHT = 0x0001,
@@ -67,6 +78,7 @@ public:
HUD_RENDER = 0x0008,
USE_FACE_COLOR = 0x0010,
TEXTURE_ANIM = 0x0020,
+ RIGGED = 0x0040,
};
static void initClass();
@@ -119,14 +131,14 @@ public:
LLDrawable* getDrawable() const { return mDrawablep; }
LLViewerObject* getViewerObject() const { return mVObjp; }
S32 getLOD() const { return mVObjp.notNull() ? mVObjp->getLOD() : 0; }
- LLVertexBuffer* getVertexBuffer() const { return mVertexBuffer; }
void setPoolType(U32 type) { mPoolType = type; }
S32 getTEOffset() { return mTEOffset; }
LLViewerTexture* getTexture() const;
void setViewerObject(LLViewerObject* object);
void setPool(LLFacePool *pool, LLViewerTexture *texturep);
-
+ void setPool(LLFacePool* pool);
+
void setDrawable(LLDrawable *drawable);
void setTEOffset(const S32 te_offset);
@@ -142,7 +154,8 @@ public:
BOOL getGeometryVolume(const LLVolume& volume,
const S32 &f,
const LLMatrix4& mat_vert, const LLMatrix3& mat_normal,
- const U16 &index_offset);
+ const U16 &index_offset,
+ bool force_rebuild = false);
// For avatar
U16 getGeometryAvatar(
@@ -161,7 +174,7 @@ public:
S32 getColors(LLStrider<LLColor4U> &colors);
S32 getIndices(LLStrider<U16> &indices);
- void setSize(const S32 numVertices, const S32 num_indices = 0);
+ void setSize(S32 numVertices, S32 num_indices = 0, bool align = false);
BOOL genVolumeBBoxes(const LLVolume &volume, S32 f,
const LLMatrix4& mat, const LLMatrix3& inv_trans_mat, BOOL global_volume = FALSE);
@@ -173,7 +186,6 @@ public:
void updateCenterAgent(); // Update center when xform has changed.
void renderSelectedUV();
- void renderForSelect(U32 data_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0);
void renderSelected(LLViewerTexture *image, const LLColor4 &color);
F32 getKey() const { return mDistance; }
@@ -184,8 +196,8 @@ public:
BOOL verify(const U32* indices_array = NULL) const;
void printDebugInfo() const;
- void setGeomIndex(U16 idx) { mGeomIndex = idx; }
- void setIndicesIndex(S32 idx) { mIndicesIndex = idx; }
+ void setGeomIndex(U16 idx);
+ void setIndicesIndex(S32 idx);
void setDrawInfo(LLDrawInfo* draw_info);
F32 getTextureVirtualSize() ;
@@ -206,6 +218,19 @@ public:
void removeAtlas() ;
BOOL switchTexture() ;
+ //vertex buffer tracking
+ void setVertexBuffer(LLVertexBuffer* buffer);
+ void clearVertexBuffer(); //sets mVertexBuffer and mLastVertexBuffer to NULL
+ LLVertexBuffer* getVertexBuffer() const { return mVertexBuffer; }
+ U32 getRiggedVertexBufferDataMask() const;
+ S32 getRiggedIndex(U32 type) const;
+ void setRiggedIndex(U32 type, S32 index);
+
+ static U32 getRiggedDataMask(U32 type);
+
+public: //aligned members
+ LLVector4a mExtents[2];
+
private:
F32 adjustPartialOverlapPixelArea(F32 cos_angle_to_view_dir, F32 radius );
BOOL calcPixelArea(F32& cos_angle_to_view_dir, F32& radius) ;
@@ -217,20 +242,19 @@ public:
LLVector3 mCenterLocal;
LLVector3 mCenterAgent;
- LLVector3 mExtents[2];
+
LLVector2 mTexExtents[2];
F32 mDistance;
- LLPointer<LLVertexBuffer> mVertexBuffer;
- LLPointer<LLVertexBuffer> mLastVertexBuffer;
F32 mLastUpdateTime;
+ F32 mLastSkinTime;
F32 mLastMoveTime;
LLMatrix4* mTextureMatrix;
LLDrawInfo* mDrawInfo;
private:
- friend class LLGeometryManager;
- friend class LLVolumeGeometryManager;
-
+ LLPointer<LLVertexBuffer> mVertexBuffer;
+ LLPointer<LLVertexBuffer> mLastVertexBuffer;
+
U32 mState;
LLFacePool* mDrawPoolp;
U32 mPoolType;
@@ -255,6 +279,8 @@ private:
S32 mTEOffset;
S32 mReferenceIndex;
+ std::vector<S32> mRiggedIndex;
+
F32 mVSize;
F32 mPixelArea;
diff --git a/indra/newview/llfasttimerview.cpp b/indra/newview/llfasttimerview.cpp
index a09c0ea0f8..35712163eb 100644
--- a/indra/newview/llfasttimerview.cpp
+++ b/indra/newview/llfasttimerview.cpp
@@ -32,7 +32,9 @@
#include "llrect.h"
#include "llerror.h"
#include "llgl.h"
+#include "llimagepng.h"
#include "llrender.h"
+#include "llrendertarget.h"
#include "lllocalcliprect.h"
#include "llmath.h"
#include "llfontgl.h"
@@ -49,6 +51,8 @@
#include "llfasttimer.h"
#include "lltreeiterators.h"
#include "llmetricperformancetester.h"
+#include "llviewerstats.h"
+
//////////////////////////////////////////////////////////////////////////////
static const S32 MAX_VISIBLE_HISTORY = 10;
@@ -1020,6 +1024,327 @@ F64 LLFastTimerView::getTime(const std::string& name)
return 0.0;
}
+void saveChart(const std::string& label, const char* suffix, LLImageRaw* scratch)
+{
+ //read result back into raw image
+ glReadPixels(0, 0, 1024, 512, GL_RGB, GL_UNSIGNED_BYTE, scratch->getData());
+
+ //write results to disk
+ LLPointer<LLImagePNG> result = new LLImagePNG();
+ result->encode(scratch, 0.f);
+
+ std::string ext = result->getExtension();
+ std::string filename = llformat("%s_%s.%s", label.c_str(), suffix, ext.c_str());
+
+ std::string out_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, filename);
+ result->save(out_file);
+}
+
+//static
+void LLFastTimerView::exportCharts(const std::string& base, const std::string& target)
+{
+ //allocate render target for drawing charts
+ LLRenderTarget buffer;
+ buffer.allocate(1024,512, GL_RGB, FALSE, FALSE);
+
+
+ LLSD cur;
+
+ LLSD base_data;
+
+ { //read base log into memory
+ S32 i = 0;
+ std::ifstream is(base.c_str());
+ while (!is.eof() && LLSDSerialize::fromXML(cur, is))
+ {
+ base_data[i++] = cur;
+ }
+ is.close();
+ }
+
+ LLSD cur_data;
+ std::set<std::string> chart_names;
+
+ { //read current log into memory
+ S32 i = 0;
+ std::ifstream is(target.c_str());
+ while (!is.eof() && LLSDSerialize::fromXML(cur, is))
+ {
+ cur_data[i++] = cur;
+
+ for (LLSD::map_iterator iter = cur.beginMap(); iter != cur.endMap(); ++iter)
+ {
+ std::string label = iter->first;
+ chart_names.insert(label);
+ }
+ }
+ is.close();
+ }
+
+ //get time domain
+ LLSD::Real cur_total_time = 0.0;
+
+ for (U32 i = 0; i < cur_data.size(); ++i)
+ {
+ cur_total_time += cur_data[i]["Total"]["Time"].asReal();
+ }
+
+ LLSD::Real base_total_time = 0.0;
+ for (U32 i = 0; i < base_data.size(); ++i)
+ {
+ base_total_time += base_data[i]["Total"]["Time"].asReal();
+ }
+
+ //allocate raw scratch space
+ LLPointer<LLImageRaw> scratch = new LLImageRaw(1024, 512, 3);
+
+ gGL.pushMatrix();
+ glLoadIdentity();
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(-0.05, 1.05, -0.05, 1.05, -1.0, 1.0);
+
+ //render charts
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+ buffer.bindTarget();
+
+ for (std::set<std::string>::iterator iter = chart_names.begin(); iter != chart_names.end(); ++iter)
+ {
+ std::string label = *iter;
+
+ LLSD::Real max_time = 0.0;
+ LLSD::Integer max_calls = 0;
+ LLSD::Real max_execution = 0.0;
+
+ std::vector<LLSD::Real> cur_execution;
+ std::vector<LLSD::Real> cur_times;
+ std::vector<LLSD::Integer> cur_calls;
+
+ std::vector<LLSD::Real> base_execution;
+ std::vector<LLSD::Real> base_times;
+ std::vector<LLSD::Integer> base_calls;
+
+ for (U32 i = 0; i < cur_data.size(); ++i)
+ {
+ LLSD::Real time = cur_data[i][label]["Time"].asReal();
+ LLSD::Integer calls = cur_data[i][label]["Calls"].asInteger();
+
+ LLSD::Real execution = 0.0;
+ if (calls > 0)
+ {
+ execution = time/calls;
+ cur_execution.push_back(execution);
+ cur_times.push_back(time);
+ }
+
+ cur_calls.push_back(calls);
+ }
+
+ for (U32 i = 0; i < base_data.size(); ++i)
+ {
+ LLSD::Real time = base_data[i][label]["Time"].asReal();
+ LLSD::Integer calls = base_data[i][label]["Calls"].asInteger();
+
+ LLSD::Real execution = 0.0;
+ if (calls > 0)
+ {
+ execution = time/calls;
+ base_execution.push_back(execution);
+ base_times.push_back(time);
+ }
+
+ base_calls.push_back(calls);
+ }
+
+ std::sort(base_calls.begin(), base_calls.end());
+ std::sort(base_times.begin(), base_times.end());
+ std::sort(base_execution.begin(), base_execution.end());
+
+ std::sort(cur_calls.begin(), cur_calls.end());
+ std::sort(cur_times.begin(), cur_times.end());
+ std::sort(cur_execution.begin(), cur_execution.end());
+
+ //remove outliers
+ const U32 OUTLIER_CUTOFF = 512;
+ if (base_times.size() > OUTLIER_CUTOFF)
+ {
+ ll_remove_outliers(base_times, 1.f);
+ }
+
+ if (base_execution.size() > OUTLIER_CUTOFF)
+ {
+ ll_remove_outliers(base_execution, 1.f);
+ }
+
+ if (cur_times.size() > OUTLIER_CUTOFF)
+ {
+ ll_remove_outliers(cur_times, 1.f);
+ }
+
+ if (cur_execution.size() > OUTLIER_CUTOFF)
+ {
+ ll_remove_outliers(cur_execution, 1.f);
+ }
+
+
+ max_time = llmax(base_times.empty() ? 0.0 : *base_times.rbegin(), cur_times.empty() ? 0.0 : *cur_times.rbegin());
+ max_calls = llmax(base_calls.empty() ? 0 : *base_calls.rbegin(), cur_calls.empty() ? 0 : *cur_calls.rbegin());
+ max_execution = llmax(base_execution.empty() ? 0.0 : *base_execution.rbegin(), cur_execution.empty() ? 0.0 : *cur_execution.rbegin());
+
+
+ LLVector3 last_p;
+
+ //====================================
+ // basic
+ //====================================
+ buffer.clear();
+
+ last_p.clear();
+
+ LLGLDisable cull(GL_CULL_FACE);
+
+ LLVector3 base_col(0, 0.7f, 0.f);
+ LLVector3 cur_col(1.f, 0.f, 0.f);
+
+ gGL.setSceneBlendType(LLRender::BT_ADD);
+
+ gGL.color3fv(base_col.mV);
+ for (U32 i = 0; i < base_times.size(); ++i)
+ {
+ gGL.begin(LLRender::TRIANGLE_STRIP);
+ gGL.vertex3fv(last_p.mV);
+ gGL.vertex3f(last_p.mV[0], 0.f, 0.f);
+ last_p.set((F32)i/(F32) base_times.size(), base_times[i]/max_time, 0.f);
+ gGL.vertex3fv(last_p.mV);
+ gGL.vertex3f(last_p.mV[0], 0.f, 0.f);
+ gGL.end();
+ }
+
+ gGL.flush();
+
+
+ last_p.clear();
+ {
+ LLGLEnable blend(GL_BLEND);
+
+ gGL.color3fv(cur_col.mV);
+ for (U32 i = 0; i < cur_times.size(); ++i)
+ {
+ gGL.begin(LLRender::TRIANGLE_STRIP);
+ gGL.vertex3f(last_p.mV[0], 0.f, 0.f);
+ gGL.vertex3fv(last_p.mV);
+ last_p.set((F32) i / (F32) cur_times.size(), cur_times[i]/max_time, 0.f);
+ gGL.vertex3f(last_p.mV[0], 0.f, 0.f);
+ gGL.vertex3fv(last_p.mV);
+ gGL.end();
+ }
+
+ gGL.flush();
+ }
+
+ saveChart(label, "time", scratch);
+
+ //======================================
+ // calls
+ //======================================
+ buffer.clear();
+
+ last_p.clear();
+
+ gGL.color3fv(base_col.mV);
+ for (U32 i = 0; i < base_calls.size(); ++i)
+ {
+ gGL.begin(LLRender::TRIANGLE_STRIP);
+ gGL.vertex3fv(last_p.mV);
+ gGL.vertex3f(last_p.mV[0], 0.f, 0.f);
+ last_p.set((F32) i / (F32) base_calls.size(), (F32)base_calls[i]/max_calls, 0.f);
+ gGL.vertex3fv(last_p.mV);
+ gGL.vertex3f(last_p.mV[0], 0.f, 0.f);
+ gGL.end();
+ }
+
+ gGL.flush();
+
+ {
+ LLGLEnable blend(GL_BLEND);
+ gGL.color3fv(cur_col.mV);
+ last_p.clear();
+
+ for (U32 i = 0; i < cur_calls.size(); ++i)
+ {
+ gGL.begin(LLRender::TRIANGLE_STRIP);
+ gGL.vertex3f(last_p.mV[0], 0.f, 0.f);
+ gGL.vertex3fv(last_p.mV);
+ last_p.set((F32) i / (F32) cur_calls.size(), (F32) cur_calls[i]/max_calls, 0.f);
+ gGL.vertex3f(last_p.mV[0], 0.f, 0.f);
+ gGL.vertex3fv(last_p.mV);
+ gGL.end();
+
+ }
+
+ gGL.flush();
+ }
+
+ saveChart(label, "calls", scratch);
+
+ //======================================
+ // execution
+ //======================================
+ buffer.clear();
+
+
+ gGL.color3fv(base_col.mV);
+ U32 count = 0;
+ U32 total_count = base_execution.size();
+
+ last_p.clear();
+
+ for (std::vector<LLSD::Real>::iterator iter = base_execution.begin(); iter != base_execution.end(); ++iter)
+ {
+ gGL.begin(LLRender::TRIANGLE_STRIP);
+ gGL.vertex3fv(last_p.mV);
+ gGL.vertex3f(last_p.mV[0], 0.f, 0.f);
+ last_p.set((F32)count/(F32)total_count, *iter/max_execution, 0.f);
+ gGL.vertex3fv(last_p.mV);
+ gGL.vertex3f(last_p.mV[0], 0.f, 0.f);
+ gGL.end();
+ count++;
+ }
+
+ last_p.clear();
+
+ {
+ LLGLEnable blend(GL_BLEND);
+ gGL.color3fv(cur_col.mV);
+ count = 0;
+ total_count = cur_execution.size();
+
+ for (std::vector<LLSD::Real>::iterator iter = cur_execution.begin(); iter != cur_execution.end(); ++iter)
+ {
+ gGL.begin(LLRender::TRIANGLE_STRIP);
+ gGL.vertex3f(last_p.mV[0], 0.f, 0.f);
+ gGL.vertex3fv(last_p.mV);
+ last_p.set((F32)count/(F32)total_count, *iter/max_execution, 0.f);
+ gGL.vertex3f(last_p.mV[0], 0.f, 0.f);
+ gGL.vertex3fv(last_p.mV);
+ gGL.end();
+ count++;
+ }
+
+ gGL.flush();
+ }
+
+ saveChart(label, "execution", scratch);
+ }
+
+ buffer.flush();
+
+ gGL.popMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ gGL.popMatrix();
+}
+
//static
LLSD LLFastTimerView::analyzePerformanceLogDefault(std::istream& is)
{
@@ -1030,6 +1355,10 @@ LLSD LLFastTimerView::analyzePerformanceLogDefault(std::istream& is)
LLSD::Real total_time = 0.0;
LLSD::Integer total_frames = 0;
+ typedef std::map<std::string,LLViewerStats::StatsAccumulator> stats_map_t;
+ stats_map_t time_stats;
+ stats_map_t sample_stats;
+
while (!is.eof() && LLSDSerialize::fromXML(cur, is))
{
for (LLSD::map_iterator iter = cur.beginMap(); iter != cur.endMap(); ++iter)
@@ -1046,35 +1375,31 @@ LLSD LLFastTimerView::analyzePerformanceLogDefault(std::istream& is)
if (time > 0.0)
{
- ret[label]["TotalTime"] = ret[label]["TotalTime"].asReal() + time;
- ret[label]["MaxTime"] = llmax(time, ret[label]["MaxTime"].asReal());
-
- if (ret[label]["MinTime"].asReal() == 0)
- {
- ret[label]["MinTime"] = time;
- }
- else
- {
- ret[label]["MinTime"] = llmin(ret[label]["MinTime"].asReal(), time);
- }
-
LLSD::Integer samples = iter->second["Calls"].asInteger();
- ret[label]["Samples"] = ret[label]["Samples"].asInteger() + samples;
- ret[label]["MaxSamples"] = llmax(ret[label]["MaxSamples"].asInteger(), samples);
-
- if (ret[label]["MinSamples"].asInteger() == 0)
- {
- ret[label]["MinSamples"] = samples;
- }
- else
- {
- ret[label]["MinSamples"] = llmin(ret[label]["MinSamples"].asInteger(), samples);
- }
+ time_stats[label].push(time);
+ sample_stats[label].push(samples);
}
}
total_frames++;
}
+
+ for(stats_map_t::iterator it = time_stats.begin(); it != time_stats.end(); ++it)
+ {
+ std::string label = it->first;
+ ret[label]["TotalTime"] = time_stats[label].mSum;
+ ret[label]["MeanTime"] = time_stats[label].getMean();
+ ret[label]["MaxTime"] = time_stats[label].getMaxValue();
+ ret[label]["MinTime"] = time_stats[label].getMinValue();
+ ret[label]["StdDevTime"] = time_stats[label].getStdDev();
+
+ ret[label]["Samples"] = sample_stats[label].mSum;
+ ret[label]["MaxSamples"] = sample_stats[label].getMaxValue();
+ ret[label]["MinSamples"] = sample_stats[label].getMinValue();
+ ret[label]["StdDevSamples"] = sample_stats[label].getStdDev();
+
+ ret[label]["Frames"] = (LLSD::Integer)time_stats[label].getCount();
+ }
ret["SessionTime"] = total_time;
ret["FrameCount"] = total_frames;
@@ -1086,14 +1411,22 @@ LLSD LLFastTimerView::analyzePerformanceLogDefault(std::istream& is)
//static
void LLFastTimerView::doAnalysisDefault(std::string baseline, std::string target, std::string output)
{
+ // Open baseline and current target, exit if one is inexistent
+ std::ifstream base_is(baseline.c_str());
+ std::ifstream target_is(target.c_str());
+ if (!base_is.is_open() || !target_is.is_open())
+ {
+ llwarns << "'-analyzeperformance' error : baseline or current target file inexistent" << llendl;
+ base_is.close();
+ target_is.close();
+ return;
+ }
//analyze baseline
- std::ifstream base_is(baseline.c_str());
LLSD base = analyzePerformanceLogDefault(base_is);
base_is.close();
//analyze current
- std::ifstream target_is(target.c_str());
LLSD current = analyzePerformanceLogDefault(target_is);
target_is.close();
@@ -1101,8 +1434,27 @@ void LLFastTimerView::doAnalysisDefault(std::string baseline, std::string target
std::ofstream os(output.c_str());
LLSD::Real session_time = current["SessionTime"].asReal();
-
- os << "Label, % Change, % of Session, Cur Min, Cur Max, Cur Mean, Cur Total, Cur Samples, Base Min, Base Max, Base Mean, Base Total, Base Samples\n";
+ os <<
+ "Label, "
+ "% Change, "
+ "% of Session, "
+ "Cur Min, "
+ "Cur Max, "
+ "Cur Mean/sample, "
+ "Cur Mean/frame, "
+ "Cur StdDev/frame, "
+ "Cur Total, "
+ "Cur Frames, "
+ "Cur Samples, "
+ "Base Min, "
+ "Base Max, "
+ "Base Mean/sample, "
+ "Base Mean/frame, "
+ "Base StdDev/frame, "
+ "Base Total, "
+ "Base Frames, "
+ "Base Samples\n";
+
for (LLSD::map_iterator iter = base.beginMap(); iter != base.endMap(); ++iter)
{
LLSD::String label = iter->first;
@@ -1114,94 +1466,53 @@ void LLFastTimerView::doAnalysisDefault(std::string baseline, std::string target
continue;
}
LLSD::Real a = base[label]["TotalTime"].asReal() / base[label]["Samples"].asReal();
- LLSD::Real b = current[label]["TotalTime"].asReal() / base[label]["Samples"].asReal();
+ LLSD::Real b = current[label]["TotalTime"].asReal() / current[label]["Samples"].asReal();
LLSD::Real diff = b-a;
LLSD::Real perc = diff/a * 100;
- os << llformat("%s, %.2f, %.4f, %.4f, %.4f, %.4f, %.4f, %d, %.4f, %.4f, %.4f, %.4f, %d\n",
+ os << llformat("%s, %.2f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %d, %d, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %d, %d\n",
label.c_str(),
(F32) perc,
(F32) (current[label]["TotalTime"].asReal()/session_time * 100.0),
+
(F32) current[label]["MinTime"].asReal(),
(F32) current[label]["MaxTime"].asReal(),
(F32) b,
+ (F32) current[label]["MeanTime"].asReal(),
+ (F32) current[label]["StdDevTime"].asReal(),
(F32) current[label]["TotalTime"].asReal(),
+ current[label]["Frames"].asInteger(),
current[label]["Samples"].asInteger(),
(F32) base[label]["MinTime"].asReal(),
(F32) base[label]["MaxTime"].asReal(),
(F32) a,
+ (F32) base[label]["MeanTime"].asReal(),
+ (F32) base[label]["StdDevTime"].asReal(),
(F32) base[label]["TotalTime"].asReal(),
+ base[label]["Frames"].asInteger(),
base[label]["Samples"].asInteger());
}
-
+ exportCharts(baseline, target);
+
os.flush();
os.close();
}
-//-------------------------
//static
-LLSD LLFastTimerView::analyzeMetricPerformanceLog(std::istream& is)
+void LLFastTimerView::outputAllMetrics()
{
- LLSD ret;
- LLSD cur;
-
- while (!is.eof() && LLSDSerialize::fromXML(cur, is))
+ if (LLMetricPerformanceTesterBasic::hasMetricPerformanceTesters())
{
- for (LLSD::map_iterator iter = cur.beginMap(); iter != cur.endMap(); ++iter)
+ for (LLMetricPerformanceTesterBasic::name_tester_map_t::iterator iter = LLMetricPerformanceTesterBasic::sTesterMap.begin();
+ iter != LLMetricPerformanceTesterBasic::sTesterMap.end(); ++iter)
{
- std::string label = iter->first;
-
- LLMetricPerformanceTester* tester = LLMetricPerformanceTester::getTester(iter->second["Name"].asString()) ;
- if(tester)
- {
- ret[label]["Name"] = iter->second["Name"] ;
-
- S32 num_of_strings = tester->getNumOfMetricStrings() ;
- for(S32 index = 0 ; index < num_of_strings ; index++)
- {
- ret[label][ tester->getMetricString(index) ] = iter->second[ tester->getMetricString(index) ] ;
- }
- }
+ LLMetricPerformanceTesterBasic* tester = ((LLMetricPerformanceTesterBasic*)iter->second);
+ tester->outputTestResults();
}
}
-
- return ret;
-}
-
-//static
-void LLFastTimerView::doAnalysisMetrics(std::string baseline, std::string target, std::string output)
-{
- if(!LLMetricPerformanceTester::hasMetricPerformanceTesters())
- {
- return ;
- }
-
- //analyze baseline
- std::ifstream base_is(baseline.c_str());
- LLSD base = analyzeMetricPerformanceLog(base_is);
- base_is.close();
-
- //analyze current
- std::ifstream target_is(target.c_str());
- LLSD current = analyzeMetricPerformanceLog(target_is);
- target_is.close();
-
- //output comparision
- std::ofstream os(output.c_str());
-
- os << "Label, Metric, Base(B), Target(T), Diff(T-B), Percentage(100*T/B)\n";
- for(LLMetricPerformanceTester::name_tester_map_t::iterator iter = LLMetricPerformanceTester::sTesterMap.begin() ;
- iter != LLMetricPerformanceTester::sTesterMap.end() ; ++iter)
- {
- LLMetricPerformanceTester* tester = ((LLMetricPerformanceTester*)iter->second) ;
- tester->analyzePerformance(&os, &base, &current) ;
- }
-
- os.flush();
- os.close();
}
//static
@@ -1215,7 +1526,7 @@ void LLFastTimerView::doAnalysis(std::string baseline, std::string target, std::
if(LLFastTimer::sMetricLog)
{
- doAnalysisMetrics(baseline, target, output) ;
+ LLMetricPerformanceTesterBasic::doAnalysisMetrics(baseline, target, output) ;
return ;
}
}
diff --git a/indra/newview/llfasttimerview.h b/indra/newview/llfasttimerview.h
index 3788897cec..ea8251191b 100644
--- a/indra/newview/llfasttimerview.h
+++ b/indra/newview/llfasttimerview.h
@@ -37,13 +37,13 @@ public:
static BOOL sAnalyzePerformance;
+ static void outputAllMetrics();
static void doAnalysis(std::string baseline, std::string target, std::string output);
private:
static void doAnalysisDefault(std::string baseline, std::string target, std::string output) ;
- static void doAnalysisMetrics(std::string baseline, std::string target, std::string output) ;
- static LLSD analyzeMetricPerformanceLog(std::istream& is) ;
static LLSD analyzePerformanceLogDefault(std::istream& is) ;
+ static void exportCharts(const std::string& base, const std::string& target);
public:
diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp
index 3981b887ad..0b17d64eb0 100644
--- a/indra/newview/llfavoritesbar.cpp
+++ b/indra/newview/llfavoritesbar.cpp
@@ -368,14 +368,15 @@ LLFavoritesBarCtrl::Params::Params()
LLFavoritesBarCtrl::LLFavoritesBarCtrl(const LLFavoritesBarCtrl::Params& p)
: LLUICtrl(p),
mFont(p.font.isProvided() ? p.font() : LLFontGL::getFontSansSerifSmall()),
- mPopupMenuHandle(),
- mInventoryItemsPopupMenuHandle(),
+ mOverflowMenuHandle(),
+ mContextMenuHandle(),
mImageDragIndication(p.image_drag_indication),
mShowDragMarker(FALSE),
mLandingTab(NULL),
mLastTab(NULL),
mTabsHighlightEnabled(TRUE)
, mUpdateDropDownItems(true)
+, mRestoreOverflowMenu(false)
{
// Register callback for menus with current registrar (will be parent panel's registrar)
LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Favorites.DoToSelected",
@@ -402,8 +403,8 @@ LLFavoritesBarCtrl::~LLFavoritesBarCtrl()
{
gInventory.removeObserver(this);
- LLView::deleteViewByHandle(mPopupMenuHandle);
- LLView::deleteViewByHandle(mInventoryItemsPopupMenuHandle);
+ LLView::deleteViewByHandle(mOverflowMenuHandle);
+ LLView::deleteViewByHandle(mContextMenuHandle);
}
BOOL LLFavoritesBarCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
@@ -414,6 +415,9 @@ BOOL LLFavoritesBarCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
{
*accept = ACCEPT_NO;
+ LLToolDragAndDrop::ESource source = LLToolDragAndDrop::getInstance()->getSource();
+ if (LLToolDragAndDrop::SOURCE_AGENT != source && LLToolDragAndDrop::SOURCE_LIBRARY != source) return FALSE;
+
switch (cargo_type)
{
@@ -517,7 +521,7 @@ void LLFavoritesBarCtrl::handleExistingFavoriteDragAndDrop(S32 x, S32 y)
gInventory.saveItemsOrder(mItems);
- LLToggleableMenu* menu = (LLToggleableMenu*) mPopupMenuHandle.get();
+ LLToggleableMenu* menu = (LLToggleableMenu*) mOverflowMenuHandle.get();
if (menu && menu->getVisible())
{
@@ -603,6 +607,15 @@ void LLFavoritesBarCtrl::changed(U32 mask)
}
else
{
+ LLInventoryModel::item_array_t items;
+ LLInventoryModel::cat_array_t cats;
+ LLIsType is_type(LLAssetType::AT_LANDMARK);
+ gInventory.collectDescendentsIf(mFavoriteFolderId, cats, items, LLInventoryModel::EXCLUDE_TRASH, is_type);
+
+ for (LLInventoryModel::item_array_t::iterator i = items.begin(); i != items.end(); ++i)
+ {
+ (*i)->getSLURL();
+ }
updateButtons();
}
}
@@ -773,7 +786,7 @@ void LLFavoritesBarCtrl::updateButtons()
mChevronButton->setVisible(TRUE);
}
// Update overflow menu
- LLToggleableMenu* overflow_menu = static_cast <LLToggleableMenu*> (mPopupMenuHandle.get());
+ LLToggleableMenu* overflow_menu = static_cast <LLToggleableMenu*> (mOverflowMenuHandle.get());
if (overflow_menu && overflow_menu->getVisible())
{
overflow_menu->setVisible(FALSE);
@@ -847,7 +860,7 @@ BOOL LLFavoritesBarCtrl::postBuild()
menu = LLUICtrlFactory::getDefaultWidget<LLMenuGL>("inventory_menu");
}
menu->setBackgroundColor(LLUIColorTable::instance().getColor("MenuPopupBgColor"));
- mInventoryItemsPopupMenuHandle = menu->getHandle();
+ mContextMenuHandle = menu->getHandle();
return TRUE;
}
@@ -878,7 +891,7 @@ BOOL LLFavoritesBarCtrl::collectFavoriteItems(LLInventoryModel::item_array_t &it
void LLFavoritesBarCtrl::showDropDownMenu()
{
- if (mPopupMenuHandle.isDead())
+ if (mOverflowMenuHandle.isDead())
{
LLToggleableMenu::Params menu_p;
menu_p.name("favorites menu");
@@ -889,10 +902,10 @@ void LLFavoritesBarCtrl::showDropDownMenu()
menu_p.preferred_width = DROP_DOWN_MENU_WIDTH;
LLToggleableMenu* menu = LLUICtrlFactory::create<LLFavoriteLandmarkToggleableMenu>(menu_p);
- mPopupMenuHandle = menu->getHandle();
+ mOverflowMenuHandle = menu->getHandle();
}
- LLToggleableMenu* menu = (LLToggleableMenu*)mPopupMenuHandle.get();
+ LLToggleableMenu* menu = (LLToggleableMenu*)mOverflowMenuHandle.get();
if (menu)
{
@@ -970,11 +983,19 @@ void LLFavoritesBarCtrl::onButtonRightClick( LLUUID item_id,LLView* fav_button,S
{
mSelectedItemID = item_id;
- LLMenuGL* menu = (LLMenuGL*)mInventoryItemsPopupMenuHandle.get();
+ LLMenuGL* menu = (LLMenuGL*)mContextMenuHandle.get();
if (!menu)
{
return;
}
+
+ // Remember that the context menu was shown simultaneously with the overflow menu,
+ // so that we can restore the overflow menu when user clicks a context menu item
+ // (which hides the overflow menu).
+ {
+ LLView* overflow_menu = mOverflowMenuHandle.get();
+ mRestoreOverflowMenu = overflow_menu && overflow_menu->getVisible();
+ }
// Release mouse capture so hover events go to the popup menu
// because this is happening during a mouse down.
@@ -1079,8 +1100,8 @@ void LLFavoritesBarCtrl::doToSelected(const LLSD& userdata)
// Pop-up the overflow menu again (it gets hidden whenever the user clicks a context menu item).
// See EXT-4217 and STORM-207.
- LLToggleableMenu* menu = (LLToggleableMenu*) mPopupMenuHandle.get();
- if (menu && !menu->getVisible())
+ LLToggleableMenu* menu = (LLToggleableMenu*) mOverflowMenuHandle.get();
+ if (mRestoreOverflowMenu && menu && !menu->getVisible())
{
showDropDownMenu();
}
@@ -1146,11 +1167,11 @@ void LLFavoritesBarCtrl::pastFromClipboard() const
void LLFavoritesBarCtrl::onButtonMouseDown(LLUUID id, LLUICtrl* ctrl, S32 x, S32 y, MASK mask)
{
// EXT-6997 (Fav bar: Pop-up menu for LM in overflow dropdown is kept after LM was dragged away)
- // mInventoryItemsPopupMenuHandle.get() - is a pop-up menu (of items) in already opened dropdown menu.
+ // mContextMenuHandle.get() - is a pop-up menu (of items) in already opened dropdown menu.
// We have to check and set visibility of pop-up menu in such a way instead of using
// LLMenuHolderGL::hideMenus() because it will close both menus(dropdown and pop-up), but
// we need to close only pop-up menu while dropdown one should be still opened.
- LLMenuGL* menu = (LLMenuGL*)mInventoryItemsPopupMenuHandle.get();
+ LLMenuGL* menu = (LLMenuGL*)mContextMenuHandle.get();
if(menu && menu->getVisible())
{
menu->setVisible(FALSE);
diff --git a/indra/newview/llfavoritesbar.h b/indra/newview/llfavoritesbar.h
index 37645523f6..1a28731c4f 100644
--- a/indra/newview/llfavoritesbar.h
+++ b/indra/newview/llfavoritesbar.h
@@ -91,13 +91,14 @@ protected:
void showDropDownMenu();
- LLHandle<LLView> mPopupMenuHandle;
- LLHandle<LLView> mInventoryItemsPopupMenuHandle;
+ LLHandle<LLView> mOverflowMenuHandle;
+ LLHandle<LLView> mContextMenuHandle;
LLUUID mFavoriteFolderId;
const LLFontGL *mFont;
S32 mFirstDropDownItem;
bool mUpdateDropDownItems;
+ bool mRestoreOverflowMenu;
LLUUID mSelectedItemID;
diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp
index ca2ef5f5b8..3bdab75acf 100644
--- a/indra/newview/llfeaturemanager.cpp
+++ b/indra/newview/llfeaturemanager.cpp
@@ -203,7 +203,7 @@ BOOL LLFeatureManager::maskFeatures(const std::string& name)
LL_DEBUGS("RenderInit") << "Unknown feature mask " << name << LL_ENDL;
return FALSE;
}
- LL_DEBUGS("RenderInit") << "Applying Feature Mask: " << name << LL_ENDL;
+ LL_INFOS("RenderInit") << "Applying GPU Feature list: " << name << LL_ENDL;
return maskList(*maskp);
}
@@ -290,11 +290,9 @@ BOOL LLFeatureManager::parseFeatureTable(std::string filename)
mTableVersion = version;
LLFeatureList *flp = NULL;
- while (!file.eof() && file.good())
+ while (file >> name)
{
char buffer[MAX_STRING]; /*Flawfinder: ignore*/
-
- file >> name;
if (name.substr(0,2) == "//")
{
@@ -303,13 +301,6 @@ BOOL LLFeatureManager::parseFeatureTable(std::string filename)
continue;
}
- if (name.empty())
- {
- // This is a blank line
- file.getline(buffer, MAX_STRING);
- continue;
- }
-
if (name == "list")
{
if (flp)
@@ -387,13 +378,16 @@ void LLFeatureManager::parseGPUTable(std::string filename)
return;
}
- std::string renderer = gGLManager.getRawGLString();
+ std::string rawRenderer = gGLManager.getRawGLString();
+ std::string renderer = rawRenderer;
for (std::string::iterator i = renderer.begin(); i != renderer.end(); ++i)
{
*i = tolower(*i);
}
-
- while (!file.eof())
+
+ bool gpuFound;
+ U32 lineNumber;
+ for (gpuFound = false, lineNumber = 0; !gpuFound && !file.eof(); lineNumber++)
{
char buffer[MAX_STRING]; /*Flawfinder: ignore*/
buffer[0] = 0;
@@ -440,6 +434,7 @@ void LLFeatureManager::parseGPUTable(std::string filename)
if (label.empty() || expr.empty() || cls.empty() || supported.empty())
{
+ LL_WARNS("RenderInit") << "invald gpu_table.txt:" << lineNumber << ": '" << buffer << "'" << LL_ENDL;
continue;
}
@@ -453,18 +448,26 @@ void LLFeatureManager::parseGPUTable(std::string filename)
if(boost::regex_search(renderer, re))
{
// if we found it, stop!
- file.close();
- LL_INFOS("RenderInit") << "GPU is " << label << llendl;
+ gpuFound = true;
mGPUString = label;
mGPUClass = (EGPUClass) strtol(cls.c_str(), NULL, 10);
mGPUSupported = (BOOL) strtol(supported.c_str(), NULL, 10);
- file.close();
- return;
}
}
file.close();
- LL_WARNS("RenderInit") << "Couldn't match GPU to a class: " << gGLManager.getRawGLString() << LL_ENDL;
+ if ( gpuFound )
+ {
+ LL_INFOS("RenderInit") << "GPU '" << rawRenderer << "' recognized as '" << mGPUString << "'" << LL_ENDL;
+ if (!mGPUSupported)
+ {
+ LL_INFOS("RenderInit") << "GPU '" << mGPUString << "' is not supported." << LL_ENDL;
+ }
+ }
+ else
+ {
+ LL_WARNS("RenderInit") << "GPU '" << rawRenderer << "' not recognized" << LL_ENDL;
+ }
}
// responder saves table into file
@@ -738,6 +741,10 @@ void LLFeatureManager::applyBaseMasks()
{
maskFeatures("ATI");
}
+ if (gGLManager.mHasATIMemInfo && gGLManager.mVRAM < 256)
+ {
+ maskFeatures("ATIVramLT256");
+ }
if (gGLManager.mATIOldDriver)
{
maskFeatures("ATIOldDriver");
@@ -754,6 +761,14 @@ void LLFeatureManager::applyBaseMasks()
{
maskFeatures("OpenGLPre15");
}
+ if (gGLManager.mGLVersion < 3.f)
+ {
+ maskFeatures("OpenGLPre30");
+ }
+ if (gGLManager.mNumTextureUnits <= 8)
+ {
+ maskFeatures("TexUnit8orLess");
+ }
// now mask by gpu string
// Replaces ' ' with '_' in mGPUString to deal with inability for parser to handle spaces
diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp
index c14be89641..8c0ed29855 100644
--- a/indra/newview/llfilepicker.cpp
+++ b/indra/newview/llfilepicker.cpp
@@ -33,6 +33,7 @@
#include "lldir.h"
#include "llframetimer.h"
#include "lltrans.h"
+#include "llviewercontrol.h"
#include "llwindow.h" // beforeDialog()
#if LL_SDL
@@ -49,12 +50,14 @@ LLFilePicker LLFilePicker::sInstance;
#define SOUND_FILTER L"Sounds (*.wav)\0*.wav\0"
#define IMAGE_FILTER L"Images (*.tga; *.bmp; *.jpg; *.jpeg; *.png)\0*.tga;*.bmp;*.jpg;*.jpeg;*.png\0"
#define ANIM_FILTER L"Animations (*.bvh)\0*.bvh\0"
+#define COLLADA_FILTER L"Scene (*.dae)\0*.dae\0"
#ifdef _CORY_TESTING
#define GEOMETRY_FILTER L"SL Geometry (*.slg)\0*.slg\0"
#endif
#define XML_FILTER L"XML files (*.xml)\0*.xml\0"
#define SLOBJECT_FILTER L"Objects (*.slobject)\0*.slobject\0"
#define RAW_FILTER L"RAW files (*.raw)\0*.raw\0"
+#define MODEL_FILTER L"Model files (*.dae)\0*.dae\0"
#endif
//
@@ -104,6 +107,20 @@ LLFilePicker::~LLFilePicker()
// nothing
}
+// utility function to check if access to local file system via file browser
+// is enabled and if not, tidy up and indicate we're not allowed to do this.
+bool LLFilePicker::check_local_file_access_enabled()
+{
+ // if local file browsing is turned off, return without opening dialog
+ bool local_file_system_browsing_enabled = gSavedSettings.getBOOL("LocalFileSystemBrowsingEnabled");
+ if ( ! local_file_system_browsing_enabled )
+ {
+ mFiles.clear();
+ return false;
+ }
+
+ return true;
+}
const std::string LLFilePicker::getFirstFile()
{
@@ -170,6 +187,10 @@ BOOL LLFilePicker::setupFilter(ELoadFilter filter)
mOFN.lpstrFilter = ANIM_FILTER \
L"\0";
break;
+ case FFLOAD_COLLADA:
+ mOFN.lpstrFilter = COLLADA_FILTER \
+ L"\0";
+ break;
#ifdef _CORY_TESTING
case FFLOAD_GEOMETRY:
mOFN.lpstrFilter = GEOMETRY_FILTER \
@@ -188,6 +209,10 @@ BOOL LLFilePicker::setupFilter(ELoadFilter filter)
mOFN.lpstrFilter = RAW_FILTER \
L"\0";
break;
+ case FFLOAD_MODEL:
+ mOFN.lpstrFilter = MODEL_FILTER \
+ L"\0";
+ break;
default:
res = FALSE;
break;
@@ -195,7 +220,7 @@ BOOL LLFilePicker::setupFilter(ELoadFilter filter)
return res;
}
-BOOL LLFilePicker::getOpenFile(ELoadFilter filter)
+BOOL LLFilePicker::getOpenFile(ELoadFilter filter, bool blocking)
{
if( mLocked )
{
@@ -203,6 +228,12 @@ BOOL LLFilePicker::getOpenFile(ELoadFilter filter)
}
BOOL success = FALSE;
+ // if local file browsing is turned off, return without opening dialog
+ if ( check_local_file_access_enabled() == false )
+ {
+ return FALSE;
+ }
+
// don't provide default file selection
mFilesW[0] = '\0';
@@ -214,8 +245,11 @@ BOOL LLFilePicker::getOpenFile(ELoadFilter filter)
setupFilter(filter);
- // Modal, so pause agent
- send_agent_pause();
+ if (blocking)
+ {
+ // Modal, so pause agent
+ send_agent_pause();
+ }
reset();
@@ -226,10 +260,14 @@ BOOL LLFilePicker::getOpenFile(ELoadFilter filter)
std::string filename = utf16str_to_utf8str(llutf16string(mFilesW));
mFiles.push_back(filename);
}
- send_agent_resume();
- // Account for the fact that the app has been stalled.
- LLFrameTimer::updateFrameTime();
+ if (blocking)
+ {
+ send_agent_resume();
+ // Account for the fact that the app has been stalled.
+ LLFrameTimer::updateFrameTime();
+ }
+
return success;
}
@@ -241,6 +279,12 @@ BOOL LLFilePicker::getMultipleOpenFiles(ELoadFilter filter)
}
BOOL success = FALSE;
+ // if local file browsing is turned off, return without opening dialog
+ if ( check_local_file_access_enabled() == false )
+ {
+ return FALSE;
+ }
+
// don't provide default file selection
mFilesW[0] = '\0';
@@ -304,6 +348,12 @@ BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const std::string& filename)
}
BOOL success = FALSE;
+ // if local file browsing is turned off, return without opening dialog
+ if ( check_local_file_access_enabled() == false )
+ {
+ return FALSE;
+ }
+
mOFN.lpstrFile = mFilesW;
if (!filename.empty())
{
@@ -370,9 +420,9 @@ BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const std::string& filename)
{
wcsncpy( mFilesW,L"untitled.jpeg", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/
}
- mOFN.lpstrDefExt = L"jpeg";
+ mOFN.lpstrDefExt = L"jpg";
mOFN.lpstrFilter =
- L"JPEG Images (*.jpeg)\0*.jpeg\0" \
+ L"JPEG Images (*.jpg *.jpeg)\0*.jpg;*.jpeg\0" \
L"\0";
break;
case FFSAVE_AVI:
@@ -537,6 +587,15 @@ Boolean LLFilePicker::navOpenFilterProc(AEDesc *theItem, void *info, void *callB
result = false;
}
}
+ else if (filter == FFLOAD_COLLADA)
+ {
+ if (fileInfo.filetype != 'DAE ' &&
+ (fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("dae"), kCFCompareCaseInsensitive) != kCFCompareEqualTo))
+ )
+ {
+ result = false;
+ }
+ }
#ifdef _CORY_TESTING
else if (filter == FFLOAD_GEOMETRY)
{
@@ -581,6 +640,12 @@ OSStatus LLFilePicker::doNavChooseDialog(ELoadFilter filter)
NavDialogRef navRef = NULL;
NavReplyRecord navReply;
+ // if local file browsing is turned off, return without opening dialog
+ if ( check_local_file_access_enabled() == false )
+ {
+ return FALSE;
+ }
+
memset(&navReply, 0, sizeof(navReply));
// NOTE: we are passing the address of a local variable here.
@@ -802,13 +867,19 @@ OSStatus LLFilePicker::doNavSaveDialog(ESaveFilter filter, const std::string& fi
return error;
}
-BOOL LLFilePicker::getOpenFile(ELoadFilter filter)
+BOOL LLFilePicker::getOpenFile(ELoadFilter filter, bool blocking)
{
if( mLocked )
return FALSE;
BOOL success = FALSE;
+ // if local file browsing is turned off, return without opening dialog
+ if ( check_local_file_access_enabled() == false )
+ {
+ return FALSE;
+ }
+
OSStatus error = noErr;
reset();
@@ -821,20 +892,29 @@ BOOL LLFilePicker::getOpenFile(ELoadFilter filter)
mNavOptions.optionFlags |= kNavSupportPackages;
}
- // Modal, so pause agent
- send_agent_pause();
+ if (blocking)
+ {
+ // Modal, so pause agent
+ send_agent_pause();
+ }
+
{
error = doNavChooseDialog(filter);
}
- send_agent_resume();
+
if (error == noErr)
{
if (getFileCount())
success = true;
}
- // Account for the fact that the app has been stalled.
- LLFrameTimer::updateFrameTime();
+ if (blocking)
+ {
+ send_agent_resume();
+ // Account for the fact that the app has been stalled.
+ LLFrameTimer::updateFrameTime();
+ }
+
return success;
}
@@ -845,6 +925,12 @@ BOOL LLFilePicker::getMultipleOpenFiles(ELoadFilter filter)
BOOL success = FALSE;
+ // if local file browsing is turned off, return without opening dialog
+ if ( check_local_file_access_enabled() == false )
+ {
+ return FALSE;
+ }
+
OSStatus error = noErr;
reset();
@@ -876,6 +962,12 @@ BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const std::string& filename)
BOOL success = FALSE;
OSStatus error = noErr;
+ // if local file browsing is turned off, return without opening dialog
+ if ( check_local_file_access_enabled() == false )
+ {
+ return FALSE;
+ }
+
reset();
mNavOptions.optionFlags &= ~kNavAllowMultipleFiles;
@@ -1083,6 +1175,12 @@ static std::string add_bvh_filter_to_gtkchooser(GtkWindow *picker)
LLTrans::getString("animation_files") + " (*.bvh)");
}
+static std::string add_collada_filter_to_gtkchooser(GtkWindow *picker)
+{
+ return add_simple_pattern_filter_to_gtkchooser(picker, "*.dae",
+ LLTrans::getString("scene_files") + " (*.dae)");
+}
+
static std::string add_imageload_filter_to_gtkchooser(GtkWindow *picker)
{
GtkFileFilter *gfilter = gtk_file_filter_new();
@@ -1100,6 +1198,12 @@ BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename
{
BOOL rtn = FALSE;
+ // if local file browsing is turned off, return without opening dialog
+ if ( check_local_file_access_enabled() == false )
+ {
+ return FALSE;
+ }
+
gViewerWindow->mWindow->beforeDialog();
reset();
@@ -1185,10 +1289,16 @@ BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename
return rtn;
}
-BOOL LLFilePicker::getOpenFile( ELoadFilter filter )
+BOOL LLFilePicker::getOpenFile( ELoadFilter filter, bool blocking )
{
BOOL rtn = FALSE;
+ // if local file browsing is turned off, return without opening dialog
+ if ( check_local_file_access_enabled() == false )
+ {
+ return FALSE;
+ }
+
gViewerWindow->mWindow->beforeDialog();
reset();
@@ -1207,6 +1317,9 @@ BOOL LLFilePicker::getOpenFile( ELoadFilter filter )
case FFLOAD_ANIM:
filtername = add_bvh_filter_to_gtkchooser(picker);
break;
+ case FFLOAD_COLLADA:
+ filtername = add_collada_filter_to_gtkchooser(picker);
+ break;
case FFLOAD_IMAGE:
filtername = add_imageload_filter_to_gtkchooser(picker);
break;
@@ -1233,6 +1346,12 @@ BOOL LLFilePicker::getMultipleOpenFiles( ELoadFilter filter )
{
BOOL rtn = FALSE;
+ // if local file browsing is turned off, return without opening dialog
+ if ( check_local_file_access_enabled() == false )
+ {
+ return FALSE;
+ }
+
gViewerWindow->mWindow->beforeDialog();
reset();
@@ -1263,6 +1382,13 @@ BOOL LLFilePicker::getMultipleOpenFiles( ELoadFilter filter )
BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename )
{
+ // if local file browsing is turned off, return without opening dialog
+ // (Even though this is a stub, I think we still should not return anything at all)
+ if ( check_local_file_access_enabled() == false )
+ {
+ return FALSE;
+ }
+
reset();
llinfos << "getSaveFile suggested filename is [" << filename
@@ -1277,6 +1403,13 @@ BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename
BOOL LLFilePicker::getOpenFile( ELoadFilter filter )
{
+ // if local file browsing is turned off, return without opening dialog
+ // (Even though this is a stub, I think we still should not return anything at all)
+ if ( check_local_file_access_enabled() == false )
+ {
+ return FALSE;
+ }
+
reset();
// HACK: Static filenames for 'open' until we implement filepicker
@@ -1295,6 +1428,13 @@ BOOL LLFilePicker::getOpenFile( ELoadFilter filter )
BOOL LLFilePicker::getMultipleOpenFiles( ELoadFilter filter )
{
+ // if local file browsing is turned off, return without opening dialog
+ // (Even though this is a stub, I think we still should not return anything at all)
+ if ( check_local_file_access_enabled() == false )
+ {
+ return FALSE;
+ }
+
reset();
return FALSE;
}
diff --git a/indra/newview/llfilepicker.h b/indra/newview/llfilepicker.h
index 5819ac4fd8..cd843a8f33 100644
--- a/indra/newview/llfilepicker.h
+++ b/indra/newview/llfilepicker.h
@@ -82,6 +82,8 @@ public:
FFLOAD_XML = 6,
FFLOAD_SLOBJECT = 7,
FFLOAD_RAW = 8,
+ FFLOAD_MODEL = 9,
+ FFLOAD_COLLADA = 10,
};
enum ESaveFilter
@@ -105,7 +107,7 @@ public:
// open the dialog. This is a modal operation
BOOL getSaveFile( ESaveFilter filter = FFSAVE_ALL, const std::string& filename = LLStringUtil::null );
- BOOL getOpenFile( ELoadFilter filter = FFLOAD_ALL );
+ BOOL getOpenFile( ELoadFilter filter = FFLOAD_ALL, bool blocking = true );
BOOL getMultipleOpenFiles( ELoadFilter filter = FFLOAD_ALL );
// Get the filename(s) found. getFirstFile() sets the pointer to
@@ -140,6 +142,10 @@ private:
//FILENAME_BUFFER_SIZE = 65536
FILENAME_BUFFER_SIZE = 65000
};
+
+ // utility function to check if access to local file system via file browser
+ // is enabled and if not, tidy up and indicate we're not allowed to do this.
+ bool check_local_file_access_enabled();
#if LL_WINDOWS
OPENFILENAMEW mOFN; // for open and save dialogs
@@ -186,4 +192,6 @@ public:
~LLFilePicker();
};
+const std::string upload_pick(void* data);
+
#endif
diff --git a/indra/newview/llfirstuse.cpp b/indra/newview/llfirstuse.cpp
index b08c113923..2c4153688a 100644
--- a/indra/newview/llfirstuse.cpp
+++ b/indra/newview/llfirstuse.cpp
@@ -78,6 +78,12 @@ void LLFirstUse::otherAvatarChatFirst(bool enable)
}
// static
+void LLFirstUse::speak(bool enable)
+{
+ firstUseNotification("FirstSpeak", enable, "HintSpeak", LLSD(), LLSD().with("target", "speak_btn").with("direction", "top"));
+}
+
+// static
void LLFirstUse::sit(bool enable)
{
firstUseNotification("FirstSit", enable, "HintSit", LLSD(), LLSD().with("target", "stand_btn").with("direction", "top"));
@@ -100,7 +106,7 @@ void LLFirstUse::useSandbox()
void LLFirstUse::notUsingDestinationGuide(bool enable)
{
// not doing this yet
- //firstUseNotification("FirstNotUseDestinationGuide", enable, "HintDestinationGuide", LLSD(), LLSD().with("target", "dest_guide_btn").with("direction", "left"));
+ firstUseNotification("FirstNotUseDestinationGuide", enable, "HintDestinationGuide", LLSD(), LLSD().with("target", "dest_guide_btn").with("direction", "top"));
}
// static
@@ -113,7 +119,19 @@ void LLFirstUse::notUsingSidePanel(bool enable)
// static
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, "HintMoveClick", LLSD(), LLSD()
+ .with("target", "nav_bar")
+ .with("direction", "bottom")
+ .with("hint_image", "click_to_move.png")
+ .with("up_arrow", ""));
+}
+
+// static
+void LLFirstUse::viewPopup(bool enable)
+{
+ firstUseNotification("FirstViewPopup", enable, "HintView", LLSD(), LLSD().with("target", "view_popup").with("direction", "right"));
}
// static
diff --git a/indra/newview/llfirstuse.h b/indra/newview/llfirstuse.h
index 3b7ff6383b..4c8c9d3cde 100644
--- a/indra/newview/llfirstuse.h
+++ b/indra/newview/llfirstuse.h
@@ -68,6 +68,8 @@ object or from inventory.
13. First time you open the debug menus (ctrl-alt-shift D)
14. First time you create/edit a sculpted prim.
+
+15. Explanation of Speak&flyout buttons.
*/
class LLNotification;
@@ -85,10 +87,12 @@ public:
static void resetFirstUse();
static void otherAvatarChatFirst(bool enable = true);
+ static void speak(bool enable = true);
static void sit(bool enable = true);
static void notUsingDestinationGuide(bool enable = true);
static void notUsingSidePanel(bool enable = true);
static void notMoving(bool enable = true);
+ static void viewPopup(bool enable = true);
static void newInventory(bool enable = true);
static void receiveLindens(bool enable = true);
static void setDisplayName(bool enable = true);
diff --git a/indra/newview/llflexibleobject.cpp b/indra/newview/llflexibleobject.cpp
index 8ab2229235..3d1650d2f5 100644
--- a/indra/newview/llflexibleobject.cpp
+++ b/indra/newview/llflexibleobject.cpp
@@ -91,11 +91,13 @@ void LLVolumeImplFlexible::onParameterChanged(U16 param_type, LLNetworkData *dat
}
}
-void LLVolumeImplFlexible::onShift(const LLVector3 &shift_vector)
+void LLVolumeImplFlexible::onShift(const LLVector4a &shift_vector)
{
+ //VECTORIZE THIS
+ LLVector3 shift(shift_vector.getF32ptr());
for (int section = 0; section < (1<<FLEXIBLE_OBJECT_MAX_SECTIONS)+1; ++section)
{
- mSection[section].mPosition += shift_vector;
+ mSection[section].mPosition += shift;
}
}
@@ -314,11 +316,13 @@ BOOL LLVolumeImplFlexible::doIdleUpdate(LLAgent &agent, LLWorld &world, const F6
return FALSE; // (we are not initialized or updated)
}
- if (force_update)
+ bool visible = mVO->mDrawable->isVisible();
+
+ if (force_update && visible)
{
gPipeline.markRebuild(mVO->mDrawable, LLDrawable::REBUILD_POSITION, FALSE);
}
- else if (mVO->mDrawable->isVisible() &&
+ else if (visible &&
!mVO->mDrawable->isState(LLDrawable::IN_REBUILD_Q1) &&
mVO->getPixelArea() > 256.f)
{
@@ -362,7 +366,7 @@ void LLVolumeImplFlexible::doFlexibleUpdate()
LLFastTimer ftm(FTM_DO_FLEXIBLE_UPDATE);
LLVolume* volume = mVO->getVolume();
LLPath *path = &volume->getPath();
- if (mSimulateRes == 0)
+ if ((mSimulateRes == 0 || !mInitialized) && mVO->mDrawable->isVisible()) // if its uninitialized but not visible, what then? - Nyx
{
mVO->markForUpdate(TRUE);
if (!doIdleUpdate(gAgent, *LLWorld::getInstance(), 0.0))
@@ -690,6 +694,8 @@ BOOL LLVolumeImplFlexible::doUpdateGeometry(LLDrawable *drawable)
}
volume->updateRelativeXform();
+
+ if (mRenderRes > -1)
{
LLFastTimer t(FTM_DO_FLEXIBLE_UPDATE);
doFlexibleUpdate();
diff --git a/indra/newview/llflexibleobject.h b/indra/newview/llflexibleobject.h
index 9b952f1985..fef43d464d 100644
--- a/indra/newview/llflexibleobject.h
+++ b/indra/newview/llflexibleobject.h
@@ -84,7 +84,7 @@ class LLVolumeImplFlexible : public LLVolumeInterface
void onSetVolume(const LLVolumeParams &volume_params, const S32 detail);
void onSetScale(const LLVector3 &scale, BOOL damped);
void onParameterChanged(U16 param_type, LLNetworkData *data, BOOL in_use, bool local_origin);
- void onShift(const LLVector3 &shift_vector);
+ void onShift(const LLVector4a &shift_vector);
bool isVolumeUnique() const { return true; }
bool isVolumeGlobal() const { return true; }
bool isActive() const { return true; }
diff --git a/indra/newview/llfloaterabout.cpp b/indra/newview/llfloaterabout.cpp
index 135137069c..2873bc0059 100644
--- a/indra/newview/llfloaterabout.cpp
+++ b/indra/newview/llfloaterabout.cpp
@@ -213,7 +213,7 @@ LLSD LLFloaterAbout::getInfo()
info["VIEWER_VERSION_STR"] = LLVersionInfo::getVersion();
info["BUILD_DATE"] = __DATE__;
info["BUILD_TIME"] = __TIME__;
- info["CHANNEL"] = gSavedSettings.getString("VersionChannelName");
+ info["CHANNEL"] = LLVersionInfo::getChannel();
info["VIEWER_RELEASE_NOTES_URL"] = get_viewer_release_notes_url();
@@ -272,7 +272,7 @@ LLSD LLFloaterAbout::getInfo()
}
// TODO: Implement media plugin version query
- info["QT_WEBKIT_VERSION"] = "4.6 (version number hard-coded)";
+ info["QT_WEBKIT_VERSION"] = "4.7.1 (version number hard-coded)";
if (gPacketsIn > 0)
{
@@ -291,7 +291,7 @@ static std::string get_viewer_release_notes_url()
std::string url = LLTrans::getString("RELEASE_NOTES_BASE_URL");
if (! LLStringUtil::endsWith(url, "/"))
url += "/";
- url += gSavedSettings.getString("VersionChannelName") + "/";
+ url += LLVersionInfo::getChannel() + "/";
url += LLVersionInfo::getShortVersion();
return LLWeb::escapeURL(url);
}
diff --git a/indra/newview/llfloateranimpreview.cpp b/indra/newview/llfloateranimpreview.cpp
index deebd69ec1..1f334815d6 100644
--- a/indra/newview/llfloateranimpreview.cpp
+++ b/indra/newview/llfloateranimpreview.cpp
@@ -994,6 +994,7 @@ void LLFloaterAnimPreview::onBtnOK(void* userdata)
LLFloaterPerms::getNextOwnerPerms(), LLFloaterPerms::getGroupPerms(), LLFloaterPerms::getEveryonePerms(),
name,
callback, expected_upload_cost, userdata);
+
}
else
{
@@ -1032,7 +1033,6 @@ LLPreviewAnimation::LLPreviewAnimation(S32 width, S32 height) : LLViewerDynamicT
mDummyAvatar->updateGeometry(mDummyAvatar->mDrawable);
mDummyAvatar->startMotion(ANIM_AGENT_STAND, BASE_ANIM_TIME_OFFSET);
mDummyAvatar->hideSkirt();
- gPipeline.markVisible(mDummyAvatar->mDrawable, *LLViewerCamera::getInstance());
// stop extraneous animations
mDummyAvatar->stopMotion( ANIM_AGENT_HEAD_ROT, TRUE );
diff --git a/indra/newview/llfloaterauction.cpp b/indra/newview/llfloaterauction.cpp
index 252c7b51ae..c95b046707 100644
--- a/indra/newview/llfloaterauction.cpp
+++ b/indra/newview/llfloaterauction.cpp
@@ -351,8 +351,8 @@ void LLFloaterAuction::doResetParcel()
body["media_height"] = (S32) 0;
body["auto_scale"] = (S32) 0;
body["media_loop"] = (S32) 0;
- body["obscure_media"] = (S32) 0;
- body["obscure_music"] = (S32) 0;
+ body["obscure_media"] = (S32) 0; // OBSOLETE - no longer used
+ body["obscure_music"] = (S32) 0; // OBSOLETE - no longer used
body["media_id"] = LLUUID::null;
body["group_id"] = MAINTENANCE_GROUP_ID; // Use maintenance group
body["pass_price"] = (S32) 10; // Defaults to $10
diff --git a/indra/newview/llfloaterbeacons.cpp b/indra/newview/llfloaterbeacons.cpp
index e24df948c4..316294a477 100644
--- a/indra/newview/llfloaterbeacons.cpp
+++ b/indra/newview/llfloaterbeacons.cpp
@@ -48,6 +48,7 @@ LLFloaterBeacons::LLFloaterBeacons(const LLSD& seed)
LLPipeline::setRenderParticleBeacons( gSavedSettings.getBOOL("particlesbeacon"));
LLPipeline::setRenderHighlights( gSavedSettings.getBOOL("renderhighlights"));
LLPipeline::setRenderBeacons( gSavedSettings.getBOOL("renderbeacons"));
+ LLPipeline::setRenderMOAPBeacons( gSavedSettings.getBOOL("moapbeacon"));
mCommitCallbackRegistrar.add("Beacons.UICheck", boost::bind(&LLFloaterBeacons::onClickUICheck, this,_1));
}
@@ -96,6 +97,7 @@ void LLFloaterBeacons::onClickUICheck(LLUICtrl *ctrl)
else if(name == "physical") LLPipeline::setRenderPhysicalBeacons(check->get());
else if(name == "sounds") LLPipeline::setRenderSoundBeacons(check->get());
else if(name == "particles") LLPipeline::setRenderParticleBeacons(check->get());
+ else if(name == "moapbeacon") LLPipeline::setRenderMOAPBeacons(check->get());
else if(name == "highlights")
{
LLPipeline::toggleRenderHighlights(NULL);
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/llfloaterbuycurrency.cpp b/indra/newview/llfloaterbuycurrency.cpp
index 58c79fdf15..e21a8594bc 100644
--- a/indra/newview/llfloaterbuycurrency.cpp
+++ b/indra/newview/llfloaterbuycurrency.cpp
@@ -267,17 +267,23 @@ void LLFloaterBuyCurrencyUI::onClickBuy()
{
mManager.buy(getString("buy_currency"));
updateUI();
+ // Update L$ balance
+ LLStatusBar::sendMoneyBalanceRequest();
}
void LLFloaterBuyCurrencyUI::onClickCancel()
{
closeFloater();
+ // Update L$ balance
+ LLStatusBar::sendMoneyBalanceRequest();
}
void LLFloaterBuyCurrencyUI::onClickErrorWeb()
{
LLWeb::loadURLExternal(mManager.errorURI());
closeFloater();
+ // Update L$ balance
+ LLStatusBar::sendMoneyBalanceRequest();
}
// static
diff --git a/indra/newview/llfloaterbuycurrencyhtml.cpp b/indra/newview/llfloaterbuycurrencyhtml.cpp
index bde620d965..013cf74c7b 100644
--- a/indra/newview/llfloaterbuycurrencyhtml.cpp
+++ b/indra/newview/llfloaterbuycurrencyhtml.cpp
@@ -82,7 +82,7 @@ void LLFloaterBuyCurrencyHTML::navigateToFinalURL()
LLStringUtil::format( buy_currency_url, replace );
// write final URL to debug console
- llinfos << "Buy currency HTML prased URL is " << buy_currency_url << llendl;
+ llinfos << "Buy currency HTML parsed URL is " << buy_currency_url << llendl;
// kick off the navigation
mBrowser->navigateTo( buy_currency_url, "text/html" );
@@ -105,7 +105,7 @@ void LLFloaterBuyCurrencyHTML::handleMediaEvent( LLPluginClassMedia* self, EMedi
//
void LLFloaterBuyCurrencyHTML::onClose( bool app_quitting )
{
- // update L$ balanace one more time
+ // Update L$ balance one more time
LLStatusBar::sendMoneyBalanceRequest();
destroy();
diff --git a/indra/newview/llfloaterbuyland.cpp b/indra/newview/llfloaterbuyland.cpp
index 83105ef27c..50b19a4221 100644
--- a/indra/newview/llfloaterbuyland.cpp
+++ b/indra/newview/llfloaterbuyland.cpp
@@ -459,10 +459,18 @@ void LLFloaterBuyLandUI::updateParcelInfo()
return;
}
- if (!authorizedBuyer.isNull() && buyer != authorizedBuyer)
+ if (!authorizedBuyer.isNull() && buyer != authorizedBuyer)
{
- mCannotBuyReason = getString("set_to_sell_to_other");
- return;
+ // Maybe the parcel is set for sale to a group we are in.
+ bool authorized_group =
+ gAgent.hasPowerInGroup(authorizedBuyer,GP_LAND_DEED)
+ && gAgent.hasPowerInGroup(authorizedBuyer,GP_LAND_SET_SALE_INFO);
+
+ if (!authorized_group)
+ {
+ mCannotBuyReason = getString("set_to_sell_to_other");
+ return;
+ }
}
}
else
diff --git a/indra/newview/llfloatercamera.cpp b/indra/newview/llfloatercamera.cpp
index ad24c6534a..1dfa904a19 100644
--- a/indra/newview/llfloatercamera.cpp
+++ b/indra/newview/llfloatercamera.cpp
@@ -40,6 +40,8 @@
#include "lltoolmgr.h"
#include "lltoolfocus.h"
#include "llslider.h"
+#include "llfirstuse.h"
+#include "llhints.h"
static LLDefaultChildRegistry::Register<LLPanelCameraItem> r("panel_camera_item");
@@ -73,6 +75,8 @@ protected:
void onZoomPlusHeldDown();
void onZoomMinusHeldDown();
void onSliderValueChanged();
+ void onCameraTrack();
+ void onCameraRotate();
F32 getOrbitRate(F32 time);
private:
@@ -162,6 +166,8 @@ LLPanelCameraZoom::LLPanelCameraZoom()
mCommitCallbackRegistrar.add("Zoom.minus", boost::bind(&LLPanelCameraZoom::onZoomMinusHeldDown, this));
mCommitCallbackRegistrar.add("Zoom.plus", boost::bind(&LLPanelCameraZoom::onZoomPlusHeldDown, this));
mCommitCallbackRegistrar.add("Slider.value_changed", boost::bind(&LLPanelCameraZoom::onSliderValueChanged, this));
+ mCommitCallbackRegistrar.add("Camera.track", boost::bind(&LLPanelCameraZoom::onCameraTrack, this));
+ mCommitCallbackRegistrar.add("Camera.rotate", boost::bind(&LLPanelCameraZoom::onCameraRotate, this));
}
BOOL LLPanelCameraZoom::postBuild()
@@ -198,6 +204,18 @@ void LLPanelCameraZoom::onZoomMinusHeldDown()
gAgentCamera.setOrbitOutKey(getOrbitRate(time));
}
+void LLPanelCameraZoom::onCameraTrack()
+{
+ // EXP-202 when camera panning activated, remove the hint
+ LLFirstUse::viewPopup( false );
+}
+
+void LLPanelCameraZoom::onCameraRotate()
+{
+ // EXP-202 when camera rotation activated, remove the hint
+ LLFirstUse::viewPopup( false );
+}
+
F32 LLPanelCameraZoom::getOrbitRate(F32 time)
{
if( time < NUDGE_TIME )
@@ -294,6 +312,8 @@ LLFloaterCamera* LLFloaterCamera::findInstance()
void LLFloaterCamera::onOpen(const LLSD& key)
{
+ LLFirstUse::viewPopup();
+
LLButton *anchor_panel = LLBottomTray::getInstance()->getChild<LLButton>("camera_btn");
setDockControl(new LLDockControl(
@@ -336,6 +356,7 @@ LLFloaterCamera::LLFloaterCamera(const LLSD& val)
mCurrMode(CAMERA_CTRL_MODE_PAN),
mPrevMode(CAMERA_CTRL_MODE_PAN)
{
+ LLHints::registerHintTarget("view_popup", LLView::getHandle());
}
// virtual
@@ -343,6 +364,7 @@ BOOL LLFloaterCamera::postBuild()
{
setIsChrome(TRUE);
setTitleVisible(TRUE); // restore title visibility after chrome applying
+ updateTransparency(TT_ACTIVE); // force using active floater transparency (STORM-730)
mRotate = getChild<LLJoystickCameraRotate>(ORBIT);
mZoom = findChild<LLPanelCameraZoom>(ZOOM);
diff --git a/indra/newview/llfloaterchat.cpp b/indra/newview/llfloaterchat.cpp
index c2c2e7fe22..2679dbb78b 100644
--- a/indra/newview/llfloaterchat.cpp
+++ b/indra/newview/llfloaterchat.cpp
@@ -413,8 +413,9 @@ LLColor4 get_text_color(const LLChat& chat)
if (!chat.mPosAgent.isExactlyZero())
{
LLVector3 pos_agent = gAgent.getPositionAgent();
- F32 distance = dist_vec(pos_agent, chat.mPosAgent);
- if (distance > gAgent.getNearChatRadius())
+ F32 distance_squared = dist_vec_squared(pos_agent, chat.mPosAgent);
+ F32 dist_near_chat = gAgent.getNearChatRadius();
+ if (distance_squared > dist_near_chat * dist_near_chat)
{
// diminish far-off chat
text_color.mV[VALPHA] = 0.8f;
diff --git a/indra/newview/llfloatercolorpicker.cpp b/indra/newview/llfloatercolorpicker.cpp
index 69f1774ff8..659e52271a 100644
--- a/indra/newview/llfloatercolorpicker.cpp
+++ b/indra/newview/llfloatercolorpicker.cpp
@@ -472,6 +472,12 @@ void LLFloaterColorPicker::onMouseCaptureLost()
setMouseDownInLumRegion(FALSE);
}
+F32 LLFloaterColorPicker::getSwatchTransparency()
+{
+ // If the floater is focused, don't apply its alpha to the color swatch (STORM-676).
+ return getTransparencyType() == TT_ACTIVE ? 1.f : LLFloater::getCurrentTransparency();
+}
+
//////////////////////////////////////////////////////////////////////////////
//
void LLFloaterColorPicker::draw()
@@ -533,8 +539,10 @@ void LLFloaterColorPicker::draw()
// base floater stuff
LLFloater::draw ();
+ const F32 alpha = getSwatchTransparency();
+
// draw image for RGB area (not really RGB but you'll see what I mean...
- gl_draw_image ( mRGBViewerImageLeft, mRGBViewerImageTop - mRGBViewerImageHeight, mRGBImage, LLColor4::white );
+ gl_draw_image ( mRGBViewerImageLeft, mRGBViewerImageTop - mRGBViewerImageHeight, mRGBImage, LLColor4::white % alpha);
// update 'cursor' into RGB Section
S32 xPos = ( S32 ) ( ( F32 )mRGBViewerImageWidth * getCurH () ) - 8;
@@ -556,7 +564,7 @@ void LLFloaterColorPicker::draw()
mRGBViewerImageTop - mRGBViewerImageHeight,
mRGBViewerImageLeft + mRGBViewerImageWidth + 1,
mRGBViewerImageTop,
- LLColor4 ( 0.0f, 0.0f, 0.0f, 1.0f ),
+ LLColor4 ( 0.0f, 0.0f, 0.0f, alpha ),
FALSE );
// draw luminance slider
@@ -569,7 +577,7 @@ void LLFloaterColorPicker::draw()
mLumRegionTop - mLumRegionHeight + y,
mLumRegionLeft + mLumRegionWidth,
mLumRegionTop - mLumRegionHeight + y - 1,
- LLColor4 ( rValSlider, gValSlider, bValSlider, 1.0f ) );
+ LLColor4 ( rValSlider, gValSlider, bValSlider, alpha ) );
}
@@ -594,7 +602,7 @@ void LLFloaterColorPicker::draw()
mSwatchRegionTop - mSwatchRegionHeight,
mSwatchRegionLeft + mSwatchRegionWidth,
mSwatchRegionTop,
- LLColor4 ( getCurR (), getCurG (), getCurB (), 1.0f ),
+ LLColor4 ( getCurR (), getCurG (), getCurB (), alpha ),
TRUE );
// draw selected color swatch outline
@@ -634,6 +642,7 @@ const LLColor4& LLFloaterColorPicker::getComplimentaryColor ( const LLColor4& ba
void LLFloaterColorPicker::drawPalette ()
{
S32 curEntry = 0;
+ const F32 alpha = getSwatchTransparency();
for ( S32 y = 0; y < numPaletteRows; ++y )
{
@@ -648,7 +657,7 @@ void LLFloaterColorPicker::drawPalette ()
// draw palette entry color
if ( mPalette [ curEntry ] )
{
- gl_rect_2d ( x1 + 2, y1 - 2, x2 - 2, y2 + 2, *mPalette [ curEntry++ ], TRUE );
+ gl_rect_2d ( x1 + 2, y1 - 2, x2 - 2, y2 + 2, *mPalette [ curEntry++ ] % alpha, TRUE );
gl_rect_2d ( x1 + 1, y1 - 1, x2 - 1, y2 + 1, LLColor4 ( 0.0f, 0.0f, 0.0f, 1.0f ), FALSE );
}
}
diff --git a/indra/newview/llfloatercolorpicker.h b/indra/newview/llfloatercolorpicker.h
index 110fa43b9c..8e387c4f7c 100644
--- a/indra/newview/llfloatercolorpicker.h
+++ b/indra/newview/llfloatercolorpicker.h
@@ -55,6 +55,7 @@ class LLFloaterColorPicker
virtual BOOL handleMouseUp ( S32 x, S32 y, MASK mask );
virtual BOOL handleHover ( S32 x, S32 y, MASK mask );
virtual void onMouseCaptureLost();
+ virtual F32 getSwatchTransparency();
// implicit methods
void createUI ();
diff --git a/indra/newview/llfloaterevent.cpp b/indra/newview/llfloaterevent.cpp
index 0b5ac8e798..a6dafda3e6 100644
--- a/indra/newview/llfloaterevent.cpp
+++ b/indra/newview/llfloaterevent.cpp
@@ -117,8 +117,3 @@ void LLFloaterEvent::setEventID(const U32 event_id)
}
}
-
-void LLFloaterEvent::draw()
-{
- LLPanel::draw();
-}
diff --git a/indra/newview/llfloaterevent.h b/indra/newview/llfloaterevent.h
index b1963309da..ed90055d95 100644
--- a/indra/newview/llfloaterevent.h
+++ b/indra/newview/llfloaterevent.h
@@ -43,7 +43,6 @@ public:
/*virtual*/ ~LLFloaterEvent();
/*virtual*/ BOOL postBuild();
- /*virtual*/ void draw();
void setEventID(const U32 event_id);
diff --git a/indra/newview/llfloatergodtools.cpp b/indra/newview/llfloatergodtools.cpp
index 662e1c4f42..a34e0353ec 100644
--- a/indra/newview/llfloatergodtools.cpp
+++ b/indra/newview/llfloatergodtools.cpp
@@ -209,13 +209,6 @@ void LLFloaterGodTools::processRegionInfo(LLMessageSystem* msg)
llassert(msg);
if (!msg) return;
- LLHost host = msg->getSender();
- if (host != gAgent.getRegionHost())
- {
- // update is for a different region than the one we're in
- return;
- }
-
//const S32 SIM_NAME_BUF = 256;
U32 region_flags;
U8 sim_access;
@@ -233,6 +226,8 @@ void LLFloaterGodTools::processRegionInfo(LLMessageSystem* msg)
S32 redirect_grid_y;
LLUUID cache_id;
+ LLHost host = msg->getSender();
+
msg->getStringFast(_PREHASH_RegionInfo, _PREHASH_SimName, sim_name);
msg->getU32Fast(_PREHASH_RegionInfo, _PREHASH_EstateID, estate_id);
msg->getU32Fast(_PREHASH_RegionInfo, _PREHASH_ParentEstateID, parent_estate_id);
@@ -242,6 +237,15 @@ void LLFloaterGodTools::processRegionInfo(LLMessageSystem* msg)
msg->getF32Fast(_PREHASH_RegionInfo, _PREHASH_ObjectBonusFactor, object_bonus_factor);
msg->getF32Fast(_PREHASH_RegionInfo, _PREHASH_BillableFactor, billable_factor);
msg->getF32Fast(_PREHASH_RegionInfo, _PREHASH_WaterHeight, water_height);
+
+ if (host != gAgent.getRegionHost())
+ {
+ // Update is for a different region than the one we're in.
+ // Just check for a waterheight change.
+ LLWorld::getInstance()->waterHeightRegionInfo(sim_name, water_height);
+ return;
+ }
+
msg->getF32Fast(_PREHASH_RegionInfo, _PREHASH_TerrainRaiseLimit, terrain_raise_limit);
msg->getF32Fast(_PREHASH_RegionInfo, _PREHASH_TerrainLowerLimit, terrain_lower_limit);
msg->getS32Fast(_PREHASH_RegionInfo, _PREHASH_PricePerMeter, price_per_meter);
diff --git a/indra/newview/llfloatergroups.cpp b/indra/newview/llfloatergroups.cpp
index 234a09d157..d84364a68a 100644
--- a/indra/newview/llfloatergroups.cpp
+++ b/indra/newview/llfloatergroups.cpp
@@ -41,6 +41,7 @@
#include "llbutton.h"
#include "llgroupactions.h"
#include "llscrolllistctrl.h"
+#include "llstartup.h"
#include "lltextbox.h"
#include "lluictrlfactory.h"
#include "lltrans.h"
@@ -171,7 +172,7 @@ void LLPanelGroups::reset()
group_list->operateOnAll(LLCtrlListInterface::OP_DELETE);
}
getChild<LLUICtrl>("groupcount")->setTextArg("[COUNT]", llformat("%d",gAgent.mGroups.count()));
- getChild<LLUICtrl>("groupcount")->setTextArg("[MAX]", llformat("%d",MAX_AGENT_GROUPS));
+ getChild<LLUICtrl>("groupcount")->setTextArg("[MAX]", llformat("%d",gMaxAgentGroups));
init_group_list(getChild<LLScrollListCtrl>("group list"), gAgent.getGroupID());
enableButtons();
@@ -182,7 +183,7 @@ BOOL LLPanelGroups::postBuild()
childSetCommitCallback("group list", onGroupList, this);
getChild<LLUICtrl>("groupcount")->setTextArg("[COUNT]", llformat("%d",gAgent.mGroups.count()));
- getChild<LLUICtrl>("groupcount")->setTextArg("[MAX]", llformat("%d",MAX_AGENT_GROUPS));
+ getChild<LLUICtrl>("groupcount")->setTextArg("[MAX]", llformat("%d",gMaxAgentGroups));
LLScrollListCtrl *list = getChild<LLScrollListCtrl>("group list");
if (list)
diff --git a/indra/newview/llfloaterhardwaresettings.cpp b/indra/newview/llfloaterhardwaresettings.cpp
index 1e91710552..42ec7d765b 100644
--- a/indra/newview/llfloaterhardwaresettings.cpp
+++ b/indra/newview/llfloaterhardwaresettings.cpp
@@ -50,7 +50,6 @@ LLFloaterHardwareSettings::LLFloaterHardwareSettings(const LLSD& key)
// but init them anyway
mUseVBO(0),
mUseAniso(0),
- mUseFBO(0),
mFSAASamples(0),
mGamma(0.0),
mVideoCardMem(0),
@@ -75,7 +74,6 @@ void LLFloaterHardwareSettings::refresh()
mUseVBO = gSavedSettings.getBOOL("RenderVBOEnable");
mUseAniso = gSavedSettings.getBOOL("RenderAnisotropic");
- mUseFBO = gSavedSettings.getBOOL("RenderUseFBO");
mFSAASamples = gSavedSettings.getU32("RenderFSAASamples");
mGamma = gSavedSettings.getF32("RenderGamma");
mVideoCardMem = gSavedSettings.getS32("TextureMemory");
@@ -104,7 +102,7 @@ void LLFloaterHardwareSettings::refreshEnabledState()
getChildView("(brightness, lower is brighter)")->setEnabled(!gPipeline.canUseWindLightShaders());
getChildView("fog")->setEnabled(!gPipeline.canUseWindLightShaders());
getChildView("fsaa")->setEnabled(gPipeline.canUseAntiAliasing());
- getChildView("antialiasing restart")->setVisible(!gSavedSettings.getBOOL("RenderUseFBO"));
+ getChildView("antialiasing restart")->setVisible(!gSavedSettings.getBOOL("RenderDeferred"));
/* Enable to reset fsaa value to disabled when feature is not available.
if (!gPipeline.canUseAntiAliasing())
@@ -139,7 +137,6 @@ void LLFloaterHardwareSettings::cancel()
{
gSavedSettings.setBOOL("RenderVBOEnable", mUseVBO);
gSavedSettings.setBOOL("RenderAnisotropic", mUseAniso);
- gSavedSettings.setBOOL("RenderUseFBO", mUseFBO);
gSavedSettings.setU32("RenderFSAASamples", mFSAASamples);
gSavedSettings.setF32("RenderGamma", mGamma);
gSavedSettings.setS32("TextureMemory", mVideoCardMem);
diff --git a/indra/newview/llfloaterhelpbrowser.cpp b/indra/newview/llfloaterhelpbrowser.cpp
index cec98e9992..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);
@@ -132,9 +133,10 @@ void LLFloaterHelpBrowser::onClickOpenWebBrowser(void* user_data)
void LLFloaterHelpBrowser::openMedia(const std::string& media_url)
{
- mBrowser->setHomePageUrl(media_url);
- //mBrowser->navigateTo("data:text/html;charset=utf-8,I'd really love to be going to:<br><b>" + media_url + "</b>"); // tofu HACK for debugging =:)
- mBrowser->navigateTo(media_url);
+ // explicitly make the media mime type for this floater since it will
+ // only ever display one type of content (Web).
+ mBrowser->setHomePageUrl(media_url, "text/html");
+ mBrowser->navigateTo(media_url, "text/html");
setCurrentURL(media_url);
}
diff --git a/indra/newview/llfloaterimagepreview.cpp b/indra/newview/llfloaterimagepreview.cpp
index c7fbdd5745..e4d8e3513d 100644
--- a/indra/newview/llfloaterimagepreview.cpp
+++ b/indra/newview/llfloaterimagepreview.cpp
@@ -63,7 +63,7 @@ const S32 PREVIEW_BORDER_WIDTH = 2;
const S32 PREVIEW_RESIZE_HANDLE_SIZE = S32(RESIZE_HANDLE_WIDTH * OO_SQRT2) + PREVIEW_BORDER_WIDTH;
const S32 PREVIEW_HPAD = PREVIEW_RESIZE_HANDLE_SIZE;
const S32 PREF_BUTTON_HEIGHT = 16 + 7 + 16;
-const S32 PREVIEW_TEXTURE_HEIGHT = 300;
+const S32 PREVIEW_TEXTURE_HEIGHT = 320;
//-----------------------------------------------------------------------------
// LLFloaterImagePreview()
@@ -325,122 +325,51 @@ void LLFloaterImagePreview::draw()
bool LLFloaterImagePreview::loadImage(const std::string& src_filename)
{
std::string exten = gDirUtilp->getExtension(src_filename);
-
- U32 codec = IMG_CODEC_INVALID;
- std::string temp_str;
- if( exten == "bmp")
- {
- codec = IMG_CODEC_BMP;
- }
- else if( exten == "tga")
- {
- codec = IMG_CODEC_TGA;
- }
- else if( exten == "jpg" || exten == "jpeg")
- {
- codec = IMG_CODEC_JPEG;
- }
- else if( exten == "png" )
- {
- codec = IMG_CODEC_PNG;
- }
+ U32 codec = LLImageBase::getCodecFromExtension(exten);
LLImageDimensionsInfo image_info;
- if(!image_info.load(src_filename,codec))
+ if (!image_info.load(src_filename,codec))
{
mImageLoadError = image_info.getLastError();
return false;
}
S32 max_width = gSavedSettings.getS32("max_texture_dimension_X");
- S32 max_heigh = gSavedSettings.getS32("max_texture_dimension_Y");
+ S32 max_height = gSavedSettings.getS32("max_texture_dimension_Y");
- if(image_info.getWidth() > max_width|| image_info.getHeight() > max_heigh)
+ if ((image_info.getWidth() > max_width) || (image_info.getHeight() > max_height))
{
LLStringUtil::format_map_t args;
args["WIDTH"] = llformat("%d", max_width);
- args["HEIGHT"] = llformat("%d", max_heigh);
+ args["HEIGHT"] = llformat("%d", max_height);
mImageLoadError = LLTrans::getString("texture_load_dimensions_error", args);
return false;
}
-
+ // Load the image
+ LLPointer<LLImageFormatted> image = LLImageFormatted::createFromType(codec);
+ if (image.isNull())
+ {
+ return false;
+ }
+ if (!image->load(src_filename))
+ {
+ return false;
+ }
+ // Decompress or expand it in a raw image structure
LLPointer<LLImageRaw> raw_image = new LLImageRaw;
-
- switch (codec)
+ if (!image->decode(raw_image, 0.0f))
{
- case IMG_CODEC_BMP:
- {
- LLPointer<LLImageBMP> bmp_image = new LLImageBMP;
-
- if (!bmp_image->load(src_filename))
- {
- return false;
- }
-
- if (!bmp_image->decode(raw_image, 0.0f))
- {
- return false;
- }
- }
- break;
- case IMG_CODEC_TGA:
- {
- LLPointer<LLImageTGA> tga_image = new LLImageTGA;
-
- if (!tga_image->load(src_filename))
- {
- return false;
- }
-
- if (!tga_image->decode(raw_image))
- {
- return false;
- }
-
- if( (tga_image->getComponents() != 3) &&
- (tga_image->getComponents() != 4) )
- {
- tga_image->setLastError( "Image files with less than 3 or more than 4 components are not supported." );
- return false;
- }
- }
- break;
- case IMG_CODEC_JPEG:
- {
- LLPointer<LLImageJPEG> jpeg_image = new LLImageJPEG;
-
- if (!jpeg_image->load(src_filename))
- {
- return false;
- }
-
- if (!jpeg_image->decode(raw_image, 0.0f))
- {
- return false;
- }
- }
- break;
- case IMG_CODEC_PNG:
- {
- LLPointer<LLImagePNG> png_image = new LLImagePNG;
-
- if (!png_image->load(src_filename))
- {
- return false;
- }
-
- if (!png_image->decode(raw_image, 0.0f))
- {
- return false;
- }
- }
- break;
- default:
return false;
}
-
+ // Check the image constraints
+ if ((image->getComponents() != 3) && (image->getComponents() != 4))
+ {
+ image->setLastError("Image files with less than 3 or more than 4 components are not supported.");
+ return false;
+ }
+
raw_image->biasedScaleToPowerOfTwo(1024);
mRawImagep = raw_image;
@@ -858,8 +787,8 @@ void LLImagePreviewSculpted::setPreviewTarget(LLImageRaw* imagep, F32 distance)
}
const LLVolumeFace &vf = mVolume->getVolumeFace(0);
- U32 num_indices = vf.mIndices.size();
- U32 num_vertices = vf.mVertices.size();
+ U32 num_indices = vf.mNumIndices;
+ U32 num_vertices = vf.mNumVertices;
mVertexBuffer = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL, 0);
mVertexBuffer->allocateBuffer(num_vertices, num_indices, TRUE);
@@ -873,10 +802,16 @@ void LLImagePreviewSculpted::setPreviewTarget(LLImageRaw* imagep, F32 distance)
mVertexBuffer->getIndexStrider(index_strider);
// build vertices and normals
+ LLStrider<LLVector3> pos;
+ pos = (LLVector3*) vf.mPositions; pos.setStride(16);
+ LLStrider<LLVector3> norm;
+ norm = (LLVector3*) vf.mNormals; norm.setStride(16);
+
+
for (U32 i = 0; i < num_vertices; i++)
{
- *(vertex_strider++) = vf.mVertices[i].mPosition;
- LLVector3 normal = vf.mVertices[i].mNormal;
+ *(vertex_strider++) = *pos++;
+ LLVector3 normal = *norm++;
normal.normalize();
*(normal_strider++) = normal;
}
@@ -895,7 +830,6 @@ void LLImagePreviewSculpted::setPreviewTarget(LLImageRaw* imagep, F32 distance)
BOOL LLImagePreviewSculpted::render()
{
mNeedsUpdate = FALSE;
-
LLGLSUIDefault def;
LLGLDisable no_blend(GL_BLEND);
LLGLEnable cull(GL_CULL_FACE);
@@ -940,7 +874,7 @@ BOOL LLImagePreviewSculpted::render()
LLViewerCamera::getInstance()->setPerspective(FALSE, mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight, FALSE);
const LLVolumeFace &vf = mVolume->getVolumeFace(0);
- U32 num_indices = vf.mIndices.size();
+ U32 num_indices = vf.mNumIndices;
mVertexBuffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL);
@@ -953,7 +887,6 @@ BOOL LLImagePreviewSculpted::render()
mVertexBuffer->draw(LLRender::TRIANGLES, num_indices, 0);
gGL.popMatrix();
-
return TRUE;
}
diff --git a/indra/newview/llfloaterland.cpp b/indra/newview/llfloaterland.cpp
index a6025661b7..0d0c1f594d 100644
--- a/indra/newview/llfloaterland.cpp
+++ b/indra/newview/llfloaterland.cpp
@@ -38,6 +38,7 @@
#include "message.h"
#include "llagent.h"
+#include "llagentaccess.h"
#include "llbutton.h"
#include "llcheckboxctrl.h"
#include "llcombobox.h"
@@ -2871,7 +2872,10 @@ void LLPanelLandCovenant::refresh()
LLTextBox* region_landtype = getChild<LLTextBox>("region_landtype_text");
if (region_landtype)
{
- region_landtype->setText(region->getSimProductName());
+ std::string land_type;
+ bool is_land_type_localized = LLTrans::findString(land_type, region->getSimProductName());
+
+ region_landtype->setText(is_land_type_localized ? land_type : region->getSimProductName());
}
LLTextBox* region_maturity = getChild<LLTextBox>("region_maturity_text");
diff --git a/indra/newview/llfloaterland.h b/indra/newview/llfloaterland.h
index a096fb64cd..8a70fa24d8 100644
--- a/indra/newview/llfloaterland.h
+++ b/indra/newview/llfloaterland.h
@@ -43,11 +43,12 @@ class LLButton;
class LLCheckBoxCtrl;
class LLRadioGroup;
class LLComboBox;
-class LLNameListCtrl;
-class LLSpinCtrl;
class LLLineEditor;
+class LLMessageSystem;
+class LLNameListCtrl;
class LLRadioGroup;
class LLParcelSelectionObserver;
+class LLSpinCtrl;
class LLTabContainer;
class LLTextBox;
class LLTextEditor;
diff --git a/indra/newview/llfloatermap.cpp b/indra/newview/llfloatermap.cpp
index a1d291fea6..641e64247b 100644
--- a/indra/newview/llfloatermap.cpp
+++ b/indra/newview/llfloatermap.cpp
@@ -42,7 +42,8 @@
#include "llviewercamera.h"
#include "lldraghandle.h"
#include "lltextbox.h"
-#include "llviewermenu.h"
+#include "llfloaterworldmap.h"
+#include "llagent.h"
//
// Constants
@@ -61,7 +62,6 @@ const S32 MAP_PADDING_BOTTOM = 0;
LLFloaterMap::LLFloaterMap(const LLSD& key)
: LLFloater(key),
- mPopupMenu(NULL),
mTextBoxEast(NULL),
mTextBoxNorth(NULL),
mTextBoxWest(NULL),
@@ -81,8 +81,14 @@ LLFloaterMap::~LLFloaterMap()
BOOL LLFloaterMap::postBuild()
{
mMap = getChild<LLNetMap>("Net Map");
- mMap->setScale(gSavedSettings.getF32("MiniMapScale"));
- mMap->setToolTipMsg(getString("ToolTipMsg"));
+ if (gSavedSettings.getBOOL("DoubleClickTeleport"))
+ {
+ mMap->setToolTipMsg(getString("AltToolTipMsg"));
+ }
+ else if (gSavedSettings.getBOOL("DoubleClickShowWorldMap"))
+ {
+ mMap->setToolTipMsg(getString("ToolTipMsg"));
+ }
sendChildToBack(mMap);
mTextBoxNorth = getChild<LLTextBox> ("floater_map_north");
@@ -94,17 +100,6 @@ BOOL LLFloaterMap::postBuild()
mTextBoxSouthWest = getChild<LLTextBox> ("floater_map_southwest");
mTextBoxNorthWest = getChild<LLTextBox> ("floater_map_northwest");
- LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
-
- registrar.add("Minimap.Zoom", boost::bind(&LLFloaterMap::handleZoom, this, _2));
- registrar.add("Minimap.Tracker", boost::bind(&LLFloaterMap::handleStopTracking, this, _2));
-
- mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_mini_map.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
- if (mPopupMenu && !LLTracker::isTracking(0))
- {
- mPopupMenu->setItemEnabled ("Stop Tracking", false);
- }
-
stretchMiniMap(getRect().getWidth() - MAP_PADDING_LEFT - MAP_PADDING_RIGHT
,getRect().getHeight() - MAP_PADDING_TOP - MAP_PADDING_BOTTOM);
@@ -122,21 +117,35 @@ BOOL LLFloaterMap::postBuild()
return TRUE;
}
-BOOL LLFloaterMap::handleDoubleClick( S32 x, S32 y, MASK mask )
+BOOL LLFloaterMap::handleDoubleClick(S32 x, S32 y, MASK mask)
{
// If floater is minimized, minimap should be shown on doubleclick (STORM-299)
- std::string floater_to_show = this->isMinimized() ? "mini_map" : "world_map";
- LLFloaterReg::showInstance(floater_to_show);
- return TRUE;
-}
+ if (isMinimized())
+ {
+ setMinimized(FALSE);
+ return TRUE;
+ }
-BOOL LLFloaterMap::handleRightMouseDown(S32 x, S32 y, MASK mask)
-{
- if (mPopupMenu)
+ LLVector3d pos_global = mMap->viewPosToGlobal(x, y);
+
+ // If we're not tracking a beacon already, double-click will set one
+ if (!LLTracker::isTracking(NULL))
{
- mPopupMenu->buildDrawLabels();
- mPopupMenu->updateParent(LLMenuGL::sMenuContainer);
- LLMenuGL::showPopup(this, mPopupMenu, x, y);
+ LLFloaterWorldMap* world_map = LLFloaterWorldMap::getInstance();
+ if (world_map)
+ {
+ world_map->trackLocation(pos_global);
+ }
+ }
+
+ if (gSavedSettings.getBOOL("DoubleClickTeleport"))
+ {
+ // If DoubleClickTeleport is on, double clicking the minimap will teleport there
+ gAgent.teleportViaLocationLookAt(pos_global);
+ }
+ else if (gSavedSettings.getBOOL("DoubleClickShowWorldMap"))
+ {
+ LLFloaterReg::showInstance("world_map");
}
return TRUE;
}
@@ -211,11 +220,6 @@ void LLFloaterMap::draw()
getDragHandle()->setMouseOpaque(TRUE);
}
- if (LLTracker::isTracking(0))
- {
- mPopupMenu->setItemEnabled ("Stop Tracking", true);
- }
-
LLFloater::draw();
}
@@ -261,7 +265,16 @@ void LLFloaterMap::handleZoom(const LLSD& userdata)
std::string level = userdata.asString();
F32 scale = 0.0f;
- if (level == std::string("close"))
+ if (level == std::string("default"))
+ {
+ LLControlVariable *pvar = gSavedSettings.getControl("MiniMapScale");
+ if(pvar)
+ {
+ pvar->resetToDefault();
+ scale = gSavedSettings.getF32("MiniMapScale");
+ }
+ }
+ else if (level == std::string("close"))
scale = LLNetMap::MAP_SCALE_MAX;
else if (level == std::string("medium"))
scale = LLNetMap::MAP_SCALE_MID;
@@ -269,19 +282,10 @@ void LLFloaterMap::handleZoom(const LLSD& userdata)
scale = LLNetMap::MAP_SCALE_MIN;
if (scale != 0.0f)
{
- gSavedSettings.setF32("MiniMapScale", scale );
mMap->setScale(scale);
}
}
-void LLFloaterMap::handleStopTracking (const LLSD& userdata)
-{
- if (mPopupMenu)
- {
- mPopupMenu->setItemEnabled ("Stop Tracking", false);
- LLTracker::stopTracking ((void*)LLTracker::isTracking(NULL));
- }
-}
void LLFloaterMap::setMinimized(BOOL b)
{
LLFloater::setMinimized(b);
diff --git a/indra/newview/llfloatermap.h b/indra/newview/llfloatermap.h
index 4cbb48fb3e..5cf66a594b 100644
--- a/indra/newview/llfloatermap.h
+++ b/indra/newview/llfloatermap.h
@@ -29,7 +29,6 @@
#include "llfloater.h"
-class LLMenuGL;
class LLNetMap;
class LLTextBox;
@@ -44,7 +43,6 @@ public:
/*virtual*/ BOOL postBuild();
/*virtual*/ BOOL handleDoubleClick( S32 x, S32 y, MASK mask );
- /*virtual*/ BOOL handleRightMouseDown( S32 x, S32 y, MASK mask );
/*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
/*virtual*/ void draw();
/*virtual*/ void onFocusLost();
@@ -54,14 +52,11 @@ public:
private:
void handleZoom(const LLSD& userdata);
- void handleStopTracking (const LLSD& userdata);
void setDirectionPos( LLTextBox* text_box, F32 rotation );
void updateMinorDirections();
void stretchMiniMap(S32 width,S32 height);
- LLMenuGL* mPopupMenu;
-
LLTextBox* mTextBoxEast;
LLTextBox* mTextBoxNorth;
LLTextBox* mTextBoxWest;
diff --git a/indra/newview/llfloatermediabrowser.cpp b/indra/newview/llfloatermediabrowser.cpp
index d20092e344..7a670dd90c 100644
--- a/indra/newview/llfloatermediabrowser.cpp
+++ b/indra/newview/llfloatermediabrowser.cpp
@@ -306,17 +306,14 @@ void LLFloaterMediaBrowser::setCurrentURL(const std::string& url)
{
mCurrentURL = url;
- // redirects will navigate momentarily to about:blank, don't add to history
- if (mCurrentURL != "about:blank")
- {
- mAddressCombo->remove(mCurrentURL);
- mAddressCombo->add(mCurrentURL);
- mAddressCombo->selectByValue(mCurrentURL);
+ mAddressCombo->remove(mCurrentURL);
+ mAddressCombo->add(mCurrentURL);
+ mAddressCombo->selectByValue(mCurrentURL);
+
+ // Serialize url history
+ LLURLHistory::removeURL("browser", mCurrentURL);
+ LLURLHistory::addURL("browser", mCurrentURL);
- // Serialize url history
- LLURLHistory::removeURL("browser", mCurrentURL);
- LLURLHistory::addURL("browser", mCurrentURL);
- }
getChildView("back")->setEnabled(mBrowser->canNavigateBack());
getChildView("forward")->setEnabled(mBrowser->canNavigateForward());
getChildView("reload")->setEnabled(TRUE);
@@ -334,8 +331,15 @@ void LLFloaterMediaBrowser::onClickRefresh(void* user_data)
{
LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data;
- self->mAddressCombo->remove(0);
- self->mBrowser->navigateTo(self->mCurrentURL);
+ if( self->mBrowser->getMediaPlugin() && self->mBrowser->getMediaPlugin()->pluginSupportsMediaBrowser())
+ {
+ bool ignore_cache = true;
+ self->mBrowser->getMediaPlugin()->browse_reload( ignore_cache );
+ }
+ else
+ {
+ self->mBrowser->navigateTo(self->mCurrentURL);
+ }
}
//static
diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp
new file mode 100644
index 0000000000..e8da1aa42c
--- /dev/null
+++ b/indra/newview/llfloatermodelpreview.cpp
@@ -0,0 +1,5017 @@
+/**
+ * @file llfloatermodelpreview.cpp
+ * @brief LLFloaterModelPreview 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 "dae.h"
+//#include "dom.h"
+#include "dom/domAsset.h"
+#include "dom/domBind_material.h"
+#include "dom/domCOLLADA.h"
+#include "dom/domConstants.h"
+#include "dom/domController.h"
+#include "dom/domEffect.h"
+#include "dom/domGeometry.h"
+#include "dom/domInstance_geometry.h"
+#include "dom/domInstance_material.h"
+#include "dom/domInstance_node.h"
+#include "dom/domInstance_effect.h"
+#include "dom/domMaterial.h"
+#include "dom/domMatrix.h"
+#include "dom/domNode.h"
+#include "dom/domProfile_COMMON.h"
+#include "dom/domRotate.h"
+#include "dom/domScale.h"
+#include "dom/domTranslate.h"
+#include "dom/domVisual_scene.h"
+
+#include "llfloatermodelpreview.h"
+
+#include "llfilepicker.h"
+#include "llimagebmp.h"
+#include "llimagetga.h"
+#include "llimagejpeg.h"
+#include "llimagepng.h"
+
+#include "llagent.h"
+#include "llbutton.h"
+#include "llcombobox.h"
+#include "lldatapacker.h"
+#include "lldrawable.h"
+#include "lldrawpoolavatar.h"
+#include "llrender.h"
+#include "llface.h"
+#include "lleconomy.h"
+#include "llfocusmgr.h"
+#include "llfloaterperms.h"
+#include "lliconctrl.h"
+#include "llmatrix4a.h"
+#include "llmenubutton.h"
+#include "llmeshrepository.h"
+#include "llsdutil_math.h"
+#include "lltextbox.h"
+#include "lltoolmgr.h"
+#include "llui.h"
+#include "llvector4a.h"
+#include "llviewercamera.h"
+#include "llviewerwindow.h"
+#include "llvoavatar.h"
+#include "llvoavatarself.h"
+#include "pipeline.h"
+#include "lluictrlfactory.h"
+#include "llviewercontrol.h"
+#include "llviewermenu.h"
+#include "llviewermenufile.h"
+#include "llviewerregion.h"
+#include "llviewertexturelist.h"
+#include "llstring.h"
+#include "llbutton.h"
+#include "llcheckboxctrl.h"
+#include "llradiogroup.h"
+#include "llsdserialize.h"
+#include "llsliderctrl.h"
+#include "llspinctrl.h"
+#include "lltoggleablemenu.h"
+#include "llvfile.h"
+#include "llvfs.h"
+#include "llcallbacklist.h"
+
+#include "glod/glod.h"
+
+//static
+S32 LLFloaterModelPreview::sUploadAmount = 10;
+LLFloaterModelPreview* LLFloaterModelPreview::sInstance = NULL;
+std::list<LLModelLoader*> LLModelLoader::sActiveLoaderList;
+
+const S32 PREVIEW_BORDER_WIDTH = 2;
+const S32 PREVIEW_RESIZE_HANDLE_SIZE = S32(RESIZE_HANDLE_WIDTH * OO_SQRT2) + PREVIEW_BORDER_WIDTH;
+const S32 PREVIEW_HPAD = PREVIEW_RESIZE_HANDLE_SIZE;
+const S32 PREF_BUTTON_HEIGHT = 16 + 7 + 16;
+const S32 PREVIEW_TEXTURE_HEIGHT = 300;
+
+void drawBoxOutline(const LLVector3& pos, const LLVector3& size);
+
+
+std::string lod_name[NUM_LOD+1] =
+{
+ "lowest",
+ "low",
+ "medium",
+ "high",
+ "I went off the end of the lod_name array. Me so smart."
+};
+
+std::string lod_triangles_name[NUM_LOD+1] =
+{
+ "lowest_triangles",
+ "low_triangles",
+ "medium_triangles",
+ "high_triangles",
+ "I went off the end of the lod_triangles_name array. Me so smart."
+};
+
+std::string lod_vertices_name[NUM_LOD+1] =
+{
+ "lowest_vertices",
+ "low_vertices",
+ "medium_vertices",
+ "high_vertices",
+ "I went off the end of the lod_vertices_name array. Me so smart."
+};
+
+std::string lod_status_name[NUM_LOD+1] =
+{
+ "lowest_status",
+ "low_status",
+ "medium_status",
+ "high_status",
+ "I went off the end of the lod_status_name array. Me so smart."
+};
+
+std::string lod_icon_name[NUM_LOD+1] =
+{
+ "status_icon_lowest",
+ "status_icon_low",
+ "status_icon_medium",
+ "status_icon_high",
+ "I went off the end of the lod_status_name array. Me so smart."
+};
+
+std::string lod_status_image[NUM_LOD+1] =
+{
+ "ModelImport_Status_Good",
+ "ModelImport_Status_Warning",
+ "ModelImport_Status_Error",
+ "I went off the end of the lod_status_image array. Me so smart."
+};
+
+std::string lod_label_name[NUM_LOD+1] =
+{
+ "lowest_label",
+ "low_label",
+ "medium_label",
+ "high_label",
+ "I went off the end of the lod_label_name array. Me so smart."
+};
+
+bool validate_face(const LLVolumeFace& face)
+{
+ for (U32 i = 0; i < face.mNumIndices; ++i)
+ {
+ if (face.mIndices[i] >= face.mNumVertices)
+ {
+ llwarns << "Face has invalid index." << llendl;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool validate_model(const LLModel* mdl)
+{
+ if (mdl->getNumVolumeFaces() == 0)
+ {
+ llwarns << "Model has no faces!" << llendl;
+ return false;
+ }
+
+ for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i)
+ {
+ if (mdl->getVolumeFace(i).mNumVertices == 0)
+ {
+ llwarns << "Face has no vertices." << llendl;
+ return false;
+ }
+
+ if (mdl->getVolumeFace(i).mNumIndices == 0)
+ {
+ llwarns << "Face has no indices." << llendl;
+ return false;
+ }
+
+ if (!validate_face(mdl->getVolumeFace(i)))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+BOOL stop_gloderror()
+{
+ GLuint error = glodGetError();
+
+ if (error != GLOD_NO_ERROR)
+ {
+ llwarns << "GLOD error detected, cannot generate LOD: " << std::hex << error << llendl;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+LLMeshFilePicker::LLMeshFilePicker(LLModelPreview* mp, S32 lod)
+ : LLFilePickerThread(LLFilePicker::FFLOAD_COLLADA)
+ {
+ mMP = mp;
+ mLOD = lod;
+ }
+
+void LLMeshFilePicker::notify(const std::string& filename)
+{
+ mMP->loadModel(mFile, mLOD);
+}
+
+
+//-----------------------------------------------------------------------------
+// LLFloaterModelPreview()
+//-----------------------------------------------------------------------------
+LLFloaterModelPreview::LLFloaterModelPreview(const LLSD& key) :
+LLFloater(key)
+{
+ sInstance = this;
+ mLastMouseX = 0;
+ mLastMouseY = 0;
+ mGLName = 0;
+ mStatusLock = new LLMutex(NULL);
+
+ mLODMode[LLModel::LOD_HIGH] = 0;
+ for (U32 i = 0; i < LLModel::LOD_HIGH; i++)
+ {
+ mLODMode[i] = 1;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// postBuild()
+//-----------------------------------------------------------------------------
+BOOL LLFloaterModelPreview::postBuild()
+{
+ if (!LLFloater::postBuild())
+ {
+ return FALSE;
+ }
+
+ childSetAction("lod_browse", onBrowseLOD, this);
+
+ childSetCommitCallback("cancel_btn", onCancel, this);
+ childSetCommitCallback("crease_angle", onGenerateNormalsCommit, this);
+ childSetCommitCallback("generate_normals", onGenerateNormalsCommit, this);
+
+ childSetCommitCallback("lod_generate", onAutoFillCommit, this);
+
+ childSetCommitCallback("lod_mode", onLODParamCommit, this);
+ childSetCommitCallback("lod_error_threshold", onLODParamCommit, this);
+ childSetCommitCallback("lod_triangle_limit", onLODParamCommitTriangleLimit, this);
+ childSetCommitCallback("build_operator", onLODParamCommit, this);
+ childSetCommitCallback("queue_mode", onLODParamCommit, this);
+ childSetCommitCallback("border_mode", onLODParamCommit, this);
+ childSetCommitCallback("share_tolerance", onLODParamCommit, this);
+
+ childSetTextArg("status", "[STATUS]", getString("status_idle"));
+
+ //childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d",sUploadAmount));
+ childSetAction("ok_btn", onUpload, this);
+ childDisable("ok_btn");
+
+ childSetAction("reset_btn", onReset, this);
+
+ childSetAction("clear_materials", onClearMaterials, this);
+
+ childSetCommitCallback("preview_lod_combo", onPreviewLODCommit, this);
+
+ childSetCommitCallback("upload_skin", onUploadSkinCommit, this);
+ childSetCommitCallback("upload_joints", onUploadJointsCommit, this);
+
+ childSetCommitCallback("import_scale", onImportScaleCommit, this);
+ childSetCommitCallback("pelvis_offset", onPelvisOffsetCommit, this);
+
+ childSetCommitCallback("lod_file_or_limit", refresh, this);
+ childSetCommitCallback("physics_load_radio", refresh, this);
+ //childSetCommitCallback("physics_optimize", refresh, this);
+ //childSetCommitCallback("physics_use_hull", refresh, this);
+
+ childDisable("upload_skin");
+ childDisable("upload_joints");
+
+ childDisable("ok_btn");
+
+ mViewOptionMenuButton = getChild<LLMenuButton>("options_gear_btn");
+
+ mCommitCallbackRegistrar.add("ModelImport.ViewOption.Action", boost::bind(&LLFloaterModelPreview::onViewOptionChecked, this, _2));
+ mEnableCallbackRegistrar.add("ModelImport.ViewOption.Check", boost::bind(&LLFloaterModelPreview::isViewOptionChecked, this, _2));
+ mEnableCallbackRegistrar.add("ModelImport.ViewOption.Enabled", boost::bind(&LLFloaterModelPreview::isViewOptionEnabled, this, _2));
+
+
+
+ mViewOptionMenu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_model_import_gear_default.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+ mViewOptionMenuButton->setMenu(mViewOptionMenu, LLMenuButton::MP_BOTTOM_LEFT);
+
+ initDecompControls();
+
+ LLView* preview_panel = getChild<LLView>("preview_panel");
+
+ mPreviewRect = preview_panel->getRect();
+
+ mModelPreview = new LLModelPreview(512, 512, this );
+ mModelPreview->setPreviewTarget(16.f);
+ mModelPreview->setDetailsCallback(boost::bind(&LLFloaterModelPreview::setDetails, this, _1, _2, _3, _4, _5));
+
+ //set callbacks for left click on line editor rows
+ for (U32 i = 0; i <= LLModel::LOD_HIGH; i++)
+ {
+ LLTextBox* text = getChild<LLTextBox>(lod_label_name[i]);
+ if (text)
+ {
+ text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i));
+ }
+
+ text = getChild<LLTextBox>(lod_triangles_name[i]);
+ if (text)
+ {
+ text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i));
+ }
+
+ text = getChild<LLTextBox>(lod_vertices_name[i]);
+ if (text)
+ {
+ text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i));
+ }
+
+ text = getChild<LLTextBox>(lod_status_name[i]);
+ if (text)
+ {
+ text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i));
+ }
+ }
+
+ return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// LLFloaterModelPreview()
+//-----------------------------------------------------------------------------
+LLFloaterModelPreview::~LLFloaterModelPreview()
+{
+ sInstance = NULL;
+
+ if ( mModelPreview && mModelPreview->getResetJointFlag() )
+ {
+ gAgentAvatarp->resetJointPositions();
+ }
+
+
+ if ( mModelPreview )
+ {
+ delete mModelPreview;
+ }
+
+ if (mGLName)
+ {
+ LLImageGL::deleteTextures(1, &mGLName );
+ }
+
+ delete mStatusLock;
+ mStatusLock = NULL;
+}
+
+void LLFloaterModelPreview::onViewOptionChecked(const LLSD& userdata)
+{
+ if (mModelPreview)
+ {
+ mModelPreview->mViewOption[userdata.asString()] = !mModelPreview->mViewOption[userdata.asString()];
+
+ mModelPreview->refresh();
+ }
+}
+
+bool LLFloaterModelPreview::isViewOptionChecked(const LLSD& userdata)
+{
+ if (mModelPreview)
+ {
+ return mModelPreview->mViewOption[userdata.asString()];
+ }
+
+ return false;
+}
+
+bool LLFloaterModelPreview::isViewOptionEnabled(const LLSD& userdata)
+{
+ return !mViewOptionDisabled[userdata.asString()];
+}
+
+void LLFloaterModelPreview::setViewOptionEnabled(const std::string& option, bool enabled)
+{
+ mViewOptionDisabled[option] = !enabled;
+}
+
+void LLFloaterModelPreview::enableViewOption(const std::string& option)
+{
+ setViewOptionEnabled(option, true);
+}
+
+void LLFloaterModelPreview::disableViewOption(const std::string& option)
+{
+ setViewOptionEnabled(option, false);
+}
+
+void LLFloaterModelPreview::loadModel(S32 lod)
+{
+ mModelPreview->mLoading = true;
+
+ (new LLMeshFilePicker(mModelPreview, lod))->getFile();
+}
+
+//static
+void LLFloaterModelPreview::onImportScaleCommit(LLUICtrl*,void* userdata)
+{
+ LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata;
+
+ if (!fp->mModelPreview)
+ {
+ return;
+ }
+
+ fp->mModelPreview->calcResourceCost();
+ fp->mModelPreview->refresh();
+}
+//static
+void LLFloaterModelPreview::onPelvisOffsetCommit( LLUICtrl*, void* userdata )
+{
+ LLFloaterModelPreview *fp =(LLFloaterModelPreview*)userdata;
+
+ if (!fp->mModelPreview)
+ {
+ return;
+ }
+ fp->mModelPreview->calcResourceCost();
+ fp->mModelPreview->refresh();
+}
+
+//static
+void LLFloaterModelPreview::onUploadJointsCommit(LLUICtrl*,void* userdata)
+{
+ LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata;
+
+ if (!fp->mModelPreview)
+ {
+ return;
+ }
+
+ fp->mModelPreview->refresh();
+}
+
+//static
+void LLFloaterModelPreview::onUploadSkinCommit(LLUICtrl*,void* userdata)
+{
+ LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata;
+
+ if (!fp->mModelPreview)
+ {
+ return;
+ }
+
+ fp->mModelPreview->calcResourceCost();
+ fp->mModelPreview->refresh();
+ fp->mModelPreview->resetPreviewTarget();
+ fp->mModelPreview->clearBuffers();
+}
+
+//static
+void LLFloaterModelPreview::onPreviewLODCommit(LLUICtrl* ctrl, void* userdata)
+{
+ LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata;
+
+ if (!fp->mModelPreview)
+ {
+ return;
+ }
+
+ S32 which_mode = 0;
+
+ LLComboBox* combo = (LLComboBox*) ctrl;
+
+ which_mode = (NUM_LOD-1)-combo->getFirstSelectedIndex(); // combo box list of lods is in reverse order
+
+ fp->mModelPreview->setPreviewLOD(which_mode);
+}
+
+//static
+void LLFloaterModelPreview::onGenerateNormalsCommit(LLUICtrl* ctrl, void* userdata)
+{
+ LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata;
+
+ fp->mModelPreview->generateNormals();
+}
+
+//static
+void LLFloaterModelPreview::onExplodeCommit(LLUICtrl* ctrl, void* userdata)
+{
+ LLFloaterModelPreview* fp = LLFloaterModelPreview::sInstance;
+
+ fp->mModelPreview->refresh();
+}
+
+//static
+void LLFloaterModelPreview::onAutoFillCommit(LLUICtrl* ctrl, void* userdata)
+{
+ LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata;
+
+ fp->mModelPreview->genLODs();
+}
+
+//static
+void LLFloaterModelPreview::onLODParamCommit(LLUICtrl* ctrl, void* userdata)
+{
+ LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata;
+ fp->mModelPreview->onLODParamCommit(false);
+}
+
+//static
+void LLFloaterModelPreview::onLODParamCommitTriangleLimit(LLUICtrl* ctrl, void* userdata)
+{
+ LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata;
+ fp->mModelPreview->onLODParamCommit(true);
+}
+
+
+//-----------------------------------------------------------------------------
+// draw()
+//-----------------------------------------------------------------------------
+void LLFloaterModelPreview::draw()
+{
+ LLFloater::draw();
+ LLRect r = getRect();
+
+ mModelPreview->update();
+
+ if (!mModelPreview->mLoading)
+ {
+ if ( mModelPreview->getLoadState() > LLModelLoader::ERROR_PARSING )
+ {
+ childSetTextArg("status", "[STATUS]", getString(LLModel::getStatusString(mModelPreview->getLoadState() - LLModelLoader::ERROR_PARSING)));
+ }
+ else
+ {
+ childSetTextArg("status", "[STATUS]", getString("status_idle"));
+ }
+ }
+
+ childSetTextArg("prim_cost", "[PRIM_COST]", llformat("%d", mModelPreview->mResourceCost));
+ childSetTextArg("description_label", "[TEXTURES]", llformat("%d", mModelPreview->mTextureSet.size()));
+
+ if (!mCurRequest.empty())
+ {
+ LLMutexLock lock(mStatusLock);
+ childSetTextArg("status", "[STATUS]", mStatusMessage);
+ }
+ else
+ {
+ childSetVisible("Simplify", true);
+ childSetVisible("simplify_cancel", false);
+ childSetVisible("Decompose", true);
+ childSetVisible("decompose_cancel", false);
+ }
+
+ U32 resource_cost = mModelPreview->mResourceCost*10;
+
+ if (childGetValue("upload_textures").asBoolean())
+ {
+ resource_cost += mModelPreview->mTextureSet.size()*10;
+ }
+
+ childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d", resource_cost));
+
+ if (mModelPreview)
+ {
+ gGL.color3f(1.f, 1.f, 1.f);
+
+ gGL.getTexUnit(0)->bind(mModelPreview);
+
+
+ LLView* preview_panel = getChild<LLView>("preview_panel");
+
+ LLRect rect = preview_panel->getRect();
+ if (rect != mPreviewRect)
+ {
+ mModelPreview->refresh();
+ mPreviewRect = preview_panel->getRect();
+ }
+
+ gGL.begin( LLRender::QUADS );
+ {
+ gGL.texCoord2f(0.f, 1.f);
+ gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mTop-1);
+ gGL.texCoord2f(0.f, 0.f);
+ gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mBottom);
+ gGL.texCoord2f(1.f, 0.f);
+ gGL.vertex2i(mPreviewRect.mRight-1, mPreviewRect.mBottom);
+ gGL.texCoord2f(1.f, 1.f);
+ gGL.vertex2i(mPreviewRect.mRight-1, mPreviewRect.mTop-1);
+ }
+ gGL.end();
+
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// handleMouseDown()
+//-----------------------------------------------------------------------------
+BOOL LLFloaterModelPreview::handleMouseDown(S32 x, S32 y, MASK mask)
+{
+ if (mPreviewRect.pointInRect(x, y))
+ {
+ bringToFront( x, y );
+ gFocusMgr.setMouseCapture(this);
+ gViewerWindow->hideCursor();
+ mLastMouseX = x;
+ mLastMouseY = y;
+ return TRUE;
+ }
+
+ return LLFloater::handleMouseDown(x, y, mask);
+}
+
+//-----------------------------------------------------------------------------
+// handleMouseUp()
+//-----------------------------------------------------------------------------
+BOOL LLFloaterModelPreview::handleMouseUp(S32 x, S32 y, MASK mask)
+{
+ gFocusMgr.setMouseCapture(FALSE);
+ gViewerWindow->showCursor();
+ return LLFloater::handleMouseUp(x, y, mask);
+}
+
+//-----------------------------------------------------------------------------
+// handleHover()
+//-----------------------------------------------------------------------------
+BOOL LLFloaterModelPreview::handleHover (S32 x, S32 y, MASK mask)
+{
+ MASK local_mask = mask & ~MASK_ALT;
+
+ if (mModelPreview && hasMouseCapture())
+ {
+ if (local_mask == MASK_PAN)
+ {
+ // pan here
+ mModelPreview->pan((F32)(x - mLastMouseX) * -0.005f, (F32)(y - mLastMouseY) * -0.005f);
+ }
+ else if (local_mask == MASK_ORBIT)
+ {
+ F32 yaw_radians = (F32)(x - mLastMouseX) * -0.01f;
+ F32 pitch_radians = (F32)(y - mLastMouseY) * 0.02f;
+
+ mModelPreview->rotate(yaw_radians, pitch_radians);
+ }
+ else
+ {
+
+ F32 yaw_radians = (F32)(x - mLastMouseX) * -0.01f;
+ F32 zoom_amt = (F32)(y - mLastMouseY) * 0.02f;
+
+ mModelPreview->rotate(yaw_radians, 0.f);
+ mModelPreview->zoom(zoom_amt);
+ }
+
+
+ mModelPreview->refresh();
+
+ LLUI::setMousePositionLocal(this, mLastMouseX, mLastMouseY);
+ }
+
+ if (!mPreviewRect.pointInRect(x, y) || !mModelPreview)
+ {
+ return LLFloater::handleHover(x, y, mask);
+ }
+ else if (local_mask == MASK_ORBIT)
+ {
+ gViewerWindow->setCursor(UI_CURSOR_TOOLCAMERA);
+ }
+ else if (local_mask == MASK_PAN)
+ {
+ gViewerWindow->setCursor(UI_CURSOR_TOOLPAN);
+ }
+ else
+ {
+ gViewerWindow->setCursor(UI_CURSOR_TOOLZOOMIN);
+ }
+
+ return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// handleScrollWheel()
+//-----------------------------------------------------------------------------
+BOOL LLFloaterModelPreview::handleScrollWheel(S32 x, S32 y, S32 clicks)
+{
+ if (mPreviewRect.pointInRect(x, y) && mModelPreview)
+ {
+ mModelPreview->zoom((F32)clicks * -0.2f);
+ mModelPreview->refresh();
+ }
+
+ return TRUE;
+}
+
+//static
+void LLFloaterModelPreview::onPhysicsParamCommit(LLUICtrl* ctrl, void* data)
+{
+ if (LLConvexDecomposition::getInstance() == NULL)
+ {
+ llinfos << "convex decomposition tool is a stub on this platform. cannot get decomp." << llendl;
+ return;
+ }
+
+ if (sInstance)
+ {
+ LLCDParam* param = (LLCDParam*) data;
+ std::string name(param->mName);
+ sInstance->mDecompParams[name] = ctrl->getValue();
+
+ if (name == "Simplify Method")
+ {
+ if (ctrl->getValue().asInteger() == 0)
+ {
+ sInstance->childSetVisible("Retain%", true);
+ sInstance->childSetVisible("Detail Scale", false);
+ }
+ else
+ {
+ sInstance->childSetVisible("Retain%", false);
+ sInstance->childSetVisible("Detail Scale", true);
+ }
+ }
+ }
+}
+
+//static
+void LLFloaterModelPreview::onPhysicsStageExecute(LLUICtrl* ctrl, void* data)
+{
+ LLCDStageData* stage_data = (LLCDStageData*) data;
+ std::string stage = stage_data->mName;
+
+ if (sInstance)
+ {
+ if (!sInstance->mCurRequest.empty())
+ {
+ llinfos << "Decomposition request still pending." << llendl;
+ return;
+ }
+
+ if (sInstance->mModelPreview)
+ {
+ for (S32 i = 0; i < sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS].size(); ++i)
+ {
+ LLModel* mdl = sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS][i];
+ DecompRequest* request = new DecompRequest(stage, mdl);
+ sInstance->mCurRequest.insert(request);
+ gMeshRepo.mDecompThread->submitRequest(request);
+ }
+ }
+
+ if (stage == "Decompose")
+ {
+ sInstance->setStatusMessage(sInstance->getString("decomposing"));
+ sInstance->childSetVisible("Decompose", false);
+ sInstance->childSetVisible("decompose_cancel", true);
+ }
+ else if (stage == "Simplify")
+ {
+ sInstance->setStatusMessage(sInstance->getString("simplifying"));
+ sInstance->childSetVisible("Simplify", false);
+ sInstance->childSetVisible("simplify_cancel", true);
+ }
+ }
+}
+
+//static
+void LLFloaterModelPreview::onPhysicsBrowse(LLUICtrl* ctrl, void* userdata)
+{
+ sInstance->loadModel(LLModel::LOD_PHYSICS);
+}
+
+//static
+void LLFloaterModelPreview::onPhysicsUseLOD(LLUICtrl* ctrl, void* userdata)
+{
+ S32 which_mode = 3;
+ LLCtrlSelectionInterface* iface = sInstance->childGetSelectionInterface("physics_lod_combo");
+ if (iface)
+ {
+ which_mode = iface->getFirstSelectedIndex();
+ }
+
+ sInstance->mModelPreview->setPhysicsFromLOD(which_mode);
+}
+
+//static
+void LLFloaterModelPreview::onCancel(LLUICtrl* ctrl, void* data)
+{
+ if (sInstance)
+ {
+ sInstance->closeFloater(false);
+ }
+}
+
+//static
+void LLFloaterModelPreview::onPhysicsStageCancel(LLUICtrl* ctrl, void*data)
+{
+ if (sInstance)
+ {
+ for (std::set<LLPointer<DecompRequest> >::iterator iter = sInstance->mCurRequest.begin();
+ iter != sInstance->mCurRequest.end(); ++iter)
+ {
+ DecompRequest* req = *iter;
+ req->mContinue = 0;
+ }
+
+ sInstance->mCurRequest.clear();
+ }
+}
+
+void LLFloaterModelPreview::initDecompControls()
+{
+ LLSD key;
+
+ childSetCommitCallback("simplify_cancel", onPhysicsStageCancel, NULL);
+ childSetCommitCallback("decompose_cancel", onPhysicsStageCancel, NULL);
+
+ childSetCommitCallback("physics_lod_combo", onPhysicsUseLOD, NULL);
+ childSetCommitCallback("physics_browse", onPhysicsBrowse, NULL);
+
+ static const LLCDStageData* stage = NULL;
+ static S32 stage_count = 0;
+
+ if (!stage && LLConvexDecomposition::getInstance() != NULL)
+ {
+ stage_count = LLConvexDecomposition::getInstance()->getStages(&stage);
+ }
+
+ static const LLCDParam* param = NULL;
+ static S32 param_count = 0;
+ if (!param && LLConvexDecomposition::getInstance() != NULL)
+ {
+ param_count = LLConvexDecomposition::getInstance()->getParameters(&param);
+ }
+
+ for (S32 j = stage_count-1; j >= 0; --j)
+ {
+ LLButton* button = getChild<LLButton>(stage[j].mName);
+ if (button)
+ {
+ button->setCommitCallback(onPhysicsStageExecute, (void*) &stage[j]);
+ }
+
+ gMeshRepo.mDecompThread->mStageID[stage[j].mName] = j;
+ // protected against stub by stage_count being 0 for stub above
+ LLConvexDecomposition::getInstance()->registerCallback(j, LLPhysicsDecomp::llcdCallback);
+
+ //llinfos << "Physics decomp stage " << stage[j].mName << " (" << j << ") parameters:" << llendl;
+ //llinfos << "------------------------------------" << llendl;
+
+ for (S32 i = 0; i < param_count; ++i)
+ {
+ if (param[i].mStage != j)
+ {
+ continue;
+ }
+
+ std::string name(param[i].mName ? param[i].mName : "");
+ std::string description(param[i].mDescription ? param[i].mDescription : "");
+
+ std::string type = "unknown";
+
+ llinfos << name << " - " << description << llendl;
+
+ if (param[i].mType == LLCDParam::LLCD_FLOAT)
+ {
+ mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mFloat);
+ //llinfos << "Type: float, Default: " << param[i].mDefault.mFloat << llendl;
+
+ LLSliderCtrl* slider = getChild<LLSliderCtrl>(name);
+ if (slider)
+ {
+ slider->setMinValue(param[i].mDetails.mRange.mLow.mFloat);
+ slider->setMaxValue(param[i].mDetails.mRange.mHigh.mFloat);
+ slider->setIncrement(param[i].mDetails.mRange.mDelta.mFloat);
+ slider->setValue(param[i].mDefault.mFloat);
+ slider->setCommitCallback(onPhysicsParamCommit, (void*) &param[i]);
+ }
+ }
+ else if (param[i].mType == LLCDParam::LLCD_INTEGER)
+ {
+ mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mIntOrEnumValue);
+ //llinfos << "Type: integer, Default: " << param[i].mDefault.mIntOrEnumValue << llendl;
+
+ LLSliderCtrl* slider = getChild<LLSliderCtrl>(name);
+ if (slider)
+ {
+ slider->setMinValue(param[i].mDetails.mRange.mLow.mIntOrEnumValue);
+ slider->setMaxValue(param[i].mDetails.mRange.mHigh.mIntOrEnumValue);
+ slider->setIncrement(param[i].mDetails.mRange.mDelta.mIntOrEnumValue);
+ slider->setValue(param[i].mDefault.mIntOrEnumValue);
+ slider->setCommitCallback(onPhysicsParamCommit, (void*) &param[i]);
+ }
+ }
+ else if (param[i].mType == LLCDParam::LLCD_BOOLEAN)
+ {
+ mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mBool);
+ //llinfos << "Type: boolean, Default: " << (param[i].mDefault.mBool ? "True" : "False") << llendl;
+
+ LLCheckBoxCtrl* check_box = getChild<LLCheckBoxCtrl>(name);
+ if (check_box)
+ {
+ check_box->setValue(param[i].mDefault.mBool);
+ check_box->setCommitCallback(onPhysicsParamCommit, (void*) &param[i]);
+ }
+ }
+ else if (param[i].mType == LLCDParam::LLCD_ENUM)
+ {
+ mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mIntOrEnumValue);
+ //llinfos << "Type: enum, Default: " << param[i].mDefault.mIntOrEnumValue << llendl;
+
+ { //plug into combo box
+
+ //llinfos << "Accepted values: " << llendl;
+ LLComboBox* combo_box = getChild<LLComboBox>(name);
+ for (S32 k = 0; k < param[i].mDetails.mEnumValues.mNumEnums; ++k)
+ {
+ //llinfos << param[i].mDetails.mEnumValues.mEnumsArray[k].mValue
+ // << " - " << param[i].mDetails.mEnumValues.mEnumsArray[k].mName << llendl;
+
+ combo_box->add(param[i].mDetails.mEnumValues.mEnumsArray[k].mName,
+ LLSD::Integer(param[i].mDetails.mEnumValues.mEnumsArray[k].mValue));
+ }
+ combo_box->setValue(param[i].mDefault.mIntOrEnumValue);
+ combo_box->setCommitCallback(onPhysicsParamCommit, (void*) &param[i]);
+ }
+
+ //llinfos << "----" << llendl;
+ }
+ //llinfos << "-----------------------------" << llendl;
+ }
+ }
+
+ childSetCommitCallback("physics_explode", LLFloaterModelPreview::onExplodeCommit, this);
+}
+
+//-----------------------------------------------------------------------------
+// onMouseCaptureLost()
+//-----------------------------------------------------------------------------
+// static
+void LLFloaterModelPreview::onMouseCaptureLostModelPreview(LLMouseHandler* handler)
+{
+ gViewerWindow->showCursor();
+}
+
+//-----------------------------------------------------------------------------
+// LLModelLoader
+//-----------------------------------------------------------------------------
+LLModelLoader::LLModelLoader( std::string filename, S32 lod, LLModelPreview* preview, JointTransformMap& jointMap,
+ std::deque<std::string>& jointsFromNodes )
+: mJointList( jointMap )
+, mJointsFromNode( jointsFromNodes )
+, LLThread("Model Loader"), mFilename(filename), mLod(lod), mPreview(preview), mFirstTransform(TRUE)
+{
+ mJointMap["mPelvis"] = "mPelvis";
+ mJointMap["mTorso"] = "mTorso";
+ mJointMap["mChest"] = "mChest";
+ mJointMap["mNeck"] = "mNeck";
+ mJointMap["mHead"] = "mHead";
+ mJointMap["mSkull"] = "mSkull";
+ mJointMap["mEyeRight"] = "mEyeRight";
+ mJointMap["mEyeLeft"] = "mEyeLeft";
+ mJointMap["mCollarLeft"] = "mCollarLeft";
+ mJointMap["mShoulderLeft"] = "mShoulderLeft";
+ mJointMap["mElbowLeft"] = "mElbowLeft";
+ mJointMap["mWristLeft"] = "mWristLeft";
+ mJointMap["mCollarRight"] = "mCollarRight";
+ mJointMap["mShoulderRight"] = "mShoulderRight";
+ mJointMap["mElbowRight"] = "mElbowRight";
+ mJointMap["mWristRight"] = "mWristRight";
+ mJointMap["mHipRight"] = "mHipRight";
+ mJointMap["mKneeRight"] = "mKneeRight";
+ mJointMap["mAnkleRight"] = "mAnkleRight";
+ mJointMap["mFootRight"] = "mFootRight";
+ mJointMap["mToeRight"] = "mToeRight";
+ mJointMap["mHipLeft"] = "mHipLeft";
+ mJointMap["mKneeLeft"] = "mKneeLeft";
+ mJointMap["mAnkleLeft"] = "mAnkleLeft";
+ mJointMap["mFootLeft"] = "mFootLeft";
+ mJointMap["mToeLeft"] = "mToeLeft";
+
+ mJointMap["avatar_mPelvis"] = "mPelvis";
+ mJointMap["avatar_mTorso"] = "mTorso";
+ mJointMap["avatar_mChest"] = "mChest";
+ mJointMap["avatar_mNeck"] = "mNeck";
+ mJointMap["avatar_mHead"] = "mHead";
+ mJointMap["avatar_mSkull"] = "mSkull";
+ mJointMap["avatar_mEyeRight"] = "mEyeRight";
+ mJointMap["avatar_mEyeLeft"] = "mEyeLeft";
+ mJointMap["avatar_mCollarLeft"] = "mCollarLeft";
+ mJointMap["avatar_mShoulderLeft"] = "mShoulderLeft";
+ mJointMap["avatar_mElbowLeft"] = "mElbowLeft";
+ mJointMap["avatar_mWristLeft"] = "mWristLeft";
+ mJointMap["avatar_mCollarRight"] = "mCollarRight";
+ mJointMap["avatar_mShoulderRight"] = "mShoulderRight";
+ mJointMap["avatar_mElbowRight"] = "mElbowRight";
+ mJointMap["avatar_mWristRight"] = "mWristRight";
+ mJointMap["avatar_mHipRight"] = "mHipRight";
+ mJointMap["avatar_mKneeRight"] = "mKneeRight";
+ mJointMap["avatar_mAnkleRight"] = "mAnkleRight";
+ mJointMap["avatar_mFootRight"] = "mFootRight";
+ mJointMap["avatar_mToeRight"] = "mToeRight";
+ mJointMap["avatar_mHipLeft"] = "mHipLeft";
+ mJointMap["avatar_mKneeLeft"] = "mKneeLeft";
+ mJointMap["avatar_mAnkleLeft"] = "mAnkleLeft";
+ mJointMap["avatar_mFootLeft"] = "mFootLeft";
+ mJointMap["avatar_mToeLeft"] = "mToeLeft";
+
+
+ mJointMap["hip"] = "mPelvis";
+ mJointMap["abdomen"] = "mTorso";
+ mJointMap["chest"] = "mChest";
+ mJointMap["neck"] = "mNeck";
+ mJointMap["head"] = "mHead";
+ mJointMap["figureHair"] = "mSkull";
+ mJointMap["lCollar"] = "mCollarLeft";
+ mJointMap["lShldr"] = "mShoulderLeft";
+ mJointMap["lForeArm"] = "mElbowLeft";
+ mJointMap["lHand"] = "mWristLeft";
+ mJointMap["rCollar"] = "mCollarRight";
+ mJointMap["rShldr"] = "mShoulderRight";
+ mJointMap["rForeArm"] = "mElbowRight";
+ mJointMap["rHand"] = "mWristRight";
+ mJointMap["rThigh"] = "mHipRight";
+ mJointMap["rShin"] = "mKneeRight";
+ mJointMap["rFoot"] = "mFootRight";
+ mJointMap["lThigh"] = "mHipLeft";
+ mJointMap["lShin"] = "mKneeLeft";
+ mJointMap["lFoot"] = "mFootLeft";
+
+ if (mPreview)
+ {
+ //only try to load from slm if viewer is configured to do so and this is the
+ //initial model load (not an LoD or physics shape)
+ mTrySLM = gSavedSettings.getBOOL("MeshImportUseSLM") && mPreview->mUploadData.empty();
+ mPreview->setLoadState(STARTING);
+ }
+ else
+ {
+ mTrySLM = false;
+ }
+
+ assert_main_thread();
+ sActiveLoaderList.push_back(this) ;
+}
+
+LLModelLoader::~LLModelLoader()
+{
+ assert_main_thread();
+ sActiveLoaderList.remove(this);
+}
+
+void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, BOOL& first_transform)
+{
+ LLVector4a box[] =
+ {
+ LLVector4a(-1, 1,-1),
+ LLVector4a(-1, 1, 1),
+ LLVector4a(-1,-1,-1),
+ LLVector4a(-1,-1, 1),
+ LLVector4a( 1, 1,-1),
+ LLVector4a( 1, 1, 1),
+ LLVector4a( 1,-1,-1),
+ LLVector4a( 1,-1, 1),
+ };
+
+ for (S32 j = 0; j < model->getNumVolumeFaces(); ++j)
+ {
+ const LLVolumeFace& face = model->getVolumeFace(j);
+
+ LLVector4a center;
+ center.setAdd(face.mExtents[0], face.mExtents[1]);
+ center.mul(0.5f);
+ LLVector4a size;
+ size.setSub(face.mExtents[1],face.mExtents[0]);
+ size.mul(0.5f);
+
+ for (U32 i = 0; i < 8; i++)
+ {
+ LLVector4a t;
+ t.setMul(size, box[i]);
+ t.add(center);
+
+ LLVector4a v;
+
+ mat.affineTransform(t, v);
+
+ if (first_transform)
+ {
+ first_transform = FALSE;
+ min = max = v;
+ }
+ else
+ {
+ update_min_max(min, max, v);
+ }
+ }
+ }
+}
+
+void stretch_extents(LLModel* model, LLMatrix4& mat, LLVector3& min, LLVector3& max, BOOL& first_transform)
+{
+ LLVector4a mina, maxa;
+ LLMatrix4a mata;
+
+ mata.loadu(mat);
+ mina.load3(min.mV);
+ maxa.load3(max.mV);
+
+ stretch_extents(model, mata, mina, maxa, first_transform);
+
+ min.set(mina.getF32ptr());
+ max.set(maxa.getF32ptr());
+}
+
+void LLModelLoader::run()
+{
+ if (!doLoadModel())
+ {
+ mPreview = NULL;
+ }
+
+ doOnIdleOneTime(boost::bind(&LLModelLoader::loadModelCallback,this));
+}
+
+bool LLModelLoader::doLoadModel()
+{
+ //first, look for a .slm file of the same name that was modified later
+ //than the .dae
+
+ if (mTrySLM)
+ {
+ std::string filename = mFilename;
+
+ std::string::size_type i = filename.rfind(".");
+ if (i != std::string::npos)
+ {
+ filename.replace(i, filename.size()-1, ".slm");
+ llstat slm_status;
+ if (LLFile::stat(filename, &slm_status) == 0)
+ { //slm file exists
+ llstat dae_status;
+ if (LLFile::stat(mFilename, &dae_status) != 0 ||
+ dae_status.st_mtime < slm_status.st_mtime)
+ {
+ if (loadFromSLM(filename))
+ { //slm successfully loaded, if this fails, fall through and
+ //try loading from dae
+
+ mLod = -1; //successfully loading from an slm implicitly sets all
+ //LoDs
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+ //no suitable slm exists, load from the .dae file
+ DAE dae;
+ domCOLLADA* dom = dae.open(mFilename);
+
+ if (!dom)
+ {
+ return false;
+ }
+
+ daeDatabase* db = dae.getDatabase();
+
+ daeInt count = db->getElementCount(NULL, COLLADA_TYPE_MESH);
+
+ daeDocument* doc = dae.getDoc(mFilename);
+ if (!doc)
+ {
+ llwarns << "can't find internal doc" << llendl;
+ return false;
+ }
+
+ daeElement* root = doc->getDomRoot();
+ if (!root)
+ {
+ llwarns << "document has no root" << llendl;
+ return false;
+ }
+
+ //get unit scale
+ mTransform.setIdentity();
+
+ domAsset::domUnit* unit = daeSafeCast<domAsset::domUnit>(root->getDescendant(daeElement::matchType(domAsset::domUnit::ID())));
+
+ if (unit)
+ {
+ F32 meter = unit->getMeter();
+ mTransform.mMatrix[0][0] = meter;
+ mTransform.mMatrix[1][1] = meter;
+ mTransform.mMatrix[2][2] = meter;
+ }
+
+ //get up axis rotation
+ LLMatrix4 rotation;
+
+ domUpAxisType up = UPAXISTYPE_Y_UP; // default is Y_UP
+ domAsset::domUp_axis* up_axis =
+ daeSafeCast<domAsset::domUp_axis>(root->getDescendant(daeElement::matchType(domAsset::domUp_axis::ID())));
+
+ if (up_axis)
+ {
+ up = up_axis->getValue();
+ }
+
+ if (up == UPAXISTYPE_X_UP)
+ {
+ rotation.initRotation(0.0f, 90.0f * DEG_TO_RAD, 0.0f);
+ }
+ else if (up == UPAXISTYPE_Y_UP)
+ {
+ rotation.initRotation(90.0f * DEG_TO_RAD, 0.0f, 0.0f);
+ }
+
+ rotation *= mTransform;
+ mTransform = rotation;
+
+
+ for (daeInt idx = 0; idx < count; ++idx)
+ { //build map of domEntities to LLModel
+ domMesh* mesh = NULL;
+ db->getElement((daeElement**) &mesh, idx, NULL, COLLADA_TYPE_MESH);
+
+ if (mesh)
+ {
+ LLPointer<LLModel> model = LLModel::loadModelFromDomMesh(mesh);
+
+ if(model->getStatus() != LLModel::NO_ERRORS)
+ {
+ setLoadState(ERROR_PARSING + model->getStatus()) ;
+ return true ; //abort
+ }
+
+ if (model.notNull() && validate_model(model))
+ {
+ mModelList.push_back(model);
+ mModel[mesh] = model;
+ }
+ }
+ }
+
+ count = db->getElementCount(NULL, COLLADA_TYPE_SKIN);
+ for (daeInt idx = 0; idx < count; ++idx)
+ { //add skinned meshes as instances
+ domSkin* skin = NULL;
+ db->getElement((daeElement**) &skin, idx, NULL, COLLADA_TYPE_SKIN);
+
+ if (skin)
+ {
+ domGeometry* geom = daeSafeCast<domGeometry>(skin->getSource().getElement());
+
+ if (geom)
+ {
+ domMesh* mesh = geom->getMesh();
+ if (mesh)
+ {
+ LLModel* model = mModel[mesh];
+ if (model)
+ {
+ LLVector3 mesh_scale_vector;
+ LLVector3 mesh_translation_vector;
+ model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector);
+
+ LLMatrix4 normalized_transformation;
+ normalized_transformation.setTranslation(mesh_translation_vector);
+
+ LLMatrix4 mesh_scale;
+ mesh_scale.initScale(mesh_scale_vector);
+ mesh_scale *= normalized_transformation;
+ normalized_transformation = mesh_scale;
+
+ glh::matrix4f inv_mat((F32*) normalized_transformation.mMatrix);
+ inv_mat = inv_mat.inverse();
+ LLMatrix4 inverse_normalized_transformation(inv_mat.m);
+
+ domSkin::domBind_shape_matrix* bind_mat = skin->getBind_shape_matrix();
+
+ if (bind_mat)
+ { //get bind shape matrix
+ domFloat4x4& dom_value = bind_mat->getValue();
+
+ LLMeshSkinInfo& skin_info = model->mSkinInfo;
+
+ for (int i = 0; i < 4; i++)
+ {
+ for(int j = 0; j < 4; j++)
+ {
+ skin_info.mBindShapeMatrix.mMatrix[i][j] = dom_value[i + j*4];
+ }
+ }
+
+ LLMatrix4 trans = normalized_transformation;
+ trans *= skin_info.mBindShapeMatrix;
+ skin_info.mBindShapeMatrix = trans;
+
+ }
+
+
+ //Some collada setup for accessing the skeleton
+ daeElement* pElement = 0;
+ dae.getDatabase()->getElement( &pElement, 0, 0, "skeleton" );
+
+ //Try to get at the skeletal instance controller
+ domInstance_controller::domSkeleton* pSkeleton = daeSafeCast<domInstance_controller::domSkeleton>( pElement );
+ bool missingSkeletonOrScene = false;
+
+ //If no skeleton, do a breadth-first search to get at specific joints
+ bool rootNode = false;
+ bool skeletonWithNoRootNode = false;
+
+ //Need to test for a skeleton that does not have a root node
+ //This occurs when your instance controller does not have an associated scene
+ if ( pSkeleton )
+ {
+ daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement();
+ if ( pSkeletonRootNode )
+ {
+ rootNode = true;
+ }
+ else
+ {
+ skeletonWithNoRootNode = true;
+ }
+
+ }
+ if ( !pSkeleton || !rootNode )
+ {
+ daeElement* pScene = root->getDescendant("visual_scene");
+ if ( !pScene )
+ {
+ llwarns<<"No visual scene - unable to parse bone offsets "<<llendl;
+ missingSkeletonOrScene = true;
+ }
+ else
+ {
+ //Get the children at this level
+ daeTArray< daeSmartRef<daeElement> > children = pScene->getChildren();
+ S32 childCount = children.getCount();
+
+ //Process any children that are joints
+ //Not all children are joints, some code be ambient lights, cameras, geometry etc..
+ for (S32 i = 0; i < childCount; ++i)
+ {
+ domNode* pNode = daeSafeCast<domNode>(children[i]);
+ if ( isNodeAJoint( pNode ) )
+ {
+ processJointNode( pNode, mJointList );
+ }
+ }
+ }
+ }
+ else
+ //Has Skeleton
+ {
+ //Get the root node of the skeleton
+ daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement();
+ if ( pSkeletonRootNode )
+ {
+ //Once we have the root node - start acccessing it's joint components
+ const int jointCnt = mJointMap.size();
+ std::map<std::string, std::string> :: const_iterator jointIt = mJointMap.begin();
+
+ //Loop over all the possible joints within the .dae - using the allowed joint list in the ctor.
+ for ( int i=0; i<jointCnt; ++i, ++jointIt )
+ {
+ //Build a joint for the resolver to work with
+ char str[64]={0};
+ sprintf(str,"./%s",(*jointIt).second.c_str() );
+ //llwarns<<"Joint "<< str <<llendl;
+
+ //Setup the resolver
+ daeSIDResolver resolver( pSkeletonRootNode, str );
+
+ //Look for the joint
+ domNode* pJoint = daeSafeCast<domNode>( resolver.getElement() );
+ if ( pJoint )
+ {
+ //Pull out the translate id and store it in the jointTranslations map
+ daeSIDResolver jointResolver( pJoint, "./translate" );
+ domTranslate* pTranslate = daeSafeCast<domTranslate>( jointResolver.getElement() );
+
+ LLMatrix4 workingTransform;
+
+ //Translation via SID
+ if ( pTranslate )
+ {
+ extractTranslation( pTranslate, workingTransform );
+ }
+ else
+ {
+ //Translation via child from element
+ daeElement* pTranslateElement = getChildFromElement( pJoint, "translate" );
+ if ( pTranslateElement && pTranslateElement->typeID() != domTranslate::ID() )
+ {
+ llwarns<< "The found element is not a translate node" <<llendl;
+ missingSkeletonOrScene = true;
+ }
+ else
+ {
+ extractTranslationViaElement( pTranslateElement, workingTransform );
+ }
+ }
+
+ //Store the joint transform w/respect to it's name.
+ mJointList[(*jointIt).second.c_str()] = workingTransform;
+ }
+ }
+
+ //If anything failed in regards to extracting the skeleton, joints or translation id,
+ //mention it
+ if ( missingSkeletonOrScene )
+ {
+ llwarns<< "Partial jointmap found in asset - did you mean to just have a partial map?" << llendl;
+ }
+ }//got skeleton?
+ }
+
+
+ domSkin::domJoints* joints = skin->getJoints();
+
+ domInputLocal_Array& joint_input = joints->getInput_array();
+
+ for (size_t i = 0; i < joint_input.getCount(); ++i)
+ {
+ domInputLocal* input = joint_input.get(i);
+ xsNMTOKEN semantic = input->getSemantic();
+
+ if (strcmp(semantic, COMMON_PROFILE_INPUT_JOINT) == 0)
+ { //found joint source, fill model->mJointMap and model->mSkinInfo.mJointNames
+ daeElement* elem = input->getSource().getElement();
+
+ domSource* source = daeSafeCast<domSource>(elem);
+ if (source)
+ {
+
+
+ domName_array* names_source = source->getName_array();
+
+ if (names_source)
+ {
+ domListOfNames &names = names_source->getValue();
+
+ for (size_t j = 0; j < names.getCount(); ++j)
+ {
+ std::string name(names.get(j));
+ if (mJointMap.find(name) != mJointMap.end())
+ {
+ name = mJointMap[name];
+ }
+ model->mSkinInfo.mJointNames.push_back(name);
+ model->mSkinInfo.mJointMap[name] = j;
+ }
+ }
+ else
+ {
+ domIDREF_array* names_source = source->getIDREF_array();
+ if (names_source)
+ {
+ xsIDREFS& names = names_source->getValue();
+
+ for (size_t j = 0; j < names.getCount(); ++j)
+ {
+ std::string name(names.get(j).getID());
+ if (mJointMap.find(name) != mJointMap.end())
+ {
+ name = mJointMap[name];
+ }
+ model->mSkinInfo.mJointNames.push_back(name);
+ model->mSkinInfo.mJointMap[name] = j;
+ }
+ }
+ }
+ }
+ }
+ else if (strcmp(semantic, COMMON_PROFILE_INPUT_INV_BIND_MATRIX) == 0)
+ { //found inv_bind_matrix array, fill model->mInvBindMatrix
+ domSource* source = daeSafeCast<domSource>(input->getSource().getElement());
+ if (source)
+ {
+ domFloat_array* t = source->getFloat_array();
+ if (t)
+ {
+ domListOfFloats& transform = t->getValue();
+ S32 count = transform.getCount()/16;
+
+ for (S32 k = 0; k < count; ++k)
+ {
+ LLMatrix4 mat;
+
+ for (int i = 0; i < 4; i++)
+ {
+ for(int j = 0; j < 4; j++)
+ {
+ mat.mMatrix[i][j] = transform[k*16 + i + j*4];
+ }
+ }
+
+ model->mSkinInfo.mInvBindMatrix.push_back(mat);
+ }
+ }
+ }
+ }
+ }
+
+ //Now that we've parsed the joint array, let's determine if we have a full rig
+ //(which means we have all the joints that are required for an avatar versus
+ //a skinned asset attached to a node in a file that contains an entire skeleton,
+ //but does not use the skeleton).
+ buildJointToNodeMappingFromScene( root );
+ mPreview->critiqueRigForUploadApplicability( model->mSkinInfo.mJointNames );
+
+ if ( !missingSkeletonOrScene )
+ {
+ //Set the joint translations on the avatar - if it's a full mapping
+ //The joints are reset in the dtor
+ if ( mPreview->getRigWithSceneParity() )
+ {
+ std::map<std::string, std::string> :: const_iterator masterJointIt = mJointMap.begin();
+ std::map<std::string, std::string> :: const_iterator masterJointItEnd = mJointMap.end();
+ for (;masterJointIt!=masterJointItEnd;++masterJointIt )
+ {
+ std::string lookingForJoint = (*masterJointIt).first.c_str();
+
+ if ( mJointList.find( lookingForJoint ) != mJointList.end() )
+ {
+ //llinfos<<"joint "<<lookingForJoint.c_str()<<llendl;
+ LLMatrix4 jointTransform = mJointList[lookingForJoint];
+ LLJoint* pJoint = gAgentAvatarp->getJoint( lookingForJoint );
+ if ( pJoint )
+ {
+ pJoint->storeCurrentXform( jointTransform.getTranslation() );
+ }
+ else
+ {
+ //Most likely an error in the asset.
+ llwarns<<"Tried to apply joint position from .dae, but it did not exist in the avatar rig." << llendl;
+ }
+ }
+ }
+ }
+ } //missingSkeletonOrScene
+
+
+ //We need to construct the alternate bind matrix (which contains the new joint positions)
+ //in the same order as they were stored in the joint buffer. The joints associated
+ //with the skeleton are not stored in the same order as they are in the exported joint buffer.
+ //This remaps the skeletal joints to be in the same order as the joints stored in the model.
+ std::vector<std::string> :: const_iterator jointIt = model->mSkinInfo.mJointNames.begin();
+ const int jointCnt = model->mSkinInfo.mJointNames.size();
+ for ( int i=0; i<jointCnt; ++i, ++jointIt )
+ {
+ std::string lookingForJoint = (*jointIt).c_str();
+ //Look for the joint xform that we extracted from the skeleton, using the jointIt as the key
+ //and store it in the alternate bind matrix
+ if ( mJointList.find( lookingForJoint ) != mJointList.end() )
+ {
+ LLMatrix4 jointTransform = mJointList[lookingForJoint];
+ LLMatrix4 newInverse = model->mSkinInfo.mInvBindMatrix[i];
+ newInverse.setTranslation( mJointList[lookingForJoint].getTranslation() );
+ model->mSkinInfo.mAlternateBindMatrix.push_back( newInverse );
+ }
+ else
+ {
+ llwarns<<"Possibly misnamed/missing joint [" <<lookingForJoint.c_str()<<" ] "<<llendl;
+ }
+ }
+
+ //grab raw position array
+
+ domVertices* verts = mesh->getVertices();
+ if (verts)
+ {
+ domInputLocal_Array& inputs = verts->getInput_array();
+ for (size_t i = 0; i < inputs.getCount() && model->mPosition.empty(); ++i)
+ {
+ if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_POSITION) == 0)
+ {
+ domSource* pos_source = daeSafeCast<domSource>(inputs[i]->getSource().getElement());
+ if (pos_source)
+ {
+ domFloat_array* pos_array = pos_source->getFloat_array();
+ if (pos_array)
+ {
+ domListOfFloats& pos = pos_array->getValue();
+
+ for (size_t j = 0; j < pos.getCount(); j += 3)
+ {
+ if (pos.getCount() <= j+2)
+ {
+ llerrs << "WTF?" << llendl;
+ }
+
+ LLVector3 v(pos[j], pos[j+1], pos[j+2]);
+
+ //transform from COLLADA space to volume space
+ v = v * inverse_normalized_transformation;
+
+ model->mPosition.push_back(v);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ //grab skin weights array
+ domSkin::domVertex_weights* weights = skin->getVertex_weights();
+ if (weights)
+ {
+ domInputLocalOffset_Array& inputs = weights->getInput_array();
+ domFloat_array* vertex_weights = NULL;
+ for (size_t i = 0; i < inputs.getCount(); ++i)
+ {
+ if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_WEIGHT) == 0)
+ {
+ domSource* weight_source = daeSafeCast<domSource>(inputs[i]->getSource().getElement());
+ if (weight_source)
+ {
+ vertex_weights = weight_source->getFloat_array();
+ }
+ }
+ }
+
+ if (vertex_weights)
+ {
+ domListOfFloats& w = vertex_weights->getValue();
+ domListOfUInts& vcount = weights->getVcount()->getValue();
+ domListOfInts& v = weights->getV()->getValue();
+
+ U32 c_idx = 0;
+ for (size_t vc_idx = 0; vc_idx < vcount.getCount(); ++vc_idx)
+ { //for each vertex
+ daeUInt count = vcount[vc_idx];
+
+ //create list of weights that influence this vertex
+ LLModel::weight_list weight_list;
+
+ for (daeUInt i = 0; i < count; ++i)
+ { //for each weight
+ daeInt joint_idx = v[c_idx++];
+ daeInt weight_idx = v[c_idx++];
+
+ if (joint_idx == -1)
+ {
+ //ignore bindings to bind_shape_matrix
+ continue;
+ }
+
+ F32 weight_value = w[weight_idx];
+
+ weight_list.push_back(LLModel::JointWeight(joint_idx, weight_value));
+ }
+
+ //sort by joint weight
+ std::sort(weight_list.begin(), weight_list.end(), LLModel::CompareWeightGreater());
+
+ std::vector<LLModel::JointWeight> wght;
+
+ F32 total = 0.f;
+
+ for (U32 i = 0; i < llmin((U32) 4, (U32) weight_list.size()); ++i)
+ { //take up to 4 most significant weights
+ if (weight_list[i].mWeight > 0.f)
+ {
+ wght.push_back( weight_list[i] );
+ total += weight_list[i].mWeight;
+ }
+ }
+
+ F32 scale = 1.f/total;
+ if (scale != 1.f)
+ { //normalize weights
+ for (U32 i = 0; i < wght.size(); ++i)
+ {
+ wght[i].mWeight *= scale;
+ }
+ }
+
+ model->mSkinWeights[model->mPosition[vc_idx]] = wght;
+ }
+
+ //add instance to scene for this model
+
+ LLMatrix4 transformation = mTransform;
+ // adjust the transformation to compensate for mesh normalization
+
+ LLMatrix4 mesh_translation;
+ mesh_translation.setTranslation(mesh_translation_vector);
+ mesh_translation *= transformation;
+ transformation = mesh_translation;
+
+ LLMatrix4 mesh_scale;
+ mesh_scale.initScale(mesh_scale_vector);
+ mesh_scale *= transformation;
+ transformation = mesh_scale;
+
+ std::vector<LLImportMaterial> materials;
+ materials.resize(model->getNumVolumeFaces());
+ mScene[transformation].push_back(LLModelInstance(model, model->mLabel, transformation, materials));
+ stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ daeElement* scene = root->getDescendant("visual_scene");
+
+ if (!scene)
+ {
+ llwarns << "document has no visual_scene" << llendl;
+ setLoadState( ERROR_PARSING );
+ return false;
+ }
+ setLoadState( DONE );
+
+ processElement(scene);
+
+ return true;
+}
+
+void LLModelLoader::setLoadState(U32 state)
+{
+ if (mPreview)
+ {
+ mPreview->setLoadState(state);
+ }
+}
+
+bool LLModelLoader::loadFromSLM(const std::string& filename)
+{
+ //only need to populate mScene with data from slm
+ llstat stat;
+
+ if (LLFile::stat(filename, &stat))
+ { //file does not exist
+ return false;
+ }
+
+ S32 file_size = (S32) stat.st_size;
+
+ llifstream ifstream(filename, std::ifstream::in | std::ifstream::binary);
+ LLSD data;
+ LLSDSerialize::fromBinary(data, ifstream, file_size);
+ ifstream.close();
+
+ //build model list for each LoD
+ model_list model[LLModel::NUM_LODS];
+
+ LLSD& mesh = data["mesh"];
+
+ LLVolumeParams volume_params;
+ volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
+
+ for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod)
+ {
+ for (U32 i = 0; i < mesh.size(); ++i)
+ {
+ std::stringstream str(mesh[i].asString());
+ LLPointer<LLModel> loaded_model = new LLModel(volume_params, (F32) lod);
+ if (loaded_model->loadModel(str))
+ {
+ loaded_model->mLocalID = i;
+ model[lod].push_back(loaded_model);
+
+ if (lod == LLModel::LOD_HIGH && !loaded_model->mSkinInfo.mJointNames.empty())
+ {
+ //check to see if rig is valid
+ mPreview->critiqueRigForUploadApplicability( loaded_model->mSkinInfo.mJointNames );
+ }
+ }
+ else
+ {
+ llassert(model[lod].empty());
+ }
+ }
+ }
+
+ if (model[LLModel::LOD_HIGH].empty())
+ { //failed to load high lod
+ return false;
+ }
+
+ //load instance list
+ model_instance_list instance_list;
+
+ LLSD& instance = data["instance"];
+
+ for (U32 i = 0; i < instance.size(); ++i)
+ {
+ //deserialize instance list
+ instance_list.push_back(LLModelInstance(instance[i]));
+
+ //match up model instance pointers
+ S32 idx = instance_list[i].mLocalMeshID;
+
+ for (U32 lod = 0; lod < LLModel::NUM_LODS; ++lod)
+ {
+ if (!model[lod].empty())
+ {
+ instance_list[i].mLOD[lod] = model[lod][idx];
+ }
+ }
+
+ instance_list[i].mModel = model[LLModel::LOD_HIGH][idx];
+ }
+
+
+ //convert instance_list to mScene
+ mFirstTransform = TRUE;
+ for (U32 i = 0; i < instance_list.size(); ++i)
+ {
+ LLModelInstance& cur_instance = instance_list[i];
+ mScene[cur_instance.mTransform].push_back(cur_instance);
+ stretch_extents(cur_instance.mModel, cur_instance.mTransform, mExtents[0], mExtents[1], mFirstTransform);
+ }
+
+ setLoadState( DONE );
+
+ return true;
+}
+
+//static
+bool LLModelLoader::isAlive(LLModelLoader* loader)
+{
+ if(!loader)
+ {
+ return false ;
+ }
+
+ std::list<LLModelLoader*>::iterator iter = sActiveLoaderList.begin() ;
+ for(; iter != sActiveLoaderList.end() && (*iter) != loader; ++iter) ;
+
+ return *iter == loader ;
+}
+
+void LLModelLoader::loadModelCallback()
+{
+ assert_main_thread();
+
+ if (mPreview)
+ {
+ mPreview->loadModelCallback(mLod);
+ }
+
+ while (!isStopped())
+ { //wait until this thread is stopped before deleting self
+ apr_sleep(100);
+ }
+
+ //doubel check if "this" is valid before deleting it, in case it is aborted during running.
+ if(!isAlive(this))
+ {
+ return ;
+ }
+
+ //cleanup model loader
+ if (mPreview)
+ {
+ mPreview->mModelLoader = NULL;
+ }
+
+ delete this;
+}
+//-----------------------------------------------------------------------------
+// buildJointToNodeMappingFromScene()
+//-----------------------------------------------------------------------------
+void LLModelLoader::buildJointToNodeMappingFromScene( daeElement* pRoot )
+{
+ daeElement* pScene = pRoot->getDescendant("visual_scene");
+ if ( pScene )
+ {
+ daeTArray< daeSmartRef<daeElement> > children = pScene->getChildren();
+ S32 childCount = children.getCount();
+ for (S32 i = 0; i < childCount; ++i)
+ {
+ domNode* pNode = daeSafeCast<domNode>(children[i]);
+ processJointToNodeMapping( pNode );
+ }
+ }
+}
+//-----------------------------------------------------------------------------
+// processJointToNodeMapping()
+//-----------------------------------------------------------------------------
+void LLModelLoader::processJointToNodeMapping( domNode* pNode )
+{
+ if ( isNodeAJoint( pNode ) )
+ {
+ //1.Store the parent
+ std::string nodeName = pNode->getName();
+ if ( !nodeName.empty() )
+ {
+ mJointsFromNode.push_front( pNode->getName() );
+ }
+ //2. Handle the kiddo's
+ daeTArray< daeSmartRef<daeElement> > childOfChild = pNode->getChildren();
+ S32 childOfChildCount = childOfChild.getCount();
+ for (S32 i = 0; i < childOfChildCount; ++i)
+ {
+ domNode* pChildNode = daeSafeCast<domNode>( childOfChild[i] );
+ if ( pChildNode )
+ {
+ processJointToNodeMapping( pChildNode );
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// critiqueRigForUploadApplicability()
+//-----------------------------------------------------------------------------
+void LLModelPreview::critiqueRigForUploadApplicability( const std::vector<std::string> &jointListFromAsset )
+{
+ critiqueJointToNodeMappingFromScene();
+
+ //Determines the following use cases for a rig:
+ //1. It is suitable for upload with skin weights & joint positions, or
+ //2. It is suitable for upload as standard av with just skin weights
+
+ bool isJointPositionUploadOK = isRigSuitableForJointPositionUpload( jointListFromAsset );
+ bool isRigLegacyOK = isRigLegacy( jointListFromAsset );
+
+ //It's OK that both could end up being true, both default to false
+ if ( isJointPositionUploadOK )
+ {
+ setRigValidForJointPositionUpload( true );
+ }
+
+ if ( isRigLegacyOK )
+ {
+ setLegacyRigValid( true );
+ }
+
+ if ( getRigWithSceneParity() && isJointPositionUploadOK )
+ {
+ setResetJointFlag( true );
+ }
+}
+//-----------------------------------------------------------------------------
+// critiqueJointToNodeMappingFromScene()
+//-----------------------------------------------------------------------------
+void LLModelPreview::critiqueJointToNodeMappingFromScene( void )
+{
+ //Do the actual nodes back the joint listing from the dae?
+ //if yes then this is a fully rigged asset, otherwise it's just a partial rig
+
+ std::deque<std::string>::iterator jointsFromNodeIt = mJointsFromNode.begin();
+ std::deque<std::string>::iterator jointsFromNodeEndIt = mJointsFromNode.end();
+ bool result = true;
+
+ if ( !mJointsFromNode.empty() )
+ {
+ for ( ;jointsFromNodeIt!=jointsFromNodeEndIt;++jointsFromNodeIt )
+ {
+ std::string name = *jointsFromNodeIt;
+ if ( mJointTransformMap.find( name ) != mJointTransformMap.end() )
+ {
+ continue;
+ }
+ else
+ {
+ llinfos<<"critiqueJointToNodeMappingFromScene is missing a: "<<name<<llendl;
+ result = false;
+ }
+ }
+ }
+ else
+ {
+ result = false;
+ }
+
+ //Determines the following use cases for a rig:
+ //1. Full av rig w/1-1 mapping from the scene and joint array
+ //2. Partial rig but w/o parity between the scene and joint array
+ if ( result )
+ {
+ setResetJointFlag( true );
+ setRigWithSceneParity( true );
+ }
+ else
+ {
+ setResetJointFlag( false );
+ }
+}
+//-----------------------------------------------------------------------------
+// isRigLegacy()
+//-----------------------------------------------------------------------------
+bool LLModelPreview::isRigLegacy( const std::vector<std::string> &jointListFromAsset )
+{
+ //No joints in asset
+ if ( jointListFromAsset.size() == 0 )
+ {
+ return false;
+ }
+
+ bool result = false;
+
+ std::deque<std::string> :: const_iterator masterJointIt = mMasterLegacyJointList.begin();
+ std::deque<std::string> :: const_iterator masterJointEndIt = mMasterLegacyJointList.end();
+
+ std::vector<std::string> :: const_iterator modelJointIt = jointListFromAsset.begin();
+ std::vector<std::string> :: const_iterator modelJointItEnd = jointListFromAsset.end();
+
+ for ( ;masterJointIt!=masterJointEndIt;++masterJointIt )
+ {
+ result = false;
+ modelJointIt = jointListFromAsset.begin();
+
+ for ( ;modelJointIt!=modelJointItEnd; ++modelJointIt )
+ {
+ if ( *masterJointIt == *modelJointIt )
+ {
+ result = true;
+ break;
+ }
+ }
+ if ( !result )
+ {
+ llinfos<<" Asset did not contain the joint (if you're u/l a fully rigged asset w/joint positions - it is required)." << *masterJointIt<< llendl;
+ break;
+ }
+ }
+ return result;
+}
+//-----------------------------------------------------------------------------
+// isRigSuitableForJointPositionUpload()
+//-----------------------------------------------------------------------------
+bool LLModelPreview::isRigSuitableForJointPositionUpload( const std::vector<std::string> &jointListFromAsset )
+{
+ bool result = false;
+
+ std::deque<std::string> :: const_iterator masterJointIt = mMasterJointList.begin();
+ std::deque<std::string> :: const_iterator masterJointEndIt = mMasterJointList.end();
+
+ std::vector<std::string> :: const_iterator modelJointIt = jointListFromAsset.begin();
+ std::vector<std::string> :: const_iterator modelJointItEnd = jointListFromAsset.end();
+
+ for ( ;masterJointIt!=masterJointEndIt;++masterJointIt )
+ {
+ result = false;
+ modelJointIt = jointListFromAsset.begin();
+
+ for ( ;modelJointIt!=modelJointItEnd; ++modelJointIt )
+ {
+ if ( *masterJointIt == *modelJointIt )
+ {
+ result = true;
+ break;
+ }
+ }
+ if ( !result )
+ {
+ llinfos<<" Asset did not contain the joint (if you're u/l a fully rigged asset w/joint positions - it is required)." << *masterJointIt<< llendl;
+ break;
+ }
+ }
+ return result;
+}
+
+
+//called in the main thread
+void LLModelLoader::loadTextures()
+{
+ BOOL is_paused = isPaused() ;
+ pause() ; //pause the loader
+
+ for(scene::iterator iter = mScene.begin(); iter != mScene.end(); ++iter)
+ {
+ for(U32 i = 0 ; i < iter->second.size(); i++)
+ {
+ for(U32 j = 0 ; j < iter->second[i].mMaterial.size() ; j++)
+ {
+ if(!iter->second[i].mMaterial[j].mDiffuseMapFilename.empty())
+ {
+ iter->second[i].mMaterial[j].mDiffuseMap =
+ LLViewerTextureManager::getFetchedTextureFromUrl("file://" + iter->second[i].mMaterial[j].mDiffuseMapFilename, TRUE, LLViewerTexture::BOOST_PREVIEW);
+ iter->second[i].mMaterial[j].mDiffuseMap->setLoadedCallback(LLModelPreview::textureLoadedCallback, 0, TRUE, FALSE, mPreview, NULL, FALSE);
+ iter->second[i].mMaterial[j].mDiffuseMap->forceToSaveRawImage();
+ }
+ }
+ }
+ }
+
+ if(!is_paused)
+ {
+ unpause() ;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// isNodeAJoint()
+//-----------------------------------------------------------------------------
+bool LLModelLoader::isNodeAJoint( domNode* pNode )
+{
+ if ( !pNode || pNode->getName() == NULL)
+ {
+ return false;
+ }
+
+ if ( mJointMap.find( pNode->getName() ) != mJointMap.end() )
+ {
+ return true;
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// extractTranslation()
+//-----------------------------------------------------------------------------
+void LLModelLoader::extractTranslation( domTranslate* pTranslate, LLMatrix4& transform )
+{
+ domFloat3 jointTrans = pTranslate->getValue();
+ LLVector3 singleJointTranslation( jointTrans[0], jointTrans[1], jointTrans[2] );
+ transform.setTranslation( singleJointTranslation );
+}
+//-----------------------------------------------------------------------------
+// extractTranslationViaElement()
+//-----------------------------------------------------------------------------
+void LLModelLoader::extractTranslationViaElement( daeElement* pTranslateElement, LLMatrix4& transform )
+{
+ domTranslate* pTranslateChild = dynamic_cast<domTranslate*>( pTranslateElement );
+ domFloat3 translateChild = pTranslateChild->getValue();
+ LLVector3 singleJointTranslation( translateChild[0], translateChild[1], translateChild[2] );
+ transform.setTranslation( singleJointTranslation );
+}
+//-----------------------------------------------------------------------------
+// processJointNode()
+//-----------------------------------------------------------------------------
+void LLModelLoader::processJointNode( domNode* pNode, JointTransformMap& jointTransforms )
+{
+ if (pNode->getName() == NULL)
+ {
+ llwarns << "nameless node, can't process" << llendl;
+ return;
+ }
+
+ //llwarns<<"ProcessJointNode# Node:" <<pNode->getName()<<llendl;
+
+ //1. handle the incoming node - extract out translation via SID or element
+
+ LLMatrix4 workingTransform;
+
+ //Pull out the translate id and store it in the jointTranslations map
+ daeSIDResolver jointResolver( pNode, "./translate" );
+ domTranslate* pTranslate = daeSafeCast<domTranslate>( jointResolver.getElement() );
+
+ //Translation via SID was successful
+ if ( pTranslate )
+ {
+ extractTranslation( pTranslate, workingTransform );
+ }
+ else
+ {
+ //Translation via child from element
+ daeElement* pTranslateElement = getChildFromElement( pNode, "translate" );
+ if ( !pTranslateElement || pTranslateElement->typeID() != domTranslate::ID() )
+ {
+ //llwarns<< "The found element is not a translate node" <<llendl;
+ daeSIDResolver jointResolver( pNode, "./matrix" );
+ domMatrix* pMatrix = daeSafeCast<domMatrix>( jointResolver.getElement() );
+ if ( pMatrix )
+ {
+ //llinfos<<"A matrix SID was however found!"<<llendl;
+ domFloat4x4 domArray = pMatrix->getValue();
+ for ( int i = 0; i < 4; i++ )
+ {
+ for( int j = 0; j < 4; j++ )
+ {
+ workingTransform.mMatrix[i][j] = domArray[i + j*4];
+ }
+ }
+ }
+ else
+ {
+ llwarns<< "The found element is not translate or matrix node - most likely a corrupt export!" <<llendl;
+ }
+ }
+ else
+ {
+ extractTranslationViaElement( pTranslateElement, workingTransform );
+ }
+ }
+
+ //Store the working transform relative to the nodes name.
+ jointTransforms[ pNode->getName() ] = workingTransform;
+
+ //2. handle the nodes children
+
+ //Gather and handle the incoming nodes children
+ daeTArray< daeSmartRef<daeElement> > childOfChild = pNode->getChildren();
+ S32 childOfChildCount = childOfChild.getCount();
+
+ for (S32 i = 0; i < childOfChildCount; ++i)
+ {
+ domNode* pChildNode = daeSafeCast<domNode>( childOfChild[i] );
+ if ( pChildNode )
+ {
+ processJointNode( pChildNode, jointTransforms );
+ }
+ }
+}
+//-----------------------------------------------------------------------------
+// getChildFromElement()
+//-----------------------------------------------------------------------------
+daeElement* LLModelLoader::getChildFromElement( daeElement* pElement, std::string const & name )
+{
+ daeElement* pChildOfElement = pElement->getChild( name.c_str() );
+ if ( pChildOfElement )
+ {
+ return pChildOfElement;
+ }
+ llwarns<< "Could not find a child [" << name << "] for the element: \"" << pElement->getAttribute("id") << "\"" << llendl;
+ return NULL;
+}
+
+void LLModelLoader::processElement(daeElement* element)
+{
+ LLMatrix4 saved_transform = mTransform;
+
+ domTranslate* translate = daeSafeCast<domTranslate>(element);
+ if (translate)
+ {
+ domFloat3 dom_value = translate->getValue();
+
+ LLMatrix4 translation;
+ translation.setTranslation(LLVector3(dom_value[0], dom_value[1], dom_value[2]));
+
+ translation *= mTransform;
+ mTransform = translation;
+ }
+
+ domRotate* rotate = daeSafeCast<domRotate>(element);
+ if (rotate)
+ {
+ domFloat4 dom_value = rotate->getValue();
+
+ LLMatrix4 rotation;
+ rotation.initRotTrans(dom_value[3] * DEG_TO_RAD, LLVector3(dom_value[0], dom_value[1], dom_value[2]), LLVector3(0, 0, 0));
+
+ rotation *= mTransform;
+ mTransform = rotation;
+ }
+
+ domScale* scale = daeSafeCast<domScale>(element);
+ if (scale)
+ {
+ domFloat3 dom_value = scale->getValue();
+
+ LLMatrix4 scaling;
+ scaling.initScale(LLVector3(dom_value[0], dom_value[1], dom_value[2]));
+
+ scaling *= mTransform;
+ mTransform = scaling;
+ }
+
+ domMatrix* matrix = daeSafeCast<domMatrix>(element);
+ if (matrix)
+ {
+ domFloat4x4 dom_value = matrix->getValue();
+
+ LLMatrix4 matrix_transform;
+
+ for (int i = 0; i < 4; i++)
+ {
+ for(int j = 0; j < 4; j++)
+ {
+ matrix_transform.mMatrix[i][j] = dom_value[i + j*4];
+ }
+ }
+
+ matrix_transform *= mTransform;
+ mTransform = matrix_transform;
+ }
+
+ domInstance_geometry* instance_geo = daeSafeCast<domInstance_geometry>(element);
+ if (instance_geo)
+ {
+ domGeometry* geo = daeSafeCast<domGeometry>(instance_geo->getUrl().getElement());
+ if (geo)
+ {
+ domMesh* mesh = daeSafeCast<domMesh>(geo->getDescendant(daeElement::matchType(domMesh::ID())));
+ if (mesh)
+ {
+ LLModel* model = mModel[mesh];
+ if (model)
+ {
+ LLMatrix4 transformation = mTransform;
+
+ std::vector<LLImportMaterial> materials = getMaterials(model, instance_geo);
+
+ // adjust the transformation to compensate for mesh normalization
+ LLVector3 mesh_scale_vector;
+ LLVector3 mesh_translation_vector;
+ model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector);
+
+ LLMatrix4 mesh_translation;
+ mesh_translation.setTranslation(mesh_translation_vector);
+ mesh_translation *= transformation;
+ transformation = mesh_translation;
+
+ LLMatrix4 mesh_scale;
+ mesh_scale.initScale(mesh_scale_vector);
+ mesh_scale *= transformation;
+ transformation = mesh_scale;
+
+ std::string label = getElementLabel(instance_geo);
+ mScene[transformation].push_back(LLModelInstance(model, label, transformation, materials));
+
+ stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform);
+ }
+ }
+ }
+ }
+
+ domInstance_node* instance_node = daeSafeCast<domInstance_node>(element);
+ if (instance_node)
+ {
+ daeElement* instance = instance_node->getUrl().getElement();
+ if (instance)
+ {
+ processElement(instance);
+ }
+ }
+
+ //process children
+ daeTArray< daeSmartRef<daeElement> > children = element->getChildren();
+ for (S32 i = 0; i < children.getCount(); i++)
+ {
+ processElement(children[i]);
+ }
+
+ domNode* node = daeSafeCast<domNode>(element);
+ if (node)
+ { //this element was a node, restore transform before processiing siblings
+ mTransform = saved_transform;
+ }
+}
+
+std::vector<LLImportMaterial> LLModelLoader::getMaterials(LLModel* model, domInstance_geometry* instance_geo)
+{
+ std::vector<LLImportMaterial> materials;
+ for (int i = 0; i < model->mMaterialList.size(); i++)
+ {
+ LLImportMaterial import_material;
+
+ domInstance_material* instance_mat = NULL;
+
+ domBind_material::domTechnique_common* technique =
+ daeSafeCast<domBind_material::domTechnique_common>(instance_geo->getDescendant(daeElement::matchType(domBind_material::domTechnique_common::ID())));
+
+ if (technique)
+ {
+ daeTArray< daeSmartRef<domInstance_material> > inst_materials = technique->getChildrenByType<domInstance_material>();
+ for (int j = 0; j < inst_materials.getCount(); j++)
+ {
+ std::string symbol(inst_materials[j]->getSymbol());
+
+ if (symbol == model->mMaterialList[i]) // found the binding
+ {
+ instance_mat = inst_materials[j];
+ }
+ }
+ }
+
+ if (instance_mat)
+ {
+ domMaterial* material = daeSafeCast<domMaterial>(instance_mat->getTarget().getElement());
+ if (material)
+ {
+ domInstance_effect* instance_effect =
+ daeSafeCast<domInstance_effect>(material->getDescendant(daeElement::matchType(domInstance_effect::ID())));
+ if (instance_effect)
+ {
+ domEffect* effect = daeSafeCast<domEffect>(instance_effect->getUrl().getElement());
+ if (effect)
+ {
+ domProfile_COMMON* profile =
+ daeSafeCast<domProfile_COMMON>(effect->getDescendant(daeElement::matchType(domProfile_COMMON::ID())));
+ if (profile)
+ {
+ import_material = profileToMaterial(profile);
+ }
+ }
+ }
+ }
+ }
+
+ materials.push_back(import_material);
+ }
+
+ return materials;
+}
+
+LLImportMaterial LLModelLoader::profileToMaterial(domProfile_COMMON* material)
+{
+ LLImportMaterial mat;
+ mat.mFullbright = FALSE;
+
+ daeElement* diffuse = material->getDescendant("diffuse");
+ if (diffuse)
+ {
+ domCommon_color_or_texture_type_complexType::domTexture* texture =
+ daeSafeCast<domCommon_color_or_texture_type_complexType::domTexture>(diffuse->getDescendant("texture"));
+ if (texture)
+ {
+ domCommon_newparam_type_Array newparams = material->getNewparam_array();
+ for (S32 i = 0; i < newparams.getCount(); i++)
+ {
+ domFx_surface_common* surface = newparams[i]->getSurface();
+ if (surface)
+ {
+ domFx_surface_init_common* init = surface->getFx_surface_init_common();
+ if (init)
+ {
+ domFx_surface_init_from_common_Array init_from = init->getInit_from_array();
+
+ if (init_from.getCount() > i)
+ {
+ domImage* image = daeSafeCast<domImage>(init_from[i]->getValue().getElement());
+ if (image)
+ {
+ // we only support init_from now - embedded data will come later
+ domImage::domInit_from* init = image->getInit_from();
+ if (init)
+ {
+ mat.mDiffuseMapFilename = cdom::uriToNativePath(init->getValue().str());
+ mat.mDiffuseMapLabel = getElementLabel(material);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ domCommon_color_or_texture_type_complexType::domColor* color =
+ daeSafeCast<domCommon_color_or_texture_type_complexType::domColor>(diffuse->getDescendant("color"));
+ if (color)
+ {
+ domFx_color_common domfx_color = color->getValue();
+ LLColor4 value = LLColor4(domfx_color[0], domfx_color[1], domfx_color[2], domfx_color[3]);
+ mat.mDiffuseColor = value;
+ }
+ }
+
+ daeElement* emission = material->getDescendant("emission");
+ if (emission)
+ {
+ LLColor4 emission_color = getDaeColor(emission);
+ if (((emission_color[0] + emission_color[1] + emission_color[2]) / 3.0) > 0.25)
+ {
+ mat.mFullbright = TRUE;
+ }
+ }
+
+ return mat;
+}
+
+// try to get a decent label for this element
+std::string LLModelLoader::getElementLabel(daeElement *element)
+{
+ // if we have a name attribute, use it
+ std::string name = element->getAttribute("name");
+ if (name.length())
+ {
+ return name;
+ }
+
+ // if we have an ID attribute, use it
+ if (element->getID())
+ {
+ return std::string(element->getID());
+ }
+
+ // if we have a parent, use it
+ daeElement* parent = element->getParent();
+ if (parent)
+ {
+ // if parent has a name, use it
+ std::string name = parent->getAttribute("name");
+ if (name.length())
+ {
+ return name;
+ }
+
+ // if parent has an ID, use it
+ if (parent->getID())
+ {
+ return std::string(parent->getID());
+ }
+ }
+
+ // try to use our type
+ daeString element_name = element->getElementName();
+ if (element_name)
+ {
+ return std::string(element_name);
+ }
+
+ // if all else fails, use "object"
+ return std::string("object");
+}
+
+LLColor4 LLModelLoader::getDaeColor(daeElement* element)
+{
+ LLColor4 value;
+ domCommon_color_or_texture_type_complexType::domColor* color =
+ daeSafeCast<domCommon_color_or_texture_type_complexType::domColor>(element->getDescendant("color"));
+ if (color)
+ {
+ domFx_color_common domfx_color = color->getValue();
+ value = LLColor4(domfx_color[0], domfx_color[1], domfx_color[2], domfx_color[3]);
+ }
+
+ return value;
+}
+
+//-----------------------------------------------------------------------------
+// LLModelPreview
+//-----------------------------------------------------------------------------
+
+LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp)
+: LLViewerDynamicTexture(width, height, 3, ORDER_MIDDLE, FALSE), LLMutex(NULL)
+, mPelvisZOffset( 0.0f )
+, mLegacyRigValid( false )
+, mRigValidJointUpload( false )
+, mResetJoints( false )
+, mRigParityWithScene( false )
+, mLastJointUpdate( false )
+{
+ mNeedsUpdate = TRUE;
+ mCameraDistance = 0.f;
+ mCameraYaw = 0.f;
+ mCameraPitch = 0.f;
+ mCameraZoom = 1.f;
+ mTextureName = 0;
+ mPreviewLOD = 0;
+ mModelLoader = NULL;
+ mMaxTriangleLimit = 0;
+ mDirty = false;
+ mGenLOD = false;
+ mLoading = false;
+ mLoadState = LLModelLoader::STARTING;
+ mGroup = 0;
+ mBuildShareTolerance = 0.f;
+ mBuildQueueMode = GLOD_QUEUE_GREEDY;
+ mBuildBorderMode = GLOD_BORDER_UNLOCK;
+ mBuildOperator = GLOD_OPERATOR_EDGE_COLLAPSE;
+
+ for (U32 i = 0; i < LLModel::NUM_LODS; ++i)
+ {
+ mRequestedTriangleCount[i] = 0;
+ }
+
+ mViewOption["show_textures"] = false;
+
+ mFMP = fmp;
+
+ mHasPivot = false;
+ mModelPivot = LLVector3( 0.0f, 0.0f, 0.0f );
+
+ glodInit();
+
+ //move into joint mapper class
+ //1. joints for joint offset verification
+ mMasterJointList.push_front("mPelvis");
+ mMasterJointList.push_front("mTorso");
+ mMasterJointList.push_front("mChest");
+ mMasterJointList.push_front("mNeck");
+ mMasterJointList.push_front("mHead");
+ mMasterJointList.push_front("mCollarLeft");
+ mMasterJointList.push_front("mShoulderLeft");
+ mMasterJointList.push_front("mElbowLeft");
+ mMasterJointList.push_front("mWristLeft");
+ mMasterJointList.push_front("mCollarRight");
+ mMasterJointList.push_front("mShoulderRight");
+ mMasterJointList.push_front("mElbowRight");
+ mMasterJointList.push_front("mWristRight");
+ mMasterJointList.push_front("mHipRight");
+ mMasterJointList.push_front("mKneeRight");
+ mMasterJointList.push_front("mFootRight");
+ mMasterJointList.push_front("mHipLeft");
+ mMasterJointList.push_front("mKneeLeft");
+ mMasterJointList.push_front("mFootLeft");
+ //2. legacy joint list - used to verify rigs that will not be using joint offsets
+ mMasterLegacyJointList.push_front("mPelvis");
+ mMasterLegacyJointList.push_front("mTorso");
+ mMasterLegacyJointList.push_front("mChest");
+ mMasterLegacyJointList.push_front("mNeck");
+ mMasterLegacyJointList.push_front("mHead");
+ mMasterLegacyJointList.push_front("mHipRight");
+ mMasterLegacyJointList.push_front("mKneeRight");
+ mMasterLegacyJointList.push_front("mFootRight");
+ mMasterLegacyJointList.push_front("mHipLeft");
+ mMasterLegacyJointList.push_front("mKneeLeft");
+ mMasterLegacyJointList.push_front("mFootLeft");
+}
+
+LLModelPreview::~LLModelPreview()
+{
+ if (mModelLoader)
+ {
+ delete mModelLoader;
+ mModelLoader = NULL;
+ }
+ //*HACK : *TODO : turn this back on when we understand why this crashes
+ //glodShutdown();
+}
+
+U32 LLModelPreview::calcResourceCost()
+{
+ assert_main_thread();
+
+ rebuildUploadData();
+
+ if (mFMP && mModelLoader)
+ {
+ if ( getLoadState() < LLModelLoader::ERROR_PARSING )
+ {
+ mFMP->childEnable("ok_btn");
+ }
+ }
+
+ //Upload skin is selected BUT check to see if the joints coming in from the asset were malformed.
+ if ( mFMP && mFMP->childGetValue("upload_skin").asBoolean() )
+ {
+ bool uploadingJointPositions = mFMP->childGetValue("upload_joints").asBoolean();
+ if ( uploadingJointPositions && !isRigValidForJointPositionUpload() )
+ {
+ mFMP->childDisable("ok_btn");
+ }
+ else
+ if ( !isLegacyRigValid() )
+ {
+ mFMP->childDisable("ok_btn");
+ }
+ //ok_btn should not have been changed unless something was wrong with joint list
+ }
+
+ U32 cost = 0;
+ std::set<LLModel*> accounted;
+ U32 num_points = 0;
+ U32 num_hulls = 0;
+
+ F32 debug_scale = mFMP ? mFMP->childGetValue("import_scale").asReal() : 1.f;
+ mPelvisZOffset = mFMP ? mFMP->childGetValue("pelvis_offset").asReal() : 3.0f;
+
+ if ( mFMP && mFMP->childGetValue("upload_joints").asBoolean() )
+ {
+ gAgentAvatarp->setPelvisOffset( mPelvisZOffset );
+ }
+
+ F32 streaming_cost = 0.f;
+ F32 physics_cost = 0.f;
+ for (U32 i = 0; i < mUploadData.size(); ++i)
+ {
+ LLModelInstance& instance = mUploadData[i];
+
+ if (accounted.find(instance.mModel) == accounted.end())
+ {
+ accounted.insert(instance.mModel);
+
+ LLModel::Decomposition& decomp =
+ instance.mLOD[LLModel::LOD_PHYSICS] ?
+ instance.mLOD[LLModel::LOD_PHYSICS]->mPhysics :
+ instance.mModel->mPhysics;
+
+ //update instance skin info for each lods pelvisZoffset
+ for ( int j=0; j<LLModel::NUM_LODS; ++j )
+ {
+ if ( instance.mLOD[j] )
+ {
+ instance.mLOD[j]->mSkinInfo.mPelvisOffset = mPelvisZOffset;
+ }
+ }
+
+ std::stringstream ostr;
+ LLSD ret = LLModel::writeModel(ostr,
+ instance.mLOD[4],
+ instance.mLOD[3],
+ instance.mLOD[2],
+ instance.mLOD[1],
+ instance.mLOD[0],
+ decomp,
+ mFMP->childGetValue("upload_skin").asBoolean(),
+ mFMP->childGetValue("upload_joints").asBoolean(),
+ TRUE);
+ cost += gMeshRepo.calcResourceCost(ret);
+
+ num_hulls += decomp.mHull.size();
+ for (U32 i = 0; i < decomp.mHull.size(); ++i)
+ {
+ num_points += decomp.mHull[i].size();
+ }
+
+ //calculate streaming cost
+ LLMatrix4 transformation = instance.mTransform;
+
+ LLVector3 position = LLVector3(0, 0, 0) * transformation;
+
+ LLVector3 x_transformed = LLVector3(1, 0, 0) * transformation - position;
+ LLVector3 y_transformed = LLVector3(0, 1, 0) * transformation - position;
+ LLVector3 z_transformed = LLVector3(0, 0, 1) * transformation - position;
+ F32 x_length = x_transformed.normalize();
+ F32 y_length = y_transformed.normalize();
+ F32 z_length = z_transformed.normalize();
+ LLVector3 scale = LLVector3(x_length, y_length, z_length);
+
+ F32 radius = scale.length()*debug_scale;
+
+ streaming_cost += LLMeshRepository::getStreamingCost(ret, radius);
+ }
+ }
+
+ F32 scale = mFMP ? mFMP->childGetValue("import_scale").asReal()*2.f : 2.f;
+
+ mDetailsSignal(mPreviewScale[0]*scale, mPreviewScale[1]*scale, mPreviewScale[2]*scale, streaming_cost, physics_cost);
+
+ updateStatusMessages();
+
+ return cost;
+}
+
+void LLFloaterModelPreview::setDetails(F32 x, F32 y, F32 z, F32 streaming_cost, F32 physics_cost)
+{
+ childSetTextArg("import_dimensions", "[X]", llformat("%.3f", x));
+ childSetTextArg("import_dimensions", "[Y]", llformat("%.3f", y));
+ childSetTextArg("import_dimensions", "[Z]", llformat("%.3f", z));
+ childSetTextArg("streaming cost", "[COST]", llformat("%.3f", streaming_cost));
+ childSetTextArg("physics cost", "[COST]", llformat("%.3f", physics_cost));
+}
+
+
+void LLModelPreview::rebuildUploadData()
+{
+ assert_main_thread();
+
+ mUploadData.clear();
+ mTextureSet.clear();
+
+ //fill uploaddata instance vectors from scene data
+
+ std::string requested_name = mFMP->getChild<LLUICtrl>("description_form")->getValue().asString();
+
+
+ LLSpinCtrl* scale_spinner = mFMP->getChild<LLSpinCtrl>("import_scale");
+
+ if (!scale_spinner)
+ {
+ llerrs << "floater_model_preview.xml MUST contain import_scale spinner." << llendl;
+ }
+
+ F32 scale = scale_spinner->getValue().asReal();
+
+ LLMatrix4 scale_mat;
+ scale_mat.initScale(LLVector3(scale, scale, scale));
+
+ F32 max_scale = 0.f;
+
+ if ( mBaseScene.size() > 0 )
+ {
+ mFMP->childEnable("ok_btn");
+ }
+
+ for (LLModelLoader::scene::iterator iter = mBaseScene.begin(); iter != mBaseScene.end(); ++iter)
+ { //for each transform in scene
+ LLMatrix4 mat = iter->first;
+
+ // compute position
+ LLVector3 position = LLVector3(0, 0, 0) * mat;
+
+ // compute scale
+ LLVector3 x_transformed = LLVector3(1, 0, 0) * mat - position;
+ LLVector3 y_transformed = LLVector3(0, 1, 0) * mat - position;
+ LLVector3 z_transformed = LLVector3(0, 0, 1) * mat - position;
+ F32 x_length = x_transformed.normalize();
+ F32 y_length = y_transformed.normalize();
+ F32 z_length = z_transformed.normalize();
+
+ max_scale = llmax(llmax(llmax(max_scale, x_length), y_length), z_length);
+
+ mat *= scale_mat;
+
+ for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter)
+ { //for each instance with said transform applied
+ LLModelInstance instance = *model_iter;
+
+ LLModel* base_model = instance.mModel;
+
+ if (base_model)
+ {
+ base_model->mRequestedLabel = requested_name;
+ }
+
+ S32 idx = 0;
+ for (idx = 0; idx < mBaseModel.size(); ++idx)
+ { //find reference instance for this model
+ if (mBaseModel[idx] == base_model)
+ {
+ break;
+ }
+ }
+
+ for (U32 i = 0; i < LLModel::NUM_LODS; i++)
+ { //fill LOD slots based on reference model index
+ if (!mModel[i].empty())
+ {
+ instance.mLOD[i] = mModel[i][idx];
+ }
+ else
+ {
+ instance.mLOD[i] = NULL;
+ }
+ }
+
+ instance.mTransform = mat;
+ mUploadData.push_back(instance);
+ }
+ }
+
+ F32 max_import_scale = DEFAULT_MAX_PRIM_SCALE/max_scale;
+
+ scale_spinner->setMaxValue(max_import_scale);
+
+ if (max_import_scale < scale)
+ {
+ scale_spinner->setValue(max_import_scale);
+ }
+
+}
+
+void LLModelPreview::saveUploadData(bool save_skinweights, bool save_joint_positions)
+{
+ if (!mLODFile[LLModel::LOD_HIGH].empty())
+ {
+ std::string filename = mLODFile[LLModel::LOD_HIGH];
+
+ std::string::size_type i = filename.rfind(".");
+ if (i != std::string::npos)
+ {
+ filename.replace(i, filename.size()-1, ".slm");
+ saveUploadData(filename, save_skinweights, save_joint_positions);
+ }
+ }
+}
+
+void LLModelPreview::saveUploadData(const std::string& filename, bool save_skinweights, bool save_joint_positions)
+{
+ if (!gSavedSettings.getBOOL("MeshImportUseSLM"))
+ {
+ return;
+ }
+
+ std::set<LLPointer<LLModel> > meshes;
+ std::map<LLModel*, std::string> mesh_binary;
+
+ LLModel::hull empty_hull;
+
+ LLSD data;
+
+ S32 mesh_id = 0;
+
+ //build list of unique models and initialize local id
+ for (U32 i = 0; i < mUploadData.size(); ++i)
+ {
+ LLModelInstance& instance = mUploadData[i];
+
+ if (meshes.find(instance.mModel) == meshes.end())
+ {
+ instance.mModel->mLocalID = mesh_id++;
+ meshes.insert(instance.mModel);
+
+ std::stringstream str;
+
+ LLModel::Decomposition& decomp =
+ instance.mLOD[LLModel::LOD_PHYSICS].notNull() ?
+ instance.mLOD[LLModel::LOD_PHYSICS]->mPhysics :
+ instance.mModel->mPhysics;
+
+ LLModel::writeModel(str,
+ instance.mLOD[LLModel::LOD_PHYSICS],
+ instance.mLOD[LLModel::LOD_HIGH],
+ instance.mLOD[LLModel::LOD_MEDIUM],
+ instance.mLOD[LLModel::LOD_LOW],
+ instance.mLOD[LLModel::LOD_IMPOSTOR],
+ decomp,
+ save_skinweights, save_joint_positions);
+
+
+ data["mesh"][instance.mModel->mLocalID] = str.str();
+ }
+
+ data["instance"][i] = instance.asLLSD();
+ }
+
+ llofstream out(filename, std::ios_base::out | std::ios_base::binary);
+ LLSDSerialize::toBinary(data, out);
+ out.flush();
+ out.close();
+}
+
+void LLModelPreview::clearModel(S32 lod)
+{
+ if (lod < 0 || lod > LLModel::LOD_PHYSICS)
+ {
+ return;
+ }
+
+ mVertexBuffer[lod].clear();
+ mModel[lod].clear();
+ mScene[lod].clear();
+}
+
+void LLModelPreview::loadModel(std::string filename, S32 lod)
+{
+ assert_main_thread();
+
+ LLMutexLock lock(this);
+
+ // This triggers if you bring up the file picker and then hit CANCEL.
+ // Just use the previous model (if any) and ignore that you brought up
+ // the file picker.
+
+ if (filename.empty())
+ {
+ if (mBaseModel.empty())
+ {
+ // this is the initial file picking. Close the whole floater
+ // if we don't have a base model to show for high LOD.
+ mFMP->closeFloater(false);
+ mLoading = false;
+ }
+ return;
+ }
+
+ if (mModelLoader)
+ {
+ llwarns << "Incompleted model load operation pending." << llendl;
+ return;
+ }
+
+ mLODFile[lod] = filename;
+
+ if (lod == LLModel::LOD_HIGH)
+ {
+ clearGLODGroup();
+ }
+
+ mModelLoader = new LLModelLoader(filename, lod, this, mJointTransformMap, mJointsFromNode );
+
+ mModelLoader->start();
+
+ mFMP->childSetTextArg("status", "[STATUS]", mFMP->getString("status_reading_file"));
+
+ setPreviewLOD(lod);
+
+ if ( getLoadState() >= LLModelLoader::ERROR_PARSING )
+ {
+ mFMP->childDisable("ok_btn");
+ }
+
+ if (lod == mPreviewLOD)
+ {
+ mFMP->childSetText("lod_file", mLODFile[mPreviewLOD]);
+ }
+ else if (lod == LLModel::LOD_PHYSICS)
+ {
+ mFMP->childSetText("physics_file", mLODFile[lod]);
+ }
+
+ mFMP->openFloater();
+}
+
+void LLModelPreview::setPhysicsFromLOD(S32 lod)
+{
+ assert_main_thread();
+
+ if (lod >= 0 && lod <= 3)
+ {
+ mModel[LLModel::LOD_PHYSICS] = mModel[lod];
+ mScene[LLModel::LOD_PHYSICS] = mScene[lod];
+ mLODFile[LLModel::LOD_PHYSICS].clear();
+ mFMP->childSetText("physics_file", mLODFile[LLModel::LOD_PHYSICS]);
+ mVertexBuffer[LLModel::LOD_PHYSICS].clear();
+ rebuildUploadData();
+ refresh();
+ updateStatusMessages();
+ }
+}
+
+void LLModelPreview::clearIncompatible(S32 lod)
+{
+ for (U32 i = 0; i <= LLModel::LOD_HIGH; i++)
+ { //clear out any entries that aren't compatible with this model
+ if (i != lod)
+ {
+ if (mModel[i].size() != mModel[lod].size())
+ {
+ mModel[i].clear();
+ mScene[i].clear();
+ mVertexBuffer[i].clear();
+
+ if (i == LLModel::LOD_HIGH)
+ {
+ mBaseModel = mModel[lod];
+ clearGLODGroup();
+ mBaseScene = mScene[lod];
+ mVertexBuffer[5].clear();
+ }
+ }
+ }
+ }
+}
+
+void LLModelPreview::clearGLODGroup()
+{
+ if (mGroup)
+ {
+ for (std::map<LLPointer<LLModel>, U32>::iterator iter = mObject.begin(); iter != mObject.end(); ++iter)
+ {
+ glodDeleteObject(iter->second);
+ stop_gloderror();
+ }
+ mObject.clear();
+
+ glodDeleteGroup(mGroup);
+ stop_gloderror();
+ mGroup = 0;
+ }
+}
+
+void LLModelPreview::loadModelCallback(S32 lod)
+{
+ assert_main_thread();
+
+ LLMutexLock lock(this);
+ if (!mModelLoader)
+ {
+ mLoading = false ;
+ return;
+ }
+ if(getLoadState() >= LLModelLoader::ERROR_PARSING)
+ {
+ mLoading = false ;
+ return ;
+ }
+
+ mModelLoader->loadTextures() ;
+
+ if (lod == -1)
+ { //populate all LoDs from model loader scene
+ mBaseModel.clear();
+ mBaseScene.clear();
+
+ bool skin_weights = false;
+ bool joint_positions = false;
+
+ for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod)
+ { //for each LoD
+
+ //clear scene and model info
+ mScene[lod].clear();
+ mModel[lod].clear();
+ mVertexBuffer[lod].clear();
+
+ if (mModelLoader->mScene.begin()->second[0].mLOD[lod].notNull())
+ { //if this LoD exists in the loaded scene
+
+ //copy scene to current LoD
+ mScene[lod] = mModelLoader->mScene;
+
+ //touch up copied scene to look like current LoD
+ for (LLModelLoader::scene::iterator iter = mScene[lod].begin(); iter != mScene[lod].end(); ++iter)
+ {
+ LLModelLoader::model_instance_list& list = iter->second;
+
+ for (LLModelLoader::model_instance_list::iterator list_iter = list.begin(); list_iter != list.end(); ++list_iter)
+ {
+ //override displayed model with current LoD
+ list_iter->mModel = list_iter->mLOD[lod];
+
+ //add current model to current LoD's model list (LLModel::mLocalID makes a good vector index)
+ S32 idx = list_iter->mModel->mLocalID;
+
+ if (mModel[lod].size() <= idx)
+ { //stretch model list to fit model at given index
+ mModel[lod].resize(idx+1);
+ }
+
+ mModel[lod][idx] = list_iter->mModel;
+ if (!list_iter->mModel->mSkinWeights.empty())
+ {
+ skin_weights = true;
+
+ if (!list_iter->mModel->mSkinInfo.mAlternateBindMatrix.empty())
+ {
+ joint_positions = true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (mFMP)
+ {
+ LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) mFMP;
+
+ if (skin_weights)
+ { //enable uploading/previewing of skin weights if present in .slm file
+ fmp->enableViewOption("show_skin_weight");
+ mViewOption["show_skin_weight"] = true;
+ fmp->childSetValue("upload_skin", true);
+ }
+
+ if (joint_positions)
+ {
+ fmp->enableViewOption("show_joint_positions");
+ mViewOption["show_joint_positions"] = true;
+ fmp->childSetValue("upload_joints", true);
+ }
+ }
+
+ //copy high lod to base scene for LoD generation
+ mBaseScene = mScene[LLModel::LOD_HIGH];
+ mBaseModel = mModel[LLModel::LOD_HIGH];
+
+ mDirty = true;
+ resetPreviewTarget();
+ }
+ else
+ { //only replace given LoD
+ mModel[lod] = mModelLoader->mModelList;
+ mScene[lod] = mModelLoader->mScene;
+ mVertexBuffer[lod].clear();
+
+ setPreviewLOD(lod);
+
+ if (lod == LLModel::LOD_HIGH)
+ { //save a copy of the highest LOD for automatic LOD manipulation
+ if (mBaseModel.empty())
+ { //first time we've loaded a model, auto-gen LoD
+ mGenLOD = true;
+ }
+
+ mBaseModel = mModel[lod];
+ clearGLODGroup();
+
+ mBaseScene = mScene[lod];
+ mVertexBuffer[5].clear();
+ }
+
+ clearIncompatible(lod);
+
+ mDirty = true;
+
+ if (lod == LLModel::LOD_HIGH)
+ {
+ resetPreviewTarget();
+ }
+ }
+
+ mLoading = false;
+ refresh();
+
+ mModelLoadedSignal();
+}
+
+void LLModelPreview::resetPreviewTarget()
+{
+ if ( mModelLoader )
+ {
+ mPreviewTarget = (mModelLoader->mExtents[0] + mModelLoader->mExtents[1]) * 0.5f;
+ mPreviewScale = (mModelLoader->mExtents[1] - mModelLoader->mExtents[0]) * 0.5f;
+ }
+
+ setPreviewTarget(mPreviewScale.magVec()*2.f);
+}
+
+void LLModelPreview::generateNormals()
+{
+ assert_main_thread();
+
+ S32 which_lod = mPreviewLOD;
+
+
+ if (which_lod > 4 || which_lod < 0 ||
+ mModel[which_lod].empty())
+ {
+ return;
+ }
+
+ F32 angle_cutoff = mFMP->childGetValue("crease_angle").asReal();
+
+ angle_cutoff *= DEG_TO_RAD;
+
+ if (which_lod == 3 && !mBaseModel.empty())
+ {
+ for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter)
+ {
+ (*iter)->generateNormals(angle_cutoff);
+ }
+
+ mVertexBuffer[5].clear();
+ }
+
+ for (LLModelLoader::model_list::iterator iter = mModel[which_lod].begin(); iter != mModel[which_lod].end(); ++iter)
+ {
+ (*iter)->generateNormals(angle_cutoff);
+ }
+
+ mVertexBuffer[which_lod].clear();
+ refresh();
+
+}
+
+void LLModelPreview::clearMaterials()
+{
+ for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter)
+ { //for each transform in current scene
+ for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter)
+ { //for each instance with that transform
+ LLModelInstance& source_instance = *model_iter;
+ LLModel* source = source_instance.mModel;
+
+ for (S32 i = 0; i < source->getNumVolumeFaces(); ++i)
+ { //for each face in instance
+ LLImportMaterial& source_material = source_instance.mMaterial[i];
+
+ //clear material info
+ source_material.mDiffuseColor = LLColor4(1,1,1,1);
+ source_material.mDiffuseMap = NULL;
+ source_material.mDiffuseMapFilename.clear();
+ source_material.mDiffuseMapLabel.clear();
+ source_material.mFullbright = false;
+ }
+ }
+ }
+
+ mVertexBuffer[mPreviewLOD].clear();
+
+ if (mPreviewLOD == LLModel::LOD_HIGH)
+ {
+ mBaseScene = mScene[mPreviewLOD];
+ mBaseModel = mModel[mPreviewLOD];
+ clearGLODGroup();
+ mVertexBuffer[5].clear();
+ }
+
+ mResourceCost = calcResourceCost();
+ refresh();
+}
+
+void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_limit)
+{
+ if (mBaseModel.empty())
+ {
+ return;
+ }
+
+ LLVertexBuffer::unbind();
+
+ stop_gloderror();
+ static U32 cur_name = 1;
+
+ S32 limit = -1;
+
+ U32 triangle_count = 0;
+
+ for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter)
+ {
+ LLModel* mdl = *iter;
+ for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i)
+ {
+ triangle_count += mdl->getVolumeFace(i).mNumIndices/3;
+ }
+ }
+
+ U32 base_triangle_count = triangle_count;
+
+ U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0;
+
+ U32 lod_mode = 0;
+
+ LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode");
+ if (iface)
+ {
+ lod_mode = iface->getFirstSelectedIndex();
+ }
+
+ F32 lod_error_threshold = mFMP->childGetValue("lod_error_threshold").asReal();
+
+ if (lod_mode == 0)
+ {
+ lod_mode = GLOD_TRIANGLE_BUDGET;
+ if (which_lod != -1)
+ {
+ limit = mFMP->childGetValue("lod_triangle_limit").asInteger();
+ }
+ }
+ else
+ {
+ lod_mode = GLOD_ERROR_THRESHOLD;
+ }
+
+ U32 build_operator = 0;
+
+ iface = mFMP->childGetSelectionInterface("build_operator");
+ if (iface)
+ {
+ build_operator = iface->getFirstSelectedIndex();
+ }
+
+ if (build_operator == 0)
+ {
+ build_operator = GLOD_OPERATOR_EDGE_COLLAPSE;
+ }
+ else
+ {
+ build_operator = GLOD_OPERATOR_HALF_EDGE_COLLAPSE;
+ }
+
+ U32 queue_mode=0;
+ iface = mFMP->childGetSelectionInterface("queue_mode");
+ if (iface)
+ {
+ queue_mode = iface->getFirstSelectedIndex();
+ }
+
+ if (queue_mode == 0)
+ {
+ queue_mode = GLOD_QUEUE_GREEDY;
+ }
+ else if (queue_mode == 1)
+ {
+ queue_mode = GLOD_QUEUE_LAZY;
+ }
+ else
+ {
+ queue_mode = GLOD_QUEUE_INDEPENDENT;
+ }
+
+ U32 border_mode = 0;
+
+ iface = mFMP->childGetSelectionInterface("border_mode");
+ if (iface)
+ {
+ border_mode = iface->getFirstSelectedIndex();
+ }
+
+ if (border_mode == 0)
+ {
+ border_mode = GLOD_BORDER_UNLOCK;
+ }
+ else
+ {
+ border_mode = GLOD_BORDER_LOCK;
+ }
+
+ bool object_dirty = false;
+ if (border_mode != mBuildBorderMode)
+ {
+ mBuildBorderMode = border_mode;
+ object_dirty = true;
+ }
+
+ if (queue_mode != mBuildQueueMode)
+ {
+ mBuildQueueMode = queue_mode;
+ object_dirty = true;
+ }
+
+ if (build_operator != mBuildOperator)
+ {
+ mBuildOperator = build_operator;
+ object_dirty = true;
+ }
+
+ F32 share_tolerance = mFMP->childGetValue("share_tolerance").asReal();
+ if (share_tolerance != mBuildShareTolerance)
+ {
+ mBuildShareTolerance = share_tolerance;
+ object_dirty = true;
+ }
+
+ if (mGroup == 0)
+ {
+ object_dirty = true;
+ mGroup = cur_name++;
+ glodNewGroup(mGroup);
+ }
+
+ if (object_dirty)
+ {
+ for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter)
+ { //build GLOD objects for each model in base model list
+ LLModel* mdl = *iter;
+
+ if (mObject[mdl] != 0)
+ {
+ glodDeleteObject(mObject[mdl]);
+ }
+
+ mObject[mdl] = cur_name++;
+
+ glodNewObject(mObject[mdl], mGroup, GLOD_DISCRETE);
+ stop_gloderror();
+
+ if (iter == mBaseModel.begin() && !mdl->mSkinWeights.empty())
+ { //regenerate vertex buffer for skinned models to prevent animation feedback during LOD generation
+ mVertexBuffer[5].clear();
+ }
+
+ if (mVertexBuffer[5].empty())
+ {
+ genBuffers(5, false);
+ }
+
+ U32 tri_count = 0;
+ for (U32 i = 0; i < mVertexBuffer[5][mdl].size(); ++i)
+ {
+ mVertexBuffer[5][mdl][i]->setBuffer(type_mask);
+ U32 num_indices = mVertexBuffer[5][mdl][i]->getNumIndices();
+ if (num_indices > 2)
+ {
+ glodInsertElements(mObject[mdl], i, GL_TRIANGLES, num_indices, GL_UNSIGNED_SHORT, mVertexBuffer[5][mdl][i]->getIndicesPointer(), 0, 0.f);
+ }
+ tri_count += num_indices/3;
+ stop_gloderror();
+ }
+
+ glodObjectParameteri(mObject[mdl], GLOD_BUILD_OPERATOR, build_operator);
+ stop_gloderror();
+
+ glodObjectParameteri(mObject[mdl], GLOD_BUILD_QUEUE_MODE, queue_mode);
+ stop_gloderror();
+
+ glodObjectParameteri(mObject[mdl], GLOD_BUILD_BORDER_MODE, border_mode);
+ stop_gloderror();
+
+ glodObjectParameterf(mObject[mdl], GLOD_BUILD_SHARE_TOLERANCE, share_tolerance);
+ stop_gloderror();
+
+ glodBuildObject(mObject[mdl]);
+ stop_gloderror();
+ }
+ }
+
+
+ S32 start = LLModel::LOD_HIGH;
+ S32 end = 0;
+
+ if (which_lod != -1)
+ {
+ start = end = which_lod;
+ }
+
+ mMaxTriangleLimit = base_triangle_count;
+
+ for (S32 lod = start; lod >= end; --lod)
+ {
+ if (which_lod == -1)
+ {
+ if (lod < start)
+ {
+ triangle_count /= decimation;
+ }
+ }
+ else
+ {
+ if (enforce_tri_limit)
+ {
+ triangle_count = limit;
+ }
+ else
+ {
+ for (S32 j=LLModel::LOD_HIGH; j>which_lod; --j)
+ {
+ triangle_count /= decimation;
+ }
+ }
+ }
+
+ mModel[lod].clear();
+ mModel[lod].resize(mBaseModel.size());
+ mVertexBuffer[lod].clear();
+
+ U32 actual_tris = 0;
+ U32 actual_verts = 0;
+ U32 submeshes = 0;
+
+ mRequestedTriangleCount[lod] = triangle_count;
+
+ glodGroupParameteri(mGroup, GLOD_ADAPT_MODE, lod_mode);
+ stop_gloderror();
+
+ glodGroupParameteri(mGroup, GLOD_ERROR_MODE, GLOD_OBJECT_SPACE_ERROR);
+ stop_gloderror();
+
+ glodGroupParameterf(mGroup, GLOD_OBJECT_SPACE_ERROR_THRESHOLD, lod_error_threshold);
+ stop_gloderror();
+
+ if (lod_mode != GLOD_TRIANGLE_BUDGET)
+ {
+ glodGroupParameteri(mGroup, GLOD_MAX_TRIANGLES, 0);
+ }
+ else
+ {
+ //SH-632: always add 1 to desired amount to avoid decimating below desired amount
+ glodGroupParameteri(mGroup, GLOD_MAX_TRIANGLES, triangle_count+1);
+ }
+
+ stop_gloderror();
+ glodAdaptGroup(mGroup);
+ stop_gloderror();
+
+ for (U32 mdl_idx = 0; mdl_idx < mBaseModel.size(); ++mdl_idx)
+ {
+ LLModel* base = mBaseModel[mdl_idx];
+
+ GLint patch_count = 0;
+ glodGetObjectParameteriv(mObject[base], GLOD_NUM_PATCHES, &patch_count);
+ stop_gloderror();
+
+ LLVolumeParams volume_params;
+ volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
+ mModel[lod][mdl_idx] = new LLModel(volume_params, 0.f);
+
+ GLint* sizes = new GLint[patch_count*2];
+ glodGetObjectParameteriv(mObject[base], GLOD_PATCH_SIZES, sizes);
+ stop_gloderror();
+
+ GLint* names = new GLint[patch_count];
+ glodGetObjectParameteriv(mObject[base], GLOD_PATCH_NAMES, names);
+ stop_gloderror();
+
+ mModel[lod][mdl_idx]->setNumVolumeFaces(patch_count);
+
+ LLModel* target_model = mModel[lod][mdl_idx];
+
+ for (GLint i = 0; i < patch_count; ++i)
+ {
+ LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(type_mask, 0);
+
+ if (sizes[i*2+1] > 0 && sizes[i*2] > 0)
+ {
+ buff->allocateBuffer(sizes[i*2+1], sizes[i*2], true);
+ buff->setBuffer(type_mask);
+ glodFillElements(mObject[base], names[i], GL_UNSIGNED_SHORT, buff->getIndicesPointer());
+ stop_gloderror();
+ }
+ else
+ { //this face was eliminated, create a dummy triangle (one vertex, 3 indices, all 0)
+ buff->allocateBuffer(1, 3, true);
+ memset(buff->getMappedData(), 0, buff->getSize());
+ memset(buff->getIndicesPointer(), 0, buff->getIndicesSize());
+ }
+
+ buff->validateRange(0, buff->getNumVerts()-1, buff->getNumIndices(), 0);
+
+ LLStrider<LLVector3> pos;
+ LLStrider<LLVector3> norm;
+ LLStrider<LLVector2> tc;
+ LLStrider<U16> index;
+
+ buff->getVertexStrider(pos);
+ buff->getNormalStrider(norm);
+ buff->getTexCoord0Strider(tc);
+ buff->getIndexStrider(index);
+
+ target_model->setVolumeFaceData(names[i], pos, norm, tc, index, buff->getNumVerts(), buff->getNumIndices());
+ actual_tris += buff->getNumIndices()/3;
+ actual_verts += buff->getNumVerts();
+ ++submeshes;
+
+ if (!validate_face(target_model->getVolumeFace(names[i])))
+ {
+ llerrs << "Invalid face generated during LOD generation." << llendl;
+ }
+ }
+
+ //blind copy skin weights and just take closest skin weight to point on
+ //decimated mesh for now (auto-generating LODs with skin weights is still a bit
+ //of an open problem).
+ target_model->mPosition = base->mPosition;
+ target_model->mSkinWeights = base->mSkinWeights;
+ target_model->mSkinInfo = base->mSkinInfo;
+ //copy material list
+ target_model->mMaterialList = base->mMaterialList;
+
+ if (!validate_model(target_model))
+ {
+ llerrs << "Invalid model generated when creating LODs" << llendl;
+ }
+
+ delete [] sizes;
+ delete [] names;
+ }
+
+ //rebuild scene based on mBaseScene
+ mScene[lod].clear();
+ mScene[lod] = mBaseScene;
+
+ for (U32 i = 0; i < mBaseModel.size(); ++i)
+ {
+ LLModel* mdl = mBaseModel[i];
+ LLModel* target = mModel[lod][i];
+ if (target)
+ {
+ for (LLModelLoader::scene::iterator iter = mScene[lod].begin(); iter != mScene[lod].end(); ++iter)
+ {
+ for (U32 j = 0; j < iter->second.size(); ++j)
+ {
+ if (iter->second[j].mModel == mdl)
+ {
+ iter->second[j].mModel = target;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ mResourceCost = calcResourceCost();
+
+ /*if (which_lod == -1 && mScene[LLModel::LOD_PHYSICS].empty())
+ { //build physics scene
+ mScene[LLModel::LOD_PHYSICS] = mScene[LLModel::LOD_LOW];
+ mModel[LLModel::LOD_PHYSICS] = mModel[LLModel::LOD_LOW];
+
+ for (U32 i = 1; i < mModel[LLModel::LOD_PHYSICS].size(); ++i)
+ {
+ mPhysicsQ.push(mModel[LLModel::LOD_PHYSICS][i]);
+ }
+ }*/
+}
+
+void LLModelPreview::updateStatusMessages()
+{
+ assert_main_thread();
+
+ //triangle/vertex/submesh count for each mesh asset for each lod
+ std::vector<S32> tris[LLModel::NUM_LODS];
+ std::vector<S32> verts[LLModel::NUM_LODS];
+ std::vector<S32> submeshes[LLModel::NUM_LODS];
+
+ //total triangle/vertex/submesh count for each lod
+ S32 total_tris[LLModel::NUM_LODS];
+ S32 total_verts[LLModel::NUM_LODS];
+ S32 total_submeshes[LLModel::NUM_LODS];
+
+ for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod)
+ {
+ //initialize total for this lod to 0
+ total_tris[lod] = total_verts[lod] = total_submeshes[lod] = 0;
+
+ for (U32 i = 0; i < mModel[lod].size(); ++i)
+ { //for each model in the lod
+ S32 cur_tris = 0;
+ S32 cur_verts = 0;
+ S32 cur_submeshes = mModel[lod][i]->getNumVolumeFaces();
+
+ for (S32 j = 0; j < cur_submeshes; ++j)
+ { //for each submesh (face), add triangles and vertices to current total
+ const LLVolumeFace& face = mModel[lod][i]->getVolumeFace(j);
+ cur_tris += face.mNumIndices/3;
+ cur_verts += face.mNumVertices;
+ }
+
+ //add this model to the lod total
+ total_tris[lod] += cur_tris;
+ total_verts[lod] += cur_verts;
+ total_submeshes[lod] += cur_submeshes;
+
+ //store this model's counts to asset data
+ tris[lod].push_back(cur_tris);
+ verts[lod].push_back(cur_verts);
+ submeshes[lod].push_back(cur_submeshes);
+ }
+ }
+
+ if (mMaxTriangleLimit == 0)
+ {
+ mMaxTriangleLimit = total_tris[LLModel::LOD_HIGH];
+ }
+
+
+ mFMP->childSetTextArg("submeshes_info", "[SUBMESHES]", llformat("%d", total_submeshes[LLModel::LOD_HIGH]));
+
+ std::string mesh_status_na = mFMP->getString("mesh_status_na");
+
+ S32 upload_status[LLModel::LOD_HIGH+1];
+
+ bool upload_ok = true;
+
+ for (S32 lod = 0; lod <= LLModel::LOD_HIGH; ++lod)
+ {
+ upload_status[lod] = 0;
+
+ std::string message = "mesh_status_good";
+
+ if (total_tris[lod] > 0)
+ {
+ mFMP->childSetText(lod_triangles_name[lod], llformat("%d", total_tris[lod]));
+ mFMP->childSetText(lod_vertices_name[lod], llformat("%d", total_verts[lod]));
+ }
+ else
+ {
+ if (lod == LLModel::LOD_HIGH)
+ {
+ upload_status[lod] = 2;
+ message = "mesh_status_missing_lod";
+ }
+ else
+ {
+ for (S32 i = lod-1; i >= 0; --i)
+ {
+ if (total_tris[i] > 0)
+ {
+ upload_status[lod] = 2;
+ message = "mesh_status_missing_lod";
+ }
+ }
+ }
+
+ mFMP->childSetText(lod_triangles_name[lod], mesh_status_na);
+ mFMP->childSetText(lod_vertices_name[lod], mesh_status_na);
+ }
+
+ const U32 lod_high = LLModel::LOD_HIGH;
+
+ if (lod != lod_high)
+ {
+ if (total_submeshes[lod] && total_submeshes[lod] != total_submeshes[lod_high])
+ { //number of submeshes is different
+ message = "mesh_status_submesh_mismatch";
+ upload_status[lod] = 2;
+ }
+ else if (!tris[lod].empty() && tris[lod].size() != tris[lod_high].size())
+ { //number of meshes is different
+ message = "mesh_status_mesh_mismatch";
+ upload_status[lod] = 2;
+ }
+ else if (!verts[lod].empty())
+ {
+ for (U32 i = 0; i < verts[lod].size(); ++i)
+ {
+ S32 max_verts = i < verts[lod+1].size() ? verts[lod+1][i] : 0;
+
+ if (max_verts > 0)
+ {
+ if (verts[lod][i] > max_verts)
+ { //too many vertices in this lod
+ message = "mesh_status_too_many_vertices";
+ upload_status[lod] = 2;
+ }
+ }
+ }
+ }
+ }
+
+ LLIconCtrl* icon = mFMP->getChild<LLIconCtrl>(lod_icon_name[lod]);
+ LLUIImagePtr img = LLUI::getUIImage(lod_status_image[upload_status[lod]]);
+ icon->setVisible(true);
+ icon->setImage(img);
+
+ if (upload_status[lod] >= 2)
+ {
+ upload_ok = false;
+ }
+
+ if (lod == mPreviewLOD)
+ {
+ mFMP->childSetText("lod_status_message_text", mFMP->getString(message));
+ icon = mFMP->getChild<LLIconCtrl>("lod_status_message_icon");
+ icon->setImage(img);
+ }
+ }
+
+ bool errorStateFromLoader = getLoadState() >= LLModelLoader::ERROR_PARSING ? true : false;
+
+ bool skinAndRigOk = true;
+ bool uploadingSkin = mFMP->childGetValue("upload_skin").asBoolean();
+ bool uploadingJointPositions = mFMP->childGetValue("upload_joints").asBoolean();
+
+ if ( uploadingSkin )
+ {
+ if ( uploadingJointPositions && !isRigValidForJointPositionUpload() )
+ {
+ skinAndRigOk = false;
+ }
+ else
+ if ( !isLegacyRigValid() )
+ {
+ skinAndRigOk = false;
+ }
+ }
+
+ if ( upload_ok && !errorStateFromLoader && skinAndRigOk )
+ {
+ mFMP->childEnable("ok_btn");
+ }
+
+ //add up physics triangles etc
+ S32 start = 0;
+ S32 end = mModel[LLModel::LOD_PHYSICS].size();
+
+ S32 phys_tris = 0;
+ S32 phys_hulls = 0;
+ S32 phys_points = 0;
+
+ for (S32 i = start; i < end; ++i)
+ { //add up hulls and points and triangles for selected mesh(es)
+ LLModel* model = mModel[LLModel::LOD_PHYSICS][i];
+ S32 cur_submeshes = model->getNumVolumeFaces();
+
+ LLModel::convex_hull_decomposition& decomp = model->mPhysics.mHull;
+
+ if (!decomp.empty())
+ {
+ phys_hulls += decomp.size();
+ for (U32 i = 0; i < decomp.size(); ++i)
+ {
+ phys_points += decomp[i].size();
+ }
+ }
+ else
+ { //choose physics shape OR decomposition, can't use both
+ for (S32 j = 0; j < cur_submeshes; ++j)
+ { //for each submesh (face), add triangles and vertices to current total
+ const LLVolumeFace& face = model->getVolumeFace(j);
+ phys_tris += face.mNumIndices/3;
+ }
+ }
+ }
+
+ if (phys_tris > 0)
+ {
+ mFMP->childSetTextArg("physics_triangles", "[TRIANGLES]", llformat("%d", phys_tris));
+ }
+ else
+ {
+ mFMP->childSetTextArg("physics_triangles", "[TRIANGLES]", mesh_status_na);
+ }
+
+ if (phys_hulls > 0)
+ {
+ mFMP->childSetTextArg("physics_hulls", "[HULLS]", llformat("%d", phys_hulls));
+ mFMP->childSetTextArg("physics_points", "[POINTS]", llformat("%d", phys_points));
+ }
+ else
+ {
+ mFMP->childSetTextArg("physics_hulls", "[HULLS]", mesh_status_na);
+ mFMP->childSetTextArg("physics_points", "[POINTS]", mesh_status_na);
+ }
+
+ LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance;
+ if (fmp)
+ {
+ if (phys_tris > 0 || phys_hulls > 0)
+ {
+ if (!fmp->isViewOptionEnabled("show_physics"))
+ {
+ fmp->enableViewOption("show_physics");
+ mViewOption["show_physics"] = true;
+ }
+ }
+ else
+ {
+ fmp->disableViewOption("show_physics");
+ mViewOption["show_physics"] = false;
+
+ }
+
+ //bool use_hull = fmp->childGetValue("physics_use_hull").asBoolean();
+
+ //fmp->childSetEnabled("physics_optimize", !use_hull);
+
+ bool enable = phys_tris > 0 || phys_hulls > 0;
+ //enable = enable && !use_hull && fmp->childGetValue("physics_optimize").asBoolean();
+
+ //enable/disable "analysis" UI
+ LLPanel* panel = fmp->getChild<LLPanel>("physics analysis");
+ LLView* child = panel->getFirstChild();
+ while (child)
+ {
+ child->setEnabled(enable);
+ child = panel->findNextSibling(child);
+ }
+
+ enable = phys_hulls > 0;
+ //enable/disable "simplification" UI
+ panel = fmp->getChild<LLPanel>("physics simplification");
+ child = panel->getFirstChild();
+ while (child)
+ {
+ child->setEnabled(enable);
+ child = panel->findNextSibling(child);
+ }
+ }
+
+ const char* lod_controls[] =
+ {
+ "lod_mode",
+ "lod_triangle_limit",
+ "lod_error_tolerance",
+ "build_operator_text",
+ "queue_mode_text",
+ "border_mode_text",
+ "share_tolerance_text",
+ "build_operator",
+ "queue_mode",
+ "border_mode",
+ "share_tolerance"
+ };
+ const U32 num_lod_controls = sizeof(lod_controls)/sizeof(char*);
+
+ const char* file_controls[] =
+ {
+ "lod_browse",
+ "lod_file"
+ };
+ const U32 num_file_controls = sizeof(file_controls)/sizeof(char*);
+
+ if (fmp)
+ {
+ //enable/disable controls based on radio groups
+ if (mFMP->childGetValue("lod_from_file").asBoolean())
+ {
+ fmp->mLODMode[mPreviewLOD] = 0;
+ for (U32 i = 0; i < num_file_controls; ++i)
+ {
+ mFMP->childEnable(file_controls[i]);
+ }
+
+ for (U32 i = 0; i < num_lod_controls; ++i)
+ {
+ mFMP->childDisable(lod_controls[i]);
+ }
+ }
+ else if (mFMP->childGetValue("lod_none").asBoolean())
+ {
+ fmp->mLODMode[mPreviewLOD] = 2;
+ for (U32 i = 0; i < num_file_controls; ++i)
+ {
+ mFMP->childDisable(file_controls[i]);
+ }
+
+ for (U32 i = 0; i < num_lod_controls; ++i)
+ {
+ mFMP->childDisable(lod_controls[i]);
+ }
+
+ if (!mModel[mPreviewLOD].empty())
+ {
+ mModel[mPreviewLOD].clear();
+ mScene[mPreviewLOD].clear();
+ mVertexBuffer[mPreviewLOD].clear();
+
+ //this can cause phasing issues with the UI, so reenter this function and return
+ updateStatusMessages();
+ return;
+ }
+ }
+ else
+ { // auto generate, also the default case for wizard which has no radio selection
+ fmp->mLODMode[mPreviewLOD] = 1;
+
+ for (U32 i = 0; i < num_file_controls; ++i)
+ {
+ mFMP->childDisable(file_controls[i]);
+ }
+
+ for (U32 i = 0; i < num_lod_controls; ++i)
+ {
+ mFMP->childEnable(lod_controls[i]);
+ }
+
+ //if (threshold)
+ {
+ U32 lod_mode = 0;
+ LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode");
+ if (iface)
+ {
+ lod_mode = iface->getFirstSelectedIndex();
+ }
+
+ LLSpinCtrl* threshold = mFMP->getChild<LLSpinCtrl>("lod_error_threshold");
+ LLSpinCtrl* limit = mFMP->getChild<LLSpinCtrl>("lod_triangle_limit");
+
+ limit->setMaxValue(mMaxTriangleLimit);
+ limit->setValue(mRequestedTriangleCount[mPreviewLOD]);
+
+ if (lod_mode == 0)
+ {
+ limit->setVisible(true);
+ threshold->setVisible(false);
+
+ limit->setMaxValue(mMaxTriangleLimit);
+ limit->setIncrement(mMaxTriangleLimit/32);
+ }
+ else
+ {
+ limit->setVisible(false);
+ threshold->setVisible(true);
+ }
+ }
+ }
+ }
+
+ if (mFMP->childGetValue("physics_load_from_file").asBoolean())
+ {
+ mFMP->childDisable("physics_lod_combo");
+ mFMP->childEnable("physics_file");
+ mFMP->childEnable("physics_browse");
+ }
+ else
+ {
+ mFMP->childEnable("physics_lod_combo");
+ mFMP->childDisable("physics_file");
+ mFMP->childDisable("physics_browse");
+ }
+}
+
+void LLModelPreview::setPreviewTarget(F32 distance)
+{
+ mCameraDistance = distance;
+ mCameraZoom = 1.f;
+ mCameraPitch = 0.f;
+ mCameraYaw = 0.f;
+ mCameraOffset.clearVec();
+}
+
+void LLModelPreview::clearBuffers()
+{
+ for (U32 i = 0; i < 6; i++)
+ {
+ mVertexBuffer[i].clear();
+ }
+}
+
+void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights)
+{
+ U32 tri_count = 0;
+ U32 vertex_count = 0;
+ U32 mesh_count = 0;
+
+
+ LLModelLoader::model_list* model = NULL;
+
+ if (lod < 0 || lod > 4)
+ {
+ model = &mBaseModel;
+ lod = 5;
+ }
+ else
+ {
+ model = &(mModel[lod]);
+ }
+
+ if (!mVertexBuffer[lod].empty())
+ {
+ mVertexBuffer[lod].clear();
+ }
+
+ mVertexBuffer[lod].clear();
+
+ LLModelLoader::model_list::iterator base_iter = mBaseModel.begin();
+
+ for (LLModelLoader::model_list::iterator iter = model->begin(); iter != model->end(); ++iter)
+ {
+ LLModel* mdl = *iter;
+ if (!mdl)
+ {
+ continue;
+ }
+
+ LLModel* base_mdl = *base_iter;
+ base_iter++;
+
+ for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i)
+ {
+ const LLVolumeFace &vf = mdl->getVolumeFace(i);
+ U32 num_vertices = vf.mNumVertices;
+ U32 num_indices = vf.mNumIndices;
+
+ if (!num_vertices || ! num_indices)
+ {
+ continue;
+ }
+
+ LLVertexBuffer* vb = NULL;
+
+ bool skinned = include_skin_weights && !mdl->mSkinWeights.empty();
+
+ U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0;
+
+ if (skinned)
+ {
+ mask |= LLVertexBuffer::MAP_WEIGHT4;
+ }
+
+ vb = new LLVertexBuffer(mask, 0);
+
+ vb->allocateBuffer(num_vertices, num_indices, TRUE);
+
+ LLStrider<LLVector3> vertex_strider;
+ LLStrider<LLVector3> normal_strider;
+ LLStrider<LLVector2> tc_strider;
+ LLStrider<U16> index_strider;
+ LLStrider<LLVector4> weights_strider;
+
+ vb->getVertexStrider(vertex_strider);
+ vb->getNormalStrider(normal_strider);
+ vb->getTexCoord0Strider(tc_strider);
+ vb->getIndexStrider(index_strider);
+
+ if (skinned)
+ {
+ vb->getWeight4Strider(weights_strider);
+ }
+
+ LLVector4a::memcpyNonAliased16((F32*) vertex_strider.get(), (F32*) vf.mPositions, num_vertices*4*sizeof(F32));
+ LLVector4a::memcpyNonAliased16((F32*) tc_strider.get(), (F32*) vf.mTexCoords, num_vertices*2*sizeof(F32));
+ LLVector4a::memcpyNonAliased16((F32*) normal_strider.get(), (F32*) vf.mNormals, num_vertices*4*sizeof(F32));
+
+ if (skinned)
+ {
+ for (U32 i = 0; i < num_vertices; i++)
+ {
+ //find closest weight to vf.mVertices[i].mPosition
+ LLVector3 pos(vf.mPositions[i].getF32ptr());
+
+ const LLModel::weight_list& weight_list = base_mdl->getJointInfluences(pos);
+
+ LLVector4 w(0,0,0,0);
+ if (weight_list.size() > 4)
+ {
+ llerrs << "WTF?" << llendl;
+ }
+
+ for (U32 i = 0; i < weight_list.size(); ++i)
+ {
+ F32 wght = llmin(weight_list[i].mWeight, 0.999999f);
+ F32 joint = (F32) weight_list[i].mJointIdx;
+ w.mV[i] = joint + wght;
+ }
+
+ *(weights_strider++) = w;
+ }
+ }
+
+ // build indices
+ for (U32 i = 0; i < num_indices; i++)
+ {
+ *(index_strider++) = vf.mIndices[i];
+ }
+
+ mVertexBuffer[lod][mdl].push_back(vb);
+
+ vertex_count += num_vertices;
+ tri_count += num_indices/3;
+ ++mesh_count;
+
+ }
+ }
+}
+
+void LLModelPreview::update()
+{
+ if (mDirty)
+ {
+ mDirty = false;
+ mResourceCost = calcResourceCost();
+ refresh();
+ updateStatusMessages();
+ }
+
+ if (mGenLOD)
+ {
+ mGenLOD = false;
+ genLODs();
+ refresh();
+ updateStatusMessages();
+ }
+
+}
+//-----------------------------------------------------------------------------
+// changeAvatarsJointPositions()
+//-----------------------------------------------------------------------------
+void LLModelPreview::changeAvatarsJointPositions( LLModel* pModel )
+{
+ if ( mMasterJointList.empty() )
+ {
+ return;
+ }
+
+ std::vector<std::string> :: const_iterator jointListItBegin = pModel->mSkinInfo.mJointNames.begin();
+ std::vector<std::string> :: const_iterator jointListItEnd = pModel->mSkinInfo.mJointNames.end();
+
+ S32 index = 0;
+ for ( ; jointListItBegin!=jointListItEnd; ++jointListItBegin, ++index )
+ {
+ std::string elem = *jointListItBegin;
+ //llinfos<<"joint "<<elem<<llendl;
+
+ S32 matrixCnt = pModel->mSkinInfo.mAlternateBindMatrix.size();
+ if ( matrixCnt < 1 )
+ {
+ llinfos<<"Total WTF moment :"<<matrixCnt<<llendl;
+ }
+ else
+ {
+ LLMatrix4 jointTransform = pModel->mSkinInfo.mAlternateBindMatrix[index];
+
+ LLJoint* pJoint = gAgentAvatarp->getJoint( elem );
+ if ( pJoint )
+ {
+ pJoint->storeCurrentXform( jointTransform.getTranslation() );
+ }
+ }
+ }
+}
+//-----------------------------------------------------------------------------
+// getTranslationForJointOffset()
+//-----------------------------------------------------------------------------
+LLVector3 LLModelPreview::getTranslationForJointOffset( std::string joint )
+{
+ LLMatrix4 jointTransform;
+ if ( mJointTransformMap.find( joint ) != mJointTransformMap.end() )
+ {
+ jointTransform = mJointTransformMap[joint];
+ return jointTransform.getTranslation();
+ }
+ return LLVector3(0.0f,0.0f,0.0f);
+}
+//-----------------------------------------------------------------------------
+// render()
+//-----------------------------------------------------------------------------
+BOOL LLModelPreview::render()
+{
+ assert_main_thread();
+
+ LLMutexLock lock(this);
+ mNeedsUpdate = FALSE;
+
+ bool edges = mViewOption["show_edges"];
+ bool joint_positions = mViewOption["show_joint_positions"];
+ bool skin_weight = mViewOption["show_skin_weight"];
+ bool textures = mViewOption["show_textures"];
+ bool physics = mViewOption["show_physics"];
+
+ S32 width = getWidth();
+ S32 height = getHeight();
+
+ LLGLSUIDefault def;
+ LLGLDisable no_blend(GL_BLEND);
+ LLGLEnable cull(GL_CULL_FACE);
+ LLGLDepthTest depth(GL_TRUE);
+ LLGLDisable fog(GL_FOG);
+
+ {
+ //clear background to blue
+ glMatrixMode(GL_PROJECTION);
+ gGL.pushMatrix();
+ glLoadIdentity();
+ glOrtho(0.0f, width, 0.0f, height, -1.0f, 1.0f);
+
+ glMatrixMode(GL_MODELVIEW);
+ gGL.pushMatrix();
+ glLoadIdentity();
+
+ gGL.color4f(0.169f, 0.169f, 0.169f, 1.f);
+
+ gl_rect_2d_simple( width, height );
+
+ glMatrixMode(GL_PROJECTION);
+ gGL.popMatrix();
+
+ glMatrixMode(GL_MODELVIEW);
+ gGL.popMatrix();
+ }
+
+ LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance;
+
+ bool has_skin_weights = false;
+ bool upload_skin = mFMP->childGetValue("upload_skin").asBoolean();
+ bool upload_joints = mFMP->childGetValue("upload_joints").asBoolean();
+
+ bool resetJoints = false;
+ if ( upload_joints != mLastJointUpdate )
+ {
+ if ( mLastJointUpdate )
+ {
+ resetJoints = true;
+ }
+
+ mLastJointUpdate = upload_joints;
+
+ }
+
+ for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter)
+ {
+ for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter)
+ {
+ LLModelInstance& instance = *model_iter;
+ LLModel* model = instance.mModel;
+ model->mPelvisOffset = mPelvisZOffset;
+ if (!model->mSkinWeights.empty())
+ {
+ has_skin_weights = true;
+ }
+ }
+ }
+
+ if (has_skin_weights)
+ { //model has skin weights, enable view options for skin weights and joint positions
+ if (fmp)
+ {
+ fmp->enableViewOption("show_skin_weight");
+ fmp->setViewOptionEnabled("show_joint_positions", skin_weight);
+ }
+ mFMP->childEnable("upload_skin");
+ }
+ else
+ {
+ mFMP->childDisable("upload_skin");
+ if (fmp)
+ {
+ mViewOption["show_skin_weight"] = false;
+ fmp->disableViewOption("show_skin_weight");
+ fmp->disableViewOption("show_joint_positions");
+ }
+ skin_weight = false;
+ }
+
+ if (upload_skin && !has_skin_weights)
+ { //can't upload skin weights if model has no skin weights
+ mFMP->childSetValue("upload_skin", false);
+ upload_skin = false;
+ }
+
+ if (!upload_skin && upload_joints)
+ { //can't upload joints if not uploading skin weights
+ mFMP->childSetValue("upload_joints", false);
+ upload_joints = false;
+ }
+
+ mFMP->childSetEnabled("upload_joints", upload_skin);
+
+ //poke at avatar when we upload custom joints
+ /*
+ if ( upload_joints )
+ {
+ for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter)
+ {
+ for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter)
+ {
+ LLModelInstance& instance = *model_iter;
+ LLModel* model = instance.mModel;
+ if ( !model->mSkinWeights.empty() )
+ {
+ changeAvatarsJointPositions( model );
+ }
+ }
+ }
+ }
+ */
+
+ F32 explode = mFMP->childGetValue("physics_explode").asReal();
+
+ glClear(GL_DEPTH_BUFFER_BIT);
+
+ LLRect preview_rect = mFMP->getChildView("preview_panel")->getRect();
+ F32 aspect = (F32) preview_rect.getWidth()/preview_rect.getHeight();
+
+ LLViewerCamera::getInstance()->setAspect(aspect);
+
+ LLViewerCamera::getInstance()->setView(LLViewerCamera::getInstance()->getDefaultFOV() / mCameraZoom);
+
+ LLVector3 offset = mCameraOffset;
+ LLVector3 target_pos = mPreviewTarget+offset;
+
+ F32 z_near = 0.001f;
+ F32 z_far = mCameraDistance+mPreviewScale.magVec()+mCameraOffset.magVec();
+
+ if (skin_weight)
+ {
+ target_pos = gAgentAvatarp->getPositionAgent();
+ z_near = 0.01f;
+ z_far = 1024.f;
+ mCameraDistance = 16.f;
+
+ //render avatar previews every frame
+ refresh();
+ }
+
+ glLoadIdentity();
+ gPipeline.enableLightsPreview();
+
+ LLQuaternion camera_rot = LLQuaternion(mCameraPitch, LLVector3::y_axis) *
+ LLQuaternion(mCameraYaw, LLVector3::z_axis);
+
+ LLQuaternion av_rot = camera_rot;
+ LLViewerCamera::getInstance()->setOriginAndLookAt(
+ target_pos + ((LLVector3(mCameraDistance, 0.f, 0.f) + offset) * av_rot), // camera
+ LLVector3::z_axis, // up
+ target_pos); // point of interest
+
+
+ LLViewerCamera::getInstance()->setPerspective(FALSE, mOrigin.mX, mOrigin.mY, width, height, FALSE, z_near, z_far);
+
+ stop_glerror();
+
+ gGL.pushMatrix();
+ const F32 BRIGHTNESS = 0.9f;
+ gGL.color3f(BRIGHTNESS, BRIGHTNESS, BRIGHTNESS);
+
+ LLGLEnable normalize(GL_NORMALIZE);
+
+ if (!mBaseModel.empty() && mVertexBuffer[5].empty())
+ {
+ genBuffers(-1, skin_weight);
+ //genBuffers(3);
+ //genLODs();
+ }
+
+ if (!mModel[mPreviewLOD].empty())
+ {
+ bool regen = mVertexBuffer[mPreviewLOD].empty();
+ if (!regen)
+ {
+ const std::vector<LLPointer<LLVertexBuffer> >& vb_vec = mVertexBuffer[mPreviewLOD].begin()->second;
+ if (!vb_vec.empty())
+ {
+ const LLVertexBuffer* buff = vb_vec[0];
+ regen = buff->hasDataType(LLVertexBuffer::TYPE_WEIGHT4) != skin_weight;
+ }
+ }
+
+ if (regen)
+ {
+ genBuffers(mPreviewLOD, skin_weight);
+ }
+
+ if (!skin_weight)
+ {
+ for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter)
+ {
+ LLModelInstance& instance = *iter;
+
+ LLModel* model = instance.mLOD[mPreviewLOD];
+
+ if (!model)
+ {
+ continue;
+ }
+
+ gGL.pushMatrix();
+ LLMatrix4 mat = instance.mTransform;
+
+ glMultMatrixf((GLfloat*) mat.mMatrix);
+
+ for (U32 i = 0; i < mVertexBuffer[mPreviewLOD][model].size(); ++i)
+ {
+ LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i];
+
+ buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0);
+
+ if (textures)
+ {
+ glColor4fv(instance.mMaterial[i].mDiffuseColor.mV);
+ if (i < instance.mMaterial.size() && instance.mMaterial[i].mDiffuseMap.notNull())
+ {
+ if (instance.mMaterial[i].mDiffuseMap->getDiscardLevel() > -1)
+ {
+ gGL.getTexUnit(0)->bind(instance.mMaterial[i].mDiffuseMap, true);
+ mTextureSet.insert(instance.mMaterial[i].mDiffuseMap.get());
+ }
+ }
+ }
+ else
+ {
+ glColor4f(1,1,1,1);
+ }
+
+ buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ glColor3f(0.4f, 0.4f, 0.4f);
+
+ if (edges)
+ {
+ glLineWidth(3.f);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ glLineWidth(1.f);
+ }
+ }
+ gGL.popMatrix();
+ }
+
+ if (physics)
+ {
+ glClear(GL_DEPTH_BUFFER_BIT);
+ LLGLEnable blend(GL_BLEND);
+ gGL.blendFunc(LLRender::BF_ONE, LLRender::BF_ZERO);
+
+ for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter)
+ {
+ LLModelInstance& instance = *iter;
+
+ LLModel* model = instance.mLOD[LLModel::LOD_PHYSICS];
+
+ if (!model)
+ {
+ continue;
+ }
+
+ gGL.pushMatrix();
+ LLMatrix4 mat = instance.mTransform;
+
+ glMultMatrixf((GLfloat*) mat.mMatrix);
+
+
+ bool render_mesh = true;
+
+ LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread;
+ if (decomp)
+ {
+ LLMutexLock(decomp->mMutex);
+
+ LLModel::Decomposition& physics = model->mPhysics;
+
+ if (physics.mMesh.empty())
+ { //build vertex buffer for physics mesh
+ gMeshRepo.buildPhysicsMesh(physics);
+ }
+
+ if (!physics.mMesh.empty())
+ { //render hull instead of mesh
+ render_mesh = false;
+ for (U32 i = 0; i < physics.mMesh.size(); ++i)
+ {
+ if (explode > 0.f)
+ {
+ gGL.pushMatrix();
+
+ LLVector3 offset = model->mHullCenter[i]-model->mCenterOfHullCenters;
+ offset *= explode;
+
+ gGL.translatef(offset.mV[0], offset.mV[1], offset.mV[2]);
+ }
+
+ static std::vector<LLColor4U> hull_colors;
+
+ if (i+1 >= hull_colors.size())
+ {
+ hull_colors.push_back(LLColor4U(rand()%128+127, rand()%128+127, rand()%128+127, 255));
+ }
+
+ glColor4ubv(hull_colors[i].mV);
+ LLVertexBuffer::drawArrays(LLRender::TRIANGLES, physics.mMesh[i].mPositions, physics.mMesh[i].mNormals);
+
+ if (explode > 0.f)
+ {
+ gGL.popMatrix();
+ }
+ }
+ }
+ }
+
+ if (render_mesh)
+ {
+ if (mVertexBuffer[LLModel::LOD_PHYSICS].empty())
+ {
+ genBuffers(LLModel::LOD_PHYSICS, false);
+ }
+ for (U32 i = 0; i < mVertexBuffer[LLModel::LOD_PHYSICS][model].size(); ++i)
+ {
+ LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][i];
+
+ buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0);
+
+ buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ glColor4f(0.4f, 0.4f, 0.0f, 0.4f);
+
+ buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
+
+ glColor3f(1.f, 1.f, 0.f);
+
+ glLineWidth(3.f);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ glLineWidth(1.f);
+ }
+ }
+
+ gGL.popMatrix();
+ }
+
+ gGL.setSceneBlendType(LLRender::BT_ALPHA);
+ }
+ }
+ else
+ {
+ LLVOAvatarSelf* avatar = gAgentAvatarp;
+ target_pos = avatar->getPositionAgent();
+
+ LLViewerCamera::getInstance()->setOriginAndLookAt(
+ target_pos + ((LLVector3(mCameraDistance, 0.f, 0.f) + offset) * av_rot), // camera
+ LLVector3::z_axis, // up
+ target_pos); // point of interest
+
+ if (joint_positions)
+ {
+ avatar->renderCollisionVolumes();
+ }
+
+ for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter)
+ {
+ for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter)
+ {
+ LLModelInstance& instance = *model_iter;
+ LLModel* model = instance.mModel;
+
+ if (!model->mSkinWeights.empty())
+ {
+ for (U32 i = 0; i < mVertexBuffer[mPreviewLOD][model].size(); ++i)
+ {
+ LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i];
+
+ const LLVolumeFace& face = model->getVolumeFace(i);
+
+ LLStrider<LLVector3> position;
+ buffer->getVertexStrider(position);
+
+ LLStrider<LLVector4> weight;
+ buffer->getWeight4Strider(weight);
+
+ //quick 'n dirty software vertex skinning
+
+ //build matrix palette
+
+ LLMatrix4 mat[64];
+ for (U32 j = 0; j < model->mSkinInfo.mJointNames.size(); ++j)
+ {
+ LLJoint* joint = avatar->getJoint(model->mSkinInfo.mJointNames[j]);
+ if (joint)
+ {
+ mat[j] = model->mSkinInfo.mInvBindMatrix[j];
+ mat[j] *= joint->getWorldMatrix();
+ }
+ }
+
+ for (U32 j = 0; j < buffer->getRequestedVerts(); ++j)
+ {
+ LLMatrix4 final_mat;
+ final_mat.mMatrix[0][0] = final_mat.mMatrix[1][1] = final_mat.mMatrix[2][2] = final_mat.mMatrix[3][3] = 0.f;
+
+ LLVector4 wght;
+ S32 idx[4];
+
+ F32 scale = 0.f;
+ for (U32 k = 0; k < 4; k++)
+ {
+ F32 w = weight[j].mV[k];
+
+ idx[k] = (S32) floorf(w);
+ wght.mV[k] = w - floorf(w);
+ scale += wght.mV[k];
+ }
+
+ wght *= 1.f/scale;
+
+ for (U32 k = 0; k < 4; k++)
+ {
+ F32* src = (F32*) mat[idx[k]].mMatrix;
+ F32* dst = (F32*) final_mat.mMatrix;
+
+ F32 w = wght.mV[k];
+
+ for (U32 l = 0; l < 16; l++)
+ {
+ dst[l] += src[l]*w;
+ }
+ }
+
+ //VECTORIZE THIS
+ LLVector3 v(face.mPositions[j].getF32ptr());
+
+ v = v * model->mSkinInfo.mBindShapeMatrix;
+ v = v * final_mat;
+
+ position[j] = v;
+ }
+
+ buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0);
+ glColor4fv(instance.mMaterial[i].mDiffuseColor.mV);
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0);
+ glColor3f(0.4f, 0.4f, 0.4f);
+
+ if (edges)
+ {
+ glLineWidth(3.f);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ glLineWidth(1.f);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ gGL.popMatrix();
+
+ return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// refresh()
+//-----------------------------------------------------------------------------
+void LLModelPreview::refresh()
+{
+ mNeedsUpdate = TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// rotate()
+//-----------------------------------------------------------------------------
+void LLModelPreview::rotate(F32 yaw_radians, F32 pitch_radians)
+{
+ mCameraYaw = mCameraYaw + yaw_radians;
+
+ mCameraPitch = llclamp(mCameraPitch + pitch_radians, F_PI_BY_TWO * -0.8f, F_PI_BY_TWO * 0.8f);
+}
+
+//-----------------------------------------------------------------------------
+// zoom()
+//-----------------------------------------------------------------------------
+void LLModelPreview::zoom(F32 zoom_amt)
+{
+ F32 new_zoom = mCameraZoom+zoom_amt;
+
+ mCameraZoom = llclamp(new_zoom, 1.f, 10.f);
+}
+
+void LLModelPreview::pan(F32 right, F32 up)
+{
+ mCameraOffset.mV[VY] = llclamp(mCameraOffset.mV[VY] + right * mCameraDistance / mCameraZoom, -1.f, 1.f);
+ mCameraOffset.mV[VZ] = llclamp(mCameraOffset.mV[VZ] + up * mCameraDistance / mCameraZoom, -1.f, 1.f);
+}
+
+void LLModelPreview::setPreviewLOD(S32 lod)
+{
+ lod = llclamp(lod, 0, (S32) LLModel::LOD_HIGH);
+
+ if (lod != mPreviewLOD)
+ {
+ mPreviewLOD = lod;
+
+ LLComboBox* combo_box = mFMP->getChild<LLComboBox>("preview_lod_combo");
+ combo_box->setCurrentByIndex((NUM_LOD-1)-mPreviewLOD); // combo box list of lods is in reverse order
+ mFMP->childSetTextArg("lod_table_footer", "[DETAIL]", mFMP->getString(lod_name[mPreviewLOD]));
+ mFMP->childSetText("lod_file", mLODFile[mPreviewLOD]);
+
+ // the wizard has three lod drop downs
+ LLComboBox* combo_box2 = mFMP->getChild<LLComboBox>("preview_lod_combo2");
+ combo_box2->setCurrentByIndex((NUM_LOD-1)-mPreviewLOD); // combo box list of lods is in reverse order
+
+ LLComboBox* combo_box3 = mFMP->getChild<LLComboBox>("preview_lod_combo3");
+ combo_box3->setCurrentByIndex((NUM_LOD-1)-mPreviewLOD); // combo box list of lods is in reverse order
+
+ LLColor4 highlight_color = LLUIColorTable::instance().getColor("MeshImportTableHighlightColor");
+ LLColor4 normal_color = LLUIColorTable::instance().getColor("MeshImportTableNormalColor");
+
+ for (S32 i = 0; i <= LLModel::LOD_HIGH; ++i)
+ {
+ const LLColor4& color = (i == lod) ? highlight_color : normal_color;
+
+ mFMP->childSetColor(lod_status_name[i], color);
+ mFMP->childSetColor(lod_label_name[i], color);
+ mFMP->childSetColor(lod_triangles_name[i], color);
+ mFMP->childSetColor(lod_vertices_name[i], color);
+ }
+
+ LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance;
+ if (fmp)
+ {
+ LLRadioGroup* radio = fmp->getChild<LLRadioGroup>("lod_file_or_limit");
+ radio->selectNthItem(fmp->mLODMode[mPreviewLOD]);
+ }
+ }
+ refresh();
+ updateStatusMessages();
+}
+
+//static
+void LLFloaterModelPreview::onBrowseLOD(void* data)
+{
+ assert_main_thread();
+
+ LLFloaterModelPreview* mp = (LLFloaterModelPreview*) data;
+ mp->loadModel(mp->mModelPreview->mPreviewLOD);
+}
+
+//static
+void LLFloaterModelPreview::onReset(void* user_data)
+{
+ assert_main_thread();
+
+ LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) user_data;
+ LLModelPreview* mp = fmp->mModelPreview;
+ std::string filename = mp->mLODFile[3];
+ mp->loadModel(filename,3);
+}
+
+//static
+void LLFloaterModelPreview::onUpload(void* user_data)
+{
+ assert_main_thread();
+
+ LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data;
+
+ mp->mModelPreview->rebuildUploadData();
+
+ bool upload_skinweights = mp->childGetValue("upload_skin").asBoolean();
+ bool upload_joint_positions = mp->childGetValue("upload_joints").asBoolean();
+
+ mp->mModelPreview->saveUploadData(upload_skinweights, upload_joint_positions);
+
+ gMeshRepo.uploadModel(mp->mModelPreview->mUploadData, mp->mModelPreview->mPreviewScale,
+ mp->childGetValue("upload_textures").asBoolean(), upload_skinweights, upload_joint_positions);
+
+ mp->closeFloater(false);
+}
+
+
+//static
+void LLFloaterModelPreview::onClearMaterials(void* user_data)
+{
+ LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data;
+ mp->mModelPreview->clearMaterials();
+}
+
+//static
+void LLFloaterModelPreview::refresh(LLUICtrl* ctrl, void* user_data)
+{
+ sInstance->mModelPreview->mDirty = true;
+}
+
+void LLFloaterModelPreview::updateResourceCost()
+{
+ U32 cost = mModelPreview->mResourceCost;
+ childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d",cost));
+}
+
+//static
+void LLModelPreview::textureLoadedCallback( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata )
+{
+ LLModelPreview* preview = (LLModelPreview*) userdata;
+ preview->refresh();
+}
+
+void LLModelPreview::onLODParamCommit(bool enforce_tri_limit)
+{
+ genLODs(mPreviewLOD, 3, enforce_tri_limit);
+ updateStatusMessages();
+ refresh();
+}
+
+LLFloaterModelPreview::DecompRequest::DecompRequest(const std::string& stage, LLModel* mdl)
+{
+ mStage = stage;
+ mContinue = 1;
+ mModel = mdl;
+ mDecompID = &mdl->mDecompID;
+ mParams = sInstance->mDecompParams;
+
+ //copy out positions and indices
+ if (mdl)
+ {
+ U16 index_offset = 0;
+
+ mPositions.clear();
+ mIndices.clear();
+
+ //queue up vertex positions and indices
+ for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i)
+ {
+ const LLVolumeFace& face = mdl->getVolumeFace(i);
+ if (mPositions.size() + face.mNumVertices > 65535)
+ {
+ continue;
+ }
+
+ for (U32 j = 0; j < face.mNumVertices; ++j)
+ {
+ mPositions.push_back(LLVector3(face.mPositions[j].getF32ptr()));
+ }
+
+ for (U32 j = 0; j < face.mNumIndices; ++j)
+ {
+ mIndices.push_back(face.mIndices[j]+index_offset);
+ }
+
+ index_offset += face.mNumVertices;
+ }
+ }
+}
+
+void LLFloaterModelPreview::setStatusMessage(const std::string& msg)
+{
+ LLMutexLock lock(mStatusLock);
+ mStatusMessage = msg;
+}
+
+S32 LLFloaterModelPreview::DecompRequest::statusCallback(const char* status, S32 p1, S32 p2)
+{
+ if (mContinue)
+ {
+ setStatusMessage(llformat("%s: %d/%d", status, p1, p2));
+ if (LLFloaterModelPreview::sInstance)
+ {
+ LLFloaterModelPreview::sInstance->setStatusMessage(mStatusMessage);
+ }
+ }
+
+ return mContinue;
+}
+
+void LLFloaterModelPreview::DecompRequest::completed()
+{ //called from the main thread
+ if (mContinue)
+ {
+ mModel->setConvexHullDecomposition(mHull);
+
+ if (sInstance)
+ {
+ if (mContinue)
+ {
+ if (sInstance->mModelPreview)
+ {
+ sInstance->mModelPreview->mDirty = true;
+ LLFloaterModelPreview::sInstance->mModelPreview->refresh();
+ }
+ }
+
+ sInstance->mCurRequest.erase(this);
+ }
+ }
+ else if (sInstance)
+ {
+ llassert(sInstance->mCurRequest.find(this) == sInstance->mCurRequest.end());
+ }
+}
diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h
new file mode 100644
index 0000000000..4d8b46807f
--- /dev/null
+++ b/indra/newview/llfloatermodelpreview.h
@@ -0,0 +1,420 @@
+/**
+ * @file llfloatermodelpreview.h
+ * @brief LLFloaterModelPreview class definition
+ *
+ * $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_LLFLOATERMODELPREVIEW_H
+#define LL_LLFLOATERMODELPREVIEW_H
+
+#include "llfloaternamedesc.h"
+
+#include "lldynamictexture.h"
+#include "llfloatermodelwizard.h"
+#include "llquaternion.h"
+#include "llmeshrepository.h"
+#include "llmodel.h"
+#include "llthread.h"
+#include "llviewermenufile.h"
+
+class LLComboBox;
+class LLJoint;
+class LLViewerJointMesh;
+class LLVOAvatar;
+class LLTextBox;
+class LLVertexBuffer;
+class LLModelPreview;
+class LLFloaterModelPreview;
+class daeElement;
+class domProfile_COMMON;
+class domInstance_geometry;
+class domNode;
+class domTranslate;
+class LLMenuButton;
+class LLToggleableMenu;
+
+typedef std::map<std::string, LLMatrix4> JointTransformMap;
+typedef std::map<std::string, LLMatrix4>:: iterator JointTransformMapIt;
+
+const S32 NUM_LOD = 4;
+
+class LLModelLoader : public LLThread
+{
+public:
+ typedef enum
+ {
+ STARTING = 0,
+ READING_FILE,
+ CREATING_FACES,
+ GENERATING_VERTEX_BUFFERS,
+ GENERATING_LOD,
+ DONE,
+ ERROR_PARSING //basically loading failed
+ } eLoadState;
+
+ U32 mState;
+ std::string mFilename;
+ S32 mLod;
+ LLModelPreview* mPreview;
+ LLMatrix4 mTransform;
+ BOOL mFirstTransform;
+ LLVector3 mExtents[2];
+ bool mTrySLM;
+
+ std::map<daeElement*, LLPointer<LLModel> > mModel;
+
+ typedef std::vector<LLPointer<LLModel> > model_list;
+ model_list mModelList;
+
+ typedef std::vector<LLModelInstance> model_instance_list;
+
+ typedef std::map<LLMatrix4, model_instance_list > scene;
+
+ scene mScene;
+
+ typedef std::queue<LLPointer<LLModel> > model_queue;
+
+ //queue of models that need a physics rep
+ model_queue mPhysicsQ;
+
+ LLModelLoader( std::string filename, S32 lod, LLModelPreview* preview, JointTransformMap& jointMap,
+ std::deque<std::string>& jointsFromNodes );
+ ~LLModelLoader() ;
+
+ virtual void run();
+ bool doLoadModel();
+ bool loadFromSLM(const std::string& filename);
+ void loadModelCallback();
+
+ void loadTextures() ; //called in the main thread.
+ void processElement(daeElement* element);
+ std::vector<LLImportMaterial> getMaterials(LLModel* model, domInstance_geometry* instance_geo);
+ LLImportMaterial profileToMaterial(domProfile_COMMON* material);
+ std::string getElementLabel(daeElement *element);
+ LLColor4 getDaeColor(daeElement* element);
+
+ daeElement* getChildFromElement( daeElement* pElement, std::string const & name );
+
+ bool isNodeAJoint( domNode* pNode );
+ void processJointNode( domNode* pNode, std::map<std::string,LLMatrix4>& jointTransforms );
+ void extractTranslation( domTranslate* pTranslate, LLMatrix4& transform );
+ void extractTranslationViaElement( daeElement* pTranslateElement, LLMatrix4& transform );
+
+ void setLoadState(U32 state);
+
+ void buildJointToNodeMappingFromScene( daeElement* pRoot );
+ void processJointToNodeMapping( domNode* pNode );
+
+
+ //map of avatar joints as named in COLLADA assets to internal joint names
+ std::map<std::string, std::string> mJointMap;
+ JointTransformMap& mJointList;
+ std::deque<std::string>& mJointsFromNode;
+
+private:
+ static std::list<LLModelLoader*> sActiveLoaderList;
+ static bool isAlive(LLModelLoader* loader) ;
+};
+
+class LLFloaterModelPreview : public LLFloater
+{
+public:
+
+ class DecompRequest : public LLPhysicsDecomp::Request
+ {
+ public:
+ S32 mContinue;
+ LLPointer<LLModel> mModel;
+
+ DecompRequest(const std::string& stage, LLModel* mdl);
+ virtual S32 statusCallback(const char* status, S32 p1, S32 p2);
+ virtual void completed();
+
+ };
+ static LLFloaterModelPreview* sInstance;
+
+ LLFloaterModelPreview(const LLSD& key);
+ virtual ~LLFloaterModelPreview();
+
+ virtual BOOL postBuild();
+
+ BOOL handleMouseDown(S32 x, S32 y, MASK mask);
+ BOOL handleMouseUp(S32 x, S32 y, MASK mask);
+ BOOL handleHover(S32 x, S32 y, MASK mask);
+ BOOL handleScrollWheel(S32 x, S32 y, S32 clicks);
+
+ static void onMouseCaptureLostModelPreview(LLMouseHandler*);
+ static void setUploadAmount(S32 amount) { sUploadAmount = amount; }
+
+ void setDetails(F32 x, F32 y, F32 z, F32 streaming_cost, F32 physics_cost);
+
+ static void onBrowseLOD(void* data);
+
+ static void onReset(void* data);
+
+ static void onUpload(void* data);
+
+ static void onClearMaterials(void* data);
+
+ static void refresh(LLUICtrl* ctrl, void* data);
+
+ void updateResourceCost();
+
+ void loadModel(S32 lod);
+
+ void onViewOptionChecked(const LLSD& userdata);
+ bool isViewOptionChecked(const LLSD& userdata);
+ bool isViewOptionEnabled(const LLSD& userdata);
+ void setViewOptionEnabled(const std::string& option, bool enabled);
+ void enableViewOption(const std::string& option);
+ void disableViewOption(const std::string& option);
+
+protected:
+ friend class LLModelPreview;
+ friend class LLMeshFilePicker;
+ friend class LLPhysicsDecomp;
+
+ static void onImportScaleCommit(LLUICtrl*, void*);
+ static void onPelvisOffsetCommit(LLUICtrl*, void*);
+ static void onUploadJointsCommit(LLUICtrl*,void*);
+ static void onUploadSkinCommit(LLUICtrl*,void*);
+
+ static void onPreviewLODCommit(LLUICtrl*,void*);
+
+ static void onGenerateNormalsCommit(LLUICtrl*,void*);
+
+ static void onAutoFillCommit(LLUICtrl*,void*);
+ static void onLODParamCommit(LLUICtrl*,void*);
+ static void onLODParamCommitTriangleLimit(LLUICtrl*,void*);
+
+ static void onExplodeCommit(LLUICtrl*, void*);
+
+ static void onPhysicsParamCommit(LLUICtrl* ctrl, void* userdata);
+ static void onPhysicsStageExecute(LLUICtrl* ctrl, void* userdata);
+ static void onCancel(LLUICtrl* ctrl, void* userdata);
+ static void onPhysicsStageCancel(LLUICtrl* ctrl, void* userdata);
+
+ static void onPhysicsBrowse(LLUICtrl* ctrl, void* userdata);
+ static void onPhysicsUseLOD(LLUICtrl* ctrl, void* userdata);
+ static void onPhysicsOptimize(LLUICtrl* ctrl, void* userdata);
+ static void onPhysicsDecomposeBack(LLUICtrl* ctrl, void* userdata);
+ static void onPhysicsSimplifyBack(LLUICtrl* ctrl, void* userdata);
+
+ void draw();
+
+ void initDecompControls();
+
+ void setStatusMessage(const std::string& msg);
+
+ LLModelPreview* mModelPreview;
+
+ LLPhysicsDecomp::decomp_params mDecompParams;
+
+ S32 mLastMouseX;
+ S32 mLastMouseY;
+ LLRect mPreviewRect;
+ U32 mGLName;
+ static S32 sUploadAmount;
+
+ std::set<LLPointer<DecompRequest> > mCurRequest;
+ std::string mStatusMessage;
+
+ //use "disabled" as false by default
+ std::map<std::string, bool> mViewOptionDisabled;
+
+ //store which lod mode each LOD is using
+ // 0 - load from file
+ // 1 - auto generate
+ // 2 - None
+ S32 mLODMode[4];
+
+ LLMenuButton* mViewOptionMenuButton;
+ LLToggleableMenu* mViewOptionMenu;
+ LLMutex* mStatusLock;
+
+};
+
+class LLMeshFilePicker : public LLFilePickerThread
+{
+public:
+ LLMeshFilePicker(LLModelPreview* mp, S32 lod);
+ virtual void notify(const std::string& filename);
+
+private:
+ LLModelPreview* mMP;
+ S32 mLOD;
+};
+
+
+class LLModelPreview : public LLViewerDynamicTexture, public LLMutex
+{
+ typedef boost::signals2::signal<void (F32 x, F32 y, F32 z, F32 streaming_cost, F32 physics_cost)> details_signal_t;
+ typedef boost::signals2::signal<void (void)> model_loaded_signal_t;
+
+public:
+ LLModelPreview(S32 width, S32 height, LLFloater* fmp);
+ virtual ~LLModelPreview();
+
+ void resetPreviewTarget();
+ void setPreviewTarget(F32 distance);
+ void setTexture(U32 name) { mTextureName = name; }
+
+ void setPhysicsFromLOD(S32 lod);
+ BOOL render();
+ void update();
+ void genBuffers(S32 lod, bool skinned);
+ void clearBuffers();
+ void refresh();
+ void rotate(F32 yaw_radians, F32 pitch_radians);
+ void zoom(F32 zoom_amt);
+ void pan(F32 right, F32 up);
+ virtual BOOL needsRender() { return mNeedsUpdate; }
+ void setPreviewLOD(S32 lod);
+ void clearModel(S32 lod);
+ void loadModel(std::string filename, S32 lod);
+ void loadModelCallback(S32 lod);
+ void genLODs(S32 which_lod = -1, U32 decimation = 3, bool enforce_tri_limit = false);
+ void generateNormals();
+ void clearMaterials();
+ U32 calcResourceCost();
+ void rebuildUploadData();
+ void saveUploadData(bool save_skinweights, bool save_joint_poisitions);
+ void saveUploadData(const std::string& filename, bool save_skinweights, bool save_joint_poisitions);
+ void clearIncompatible(S32 lod);
+ void updateStatusMessages();
+ void clearGLODGroup();
+ void onLODParamCommit(bool enforce_tri_limit);
+
+ const bool getModelPivot( void ) const { return mHasPivot; }
+ void setHasPivot( bool val ) { mHasPivot = val; }
+ void setModelPivot( const LLVector3& pivot ) { mModelPivot = pivot; }
+
+ //Sets the current avatars joints to new positions
+ //Makes in world go to shit, however
+ void changeAvatarsJointPositions( LLModel* pModel );
+ //Determines the viability of an asset to be used as an avatar rig (w or w/o joint upload caps)
+ void critiqueRigForUploadApplicability( const std::vector<std::string> &jointListFromAsset );
+ void critiqueJointToNodeMappingFromScene( void );
+ //Is a rig valid so that it can be used as a criteria for allowing for uploading of joint positions
+ //Accessors for joint position upload friendly rigs
+ const bool isRigValidForJointPositionUpload( void ) const { return mRigValidJointUpload; }
+ void setRigValidForJointPositionUpload( bool rigValid ) { mRigValidJointUpload = rigValid; }
+ bool isRigSuitableForJointPositionUpload( const std::vector<std::string> &jointListFromAsset );
+ //Determines if a rig is a legacy from the joint list
+ bool isRigLegacy( const std::vector<std::string> &jointListFromAsset );
+ //Accessors for the legacy rigs
+ const bool isLegacyRigValid( void ) const { return mLegacyRigValid; }
+ void setLegacyRigValid( bool rigValid ) { mLegacyRigValid = rigValid; }
+
+ static void textureLoadedCallback( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata );
+
+ boost::signals2::connection setDetailsCallback( const details_signal_t::slot_type& cb ){ return mDetailsSignal.connect(cb); }
+ boost::signals2::connection setModelLoadedCallback( const model_loaded_signal_t::slot_type& cb ){ return mModelLoadedSignal.connect(cb); }
+
+ void setLoadState( U32 state ) { mLoadState = state; }
+ U32 getLoadState() { return mLoadState; }
+ //setRestJointFlag: If an asset comes through that changes the joints, we want the reset to persist
+ void setResetJointFlag( bool state ) { if ( !mResetJoints ) mResetJoints = state; }
+ const bool getResetJointFlag( void ) const { return mResetJoints; }
+ void setRigWithSceneParity( bool state ) { mRigParityWithScene = state; }
+ const bool getRigWithSceneParity( void ) const { return mRigParityWithScene; }
+
+ LLVector3 getTranslationForJointOffset( std::string joint );
+
+ protected:
+ friend class LLModelLoader;
+ friend class LLFloaterModelPreview;
+ friend class LLFloaterModelWizard;
+ friend class LLFloaterModelPreview::DecompRequest;
+ friend class LLFloaterModelWizard::DecompRequest;
+ friend class LLPhysicsDecomp;
+
+ LLFloater* mFMP;
+
+ BOOL mNeedsUpdate;
+ bool mDirty;
+ bool mGenLOD;
+ U32 mTextureName;
+ F32 mCameraDistance;
+ F32 mCameraYaw;
+ F32 mCameraPitch;
+ F32 mCameraZoom;
+ LLVector3 mCameraOffset;
+ LLVector3 mPreviewTarget;
+ LLVector3 mPreviewScale;
+ S32 mPreviewLOD;
+ U32 mResourceCost;
+ std::string mLODFile[LLModel::NUM_LODS];
+ bool mLoading;
+ U32 mLoadState;
+ bool mResetJoints;
+ bool mRigParityWithScene;
+
+ std::map<std::string, bool> mViewOption;
+
+ //GLOD object parameters (must rebuild object if these change)
+ F32 mBuildShareTolerance;
+ U32 mBuildQueueMode;
+ U32 mBuildOperator;
+ U32 mBuildBorderMode;
+ S32 mRequestedTriangleCount[LLModel::NUM_LODS];
+
+
+ LLModelLoader* mModelLoader;
+
+ LLModelLoader::scene mScene[LLModel::NUM_LODS];
+ LLModelLoader::scene mBaseScene;
+
+ LLModelLoader::model_list mModel[LLModel::NUM_LODS];
+ LLModelLoader::model_list mBaseModel;
+
+ U32 mGroup;
+ std::map<LLPointer<LLModel>, U32> mObject;
+ U32 mMaxTriangleLimit;
+
+ LLMeshUploadThread::instance_list mUploadData;
+ std::set<LLViewerFetchedTexture* > mTextureSet;
+
+ //map of vertex buffers to models (one vertex buffer in vector per face in model
+ std::map<LLModel*, std::vector<LLPointer<LLVertexBuffer> > > mVertexBuffer[LLModel::NUM_LODS+1];
+
+ details_signal_t mDetailsSignal;
+ model_loaded_signal_t mModelLoadedSignal;
+
+ LLVector3 mModelPivot;
+ bool mHasPivot;
+
+ float mPelvisZOffset;
+
+ bool mRigValidJointUpload;
+ bool mLegacyRigValid;
+
+ bool mLastJointUpdate;
+
+ std::deque<std::string> mMasterJointList;
+ std::deque<std::string> mMasterLegacyJointList;
+ std::deque<std::string> mJointsFromNode;
+ JointTransformMap mJointTransformMap;
+};
+
+#endif // LL_LLFLOATERMODELPREVIEW_H
diff --git a/indra/newview/llfloatermodelwizard.cpp b/indra/newview/llfloatermodelwizard.cpp
new file mode 100644
index 0000000000..faf81dbc5c
--- /dev/null
+++ b/indra/newview/llfloatermodelwizard.cpp
@@ -0,0 +1,679 @@
+/**
+ * @file llfloatermodelwizard.cpp
+ * @author Leyla Farazha
+ * @brief Implementation of the LLFloaterModelWizard class.
+ *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llbutton.h"
+#include "lldrawable.h"
+#include "llcheckboxctrl.h"
+#include "llcombobox.h"
+#include "llfloater.h"
+#include "llfloatermodelwizard.h"
+#include "llfloatermodelpreview.h"
+#include "llfloaterreg.h"
+#include "llsliderctrl.h"
+#include "lltoolmgr.h"
+#include "llviewerwindow.h"
+
+LLFloaterModelWizard* LLFloaterModelWizard::sInstance = NULL;
+
+static const std::string stateNames[]={
+ "choose_file",
+ "optimize",
+ "physics",
+ "physics2",
+ "review",
+ "upload"};
+
+LLFloaterModelWizard::LLFloaterModelWizard(const LLSD& key)
+ : LLFloater(key)
+{
+ mLastEnabledState = CHOOSE_FILE;
+ sInstance = this;
+
+ mCommitCallbackRegistrar.add("Wizard.Choose", boost::bind(&LLFloaterModelWizard::setState, this, CHOOSE_FILE));
+ mCommitCallbackRegistrar.add("Wizard.Optimize", boost::bind(&LLFloaterModelWizard::setState, this, OPTIMIZE));
+ mCommitCallbackRegistrar.add("Wizard.Physics", boost::bind(&LLFloaterModelWizard::setState, this, PHYSICS));
+ mCommitCallbackRegistrar.add("Wizard.Physics2", boost::bind(&LLFloaterModelWizard::setState, this, PHYSICS2));
+ mCommitCallbackRegistrar.add("Wizard.Review", boost::bind(&LLFloaterModelWizard::setState, this, REVIEW));
+ mCommitCallbackRegistrar.add("Wizard.Upload", boost::bind(&LLFloaterModelWizard::setState, this, UPLOAD));
+}
+LLFloaterModelWizard::~LLFloaterModelWizard()
+{
+ sInstance = NULL;
+}
+void LLFloaterModelWizard::setState(int state)
+{
+
+ mState = state;
+
+ for(size_t t=0; t<LL_ARRAY_SIZE(stateNames); ++t)
+ {
+ LLView *view = getChildView(stateNames[t]+"_panel");
+ if (view)
+ {
+ view->setVisible(state == (int) t ? TRUE : FALSE);
+ }
+ }
+
+ if (state == CHOOSE_FILE)
+ {
+ mModelPreview->mViewOption["show_physics"] = false;
+
+ getChildView("close")->setVisible(false);
+ getChildView("back")->setVisible(true);
+ getChildView("back")->setEnabled(false);
+ getChildView("next")->setVisible(true);
+ getChildView("upload")->setVisible(false);
+ getChildView("cancel")->setVisible(true);
+ }
+
+ if (state == OPTIMIZE)
+ {
+ if (mLastEnabledState < state)
+ {
+ mModelPreview->genLODs(-1);
+ }
+
+ mModelPreview->mViewOption["show_physics"] = false;
+
+ getChildView("back")->setVisible(true);
+ getChildView("back")->setEnabled(true);
+ getChildView("close")->setVisible(false);
+ getChildView("next")->setVisible(true);
+ getChildView("upload")->setVisible(false);
+ getChildView("cancel")->setVisible(true);
+ }
+
+ if (state == PHYSICS)
+ {
+ if (mLastEnabledState < state)
+ {
+ mModelPreview->setPhysicsFromLOD(1);
+ }
+
+ mModelPreview->mViewOption["show_physics"] = true;
+
+ getChildView("next")->setVisible(true);
+ getChildView("upload")->setVisible(false);
+ getChildView("close")->setVisible(false);
+ getChildView("back")->setVisible(true);
+ getChildView("back")->setEnabled(true);
+ getChildView("cancel")->setVisible(true);
+ }
+
+ if (state == PHYSICS2)
+ {
+ if (mLastEnabledState < state)
+ {
+ executePhysicsStage("Decompose");
+ }
+
+ mModelPreview->mViewOption["show_physics"] = true;
+
+ getChildView("next")->setVisible(true);
+ getChildView("next")->setEnabled(true);
+ getChildView("upload")->setVisible(false);
+ getChildView("close")->setVisible(false);
+ getChildView("back")->setVisible(true);
+ getChildView("back")->setEnabled(true);
+ getChildView("cancel")->setVisible(true);
+ }
+
+ if (state == REVIEW)
+ {
+
+ mModelPreview->mViewOption["show_physics"] = false;
+
+ getChildView("close")->setVisible(false);
+ getChildView("next")->setVisible(false);
+ getChildView("back")->setVisible(true);
+ getChildView("back")->setEnabled(true);
+ getChildView("upload")->setVisible(true);
+ getChildView("cancel")->setVisible(true);
+ }
+
+ if (state == UPLOAD)
+ {
+ getChildView("close")->setVisible(true);
+ getChildView("next")->setVisible(false);
+ getChildView("back")->setVisible(false);
+ getChildView("upload")->setVisible(false);
+ getChildView("cancel")->setVisible(false);
+ }
+
+ updateButtons();
+}
+
+
+
+void LLFloaterModelWizard::updateButtons()
+{
+ if (mLastEnabledState < mState)
+ {
+ mLastEnabledState = mState;
+ }
+
+ for(size_t i=0; i<LL_ARRAY_SIZE(stateNames); ++i)
+ {
+ LLButton *button = getChild<LLButton>(stateNames[i]+"_btn");
+
+ if (i == mState)
+ {
+ button->setEnabled(TRUE);
+ button->setToggleState(TRUE);
+ }
+ else if (i <= mLastEnabledState)
+ {
+ button->setEnabled(TRUE);
+ button->setToggleState(FALSE);
+ }
+ else
+ {
+ button->setEnabled(FALSE);
+ }
+ }
+
+ LLButton *physics_button = getChild<LLButton>(stateNames[PHYSICS]+"_btn");
+
+ if (mState == PHYSICS2)
+ {
+ physics_button->setVisible(false);
+ }
+ else
+ {
+ physics_button->setVisible(true);
+ }
+
+}
+
+void LLFloaterModelWizard::loadModel()
+{
+ mModelPreview->mLoading = TRUE;
+
+ (new LLMeshFilePicker(mModelPreview, 3))->getFile();
+}
+
+void LLFloaterModelWizard::onClickCancel()
+{
+ closeFloater();
+}
+
+void LLFloaterModelWizard::onClickBack()
+{
+ setState(llmax((int) CHOOSE_FILE, mState-1));
+}
+
+void LLFloaterModelWizard::onClickNext()
+{
+ setState(llmin((int) UPLOAD, mState+1));
+}
+
+bool LLFloaterModelWizard::onEnableNext()
+{
+ return true;
+}
+
+bool LLFloaterModelWizard::onEnableBack()
+{
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// handleMouseDown()
+//-----------------------------------------------------------------------------
+BOOL LLFloaterModelWizard::handleMouseDown(S32 x, S32 y, MASK mask)
+{
+ if (mPreviewRect.pointInRect(x, y))
+ {
+ bringToFront( x, y );
+ gFocusMgr.setMouseCapture(this);
+ gViewerWindow->hideCursor();
+ mLastMouseX = x;
+ mLastMouseY = y;
+ return TRUE;
+ }
+
+ return LLFloater::handleMouseDown(x, y, mask);
+}
+
+//-----------------------------------------------------------------------------
+// handleMouseUp()
+//-----------------------------------------------------------------------------
+BOOL LLFloaterModelWizard::handleMouseUp(S32 x, S32 y, MASK mask)
+{
+ gFocusMgr.setMouseCapture(FALSE);
+ gViewerWindow->showCursor();
+ return LLFloater::handleMouseUp(x, y, mask);
+}
+
+//-----------------------------------------------------------------------------
+// handleHover()
+//-----------------------------------------------------------------------------
+BOOL LLFloaterModelWizard::handleHover (S32 x, S32 y, MASK mask)
+{
+ MASK local_mask = mask & ~MASK_ALT;
+
+ if (mModelPreview && hasMouseCapture())
+ {
+ if (local_mask == MASK_PAN)
+ {
+ // pan here
+ mModelPreview->pan((F32)(x - mLastMouseX) * -0.005f, (F32)(y - mLastMouseY) * -0.005f);
+ }
+ else if (local_mask == MASK_ORBIT)
+ {
+ F32 yaw_radians = (F32)(x - mLastMouseX) * -0.01f;
+ F32 pitch_radians = (F32)(y - mLastMouseY) * 0.02f;
+
+ mModelPreview->rotate(yaw_radians, pitch_radians);
+ }
+ else
+ {
+
+ F32 yaw_radians = (F32)(x - mLastMouseX) * -0.01f;
+ F32 zoom_amt = (F32)(y - mLastMouseY) * 0.02f;
+
+ mModelPreview->rotate(yaw_radians, 0.f);
+ mModelPreview->zoom(zoom_amt);
+ }
+
+
+ mModelPreview->refresh();
+
+ LLUI::setMousePositionLocal(this, mLastMouseX, mLastMouseY);
+ }
+
+ if (!mPreviewRect.pointInRect(x, y) || !mModelPreview)
+ {
+ return LLFloater::handleHover(x, y, mask);
+ }
+ else if (local_mask == MASK_ORBIT)
+ {
+ gViewerWindow->setCursor(UI_CURSOR_TOOLCAMERA);
+ }
+ else if (local_mask == MASK_PAN)
+ {
+ gViewerWindow->setCursor(UI_CURSOR_TOOLPAN);
+ }
+ else
+ {
+ gViewerWindow->setCursor(UI_CURSOR_TOOLZOOMIN);
+ }
+
+ return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// handleScrollWheel()
+//-----------------------------------------------------------------------------
+BOOL LLFloaterModelWizard::handleScrollWheel(S32 x, S32 y, S32 clicks)
+{
+ if (mPreviewRect.pointInRect(x, y) && mModelPreview)
+ {
+ mModelPreview->zoom((F32)clicks * -0.2f);
+ mModelPreview->refresh();
+ }
+
+ return TRUE;
+}
+
+void LLFloaterModelWizard::initDecompControls()
+{
+ LLSD key;
+
+ static const LLCDStageData* stage = NULL;
+ static S32 stage_count = 0;
+
+ if (!stage && LLConvexDecomposition::getInstance() != NULL)
+ {
+ stage_count = LLConvexDecomposition::getInstance()->getStages(&stage);
+ }
+
+ static const LLCDParam* param = NULL;
+ static S32 param_count = 0;
+ if (!param && LLConvexDecomposition::getInstance() != NULL)
+ {
+ param_count = LLConvexDecomposition::getInstance()->getParameters(&param);
+ }
+
+ for (S32 j = stage_count-1; j >= 0; --j)
+ {
+ gMeshRepo.mDecompThread->mStageID[stage[j].mName] = j;
+ // protected against stub by stage_count being 0 for stub above
+ LLConvexDecomposition::getInstance()->registerCallback(j, LLPhysicsDecomp::llcdCallback);
+
+ for (S32 i = 0; i < param_count; ++i)
+ {
+ if (param[i].mStage != j)
+ {
+ continue;
+ }
+
+ std::string name(param[i].mName ? param[i].mName : "");
+ std::string description(param[i].mDescription ? param[i].mDescription : "");
+
+ if (param[i].mType == LLCDParam::LLCD_FLOAT)
+ {
+ mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mFloat);
+ }
+ else if (param[i].mType == LLCDParam::LLCD_INTEGER)
+ {
+ mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mIntOrEnumValue);
+ }
+ else if (param[i].mType == LLCDParam::LLCD_BOOLEAN)
+ {
+ mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mBool);
+ }
+ else if (param[i].mType == LLCDParam::LLCD_ENUM)
+ {
+ mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mIntOrEnumValue);
+ }
+ }
+ }
+
+ mDecompParams["Simplify Method"] = 0; // set it to retain %
+}
+
+//static
+void LLFloaterModelWizard::executePhysicsStage(std::string stage_name)
+{
+ if (sInstance)
+ {
+ F64 physics_accuracy = sInstance->getChild<LLSliderCtrl>("physics_slider")->getValue().asReal();
+
+ sInstance->mDecompParams["Retain%"] = physics_accuracy;
+
+ if (!sInstance->mCurRequest.empty())
+ {
+ llinfos << "Decomposition request still pending." << llendl;
+ return;
+ }
+
+ if (sInstance->mModelPreview)
+ {
+ for (S32 i = 0; i < sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS].size(); ++i)
+ {
+ LLModel* mdl = sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS][i];
+ DecompRequest* request = new DecompRequest(stage_name, mdl);
+ sInstance->mCurRequest.insert(request);
+ gMeshRepo.mDecompThread->submitRequest(request);
+ }
+ }
+ }
+}
+
+LLFloaterModelWizard::DecompRequest::DecompRequest(const std::string& stage, LLModel* mdl)
+{
+ mStage = stage;
+ mContinue = 1;
+ mModel = mdl;
+ mDecompID = &mdl->mDecompID;
+ mParams = sInstance->mDecompParams;
+
+ //copy out positions and indices
+ if (mdl)
+ {
+ U16 index_offset = 0;
+
+ mPositions.clear();
+ mIndices.clear();
+
+ //queue up vertex positions and indices
+ for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i)
+ {
+ const LLVolumeFace& face = mdl->getVolumeFace(i);
+ if (mPositions.size() + face.mNumVertices > 65535)
+ {
+ continue;
+ }
+
+ for (U32 j = 0; j < face.mNumVertices; ++j)
+ {
+ mPositions.push_back(LLVector3(face.mPositions[j].getF32ptr()));
+ }
+
+ for (U32 j = 0; j < face.mNumIndices; ++j)
+ {
+ mIndices.push_back(face.mIndices[j]+index_offset);
+ }
+
+ index_offset += face.mNumVertices;
+ }
+ }
+}
+
+
+S32 LLFloaterModelWizard::DecompRequest::statusCallback(const char* status, S32 p1, S32 p2)
+{
+ setStatusMessage(llformat("%s: %d/%d", status, p1, p2));
+
+ return mContinue;
+}
+
+void LLFloaterModelWizard::DecompRequest::completed()
+{ //called from the main thread
+ mModel->setConvexHullDecomposition(mHull);
+
+ if (sInstance)
+ {
+ if (sInstance->mModelPreview)
+ {
+ sInstance->mModelPreview->mDirty = true;
+ LLFloaterModelWizard::sInstance->mModelPreview->refresh();
+ }
+
+ sInstance->mCurRequest.erase(this);
+ }
+
+ if (mStage == "Decompose")
+ {
+ executePhysicsStage("Simplify");
+ }
+}
+
+
+BOOL LLFloaterModelWizard::postBuild()
+{
+ LLView* preview_panel = getChildView("preview_panel");
+
+ childSetValue("import_scale", (F32) 0.67335826);
+
+ getChild<LLUICtrl>("browse")->setCommitCallback(boost::bind(&LLFloaterModelWizard::loadModel, this));
+ //getChild<LLUICtrl>("lod_file")->setCommitCallback(boost::bind(&LLFloaterModelWizard::loadModel, this));
+ getChild<LLUICtrl>("cancel")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onClickCancel, this));
+ getChild<LLUICtrl>("close")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onClickCancel, this));
+ getChild<LLUICtrl>("back")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onClickBack, this));
+ getChild<LLUICtrl>("next")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onClickNext, this));
+ getChild<LLUICtrl>("preview_lod_combo")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onPreviewLODCommit, this, _1));
+ getChild<LLUICtrl>("preview_lod_combo2")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onPreviewLODCommit, this, _1));
+ getChild<LLUICtrl>("preview_lod_combo3")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onPreviewLODCommit, this, _1));
+ getChild<LLUICtrl>("accuracy_slider")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onAccuracyPerformance, this, _2));
+ getChild<LLUICtrl>("upload")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onUpload, this));
+ getChild<LLUICtrl>("physics_slider")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onPhysicsChanged, this));
+
+ LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
+
+ enable_registrar.add("Next.OnEnable", boost::bind(&LLFloaterModelWizard::onEnableNext, this));
+ enable_registrar.add("Back.OnEnable", boost::bind(&LLFloaterModelWizard::onEnableBack, this));
+
+
+ mPreviewRect = preview_panel->getRect();
+
+ mModelPreview = new LLModelPreview(512, 512, this);
+ mModelPreview->setPreviewTarget(16.f);
+ mModelPreview->setDetailsCallback(boost::bind(&LLFloaterModelWizard::setDetails, this, _1, _2, _3, _4, _5));
+ mModelPreview->setModelLoadedCallback(boost::bind(&LLFloaterModelWizard::modelLoadedCallback, this));
+ mModelPreview->mViewOption["show_textures"] = true;
+
+ center();
+
+ setState(CHOOSE_FILE);
+
+ childSetTextArg("import_dimensions", "[X]", LLStringUtil::null);
+ childSetTextArg("import_dimensions", "[Y]", LLStringUtil::null);
+ childSetTextArg("import_dimensions", "[Z]", LLStringUtil::null);
+
+ initDecompControls();
+
+ return TRUE;
+}
+
+
+void LLFloaterModelWizard::setDetails(F32 x, F32 y, F32 z, F32 streaming_cost, F32 physics_cost)
+{
+ // iterate through all the panels, setting the dimensions
+ for(size_t t=0; t<LL_ARRAY_SIZE(stateNames); ++t)
+ {
+ LLPanel *panel = getChild<LLPanel>(stateNames[t]+"_panel");
+ if (panel)
+ {
+ panel->childSetText("dimension_x", llformat("%.1f", x));
+ panel->childSetText("dimension_y", llformat("%.1f", y));
+ panel->childSetText("dimension_z", llformat("%.1f", z));
+ panel->childSetTextArg("streaming cost", "[COST]", llformat("%.3f", streaming_cost));
+ panel->childSetTextArg("physics cost", "[COST]", llformat("%.3f", physics_cost));
+ }
+ }
+}
+
+void LLFloaterModelWizard::modelLoadedCallback()
+{
+ mLastEnabledState = CHOOSE_FILE;
+ getChild<LLCheckBoxCtrl>("confirm_checkbox")->set(FALSE);
+ updateButtons();
+}
+
+void LLFloaterModelWizard::onPhysicsChanged()
+{
+ mLastEnabledState = PHYSICS;
+ updateButtons();
+}
+
+void LLFloaterModelWizard::onUpload()
+{
+ mModelPreview->rebuildUploadData();
+
+ gMeshRepo.uploadModel(mModelPreview->mUploadData, mModelPreview->mPreviewScale,
+ true, false, false);
+
+ setState(UPLOAD);
+
+}
+
+void LLFloaterModelWizard::onAccuracyPerformance(const LLSD& data)
+{
+ int val = (int) data.asInteger();
+
+ mModelPreview->genLODs(-1, NUM_LOD-val);
+
+ mModelPreview->refresh();
+}
+
+
+void LLFloaterModelWizard::onPreviewLODCommit(LLUICtrl* ctrl)
+{
+ if (!mModelPreview)
+ {
+ return;
+ }
+
+ S32 which_mode = 0;
+
+ LLComboBox* combo = (LLComboBox*) ctrl;
+
+ which_mode = (NUM_LOD-1)-combo->getFirstSelectedIndex(); // combo box list of lods is in reverse order
+
+ mModelPreview->setPreviewLOD(which_mode);
+}
+
+void LLFloaterModelWizard::refresh()
+{
+ if (mState == CHOOSE_FILE)
+ {
+ bool model_loaded = false;
+
+ if (mModelPreview && mModelPreview->getLoadState() == LLModelLoader::DONE)
+ {
+ model_loaded = true;
+ }
+
+ getChildView("next")->setEnabled(model_loaded);
+ }
+ if (mState == REVIEW)
+ {
+ getChildView("upload")->setEnabled(getChild<LLCheckBoxCtrl>("confirm_checkbox")->getValue().asBoolean());
+ }
+
+}
+
+void LLFloaterModelWizard::draw()
+{
+ refresh();
+
+ LLFloater::draw();
+ LLRect r = getRect();
+
+ mModelPreview->update();
+
+ if (mModelPreview)
+ {
+ gGL.color3f(1.f, 1.f, 1.f);
+
+ gGL.getTexUnit(0)->bind(mModelPreview);
+
+ LLView *view = getChildView(stateNames[mState]+"_panel");
+ LLView* preview_panel = view->getChildView("preview_panel");
+
+ LLRect rect = preview_panel->getRect();
+ if (rect != mPreviewRect)
+ {
+ mModelPreview->refresh();
+ mPreviewRect = preview_panel->getRect();
+ }
+
+ LLRect item_rect;
+ preview_panel->localRectToOtherView(preview_panel->getLocalRect(), &item_rect, this);
+
+ gGL.begin( LLRender::QUADS );
+ {
+ gGL.texCoord2f(0.f, 1.f);
+ gGL.vertex2i(item_rect.mLeft, item_rect.mTop-1);
+ gGL.texCoord2f(0.f, 0.f);
+ gGL.vertex2i(item_rect.mLeft, item_rect.mBottom);
+ gGL.texCoord2f(1.f, 0.f);
+ gGL.vertex2i(item_rect.mRight-1, item_rect.mBottom);
+ gGL.texCoord2f(1.f, 1.f);
+ gGL.vertex2i(item_rect.mRight-1, item_rect.mTop-1);
+ }
+ gGL.end();
+
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ }
+}
diff --git a/indra/newview/llfloatermodelwizard.h b/indra/newview/llfloatermodelwizard.h
new file mode 100644
index 0000000000..b166d26295
--- /dev/null
+++ b/indra/newview/llfloatermodelwizard.h
@@ -0,0 +1,113 @@
+/**
+ * @file llfloatermodelwizard.h
+ *
+ * $LicenseInfo:firstyear=2009&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 LLFLOATERMODELWIZARD_H
+#define LLFLOATERMODELWIZARD_H
+
+
+#include "llmeshrepository.h"
+#include "llmodel.h"
+#include "llthread.h"
+
+
+class LLModelPreview;
+
+
+class LLFloaterModelWizard : public LLFloater
+{
+public:
+
+ class DecompRequest : public LLPhysicsDecomp::Request
+ {
+ public:
+ S32 mContinue;
+ LLPointer<LLModel> mModel;
+
+ DecompRequest(const std::string& stage, LLModel* mdl);
+ virtual S32 statusCallback(const char* status, S32 p1, S32 p2);
+ virtual void completed();
+
+ };
+
+ static LLFloaterModelWizard* sInstance;
+
+ LLFloaterModelWizard(const LLSD& key);
+ virtual ~LLFloaterModelWizard();
+ /*virtual*/ BOOL postBuild();
+ void draw();
+ void refresh();
+
+ BOOL handleMouseDown(S32 x, S32 y, MASK mask);
+ BOOL handleMouseUp(S32 x, S32 y, MASK mask);
+ BOOL handleHover(S32 x, S32 y, MASK mask);
+ BOOL handleScrollWheel(S32 x, S32 y, S32 clicks);
+
+ void setDetails(F32 x, F32 y, F32 z, F32 streaming_cost, F32 physics_cost);
+ void modelLoadedCallback();
+ void onPhysicsChanged();
+ void initDecompControls();
+
+ LLPhysicsDecomp::decomp_params mDecompParams;
+ std::set<LLPointer<DecompRequest> > mCurRequest;
+ std::string mStatusMessage;
+ static void executePhysicsStage(std::string stage_name);
+
+private:
+ enum EWizardState
+ {
+ CHOOSE_FILE = 0,
+ OPTIMIZE,
+ PHYSICS,
+ PHYSICS2,
+ REVIEW,
+ UPLOAD
+ };
+
+ void setState(int state);
+ void updateButtons();
+ void onClickCancel();
+ void onClickBack();
+ void onClickNext();
+ bool onEnableNext();
+ bool onEnableBack();
+ void loadModel();
+ void onPreviewLODCommit(LLUICtrl*);
+ void onAccuracyPerformance(const LLSD& data);
+ void onUpload();
+
+ LLModelPreview* mModelPreview;
+ LLRect mPreviewRect;
+ int mState;
+
+ S32 mLastMouseX;
+ S32 mLastMouseY;
+
+ U32 mLastEnabledState;
+
+
+};
+
+
+#endif
diff --git a/indra/newview/llfloaternotificationsconsole.cpp b/indra/newview/llfloaternotificationsconsole.cpp
index 42dc60f9e0..29af81d64c 100644
--- a/indra/newview/llfloaternotificationsconsole.cpp
+++ b/indra/newview/llfloaternotificationsconsole.cpp
@@ -174,6 +174,7 @@ BOOL LLFloaterNotificationConsole::postBuild()
// these are in the order of processing
addChannel("Unexpired");
addChannel("Ignore");
+ addChannel("VisibilityRules");
addChannel("Visible", true);
// all the ones below attach to the Visible channel
addChannel("Persistent");
diff --git a/indra/newview/llfloaterpostcard.cpp b/indra/newview/llfloaterpostcard.cpp
index e8e9f76912..dd0b1d999c 100644
--- a/indra/newview/llfloaterpostcard.cpp
+++ b/indra/newview/llfloaterpostcard.cpp
@@ -112,11 +112,14 @@ LLFloaterPostcard* LLFloaterPostcard::showFromSnapshot(LLImageJPEG *jpeg, LLView
// Take the images from the caller
// It's now our job to clean them up
LLFloaterPostcard* instance = LLFloaterReg::showTypedInstance<LLFloaterPostcard>("postcard", LLSD(img->getID()));
-
- instance->mJPEGImage = jpeg;
- instance->mViewerImage = img;
- instance->mImageScale = image_scale;
- instance->mPosTakenGlobal = pos_taken_global;
+
+ if (instance) // may be 0 if we're in mouselook mode
+ {
+ instance->mJPEGImage = jpeg;
+ instance->mViewerImage = img;
+ instance->mImageScale = image_scale;
+ instance->mPosTakenGlobal = pos_taken_global;
+ }
return instance;
}
@@ -128,6 +131,8 @@ void LLFloaterPostcard::draw()
if(!isMinimized() && mViewerImage.notNull() && mJPEGImage.notNull())
{
+ // Force the texture to be 100% opaque when the floater is focused.
+ F32 alpha = getTransparencyType() == TT_ACTIVE ? 1.0f : getCurrentTransparency();
LLRect rect(getRect());
// first set the max extents of our preview
@@ -149,7 +154,7 @@ void LLFloaterPostcard::draw()
}
{
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- gl_rect_2d(rect, LLColor4(0.f, 0.f, 0.f, 1.f));
+ gl_rect_2d(rect, LLColor4(0.f, 0.f, 0.f, 1.f) % alpha);
rect.stretch(-1);
}
{
@@ -164,7 +169,7 @@ void LLFloaterPostcard::draw()
rect.getWidth(),
rect.getHeight(),
mViewerImage.get(),
- LLColor4::white);
+ LLColor4::white % alpha);
}
glMatrixMode(GL_TEXTURE);
glPopMatrix();
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 2bea3d37ff..4b15695cbf 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -43,6 +43,7 @@
#include "llcombobox.h"
#include "llcommandhandler.h"
#include "lldirpicker.h"
+#include "lleventtimer.h"
#include "llfeaturemanager.h"
#include "llfocusmgr.h"
//#include "llfirstuse.h"
@@ -73,6 +74,7 @@
#include "llviewerwindow.h"
#include "llviewermessage.h"
#include "llviewershadermgr.h"
+#include "llviewerthrottle.h"
#include "llvotree.h"
#include "llvosky.h"
@@ -105,9 +107,11 @@
#include "llteleporthistorystorage.h"
#include "lllogininstance.h" // to check if logged in yet
+#include "llsdserialize.h"
const F32 MAX_USER_FAR_CLIP = 512.f;
const F32 MIN_USER_FAR_CLIP = 64.f;
+const F32 BANDWIDTH_UPDATER_TIMEOUT = 0.5f;
//control value for middle mouse as talk2push button
const static std::string MIDDLE_MOUSE_CV = "MiddleMouse";
@@ -282,8 +286,12 @@ std::string LLFloaterPreference::sSkin = "";
LLFloaterPreference::LLFloaterPreference(const LLSD& key)
: LLFloater(key),
mGotPersonalInfo(false),
- mOriginalIMViaEmail(false)
+ mOriginalIMViaEmail(false),
+ mLanguageChanged(false),
+ mAvatarDataInitialized(false),
+ mDoubleClickActionDirty(false)
{
+
//Build Floater is now Called from LLFloaterReg::add("preferences", "floater_preferences.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreference>);
static bool registered_dialog = false;
@@ -320,12 +328,80 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key)
mCommitCallbackRegistrar.add("Pref.getUIColor", boost::bind(&LLFloaterPreference::getUIColor, this ,_1, _2));
mCommitCallbackRegistrar.add("Pref.MaturitySettings", boost::bind(&LLFloaterPreference::onChangeMaturity, this));
mCommitCallbackRegistrar.add("Pref.BlockList", boost::bind(&LLFloaterPreference::onClickBlockList, this));
-
- sSkin = gSavedSettings.getString("SkinCurrent");
+ sSkin = gSavedSettings.getString("SkinCurrent");
+
+ mCommitCallbackRegistrar.add("Pref.CommitDoubleClickChekbox", boost::bind(&LLFloaterPreference::onDoubleClickCheckBox, this, _1));
+ mCommitCallbackRegistrar.add("Pref.CommitRadioDoubleClick", boost::bind(&LLFloaterPreference::onDoubleClickRadio, this));
+
gSavedSettings.getControl("NameTagShowUsernames")->getCommitSignal()->connect(boost::bind(&handleNameTagOptionChanged, _2));
gSavedSettings.getControl("NameTagShowFriends")->getCommitSignal()->connect(boost::bind(&handleNameTagOptionChanged, _2));
gSavedSettings.getControl("UseDisplayNames")->getCommitSignal()->connect(boost::bind(&handleDisplayNamesOptionChanged, _2));
+
+ LLAvatarPropertiesProcessor::getInstance()->addObserver( gAgent.getID(), this );
+}
+
+void LLFloaterPreference::processProperties( void* pData, EAvatarProcessorType type )
+{
+ if ( APT_PROPERTIES == type )
+ {
+ const LLAvatarData* pAvatarData = static_cast<const LLAvatarData*>( pData );
+ if (pAvatarData && (gAgent.getID() == pAvatarData->avatar_id) && (pAvatarData->avatar_id != LLUUID::null))
+ {
+ storeAvatarProperties( pAvatarData );
+ processProfileProperties( pAvatarData );
+ }
+ }
+}
+
+void LLFloaterPreference::storeAvatarProperties( const LLAvatarData* pAvatarData )
+{
+ 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 )
+{
+ getChild<LLUICtrl>("online_searchresults")->setValue( (bool)(pAvatarData->flags & AVATAR_ALLOW_PUBLISH) );
+}
+
+void LLFloaterPreference::saveAvatarProperties( void )
+{
+ const BOOL allowPublish = getChild<LLUICtrl>("online_searchresults")->getValue();
+
+ if (allowPublish)
+ {
+ mAvatarProperties.flags |= AVATAR_ALLOW_PUBLISH;
+ }
+
+ //
+ // 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()
@@ -338,14 +414,22 @@ BOOL LLFloaterPreference::postBuild()
gSavedSettings.getControl("ChatFontSize")->getSignal()->connect(boost::bind(&LLNearbyChat::processChatHistoryStyleUpdate, _2));
+ gSavedSettings.getControl("ChatFontSize")->getSignal()->connect(boost::bind(&LLViewerChat::signalChatFontChanged));
+
+ gSavedSettings.getControl("ChatBubbleOpacity")->getSignal()->connect(boost::bind(&LLFloaterPreference::onNameTagOpacityChange, this, _2));
+
LLTabContainer* tabcontainer = getChild<LLTabContainer>("pref core");
if (!tabcontainer->selectTab(gSavedSettings.getS32("LastPrefTab")))
tabcontainer->selectFirstTab();
+ updateDoubleClickControls();
+
getChild<LLUICtrl>("cache_location")->setEnabled(FALSE); // make it read-only but selectable (STORM-227)
std::string cache_location = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "");
setCacheLocation(cache_location);
+ getChild<LLComboBox>("language_combobox")->setCommitCallback(boost::bind(&LLFloaterPreference::onLanguageChange, this));
+
// if floater is opened before login set default localized busy message
if (LLStartUp::getStartupState() < STATE_STARTED)
{
@@ -405,6 +489,8 @@ void LLFloaterPreference::saveSettings()
void LLFloaterPreference::apply()
{
+ LLAvatarPropertiesProcessor::getInstance()->addObserver( gAgent.getID(), this );
+
LLTabContainer* tabcontainer = getChild<LLTabContainer>("pref core");
if (sSkin != gSavedSettings.getString("SkinCurrent"))
{
@@ -475,6 +561,14 @@ void LLFloaterPreference::apply()
gAgent.sendAgentUpdateUserInfo(new_im_via_email,mDirectoryVisibility);
}
}
+
+ saveAvatarProperties();
+
+ if (mDoubleClickActionDirty)
+ {
+ updateDoubleClickSettings();
+ mDoubleClickActionDirty = false;
+ }
}
void LLFloaterPreference::cancel()
@@ -501,10 +595,17 @@ void LLFloaterPreference::cancel()
// reverts any changes to current skin
gSavedSettings.setString("SkinCurrent", sSkin);
+
+ if (mDoubleClickActionDirty)
+ {
+ updateDoubleClickControls();
+ mDoubleClickActionDirty = false;
+ }
}
void LLFloaterPreference::onOpen(const LLSD& key)
{
+
// this variable and if that follows it are used to properly handle busy mode response message
static bool initialized = FALSE;
// if user is logged in and we haven't initialized busy_response yet, do it
@@ -531,7 +632,7 @@ void LLFloaterPreference::onOpen(const LLSD& key)
(gAgent.isMature() || gAgent.isGodlike());
LLComboBox* maturity_combo = getChild<LLComboBox>("maturity_desired_combobox");
-
+ LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesRequest( gAgent.getID() );
if (can_choose_maturity)
{
// if they're not adult or a god, they shouldn't see the adult selection, so delete it
@@ -553,6 +654,9 @@ void LLFloaterPreference::onOpen(const LLSD& key)
getChildView("maturity_desired_combobox")->setVisible( false);
}
+ // Forget previous language changes.
+ mLanguageChanged = false;
+
// Display selected maturity icons.
onChangeMaturity();
@@ -710,6 +814,28 @@ void LLFloaterPreference::onClickBrowserClearCache()
LLNotificationsUtil::add("ConfirmClearBrowserCache", LLSD(), LLSD(), callback_clear_browser_cache);
}
+// Called when user changes language via the combobox.
+void LLFloaterPreference::onLanguageChange()
+{
+ // Let the user know that the change will only take effect after restart.
+ // Do it only once so that we're not too irritating.
+ if (!mLanguageChanged)
+ {
+ LLNotificationsUtil::add("ChangeLanguage");
+ mLanguageChanged = true;
+ }
+}
+
+void LLFloaterPreference::onNameTagOpacityChange(const LLSD& newvalue)
+{
+ LLColorSwatchCtrl* color_swatch = findChild<LLColorSwatchCtrl>("background");
+ if (color_swatch)
+ {
+ LLColor4 new_color = color_swatch->get();
+ color_swatch->set( new_color.setAlpha(newvalue.asReal()) );
+ }
+}
+
void LLFloaterPreference::onClickSetCache()
{
std::string cur_name(gSavedSettings.getString("CacheLocation"));
@@ -803,7 +929,7 @@ void LLFloaterPreference::buildPopupLists()
LLScrollListItem* item = NULL;
- bool show_popup = formp->getIgnored();
+ bool show_popup = !formp->getIgnored();
if (!show_popup)
{
if (ignore == LLNotificationForm::IGNORE_WITH_LAST_RESPONSE)
@@ -861,9 +987,15 @@ void LLFloaterPreference::refreshEnabledState()
LLCheckBoxCtrl* ctrl_avatar_vp = getChild<LLCheckBoxCtrl>("AvatarVertexProgram");
// Avatar Render Mode
LLCheckBoxCtrl* ctrl_avatar_cloth = getChild<LLCheckBoxCtrl>("AvatarCloth");
+
+ bool avatar_vp_enabled = LLFeatureManager::getInstance()->isFeatureAvailable("RenderAvatarVP");
+ if (LLViewerShaderMgr::sInitialized)
+ {
+ S32 max_avatar_shader = LLViewerShaderMgr::instance()->mMaxAvatarShaderLevel;
+ avatar_vp_enabled = (max_avatar_shader > 0) ? TRUE : FALSE;
+ }
- S32 max_avatar_shader = LLViewerShaderMgr::instance()->mMaxAvatarShaderLevel;
- ctrl_avatar_vp->setEnabled((max_avatar_shader > 0) ? TRUE : FALSE);
+ ctrl_avatar_vp->setEnabled(avatar_vp_enabled);
if (gSavedSettings.getBOOL("VertexShaderEnable") == FALSE ||
gSavedSettings.getBOOL("RenderAvatarVP") == FALSE)
@@ -880,7 +1012,7 @@ void LLFloaterPreference::refreshEnabledState()
LLCheckBoxCtrl* ctrl_shader_enable = getChild<LLCheckBoxCtrl>("BasicShaders");
// radio set for terrain detail mode
LLRadioGroup* mRadioTerrainDetail = getChild<LLRadioGroup>("TerrainDetailRadio"); // can be linked with control var
-
+
ctrl_shader_enable->setEnabled(LLFeatureManager::getInstance()->isFeatureAvailable("VertexShaderEnable"));
BOOL shaders = ctrl_shader_enable->get();
@@ -903,26 +1035,28 @@ void LLFloaterPreference::refreshEnabledState()
//Deferred/SSAO/Shadows
LLCheckBoxCtrl* ctrl_deferred = getChild<LLCheckBoxCtrl>("UseLightShaders");
- if (LLFeatureManager::getInstance()->isFeatureAvailable("RenderUseFBO") &&
- LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") &&
- shaders)
- {
- BOOL enabled = (ctrl_wind_light->get()) ? TRUE : FALSE;
+
+ BOOL enabled = LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") &&
+ shaders &&
+ gGLManager.mHasFramebufferObject &&
+ gSavedSettings.getBOOL("RenderAvatarVP") &&
+ (ctrl_wind_light->get()) ? TRUE : FALSE;
- ctrl_deferred->setEnabled(enabled);
+ ctrl_deferred->setEnabled(enabled);
- LLCheckBoxCtrl* ctrl_ssao = getChild<LLCheckBoxCtrl>("UseSSAO");
- LLComboBox* ctrl_shadow = getChild<LLComboBox>("ShadowDetail");
+ LLCheckBoxCtrl* ctrl_ssao = getChild<LLCheckBoxCtrl>("UseSSAO");
+ LLCheckBoxCtrl* ctrl_dof = getChild<LLCheckBoxCtrl>("UseDoF");
+ LLComboBox* ctrl_shadow = getChild<LLComboBox>("ShadowDetail");
- enabled = enabled && LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferredSSAO") && (ctrl_deferred->get() ? TRUE : FALSE);
+ enabled = enabled && LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferredSSAO") && (ctrl_deferred->get() ? TRUE : FALSE);
- ctrl_ssao->setEnabled(enabled);
-
- enabled = enabled && LLFeatureManager::getInstance()->isFeatureAvailable("RenderShadowDetail");
+ ctrl_ssao->setEnabled(enabled);
+ ctrl_dof->setEnabled(enabled);
- ctrl_shadow->setEnabled(enabled);
- }
+ enabled = enabled && LLFeatureManager::getInstance()->isFeatureAvailable("RenderShadowDetail");
+ ctrl_shadow->setEnabled(enabled);
+
// now turn off any features that are unavailable
disableUnavailableSettings();
@@ -941,6 +1075,7 @@ void LLFloaterPreference::disableUnavailableSettings()
LLCheckBoxCtrl* ctrl_deferred = getChild<LLCheckBoxCtrl>("UseLightShaders");
LLComboBox* ctrl_shadows = getChild<LLComboBox>("ShadowDetail");
LLCheckBoxCtrl* ctrl_ssao = getChild<LLCheckBoxCtrl>("UseSSAO");
+ LLCheckBoxCtrl* ctrl_dof = getChild<LLCheckBoxCtrl>("UseDoF");
// if vertex shaders off, disable all shader related products
if(!LLFeatureManager::getInstance()->isFeatureAvailable("VertexShaderEnable"))
@@ -966,6 +1101,9 @@ void LLFloaterPreference::disableUnavailableSettings()
ctrl_ssao->setEnabled(FALSE);
ctrl_ssao->setValue(FALSE);
+ ctrl_dof->setEnabled(FALSE);
+ ctrl_dof->setValue(FALSE);
+
ctrl_deferred->setEnabled(FALSE);
ctrl_deferred->setValue(FALSE);
}
@@ -983,12 +1121,16 @@ void LLFloaterPreference::disableUnavailableSettings()
ctrl_ssao->setEnabled(FALSE);
ctrl_ssao->setValue(FALSE);
+ ctrl_dof->setEnabled(FALSE);
+ ctrl_dof->setValue(FALSE);
+
ctrl_deferred->setEnabled(FALSE);
ctrl_deferred->setValue(FALSE);
}
// disabled deferred
- if(!LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred"))
+ if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") ||
+ !gGLManager.mHasFramebufferObject)
{
ctrl_shadows->setEnabled(FALSE);
ctrl_shadows->setValue(0);
@@ -996,6 +1138,9 @@ void LLFloaterPreference::disableUnavailableSettings()
ctrl_ssao->setEnabled(FALSE);
ctrl_ssao->setValue(FALSE);
+ ctrl_dof->setEnabled(FALSE);
+ ctrl_dof->setValue(FALSE);
+
ctrl_deferred->setEnabled(FALSE);
ctrl_deferred->setValue(FALSE);
}
@@ -1037,6 +1182,9 @@ void LLFloaterPreference::disableUnavailableSettings()
ctrl_ssao->setEnabled(FALSE);
ctrl_ssao->setValue(FALSE);
+ ctrl_dof->setEnabled(FALSE);
+ ctrl_dof->setValue(FALSE);
+
ctrl_deferred->setEnabled(FALSE);
ctrl_deferred->setValue(FALSE);
}
@@ -1067,6 +1215,7 @@ void LLFloaterPreference::refresh()
updateSliderText(getChild<LLSliderCtrl>("FlexibleMeshDetail", true), getChild<LLTextBox>("FlexibleMeshDetailText", true));
updateSliderText(getChild<LLSliderCtrl>("TreeMeshDetail", true), getChild<LLTextBox>("TreeMeshDetailText", true));
updateSliderText(getChild<LLSliderCtrl>("AvatarMeshDetail", true), getChild<LLTextBox>("AvatarMeshDetailText", true));
+ updateSliderText(getChild<LLSliderCtrl>("AvatarPhysicsDetail", true), getChild<LLTextBox>("AvatarPhysicsDetailText", true));
updateSliderText(getChild<LLSliderCtrl>("TerrainMeshDetail", true), getChild<LLTextBox>("TerrainMeshDetailText", true));
updateSliderText(getChild<LLSliderCtrl>("RenderPostProcess", true), getChild<LLTextBox>("PostProcessText", true));
updateSliderText(getChild<LLSliderCtrl>("SkyMeshDetail", true), getChild<LLTextBox>("SkyMeshDetailText", true));
@@ -1155,7 +1304,7 @@ void LLFloaterPreference::onClickDisablePopup()
for (itor = items.begin(); itor != items.end(); ++itor)
{
LLNotificationTemplatePtr templatep = LLNotifications::instance().getTemplate(*(std::string*)((*itor)->getUserdata()));
- templatep->mForm->setIgnored(false);
+ templatep->mForm->setIgnored(true);
}
buildPopupLists();
@@ -1169,7 +1318,7 @@ void LLFloaterPreference::resetAllIgnored()
{
if (iter->second->mForm->getIgnoreType() != LLNotificationForm::IGNORE_NO)
{
- iter->second->mForm->setIgnored(true);
+ iter->second->mForm->setIgnored(false);
}
}
}
@@ -1182,7 +1331,7 @@ void LLFloaterPreference::setAllIgnored()
{
if (iter->second->mForm->getIgnoreType() != LLNotificationForm::IGNORE_NO)
{
- iter->second->mForm->setIgnored(false);
+ iter->second->mForm->setIgnored(true);
}
}
}
@@ -1221,6 +1370,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);
@@ -1241,12 +1392,13 @@ void LLFloaterPreference::setPersonalInfo(const std::string& visibility, bool im
// getChild<LLUICtrl>("busy_response")->setValue(gSavedSettings.getString("BusyModeResponse2"));
+ getChildView("favorites_on_login_check")->setEnabled(TRUE);
getChildView("log_nearby_chat")->setEnabled(TRUE);
getChildView("log_instant_messages")->setEnabled(TRUE);
getChildView("show_timestamps_check_im")->setEnabled(TRUE);
getChildView("log_path_string")->setEnabled(FALSE);// LineEditor becomes readonly in this case.
getChildView("log_path_button")->setEnabled(TRUE);
-
+ childEnable("logfile_name_datestamp");
std::string display_email(email);
getChild<LLUICtrl>("email_address")->setValue(display_email);
@@ -1318,6 +1470,68 @@ void LLFloaterPreference::onClickBlockList()
}
}
+void LLFloaterPreference::onDoubleClickCheckBox(LLUICtrl* ctrl)
+{
+ if (!ctrl) return;
+ mDoubleClickActionDirty = true;
+ LLRadioGroup* radio_double_click_action = getChild<LLRadioGroup>("double_click_action");
+ if (!radio_double_click_action) return;
+ // select default value("teleport") in radio-group.
+ radio_double_click_action->setSelectedIndex(0);
+ // set radio-group enabled depending on state of checkbox
+ radio_double_click_action->setEnabled(ctrl->getValue());
+}
+
+void LLFloaterPreference::onDoubleClickRadio()
+{
+ mDoubleClickActionDirty = true;
+}
+
+void LLFloaterPreference::updateDoubleClickSettings()
+{
+ LLCheckBoxCtrl* double_click_action_cb = getChild<LLCheckBoxCtrl>("double_click_chkbox");
+ if (!double_click_action_cb) return;
+ bool enable = double_click_action_cb->getValue().asBoolean();
+
+ LLRadioGroup* radio_double_click_action = getChild<LLRadioGroup>("double_click_action");
+ if (!radio_double_click_action) return;
+
+ // enable double click radio-group depending on state of checkbox
+ radio_double_click_action->setEnabled(enable);
+
+ if (!enable)
+ {
+ // set double click action settings values to false if checkbox was unchecked
+ gSavedSettings.setBOOL("DoubleClickAutoPilot", false);
+ gSavedSettings.setBOOL("DoubleClickTeleport", false);
+ }
+ else
+ {
+ std::string selected = radio_double_click_action->getValue().asString();
+ bool teleport_selected = selected == "radio_teleport";
+ // set double click action settings values depending on chosen radio-button
+ gSavedSettings.setBOOL( "DoubleClickTeleport", teleport_selected );
+ gSavedSettings.setBOOL( "DoubleClickAutoPilot", !teleport_selected );
+ }
+}
+
+void LLFloaterPreference::updateDoubleClickControls()
+{
+ // check is one of double-click actions settings enabled
+ bool double_click_action_enabled = gSavedSettings.getBOOL("DoubleClickAutoPilot") || gSavedSettings.getBOOL("DoubleClickTeleport");
+ LLCheckBoxCtrl* double_click_action_cb = getChild<LLCheckBoxCtrl>("double_click_chkbox");
+ if (double_click_action_cb)
+ {
+ // check checkbox if one of double-click actions settings enabled, uncheck otherwise
+ double_click_action_cb->setValue(double_click_action_enabled);
+ }
+ LLRadioGroup* double_click_action_radio = getChild<LLRadioGroup>("double_click_action");
+ if (!double_click_action_radio) return;
+ // set radio-group enabled if one of double-click actions settings enabled
+ double_click_action_radio->setEnabled(double_click_action_enabled);
+ // select button in radio-group depending on setting
+ double_click_action_radio->setSelectedIndex(gSavedSettings.getBOOL("DoubleClickAutoPilot"));
+}
void LLFloaterPreference::applyUIColor(LLUICtrl* ctrl, const LLSD& param)
{
@@ -1337,12 +1551,59 @@ void LLFloaterPreference::setCacheLocation(const LLStringExplicit& location)
cache_location_editor->setToolTip(location);
}
+//------------------------------Updater---------------------------------------
+
+static bool handleBandwidthChanged(const LLSD& newvalue)
+{
+ gViewerThrottle.setMaxBandwidth((F32) newvalue.asReal());
+ return true;
+}
+
+class LLPanelPreference::Updater : public LLEventTimer
+{
+
+public:
+
+ typedef boost::function<bool(const LLSD&)> callback_t;
+
+ Updater(callback_t cb, F32 period)
+ :LLEventTimer(period),
+ mCallback(cb)
+ {
+ mEventTimer.stop();
+ }
+
+ virtual ~Updater(){}
+
+ void update(const LLSD& new_value)
+ {
+ mNewValue = new_value;
+ mEventTimer.start();
+ }
+
+protected:
+
+ BOOL tick()
+ {
+ mCallback(mNewValue);
+ mEventTimer.stop();
+
+ return FALSE;
+ }
+
+private:
+
+ LLSD mNewValue;
+ callback_t mCallback;
+};
//----------------------------------------------------------------------------
static LLRegisterPanelClassWrapper<LLPanelPreference> t_places("panel_preference");
LLPanelPreference::LLPanelPreference()
-: LLPanel()
+: LLPanel(),
+ mBandWidthUpdater(NULL)
{
mCommitCallbackRegistrar.add("Pref.setControlFalse", boost::bind(&LLPanelPreference::setControlFalse,this, _2));
+ mCommitCallbackRegistrar.add("Pref.updateMediaAutoPlayCheckbox", boost::bind(&LLPanelPreference::updateMediaAutoPlayCheckbox, this, _1));
}
//virtual
@@ -1394,6 +1655,10 @@ BOOL LLPanelPreference::postBuild()
{
getChild<LLCheckBoxCtrl>("voice_call_friends_only_check")->setCommitCallback(boost::bind(&showFriendsOnlyWarning, _1, _2));
}
+ if (hasChild("favorites_on_login_check"))
+ {
+ getChild<LLCheckBoxCtrl>("favorites_on_login_check")->setCommitCallback(boost::bind(&showFavoritesOnLoginWarning, _1, _2));
+ }
// Panel Advanced
if (hasChild("modifier_combo"))
@@ -1405,10 +1670,24 @@ BOOL LLPanelPreference::postBuild()
}
}
+ //////////////////////PanelSetup ///////////////////
+ if (hasChild("max_bandwidth"))
+ {
+ mBandWidthUpdater = new LLPanelPreference::Updater(boost::bind(&handleBandwidthChanged, _1), BANDWIDTH_UPDATER_TIMEOUT);
+ gSavedSettings.getControl("ThrottleBandwidthKBPS")->getSignal()->connect(boost::bind(&LLPanelPreference::Updater::update, mBandWidthUpdater, _2));
+ }
+
apply();
return true;
}
+LLPanelPreference::~LLPanelPreference()
+{
+ if (mBandWidthUpdater)
+ {
+ delete mBandWidthUpdater;
+ }
+}
void LLPanelPreference::apply()
{
// no-op
@@ -1461,6 +1740,14 @@ void LLPanelPreference::showFriendsOnlyWarning(LLUICtrl* checkbox, const LLSD& v
}
}
+void LLPanelPreference::showFavoritesOnLoginWarning(LLUICtrl* checkbox, const LLSD& value)
+{
+ if (checkbox && checkbox->getValue())
+ {
+ LLNotificationsUtil::add("FavoritesOnLogin");
+ }
+}
+
void LLPanelPreference::cancel()
{
for (control_values_map_t::iterator iter = mSavedValues.begin();
@@ -1492,6 +1779,21 @@ void LLPanelPreference::setControlFalse(const LLSD& user_data)
control->set(LLSD(FALSE));
}
+void LLPanelPreference::updateMediaAutoPlayCheckbox(LLUICtrl* ctrl)
+{
+ std::string name = ctrl->getName();
+
+ // Disable "Allow Media to auto play" only when both
+ // "Streaming Music" and "Media" are unchecked. STORM-513.
+ if ((name == "enable_music") || (name == "enable_media"))
+ {
+ bool music_enabled = getChild<LLCheckBoxCtrl>("enable_music")->get();
+ bool media_enabled = getChild<LLCheckBoxCtrl>("enable_media")->get();
+
+ getChild<LLCheckBoxCtrl>("media_auto_play_btn")->setEnabled(music_enabled || media_enabled);
+ }
+}
+
static LLRegisterPanelClassWrapper<LLPanelPreferenceGraphics> t_pref_graph("panel_preference_graphics");
BOOL LLPanelPreferenceGraphics::postBuild()
@@ -1509,7 +1811,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 e99731b92e..5fe509fb37 100644
--- a/indra/newview/llfloaterpreference.h
+++ b/indra/newview/llfloaterpreference.h
@@ -34,6 +34,7 @@
#define LL_LLFLOATERPREFERENCE_H
#include "llfloater.h"
+#include "llavatarpropertiesprocessor.h"
class LLPanelPreference;
class LLPanelLCD;
@@ -55,7 +56,7 @@ typedef enum
// Floater to control preferences (display, audio, bandwidth, general.
-class LLFloaterPreference : public LLFloater
+class LLFloaterPreference : public LLFloater, public LLAvatarPropertiesObserver
{
public:
LLFloaterPreference(const LLSD& key);
@@ -77,12 +78,19 @@ public:
// translate user's busy response message according to current locale if message is default, otherwise do nothing
static void initBusyResponse();
+ void processProperties( void* pData, EAvatarProcessorType type );
+ void processProfileProperties(const LLAvatarData* pAvatarData );
+ void storeAvatarProperties( const LLAvatarData* pAvatarData );
+ void saveAvatarProperties( void );
+
protected:
void onBtnOK();
void onBtnCancel();
void onBtnApply();
void onClickBrowserClearCache();
+ void onLanguageChange();
+ void onNameTagOpacityChange(const LLSD& newvalue);
// set value of "BusyResponseChanged" in account settings depending on whether busy response
// string differs from default after user changes.
@@ -95,6 +103,14 @@ protected:
void setHardwareDefaults();
// callback for when client turns on shaders
void onVertexShaderEnable();
+ // callback for changing double click action checkbox
+ void onDoubleClickCheckBox(LLUICtrl* ctrl);
+ // callback for selecting double click action radio-button
+ void onDoubleClickRadio();
+ // updates double-click action settings depending on controls from preferences
+ void updateDoubleClickSettings();
+ // updates double-click action controls depending on values from settings.xml
+ void updateDoubleClickControls();
// This function squirrels away the current values of the controls so that
// cancel() can restore them.
@@ -145,11 +161,18 @@ public:
static void refreshSkin(void* data);
private:
static std::string sSkin;
+ // set true if state of double-click action checkbox or radio-group was changed by user
+ // (reset back to false on apply or cancel)
+ bool mDoubleClickActionDirty;
bool mGotPersonalInfo;
bool mOriginalIMViaEmail;
+ bool mLanguageChanged;
+ bool mAvatarDataInitialized;
bool mOriginalHideOnlineStatus;
std::string mDirectoryVisibility;
+
+ LLAvatarData mAvatarProperties;
};
class LLPanelPreference : public LLPanel
@@ -158,24 +181,35 @@ public:
LLPanelPreference();
/*virtual*/ BOOL postBuild();
+ virtual ~LLPanelPreference();
+
virtual void apply();
virtual void cancel();
void setControlFalse(const LLSD& user_data);
virtual void setHardwareDefaults(){};
+ // Disables "Allow Media to auto play" check box only when both
+ // "Streaming Music" and "Media" are unchecked. Otherwise enables it.
+ void updateMediaAutoPlayCheckbox(LLUICtrl* ctrl);
+
// This function squirrels away the current values of the controls so that
// cancel() can restore them.
virtual void saveSettings();
+ class Updater;
private:
//for "Only friends and groups can call or IM me"
static void showFriendsOnlyWarning(LLUICtrl*, const LLSD&);
+ //for "Show my Favorite Landmarks at Login"
+ static void showFavoritesOnLoginWarning(LLUICtrl* checkbox, const LLSD& value);
typedef std::map<LLControlVariable*, LLSD> control_values_map_t;
control_values_map_t mSavedValues;
typedef std::map<std::string, LLColor4> string_color_map_t;
string_color_map_t mSavedColors;
+
+ Updater* mBandWidthUpdater;
};
class LLPanelPreferenceGraphics : public LLPanelPreference
diff --git a/indra/newview/llfloaterregiondebugconsole.cpp b/indra/newview/llfloaterregiondebugconsole.cpp
new file mode 100644
index 0000000000..c7fab2573f
--- /dev/null
+++ b/indra/newview/llfloaterregiondebugconsole.cpp
@@ -0,0 +1,224 @@
+/**
+ * @file llfloaterregiondebugconsole.h
+ * @author Brad Kittenbrink <brad@lindenlab.com>
+ * @brief Quick and dirty console for region debug settings
+ *
+ * $LicenseInfo:firstyear=2010&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 "llfloaterregiondebugconsole.h"
+
+#include "llagent.h"
+#include "llhttpclient.h"
+#include "llhttpnode.h"
+#include "lllineeditor.h"
+#include "lltexteditor.h"
+#include "llviewerregion.h"
+
+// Two versions of the sim console API are supported.
+//
+// SimConsole capability (deprecated):
+// This is the initial implementation that is supported by some versions of the
+// simulator. It is simple and straight forward, just POST a command and the
+// body of the response has the result. This API is deprecated because it
+// doesn't allow the sim to use any asynchronous API.
+//
+// SimConsoleAsync capability:
+// This capability replaces the original SimConsole capability. It is similar
+// in that the command is POSTed to the SimConsoleAsync cap, but the response
+// comes in through the event poll, which gives the simulator more flexibility
+// and allows it to perform complex operations without blocking any frames.
+//
+// We will assume the SimConsoleAsync capability is available, and fall back to
+// the SimConsole cap if it is not. The simulator will only support one or the
+// other.
+
+namespace
+{
+ // Signal used to notify the floater of responses from the asynchronous
+ // API.
+ console_reply_signal_t sConsoleReplySignal;
+
+ const std::string PROMPT("\n\n> ");
+ const std::string UNABLE_TO_SEND_COMMAND(
+ "ERROR: The last command was not received by the server.");
+ const std::string CONSOLE_UNAVAILABLE(
+ "ERROR: No console available for this region/simulator.");
+ const std::string CONSOLE_NOT_SUPPORTED(
+ "This region does not support the simulator console.");
+
+ // This responder handles the initial response. Unless error() is called
+ // we assume that the simulator has received our request. Error will be
+ // called if this request times out.
+ class AsyncConsoleResponder : public LLHTTPClient::Responder
+ {
+ public:
+ /* virtual */
+ void error(U32 status, const std::string& reason)
+ {
+ sConsoleReplySignal(UNABLE_TO_SEND_COMMAND);
+ }
+ };
+
+ class ConsoleResponder : public LLHTTPClient::Responder
+ {
+ public:
+ ConsoleResponder(LLTextEditor *output) : mOutput(output)
+ {
+ }
+
+ /*virtual*/
+ void error(U32 status, const std::string& reason)
+ {
+ if (mOutput)
+ {
+ mOutput->appendText(
+ UNABLE_TO_SEND_COMMAND + PROMPT,
+ false);
+ }
+ }
+
+ /*virtual*/
+ void result(const LLSD& content)
+ {
+ if (mOutput)
+ {
+ mOutput->appendText(
+ content.asString() + PROMPT, false);
+ }
+ }
+
+ LLTextEditor * mOutput;
+ };
+
+ // This handles responses for console commands sent via the asynchronous
+ // API.
+ class ConsoleResponseNode : public LLHTTPNode
+ {
+ public:
+ /* virtual */
+ void post(
+ LLHTTPNode::ResponsePtr reponse,
+ const LLSD& context,
+ const LLSD& input) const
+ {
+ llinfos << "Received response from the debug console: "
+ << input << llendl;
+ sConsoleReplySignal(input["body"].asString());
+ }
+ };
+}
+
+boost::signals2::connection LLFloaterRegionDebugConsole::setConsoleReplyCallback(const console_reply_signal_t::slot_type& cb)
+{
+ return sConsoleReplySignal.connect(cb);
+}
+
+LLFloaterRegionDebugConsole::LLFloaterRegionDebugConsole(LLSD const & key)
+: LLFloater(key), mOutput(NULL)
+{
+ mReplySignalConnection = sConsoleReplySignal.connect(
+ boost::bind(
+ &LLFloaterRegionDebugConsole::onReplyReceived,
+ this,
+ _1));
+}
+
+LLFloaterRegionDebugConsole::~LLFloaterRegionDebugConsole()
+{
+ mReplySignalConnection.disconnect();
+}
+
+BOOL LLFloaterRegionDebugConsole::postBuild()
+{
+ LLLineEditor* input = getChild<LLLineEditor>("region_debug_console_input");
+ input->setEnableLineHistory(true);
+ input->setCommitCallback(boost::bind(&LLFloaterRegionDebugConsole::onInput, this, _1, _2));
+ input->setFocus(true);
+ input->setCommitOnFocusLost(false);
+
+ mOutput = getChild<LLTextEditor>("region_debug_console_output");
+
+ std::string url = gAgent.getRegion()->getCapability("SimConsoleAsync");
+ if (url.empty())
+ {
+ // Fall back to see if the old API is supported.
+ url = gAgent.getRegion()->getCapability("SimConsole");
+ if (url.empty())
+ {
+ mOutput->appendText(
+ CONSOLE_NOT_SUPPORTED + PROMPT,
+ false);
+ return TRUE;
+ }
+ }
+
+ mOutput->appendText("> ", false);
+ return TRUE;
+}
+
+void LLFloaterRegionDebugConsole::onInput(LLUICtrl* ctrl, const LLSD& param)
+{
+ LLLineEditor* input = static_cast<LLLineEditor*>(ctrl);
+ std::string text = input->getText() + "\n";
+
+ std::string url = gAgent.getRegion()->getCapability("SimConsoleAsync");
+ if (url.empty())
+ {
+ // Fall back to the old API
+ url = gAgent.getRegion()->getCapability("SimConsole");
+ if (url.empty())
+ {
+ text += CONSOLE_UNAVAILABLE + PROMPT;
+ }
+ else
+ {
+ // Using SimConsole (deprecated)
+ LLHTTPClient::post(
+ url,
+ LLSD(input->getText()),
+ new ConsoleResponder(mOutput));
+ }
+ }
+ else
+ {
+ // Using SimConsoleAsync
+ LLHTTPClient::post(
+ url,
+ LLSD(input->getText()),
+ new AsyncConsoleResponder);
+ }
+
+ mOutput->appendText(text, false);
+ input->clear();
+}
+
+void LLFloaterRegionDebugConsole::onReplyReceived(const std::string& output)
+{
+ mOutput->appendText(output + PROMPT, false);
+}
+
+LLHTTPRegistration<ConsoleResponseNode>
+ gHTTPRegistrationMessageDebugConsoleResponse(
+ "/message/SimConsoleResponse");
diff --git a/indra/newview/llfloaterregiondebugconsole.h b/indra/newview/llfloaterregiondebugconsole.h
new file mode 100644
index 0000000000..fd3af4152e
--- /dev/null
+++ b/indra/newview/llfloaterregiondebugconsole.h
@@ -0,0 +1,62 @@
+/**
+ * @file llfloaterregiondebugconsole.h
+ * @author Brad Kittenbrink <brad@lindenlab.com>
+ * @brief Quick and dirty console for region debug settings
+ *
+ * $LicenseInfo:firstyear=2010&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_LLFLOATERREGIONDEBUGCONSOLE_H
+#define LL_LLFLOATERREGIONDEBUGCONSOLE_H
+
+#include <boost/signals2.hpp>
+
+#include "llfloater.h"
+#include "llhttpclient.h"
+
+class LLTextEditor;
+
+typedef boost::signals2::signal<
+ void (const std::string& output)> console_reply_signal_t;
+
+class LLFloaterRegionDebugConsole : public LLFloater, public LLHTTPClient::Responder
+{
+public:
+ LLFloaterRegionDebugConsole(LLSD const & key);
+ virtual ~LLFloaterRegionDebugConsole();
+
+ // virtual
+ BOOL postBuild();
+
+ void onInput(LLUICtrl* ctrl, const LLSD& param);
+
+ LLTextEditor * mOutput;
+
+ static boost::signals2::connection setConsoleReplyCallback(const console_reply_signal_t::slot_type& cb);
+
+ private:
+ void onReplyReceived(const std::string& output);
+
+ boost::signals2::connection mReplySignalConnection;
+};
+
+#endif // LL_LLFLOATERREGIONDEBUGCONSOLE_H
diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp
index 7792b3fb40..34fda49375 100644
--- a/indra/newview/llfloaterregioninfo.cpp
+++ b/indra/newview/llfloaterregioninfo.cpp
@@ -53,6 +53,7 @@
#include "llfloatertopobjects.h" // added to fix SL-32336
#include "llfloatergroups.h"
#include "llfloaterreg.h"
+#include "llfloaterregiondebugconsole.h"
#include "llfloatertelehub.h"
#include "llfloaterwindlight.h"
#include "llinventorymodel.h"
@@ -159,9 +160,30 @@ bool estate_dispatch_initialized = false;
//S32 LLFloaterRegionInfo::sRequestSerial = 0;
LLUUID LLFloaterRegionInfo::sRequestInvoice;
+
+void LLFloaterRegionInfo::onConsoleReplyReceived(const std::string& output)
+{
+ llwarns << "here is what they're giving us: " << output << llendl;
+
+ if (output.find("FALSE") != std::string::npos)
+ {
+ getChild<LLUICtrl>("mesh_rez_enabled_check")->setValue(FALSE);
+ }
+ else
+ {
+ getChild<LLUICtrl>("mesh_rez_enabled_check")->setValue(TRUE);
+ }
+}
+
+
LLFloaterRegionInfo::LLFloaterRegionInfo(const LLSD& seed)
: LLFloater(seed)
{
+ mConsoleReplySignalConnection = LLFloaterRegionDebugConsole::setConsoleReplyCallback(
+ boost::bind(
+ &LLFloaterRegionInfo::onConsoleReplyReceived,
+ this,
+ _1));
}
BOOL LLFloaterRegionInfo::postBuild()
@@ -211,12 +233,14 @@ BOOL LLFloaterRegionInfo::postBuild()
LLFloaterRegionInfo::~LLFloaterRegionInfo()
{
+ mConsoleReplySignalConnection.disconnect();
}
void LLFloaterRegionInfo::onOpen(const LLSD& key)
{
refreshFromRegion(gAgent.getRegion());
requestRegionInfo();
+ requestMeshRezInfo();
}
// static
@@ -584,6 +608,7 @@ BOOL LLPanelRegionGeneralInfo::postBuild()
initCtrl("access_combo");
initCtrl("restrict_pushobject");
initCtrl("block_parcel_search_check");
+ initCtrl("mesh_rez_enabled_check");
childSetAction("kick_btn", boost::bind(&LLPanelRegionGeneralInfo::onClickKick, this));
childSetAction("kick_all_btn", onClickKickAll, this);
@@ -691,7 +716,42 @@ bool LLPanelRegionGeneralInfo::onMessageCommit(const LLSD& notification, const L
return false;
}
+class ConsoleRequestResponder : public LLHTTPClient::Responder
+{
+public:
+ /*virtual*/
+ void error(U32 status, const std::string& reason)
+ {
+ llwarns << "requesting mesh_rez_enabled failed" << llendl;
+ }
+};
+
+
+// called if this request times out.
+class ConsoleUpdateResponder : public LLHTTPClient::Responder
+{
+public:
+ /* virtual */
+ void error(U32 status, const std::string& reason)
+ {
+ llwarns << "Updating mesh enabled region setting failed" << llendl;
+ }
+};
+
+void LLFloaterRegionInfo::requestMeshRezInfo()
+{
+ std::string sim_console_url = gAgent.getRegion()->getCapability("SimConsoleAsync");
+ if (!sim_console_url.empty())
+ {
+ std::string request_str = "get mesh_rez_enabled";
+
+ LLHTTPClient::post(
+ sim_console_url,
+ LLSD(request_str),
+ new ConsoleRequestResponder);
+ }
+}
// setregioninfo
// strings[0] = 'Y' - block terraform, 'N' - not
@@ -764,6 +824,27 @@ BOOL LLPanelRegionGeneralInfo::sendUpdate()
sendEstateOwnerMessage(gMessageSystem, "setregioninfo", invoice, strings);
}
+ std::string sim_console_url = gAgent.getRegion()->getCapability("SimConsoleAsync");
+
+ if (!sim_console_url.empty())
+ {
+ std::string update_str = "set mesh_rez_enabled ";
+ if (getChild<LLUICtrl>("mesh_rez_enabled_check")->getValue().asBoolean())
+ {
+ update_str += "true";
+ }
+ else
+ {
+ update_str += "false";
+ }
+
+ LLHTTPClient::post(
+ sim_console_url,
+ LLSD(update_str),
+ new ConsoleUpdateResponder);
+ }
+
+
// if we changed access levels, tell user about it
LLViewerRegion* region = gAgent.getRegion();
if (region && (getChild<LLUICtrl>("access_combo")->getValue().asInteger() != region->getSimAccess()) )
diff --git a/indra/newview/llfloaterregioninfo.h b/indra/newview/llfloaterregioninfo.h
index c0758fa92d..2b87c27fcf 100644
--- a/indra/newview/llfloaterregioninfo.h
+++ b/indra/newview/llfloaterregioninfo.h
@@ -84,11 +84,16 @@ public:
virtual void refresh();
void requestRegionInfo();
+ void requestMeshRezInfo();
private:
LLFloaterRegionInfo(const LLSD& seed);
~LLFloaterRegionInfo();
+
+ void onConsoleReplyReceived(const std::string& output);
+
+ boost::signals2::connection mConsoleReplySignalConnection;;
protected:
void refreshFromRegion(LLViewerRegion* region);
diff --git a/indra/newview/llfloatersearch.cpp b/indra/newview/llfloatersearch.cpp
index 3ed4aec89a..d5806e375c 100644
--- a/indra/newview/llfloatersearch.cpp
+++ b/indra/newview/llfloatersearch.cpp
@@ -31,6 +31,7 @@
#include "llfloaterreg.h"
#include "llfloatersearch.h"
#include "llmediactrl.h"
+#include "llnotificationsutil.h"
#include "lllogininstance.h"
#include "lluri.h"
#include "llagent.h"
@@ -46,6 +47,12 @@ public:
LLSearchHandler() : LLCommandHandler("search", UNTRUSTED_THROTTLE) { }
bool handle(const LLSD& tokens, const LLSD& query_map, LLMediaCtrl* web)
{
+ if (!LLUI::sSettingGroups["config"]->getBOOL("EnableSearch"))
+ {
+ LLNotificationsUtil::add("NoSearch", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit"));
+ return true;
+ }
+
const size_t parts = tokens.size();
// get the (optional) category for the search
@@ -200,5 +207,5 @@ void LLFloaterSearch::search(const LLSD &key)
url = LLWeb::expandURLSubstitutions(url, subs);
// and load the URL in the web view
- mBrowser->navigateTo(url);
+ mBrowser->navigateTo(url, "text/html");
}
diff --git a/indra/newview/llfloatersettingsdebug.cpp b/indra/newview/llfloatersettingsdebug.cpp
index 71882fbb83..07f5220ab7 100644
--- a/indra/newview/llfloatersettingsdebug.cpp
+++ b/indra/newview/llfloatersettingsdebug.cpp
@@ -178,7 +178,7 @@ void LLFloaterSettingsDebug::onClickDefault()
if (controlp)
{
- controlp->resetToDefault();
+ controlp->resetToDefault(true);
updateControl(controlp);
}
}
diff --git a/indra/newview/llfloatersidetraytab.cpp b/indra/newview/llfloatersidetraytab.cpp
index f13b4db3a0..9f15e62d84 100644
--- a/indra/newview/llfloatersidetraytab.cpp
+++ b/indra/newview/llfloatersidetraytab.cpp
@@ -30,6 +30,7 @@
// newview includes
#include "lltransientfloatermgr.h"
+#include "llsidetray.h"
LLFloaterSideTrayTab::LLFloaterSideTrayTab(const LLSD& key, const Params& params)
: LLFloater(key, params)
@@ -43,3 +44,9 @@ LLFloaterSideTrayTab::~LLFloaterSideTrayTab()
{
LLTransientFloaterMgr::getInstance()->removeControlView(LLTransientFloaterMgr::GLOBAL, this);
}
+
+void LLFloaterSideTrayTab::onClose(bool app_quitting)
+{
+ // The floater is already being closed, so don't toggle it once more (that may crash viewer).
+ LLSideTray::getInstance()->setTabDocked(getName(), /* dock = */ true, /* toggle_floater = */ false);
+}
diff --git a/indra/newview/llfloatersidetraytab.h b/indra/newview/llfloatersidetraytab.h
index e47f82e8ba..89f2444a0e 100644
--- a/indra/newview/llfloatersidetraytab.h
+++ b/indra/newview/llfloatersidetraytab.h
@@ -42,6 +42,8 @@ class LLFloaterSideTrayTab : public LLFloater
public:
LLFloaterSideTrayTab(const LLSD& key, const Params& params = getDefaultParams());
~LLFloaterSideTrayTab();
+
+ void onClose(bool app_quitting);
};
#endif // LL_LLFLOATERSIDETRAYTAB_H
diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp
index 36e8ad9dfc..00dc7b1627 100644
--- a/indra/newview/llfloatersnapshot.cpp
+++ b/indra/newview/llfloatersnapshot.cpp
@@ -53,6 +53,7 @@
#include "llfloaterpostcard.h"
#include "llcheckboxctrl.h"
#include "llradiogroup.h"
+#include "llslurl.h"
#include "lltoolfocus.h"
#include "lltoolmgr.h"
#include "llwebsharing.h"
@@ -1212,8 +1213,6 @@ LLViewerWindow::ESnapshotType LLFloaterSnapshot::Impl::getLayerType(LLFloaterSna
type = LLViewerWindow::SNAPSHOT_TYPE_COLOR;
else if (id == "depth")
type = LLViewerWindow::SNAPSHOT_TYPE_DEPTH;
- else if (id == "objects")
- type = LLViewerWindow::SNAPSHOT_TYPE_OBJECT_ID;
return type;
}
@@ -1365,6 +1364,36 @@ void LLFloaterSnapshot::Impl::updateControls(LLFloaterSnapshot* floater)
floater->getChildView("auto_snapshot_check")->setVisible( is_advance);
floater->getChildView("image_quality_slider")->setVisible( is_advance && show_slider);
+ if (gSavedSettings.getBOOL("RenderUIInSnapshot") || gSavedSettings.getBOOL("RenderHUDInSnapshot"))
+ { //clamp snapshot resolution to window size when showing UI or HUD in snapshot
+
+ LLSpinCtrl* width_ctrl = floater->getChild<LLSpinCtrl>("snapshot_width");
+ LLSpinCtrl* height_ctrl = floater->getChild<LLSpinCtrl>("snapshot_height");
+
+ S32 width = gViewerWindow->getWindowWidthRaw();
+ S32 height = gViewerWindow->getWindowHeightRaw();
+
+ width_ctrl->setMaxValue(width);
+
+ height_ctrl->setMaxValue(height);
+
+ if (width_ctrl->getValue().asInteger() > width)
+ {
+ width_ctrl->forceSetValue(width);
+ }
+ if (height_ctrl->getValue().asInteger() > height)
+ {
+ height_ctrl->forceSetValue(height);
+ }
+ }
+ else
+ {
+ LLSpinCtrl* width = floater->getChild<LLSpinCtrl>("snapshot_width");
+ width->setMaxValue(6016);
+ LLSpinCtrl* height = floater->getChild<LLSpinCtrl>("snapshot_height");
+ height->setMaxValue(6016);
+ }
+
LLSnapshotLivePreview* previewp = getPreviewView(floater);
BOOL got_bytes = previewp && previewp->getDataSize() > 0;
BOOL got_snap = previewp && previewp->getSnapshotUpToDate();
@@ -1812,6 +1841,13 @@ void LLFloaterSnapshot::Impl::updateResolution(LLUICtrl* ctrl, void* data, BOOL
previewp->getSize(width, height);
+ if (gSavedSettings.getBOOL("RenderUIInSnapshot") || gSavedSettings.getBOOL("RenderHUDInSnapshot"))
+ { //clamp snapshot resolution to window size when showing UI or HUD in snapshot
+ width = llmin(width, gViewerWindow->getWindowWidthRaw());
+ height = llmin(height, gViewerWindow->getWindowHeightRaw());
+ }
+
+
if(checkImageSize(previewp, width, height, TRUE, previewp->getMaxImageSize()))
{
resetSnapshotSizeOnUI(view, width, height) ;
@@ -2191,9 +2227,11 @@ void LLFloaterSnapshot::draw()
S32 offset_y = thumbnail_rect.mBottom + (thumbnail_rect.getHeight() - previewp->getThumbnailHeight()) / 2 ;
glMatrixMode(GL_MODELVIEW);
+ // Apply floater transparency to the texture unless the floater is focused.
+ F32 alpha = getTransparencyType() == TT_ACTIVE ? 1.0f : getCurrentTransparency();
gl_draw_scaled_image(offset_x, offset_y,
previewp->getThumbnailWidth(), previewp->getThumbnailHeight(),
- previewp->getThumbnailImage(), LLColor4::white);
+ previewp->getThumbnailImage(), LLColor4::white % alpha);
previewp->drawPreviewRect(offset_x, offset_y) ;
}
diff --git a/indra/newview/llfloatersounddevices.cpp b/indra/newview/llfloatersounddevices.cpp
new file mode 100644
index 0000000000..9fe7c7f9dd
--- /dev/null
+++ b/indra/newview/llfloatersounddevices.cpp
@@ -0,0 +1,90 @@
+/**
+ * @file llfloatersounddevices.cpp
+ * @author Leyla Farazha
+ * @brief Sound Preferences used for minimal skin
+ *
+* $LicenseInfo:firstyear=2011&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 "llfloatersounddevices.h"
+
+#include "llbottomtray.h"
+#include "lldraghandle.h"
+
+#include "llpanelvoicedevicesettings.h"
+
+// Library includes
+#include "indra_constants.h"
+
+// protected
+LLFloaterSoundDevices::LLFloaterSoundDevices(const LLSD& key)
+: LLTransientDockableFloater(NULL, false, key)
+{
+ LLTransientFloaterMgr::getInstance()->addControlView(this);
+
+ // force docked state since this floater doesn't save it between recreations
+ setDocked(true);
+}
+
+LLFloaterSoundDevices::~LLFloaterSoundDevices()
+{
+ LLTransientFloaterMgr::getInstance()->removeControlView(this);
+}
+
+// virtual
+BOOL LLFloaterSoundDevices::postBuild()
+{
+ LLTransientDockableFloater::postBuild();
+
+ LLView *anchor_panel = LLBottomTray::getInstance()->getChild<LLView>("flyout_btn");
+ setDockControl(new LLDockControl(anchor_panel, this, getDockTongue(), LLDockControl::TOP));
+
+ setIsChrome(TRUE);
+ if (mDragHandle)
+ mDragHandle->setTitleVisible(TRUE);
+ updateTransparency(TT_ACTIVE); // force using active floater transparency (STORM-730)
+
+ LLPanelVoiceDeviceSettings* panel = findChild<LLPanelVoiceDeviceSettings>("device_settings_panel");
+ if (panel)
+ {
+ panel->setUseTuningMode(false);
+ }
+ return TRUE;
+}
+
+//virtual
+void LLFloaterSoundDevices::setDocked(bool docked, bool pop_on_undock/* = true*/)
+{
+ LLTransientDockableFloater::setDocked(docked, pop_on_undock);
+}
+
+// virtual
+void LLFloaterSoundDevices::setFocus( BOOL b )
+{
+ LLTransientDockableFloater::setFocus(b);
+
+ // Force using active floater transparency
+ // We have to override setFocus() for because selecting an item of the
+ // combobox causes the floater to lose focus and thus become transparent.
+ updateTransparency(TT_ACTIVE);
+}
diff --git a/indra/newview/llfloatersounddevices.h b/indra/newview/llfloatersounddevices.h
new file mode 100644
index 0000000000..f09ee3b069
--- /dev/null
+++ b/indra/newview/llfloatersounddevices.h
@@ -0,0 +1,49 @@
+/**
+ * @file llfloatersounddevices.h
+ * @author Leyla Farazha
+ * @brief Sound Preferences used for minimal skin
+ *
+* $LicenseInfo:firstyear=2011&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_LLFLOATERSOUNDDEVICES_H
+#define LL_LLFLOATERSOUNDDEVICES_H
+
+#include "lltransientdockablefloater.h"
+
+class LLFloaterSoundDevices : public LLTransientDockableFloater
+{
+public:
+
+ LOG_CLASS(LLFloaterSoundDevices);
+
+ LLFloaterSoundDevices(const LLSD& key);
+ ~LLFloaterSoundDevices();
+
+ /*virtual*/ BOOL postBuild();
+ /*virtual*/ void setDocked(bool docked, bool pop_on_undock = true);
+ /*virtual*/ void setFocus( BOOL b );
+};
+
+
+#endif //LL_LLFLOATERSOUNDDEVICES_H
+
diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp
index 370bf05bf7..73c1f99fa0 100644
--- a/indra/newview/llfloatertools.cpp
+++ b/indra/newview/llfloatertools.cpp
@@ -32,6 +32,7 @@
#include "llcoord.h"
//#include "llgl.h"
+#include "llagent.h"
#include "llagentcamera.h"
#include "llbutton.h"
#include "llcheckboxctrl.h"
@@ -220,6 +221,8 @@ BOOL LLFloaterTools::postBuild()
mRadioGroupEdit = getChild<LLRadioGroup>("edit_radio_group");
mBtnGridOptions = getChild<LLButton>("Options...");
mTitleMedia = getChild<LLMediaCtrl>("title_media");
+ mBtnLink = getChild<LLButton>("link_btn");
+ mBtnUnlink = getChild<LLButton>("unlink_btn");
mCheckSelectIndividual = getChild<LLCheckBoxCtrl>("checkbox edit linked parts");
getChild<LLUICtrl>("checkbox edit linked parts")->setValue((BOOL)gSavedSettings.getBOOL("EditLinkedParts"));
@@ -315,6 +318,9 @@ LLFloaterTools::LLFloaterTools(const LLSD& key)
mBtnRotateReset(NULL),
mBtnRotateRight(NULL),
+ mBtnLink(NULL),
+ mBtnUnlink(NULL),
+
mBtnDelete(NULL),
mBtnDuplicate(NULL),
mBtnDuplicateInPlace(NULL),
@@ -341,7 +347,7 @@ LLFloaterTools::LLFloaterTools(const LLSD& key)
mNeedMediaTitle(TRUE)
{
gFloaterTools = this;
-
+
setAutoFocus(FALSE);
mFactoryMap["General"] = LLCallbackMap(createPanelPermissions, this);//LLPanelPermissions
mFactoryMap["Object"] = LLCallbackMap(createPanelObject, this);//LLPanelObject
@@ -366,6 +372,9 @@ LLFloaterTools::LLFloaterTools(const LLSD& key)
mCommitCallbackRegistrar.add("BuildTool.DeleteMedia", boost::bind(&LLFloaterTools::onClickBtnDeleteMedia,this));
mCommitCallbackRegistrar.add("BuildTool.EditMedia", boost::bind(&LLFloaterTools::onClickBtnEditMedia,this));
+ mCommitCallbackRegistrar.add("BuildTool.LinkObjects", boost::bind(&LLSelectMgr::linkObjects, LLSelectMgr::getInstance()));
+ mCommitCallbackRegistrar.add("BuildTool.UnlinkObjects", boost::bind(&LLSelectMgr::unlinkObjects, LLSelectMgr::getInstance()));
+
}
LLFloaterTools::~LLFloaterTools()
@@ -412,27 +421,83 @@ void LLFloaterTools::refresh()
// Refresh object and prim count labels
LLLocale locale(LLLocale::USER_LOCALE);
- std::string obj_count_string;
- LLResMgr::getInstance()->getIntegerString(obj_count_string, LLSelectMgr::getInstance()->getSelection()->getRootObjectCount());
- getChild<LLUICtrl>("obj_count")->setTextArg("[COUNT]", obj_count_string);
- std::string prim_count_string;
- LLResMgr::getInstance()->getIntegerString(prim_count_string, LLSelectMgr::getInstance()->getSelection()->getObjectCount());
- getChild<LLUICtrl>("prim_count")->setTextArg("[COUNT]", prim_count_string);
-
- // calculate selection rendering cost
- if (sShowObjectCost)
- {
- std::string prim_cost_string;
- LLResMgr::getInstance()->getIntegerString(prim_cost_string, calcRenderCost());
- getChild<LLUICtrl>("RenderingCost")->setTextArg("[COUNT]", prim_cost_string);
+
+ if ((gAgent.getRegion() && gAgent.getRegion()->getCapability("GetMesh").empty()) || !gSavedSettings.getBOOL("MeshEnabled"))
+ {
+ std::string obj_count_string;
+ LLResMgr::getInstance()->getIntegerString(obj_count_string, LLSelectMgr::getInstance()->getSelection()->getRootObjectCount());
+ getChild<LLUICtrl>("obj_count")->setTextArg("[COUNT]", obj_count_string);
+ std::string prim_count_string;
+ LLResMgr::getInstance()->getIntegerString(prim_count_string, LLSelectMgr::getInstance()->getSelection()->getObjectCount());
+ getChild<LLUICtrl>("prim_count")->setTextArg("[COUNT]", prim_count_string);
+
+ // calculate selection rendering cost
+ if (sShowObjectCost)
+ {
+ std::string prim_cost_string;
+ LLResMgr::getInstance()->getIntegerString(prim_cost_string, calcRenderCost());
+ getChild<LLUICtrl>("RenderingCost")->setTextArg("[COUNT]", prim_cost_string);
+ }
+
+ // disable the object and prim counts if nothing selected
+ bool have_selection = ! LLSelectMgr::getInstance()->getSelection()->isEmpty();
+ getChildView("obj_count")->setEnabled(have_selection);
+ getChildView("prim_count")->setEnabled(have_selection);
+ getChildView("RenderingCost")->setEnabled(have_selection && sShowObjectCost);
}
+ else
+ {
+ // Get the number of objects selected
+ std::string root_object_count_string;
+ std::string object_count_string;
+
+ LLResMgr::getInstance()->getIntegerString(
+ root_object_count_string,
+ LLSelectMgr::getInstance()->getSelection()->getRootObjectCount());
+ LLResMgr::getInstance()->getIntegerString(
+ object_count_string,
+ LLSelectMgr::getInstance()->getSelection()->getObjectCount());
+
+ F32 obj_cost =
+ LLSelectMgr::getInstance()->getSelection()->getSelectedObjectCost();
+ F32 link_cost =
+ LLSelectMgr::getInstance()->getSelection()->getSelectedLinksetCost();
+ F32 obj_physics_cost =
+ LLSelectMgr::getInstance()->getSelection()->getSelectedPhysicsCost();
+ F32 link_physics_cost =
+ LLSelectMgr::getInstance()->getSelection()->getSelectedLinksetPhysicsCost();
+
+ // Update the text for the counts
+ childSetTextArg(
+ "linked_set_count",
+ "[COUNT]",
+ root_object_count_string);
+ childSetTextArg("object_count", "[COUNT]", object_count_string);
+
+ // Update the text for the resource costs
+ childSetTextArg("linked_set_cost","[COST]",llformat("%.1f", link_cost));
+ childSetTextArg("object_cost", "[COST]", llformat("%.1f", obj_cost));
+ childSetTextArg("linked_set_cost","[PHYSICS]",llformat("%.1f", link_physics_cost));
+ childSetTextArg("object_cost", "[PHYSICS]", llformat("%.1f", obj_physics_cost));
+
+ // Display rendering cost if needed
+ if (sShowObjectCost)
+ {
+ std::string prim_cost_string;
+ LLResMgr::getInstance()->getIntegerString(prim_cost_string, calcRenderCost());
+ getChild<LLUICtrl>("RenderingCost")->setTextArg("[COUNT]", prim_cost_string);
+ }
+
+ // disable the object and prim counts if nothing selected
+ bool have_selection = ! LLSelectMgr::getInstance()->getSelection()->isEmpty();
+ childSetEnabled("linked_set_count", have_selection);
+ childSetEnabled("object_count", have_selection);
+ childSetEnabled("linked_set_cost", have_selection);
+ childSetEnabled("object_cost", have_selection);
+ getChildView("RenderingCost")->setEnabled(have_selection && sShowObjectCost);
+ }
- // disable the object and prim counts if nothing selected
- bool have_selection = ! LLSelectMgr::getInstance()->getSelection()->isEmpty();
- getChildView("obj_count")->setEnabled(have_selection);
- getChildView("prim_count")->setEnabled(have_selection);
- getChildView("RenderingCost")->setEnabled(have_selection && sShowObjectCost);
// Refresh child tabs
mPanelPermissions->refresh();
@@ -566,6 +631,12 @@ void LLFloaterTools::updatePopup(LLCoordGL center, MASK mask)
bool linked_parts = gSavedSettings.getBOOL("EditLinkedParts");
getChildView("RenderingCost")->setVisible( !linked_parts && (edit_visible || focus_visible || move_visible) && sShowObjectCost);
+ mBtnLink->setVisible(edit_visible);
+ mBtnUnlink->setVisible(edit_visible);
+
+ mBtnLink->setEnabled(LLSelectMgr::instance().enableLinkObjects());
+ mBtnUnlink->setEnabled(LLSelectMgr::instance().enableUnlinkObjects());
+
if (mCheckSelectIndividual)
{
mCheckSelectIndividual->setVisible(edit_visible);
@@ -716,8 +787,18 @@ void LLFloaterTools::updatePopup(LLCoordGL center, MASK mask)
getChildView("Strength:")->setVisible( land_visible);
}
- getChildView("obj_count")->setVisible( !land_visible);
- getChildView("prim_count")->setVisible( !land_visible);
+ bool show_mesh_cost = gAgent.getRegion() &&
+ !gAgent.getRegion()->getCapability("GetMesh").empty() &&
+ gSavedSettings.getBOOL("MeshEnabled");
+
+ getChildView("obj_count")->setVisible( !land_visible && !show_mesh_cost);
+ getChildView("prim_count")->setVisible( !land_visible && !show_mesh_cost);
+ getChildView("linked_set_count")->setVisible( !land_visible && show_mesh_cost);
+ getChildView("linked_set_cost")->setVisible( !land_visible && show_mesh_cost);
+ getChildView("object_count")->setVisible( !land_visible && show_mesh_cost);
+ getChildView("object_cost")->setVisible( !land_visible && show_mesh_cost);
+ getChildView("RenderingCost")->setVisible( !land_visible && sShowObjectCost);
+
mTab->setVisible(!land_visible);
mPanelLandInfo->setVisible(land_visible);
}
@@ -974,30 +1055,33 @@ void LLFloaterTools::onClickGridOptions()
S32 LLFloaterTools::calcRenderCost()
{
- S32 cost = 0;
- std::set<LLUUID> textures;
-
- for (LLObjectSelection::iterator selection_iter = LLSelectMgr::getInstance()->getSelection()->begin();
- selection_iter != LLSelectMgr::getInstance()->getSelection()->end();
- ++selection_iter)
- {
- LLSelectNode *select_node = *selection_iter;
- if (select_node)
- {
- LLVOVolume *viewer_volume = (LLVOVolume*)select_node->getObject();
- if (viewer_volume)
- {
- cost += viewer_volume->getRenderCost(textures);
- cost += textures.size() * LLVOVolume::ARC_TEXTURE_COST;
- textures.clear();
- }
- }
- }
-
-
- return cost;
+ S32 cost = 0;
+ std::set<LLUUID> textures;
+
+ for (LLObjectSelection::iterator selection_iter = LLSelectMgr::getInstance()->getSelection()->begin();
+ selection_iter != LLSelectMgr::getInstance()->getSelection()->end();
+ ++selection_iter)
+ {
+ LLSelectNode *select_node = *selection_iter;
+ if (select_node)
+ {
+ LLViewerObject *vobj = select_node->getObject();
+ if (vobj->getVolume())
+ {
+ LLVOVolume* volume = (LLVOVolume*) vobj;
+
+ cost += volume->getRenderCost(textures);
+ cost += textures.size() * LLVOVolume::ARC_TEXTURE_COST;
+ textures.clear();
+ }
+ }
+ }
+
+
+ return cost;
}
+
// static
void LLFloaterTools::setEditTool(void* tool_pointer)
{
diff --git a/indra/newview/llfloatertools.h b/indra/newview/llfloatertools.h
index 87c3d2ab47..fd81a75397 100644
--- a/indra/newview/llfloatertools.h
+++ b/indra/newview/llfloatertools.h
@@ -135,6 +135,8 @@ public:
LLRadioGroup* mRadioGroupEdit;
LLCheckBoxCtrl *mCheckSelectIndividual;
+ LLButton* mBtnLink;
+ LLButton* mBtnUnlink;
LLCheckBoxCtrl* mCheckSnapToGrid;
LLButton* mBtnGridOptions;
diff --git a/indra/newview/llfloatertopobjects.cpp b/indra/newview/llfloatertopobjects.cpp
index e5c4547226..87d048c15b 100644
--- a/indra/newview/llfloatertopobjects.cpp
+++ b/indra/newview/llfloatertopobjects.cpp
@@ -147,17 +147,6 @@ void LLFloaterTopObjects::handle_land_reply(LLMessageSystem* msg, void** data)
}
-void LLFloaterTopObjects::onAvatarNameCache(const LLUUID& agent_id,
- const LLAvatarName& av_name,
- LLSD element)
-{
- LLScrollListCtrl *list = getChild<LLScrollListCtrl>("objects_list");
-
- element["columns"][2]["value"] = av_name.getCompleteName();
-
- list->addElement(element);
-}
-
void LLFloaterTopObjects::handleReply(LLMessageSystem *msg, void** data)
{
U32 request_flags;
@@ -182,7 +171,6 @@ void LLFloaterTopObjects::handleReply(LLMessageSystem *msg, void** data)
F32 mono_score = 0.f;
bool have_extended_data = false;
S32 public_urls = 0;
- LLUUID owner_id;
msg->getU32Fast(_PREHASH_ReportData, _PREHASH_TaskLocalID, task_local_id, block);
msg->getUUIDFast(_PREHASH_ReportData, _PREHASH_TaskID, task_id, block);
@@ -197,11 +185,9 @@ void LLFloaterTopObjects::handleReply(LLMessageSystem *msg, void** data)
have_extended_data = true;
msg->getU32("DataExtended", "TimeStamp", time_stamp, block);
msg->getF32("DataExtended", "MonoScore", mono_score, block);
- msg->getS32(_PREHASH_ReportData,"PublicURLs",public_urls,block);
- msg->getUUID("DataExtended","OwnerID",owner_id,block);
+ msg->getS32("DataExtended", "PublicURLs", public_urls, block);
}
-
LLSD element;
element["id"] = task_id;
@@ -237,7 +223,8 @@ void LLFloaterTopObjects::handleReply(LLMessageSystem *msg, void** data)
columns[3]["value"] = llformat("<%0.1f,%0.1f,%0.1f>", location_x, location_y, location_z);
columns[3]["font"] = "SANSSERIF";
columns[4]["column"] = "time";
- columns[4]["value"] = formatted_time((time_t)time_stamp);
+ columns[4]["type"] = "date";
+ columns[4]["value"] = LLDate((time_t)time_stamp);
columns[4]["font"] = "SANSSERIF";
if (mCurrentMode == STAT_REPORT_TOP_SCRIPTS
@@ -252,16 +239,8 @@ void LLFloaterTopObjects::handleReply(LLMessageSystem *msg, void** data)
columns[6]["font"] = "SANSSERIF";
}
element["columns"] = columns;
+ list->addElement(element);
- if (!owner_id.isNull())
- {
- LLAvatarNameCache::get(owner_id, boost::bind(&LLFloaterTopObjects::onAvatarNameCache, this, _1, _2, element));
- }
- else
- {
- list->addElement(element);
- }
-
mObjectListData.append(element);
mObjectListIDs.push_back(task_id);
diff --git a/indra/newview/llfloatertopobjects.h b/indra/newview/llfloatertopobjects.h
index edd91c491f..a608ca20f1 100644
--- a/indra/newview/llfloatertopobjects.h
+++ b/indra/newview/llfloatertopobjects.h
@@ -29,11 +29,8 @@
#include "llfloater.h"
-class LLAvatarName;
class LLUICtrl;
-#include <boost/signals2.hpp> // boost::signals2::trackable
-
class LLFloaterTopObjects : public LLFloater
{
friend class LLFloaterReg;
@@ -54,8 +51,6 @@ public:
static void setMode(U32 mode);
- void onAvatarNameCache(const LLUUID& id, const LLAvatarName& av_name, LLSD element);
-
private:
LLFloaterTopObjects(const LLSD& key);
~LLFloaterTopObjects();
diff --git a/indra/newview/llfloateruipreview.cpp b/indra/newview/llfloateruipreview.cpp
index 5dc8067648..4c9c4cb154 100644
--- a/indra/newview/llfloateruipreview.cpp
+++ b/indra/newview/llfloateruipreview.cpp
@@ -35,7 +35,9 @@
#include "llfloateruipreview.h" // Own header
// Internal utility
+#include "lldiriterator.h"
#include "lleventtimer.h"
+#include "llexternaleditor.h"
#include "llrender.h"
#include "llsdutil.h"
#include "llxmltree.h"
@@ -160,6 +162,8 @@ public:
DiffMap mDiffsMap; // map, of filename to pair of list of changed element paths and list of errors
private:
+ LLExternalEditor mExternalEditor;
+
// XUI elements for this floater
LLScrollListCtrl* mFileList; // scroll list control for file list
LLLineEditor* mEditorPathTextBox; // text field for path to editor executable
@@ -185,7 +189,7 @@ private:
std::string mSavedDiffPath; // stored diff file path so closing this floater doesn't reset it
// Internal functionality
- static void popupAndPrintWarning(std::string& warning); // pop up a warning
+ static void popupAndPrintWarning(const std::string& warning); // pop up a warning
std::string getLocalizedDirectory(); // build and return the path to the XUI directory for the currently-selected localization
void scanDiffFile(LLXmlTreeNode* file_node); // scan a given XML node for diff entries and highlight them in its associated file
void highlightChangedElements(); // look up the list of elements to highlight and highlight them in the current floater
@@ -478,9 +482,11 @@ BOOL LLFloaterUIPreview::postBuild()
std::string language_directory;
std::string xui_dir = get_xui_dir(); // directory containing localizations -- don't forget trailing delim
mLanguageSelection->removeall(); // clear out anything temporarily in list from XML
+
+ LLDirIterator iter(xui_dir, "*");
while(found) // for every directory
{
- if((found = gDirUtilp->getNextFileInDir(xui_dir, "*", language_directory, FALSE))) // get next directory
+ if((found = iter.next(language_directory))) // get next directory
{
std::string full_path = xui_dir + language_directory;
if(LLFile::isfile(full_path.c_str())) // if it's not a directory, skip it
@@ -597,7 +603,7 @@ void LLFloaterUIPreview::onClose(bool app_quitting)
// Error handling (to avoid code repetition)
// *TODO: this is currently unlocalized. Add to alerts/notifications.xml, someday, maybe.
-void LLFloaterUIPreview::popupAndPrintWarning(std::string& warning)
+void LLFloaterUIPreview::popupAndPrintWarning(const std::string& warning)
{
llwarns << warning << llendl;
LLSD args;
@@ -632,42 +638,51 @@ void LLFloaterUIPreview::refreshList()
mFileList->clearRows(); // empty list
std::string name;
BOOL found = TRUE;
+
+ LLDirIterator floater_iter(getLocalizedDirectory(), "floater_*.xml");
while(found) // for every floater file that matches the pattern
{
- if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "floater_*.xml", name, FALSE))) // get next file matching pattern
+ if((found = floater_iter.next(name))) // get next file matching pattern
{
addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path)
}
}
found = TRUE;
+
+ LLDirIterator inspect_iter(getLocalizedDirectory(), "inspect_*.xml");
while(found) // for every inspector file that matches the pattern
{
- if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "inspect_*.xml", name, FALSE))) // get next file matching pattern
+ if((found = inspect_iter.next(name))) // get next file matching pattern
{
addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path)
}
}
found = TRUE;
+
+ LLDirIterator menu_iter(getLocalizedDirectory(), "menu_*.xml");
while(found) // for every menu file that matches the pattern
{
- if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "menu_*.xml", name, FALSE))) // get next file matching pattern
+ if((found = menu_iter.next(name))) // get next file matching pattern
{
addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path)
}
}
found = TRUE;
+
+ LLDirIterator panel_iter(getLocalizedDirectory(), "panel_*.xml");
while(found) // for every panel file that matches the pattern
{
- if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "panel_*.xml", name, FALSE))) // get next file matching pattern
+ if((found = panel_iter.next(name))) // get next file matching pattern
{
addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path)
}
}
-
found = TRUE;
+
+ LLDirIterator sidepanel_iter(getLocalizedDirectory(), "sidepanel_*.xml");
while(found) // for every sidepanel file that matches the pattern
{
- if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "sidepanel_*.xml", name, FALSE))) // get next file matching pattern
+ if((found = sidepanel_iter.next(name))) // get next file matching pattern
{
addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path)
}
@@ -998,190 +1013,66 @@ void LLFloaterUIPreview::displayFloater(BOOL click, S32 ID, bool save)
// Respond to button click to edit currently-selected floater
void LLFloaterUIPreview::onClickEditFloater()
{
- std::string file_name = mFileList->getSelectedItemLabel(1); // get the file name of the currently-selected floater
- if(std::string("") == file_name) // if no item is selected
- {
- return; // ignore click
- }
- std::string path = getLocalizedDirectory() + file_name;
-
- // stat file to see if it exists (some localized versions may not have it there are no diffs, and then we try to open an nonexistent file)
- llstat dummy;
- if(LLFile::stat(path.c_str(), &dummy)) // if the file does not exist
- {
- std::string warning = "No file for this floater exists in the selected localization. Opening the EN version instead.";
- popupAndPrintWarning(warning);
-
- path = get_xui_dir() + mDelim + "en" + mDelim + file_name; // open the en version instead, by default
- }
-
- // get executable path
- const char* exe_path_char;
- std::string path_in_textfield = mEditorPathTextBox->getText();
- if(std::string("") != path_in_textfield) // if the text field is not emtpy, use its path
+ // Determine file to edit.
+ std::string file_path;
{
- exe_path_char = path_in_textfield.c_str();
- }
- else if (!LLUI::sSettingGroups["config"]->getString("XUIEditor").empty())
- {
- exe_path_char = LLUI::sSettingGroups["config"]->getString("XUIEditor").c_str();
- }
- else // otherwise use the path specified by the environment variable
- {
- exe_path_char = getenv("LL_XUI_EDITOR");
- }
-
- // error check executable path
- if(NULL == exe_path_char)
- {
- std::string warning = "Select an editor by setting the environment variable LL_XUI_EDITOR or specifying its path in the \"Editor Path\" field.";
- popupAndPrintWarning(warning);
- return;
- }
- std::string exe_path = exe_path_char; // do this after error check, otherwise internal strlen call fails on bad char*
-
- // remove any quotes; they're added back in later where necessary
- int found_at;
- while((found_at = exe_path.find("\"")) != -1 || (found_at = exe_path.find("'")) != -1)
- {
- exe_path.erase(found_at,1);
- }
-
- llstat s;
- if(!LLFile::stat(exe_path.c_str(), &s)) // If the executable exists
- {
- // build paths and arguments
- std::string quote = std::string("\"");
- std::string args;
- std::string custom_args = mEditorArgsTextBox->getText();
- int position_of_file = custom_args.find(std::string("%FILE%"), 0); // prepare to replace %FILE% with actual file path
- std::string first_part_of_args = "";
- std::string second_part_of_args = "";
- if(-1 == position_of_file) // default: Executable.exe File.xml
+ std::string file_name = mFileList->getSelectedItemLabel(1); // get the file name of the currently-selected floater
+ if (file_name.empty()) // if no item is selected
{
- args = quote + path + quote; // execute the command Program.exe "File.xml"
- }
- else // use advanced command-line arguments, e.g. "Program.exe -safe File.xml" -windowed for "-safe %FILE% -windowed"
- {
- first_part_of_args = custom_args.substr(0,position_of_file); // get part of args before file name
- second_part_of_args = custom_args.substr(position_of_file+6,custom_args.length()); // get part of args after file name
- custom_args = first_part_of_args + std::string("\"") + path + std::string("\"") + second_part_of_args; // replace %FILE% with "<file path>" and put back together
- args = custom_args; // and save in the variable that is actually used
+ llwarns << "No file selected" << llendl;
+ return; // ignore click
}
+ file_path = getLocalizedDirectory() + file_name;
- // find directory in which executable resides by taking everything after last slash
- int last_slash_position = exe_path.find_last_of(mDelim);
- if(-1 == last_slash_position)
+ // stat file to see if it exists (some localized versions may not have it there are no diffs, and then we try to open an nonexistent file)
+ llstat dummy;
+ if(LLFile::stat(file_path.c_str(), &dummy)) // if the file does not exist
{
- std::string warning = std::string("Unable to find a valid path to the specified executable for XUI XML editing: ") + exe_path;
- popupAndPrintWarning(warning);
- return;
+ popupAndPrintWarning("No file for this floater exists in the selected localization. Opening the EN version instead.");
+ file_path = get_xui_dir() + mDelim + "en" + mDelim + file_name; // open the en version instead, by default
}
- std::string exe_dir = exe_path.substr(0,last_slash_position); // strip executable off, e.g. get "C:\Program Files\TextPad 5" (with or without trailing slash)
+ }
-#if LL_WINDOWS
- PROCESS_INFORMATION pinfo;
- STARTUPINFOA sinfo;
- memset(&sinfo, 0, sizeof(sinfo));
- memset(&pinfo, 0, sizeof(pinfo));
+ // Set the editor command.
+ std::string cmd_override;
+ {
+ std::string bin = mEditorPathTextBox->getText();
+ if (!bin.empty())
+ {
+ // surround command with double quotes for the case if the path contains spaces
+ if (bin.find("\"") == std::string::npos)
+ {
+ bin = "\"" + bin + "\"";
+ }
- std::string exe_name = exe_path.substr(last_slash_position+1);
- args = quote + exe_name + quote + std::string(" ") + args; // and prepend the executable name, so we get 'Program.exe "Arg1"'
+ std::string args = mEditorArgsTextBox->getText();
+ cmd_override = bin + " " + args;
+ }
+ }
- char *args2 = new char[args.size() + 1]; // Windows requires that the second parameter to CreateProcessA be a writable (non-const) string...
- strcpy(args2, args.c_str());
+ LLExternalEditor::EErrorCode status = mExternalEditor.setCommand("LL_XUI_EDITOR", cmd_override);
+ if (status != LLExternalEditor::EC_SUCCESS)
+ {
+ std::string warning;
- // we don't want the current directory to be the executable directory, since the file path is now relative. By using
- // NULL for the current directory instead of exe_dir.c_str(), the path to the target file will work.
- if(!CreateProcessA(exe_path.c_str(), args2, NULL, NULL, FALSE, 0, NULL, NULL, &sinfo, &pinfo))
+ if (status == LLExternalEditor::EC_NOT_SPECIFIED) // Use custom message for this error.
{
- // DWORD dwErr = GetLastError();
- std::string warning = "Creating editor process failed!";
- popupAndPrintWarning(warning);
+ warning = getString("ExternalEditorNotSet");
}
else
{
- // foo = pinfo.dwProcessId; // get your pid here if you want to use it later on
- // sGatewayHandle = pinfo.hProcess;
- CloseHandle(pinfo.hThread); // stops leaks - nothing else
+ warning = LLExternalEditor::getErrorMessage(status);
}
- delete[] args2;
-#else // if !LL_WINDOWS
- // This code was copied from the code to run SLVoice, with some modification; should work in UNIX (Mac/Darwin or Linux)
- {
- std::vector<std::string> arglist;
- arglist.push_back(exe_path.c_str());
-
- // Split the argument string into separate strings for each argument
- typedef boost::tokenizer< boost::char_separator<char> > tokenizer;
- boost::char_separator<char> sep("","\" ", boost::drop_empty_tokens);
-
- tokenizer tokens(args, sep);
- tokenizer::iterator token_iter;
- BOOL inside_quotes = FALSE;
- BOOL last_was_space = FALSE;
- for(token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter)
- {
- if(!strncmp("\"",(*token_iter).c_str(),2))
- {
- inside_quotes = !inside_quotes;
- }
- else if(!strncmp(" ",(*token_iter).c_str(),2))
- {
- if(inside_quotes)
- {
- arglist.back().append(std::string(" "));
- last_was_space = TRUE;
- }
- }
- else
- {
- std::string to_push = *token_iter;
- if(last_was_space)
- {
- arglist.back().append(to_push);
- last_was_space = FALSE;
- }
- else
- {
- arglist.push_back(to_push);
- }
- }
- }
-
- // create an argv vector for the child process
- char **fakeargv = new char*[arglist.size() + 1];
- int i;
- for(i=0; i < arglist.size(); i++)
- fakeargv[i] = const_cast<char*>(arglist[i].c_str());
-
- fakeargv[i] = NULL;
-
- fflush(NULL); // flush all buffers before the child inherits them
- pid_t id = vfork();
- if(id == 0)
- {
- // child
- execv(exe_path.c_str(), fakeargv);
-
- // If we reach this point, the exec failed.
- // Use _exit() instead of exit() per the vfork man page.
- std::string warning = "Creating editor process failed (vfork/execv)!";
- popupAndPrintWarning(warning);
- _exit(0);
- }
-
- // parent
- delete[] fakeargv;
- // sGatewayPID = id;
- }
-#endif // LL_WINDOWS
+ popupAndPrintWarning(warning);
+ return;
}
- else
+
+ // Run the editor.
+ if (mExternalEditor.run(file_path) != LLExternalEditor::EC_SUCCESS)
{
- std::string warning = "Unable to find path to external XML editor for XUI preview tool";
- popupAndPrintWarning(warning);
+ popupAndPrintWarning(LLExternalEditor::getErrorMessage(status));
+ return;
}
}
diff --git a/indra/newview/llfloaterwebcontent.cpp b/indra/newview/llfloaterwebcontent.cpp
new file mode 100644
index 0000000000..058567492b
--- /dev/null
+++ b/indra/newview/llfloaterwebcontent.cpp
@@ -0,0 +1,402 @@
+/**
+ * @file llfloaterwebcontent.cpp
+ * @brief floater for displaying web content - e.g. profiles and search (eventually)
+ *
+ * $LicenseInfo:firstyear=2006&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 "llcombobox.h"
+#include "lliconctrl.h"
+#include "llfloaterreg.h"
+#include "lllayoutstack.h"
+#include "llpluginclassmedia.h"
+#include "llprogressbar.h"
+#include "lltextbox.h"
+#include "llurlhistory.h"
+#include "llviewercontrol.h"
+#include "llweb.h"
+#include "llwindow.h"
+
+#include "llfloaterwebcontent.h"
+
+LLFloaterWebContent::LLFloaterWebContent( const LLSD& key )
+ : LLFloater( key )
+{
+ mCommitCallbackRegistrar.add( "WebContent.Back", boost::bind( &LLFloaterWebContent::onClickBack, this ));
+ mCommitCallbackRegistrar.add( "WebContent.Forward", boost::bind( &LLFloaterWebContent::onClickForward, this ));
+ mCommitCallbackRegistrar.add( "WebContent.Reload", boost::bind( &LLFloaterWebContent::onClickReload, this ));
+ mCommitCallbackRegistrar.add( "WebContent.Stop", boost::bind( &LLFloaterWebContent::onClickStop, this ));
+ mCommitCallbackRegistrar.add( "WebContent.EnterAddress", boost::bind( &LLFloaterWebContent::onEnterAddress, this ));
+ mCommitCallbackRegistrar.add( "WebContent.PopExternal", boost::bind( &LLFloaterWebContent::onPopExternal, this ));
+}
+
+BOOL LLFloaterWebContent::postBuild()
+{
+ // these are used in a bunch of places so cache them
+ mWebBrowser = getChild< LLMediaCtrl >( "webbrowser" );
+ mAddressCombo = getChild< LLComboBox >( "address" );
+ mStatusBarText = getChild< LLTextBox >( "statusbartext" );
+ mStatusBarProgress = getChild<LLProgressBar>("statusbarprogress" );
+
+ // observe browser events
+ mWebBrowser->addObserver( this );
+
+ // these buttons are always enabled
+ getChildView("reload")->setEnabled( true );
+ getChildView("popexternal")->setEnabled( true );
+
+ // cache image for secure browsing
+ mSecureLockIcon = getChild< LLIconCtrl >("media_secure_lock_flag");
+
+ // initialize the URL history using the system URL History manager
+ initializeURLHistory();
+
+ return TRUE;
+}
+
+void LLFloaterWebContent::initializeURLHistory()
+{
+ // start with an empty list
+ LLCtrlListInterface* url_list = childGetListInterface("address");
+ if (url_list)
+ {
+ url_list->operateOnAll(LLCtrlListInterface::OP_DELETE);
+ }
+
+ // Get all of the entries in the "browser" collection
+ LLSD browser_history = LLURLHistory::getURLHistory("browser");
+ LLSD::array_iterator iter_history =
+ browser_history.beginArray();
+ LLSD::array_iterator end_history =
+ browser_history.endArray();
+ for(; iter_history != end_history; ++iter_history)
+ {
+ std::string url = (*iter_history).asString();
+ if(! url.empty())
+ url_list->addSimpleElement(url);
+ }
+}
+
+//static
+void LLFloaterWebContent::create( const std::string &url, const std::string& target, const std::string& uuid )
+{
+ lldebugs << "url = " << url << ", target = " << target << ", uuid = " << uuid << llendl;
+
+ std::string tag = target;
+
+ if(target.empty() || target == "_blank")
+ {
+ if(!uuid.empty())
+ {
+ tag = uuid;
+ }
+ else
+ {
+ // create a unique tag for this instance
+ LLUUID id;
+ id.generate();
+ tag = id.asString();
+ }
+ }
+
+ S32 browser_window_limit = gSavedSettings.getS32("WebContentWindowLimit");
+
+ if(LLFloaterReg::findInstance("web_content", tag) != NULL)
+ {
+ // There's already a web browser for this tag, so we won't be opening a new window.
+ }
+ else if(browser_window_limit != 0)
+ {
+ // showInstance will open a new window. Figure out how many web browsers are already open,
+ // and close the least recently opened one if this will put us over the limit.
+
+ LLFloaterReg::const_instance_list_t &instances = LLFloaterReg::getFloaterList("web_content");
+ lldebugs << "total instance count is " << instances.size() << llendl;
+
+ for(LLFloaterReg::const_instance_list_t::const_iterator iter = instances.begin(); iter != instances.end(); iter++)
+ {
+ lldebugs << " " << (*iter)->getKey() << llendl;
+ }
+
+ if(instances.size() >= (size_t)browser_window_limit)
+ {
+ // Destroy the least recently opened instance
+ (*instances.begin())->closeFloater();
+ }
+ }
+
+ LLFloaterWebContent *browser = dynamic_cast<LLFloaterWebContent*> (LLFloaterReg::showInstance("web_content", tag));
+ llassert(browser);
+ if(browser)
+ {
+ browser->mUUID = uuid;
+
+ // tell the browser instance to load the specified URL
+ browser->open_media(url, target);
+ LLViewerMedia::proxyWindowOpened(target, uuid);
+ }
+}
+
+//static
+void LLFloaterWebContent::closeRequest(const std::string &uuid)
+{
+ LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("web_content");
+ lldebugs << "instance list size is " << inst_list.size() << ", incoming uuid is " << uuid << llendl;
+ for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end(); ++iter)
+ {
+ LLFloaterWebContent* i = dynamic_cast<LLFloaterWebContent*>(*iter);
+ lldebugs << " " << i->mUUID << llendl;
+ if (i && i->mUUID == uuid)
+ {
+ i->closeFloater(false);
+ return;
+ }
+ }
+}
+
+//static
+void LLFloaterWebContent::geometryChanged(const std::string &uuid, S32 x, S32 y, S32 width, S32 height)
+{
+ LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("web_content");
+ lldebugs << "instance list size is " << inst_list.size() << ", incoming uuid is " << uuid << llendl;
+ for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end(); ++iter)
+ {
+ LLFloaterWebContent* i = dynamic_cast<LLFloaterWebContent*>(*iter);
+ lldebugs << " " << i->mUUID << llendl;
+ if (i && i->mUUID == uuid)
+ {
+ i->geometryChanged(x, y, width, height);
+ return;
+ }
+ }
+}
+
+void LLFloaterWebContent::geometryChanged(S32 x, S32 y, S32 width, S32 height)
+{
+ // Make sure the layout of the browser control is updated, so this calculation is correct.
+ LLLayoutStack::updateClass();
+
+ // TODO: need to adjust size and constrain position to make sure floaters aren't moved outside the window view, etc.
+ LLCoordWindow window_size;
+ getWindow()->getSize(&window_size);
+
+ // Adjust width and height for the size of the chrome on the web Browser window.
+ width += getRect().getWidth() - mWebBrowser->getRect().getWidth();
+ height += getRect().getHeight() - mWebBrowser->getRect().getHeight();
+
+ LLRect geom;
+ geom.setOriginAndSize(x, window_size.mY - (y + height), width, height);
+
+ lldebugs << "geometry change: " << geom << llendl;
+
+ handleReshape(geom,false);
+}
+
+void LLFloaterWebContent::open_media(const std::string& web_url, const std::string& target)
+{
+ // Specifying a mime type of text/html here causes the plugin system to skip the MIME type probe and just open a browser plugin.
+ mWebBrowser->setHomePageUrl(web_url, "text/html");
+ mWebBrowser->setTarget(target);
+ mWebBrowser->navigateTo(web_url, "text/html");
+ set_current_url(web_url);
+}
+
+//virtual
+void LLFloaterWebContent::onClose(bool app_quitting)
+{
+ LLViewerMedia::proxyWindowClosed(mUUID);
+ destroy();
+}
+
+// virtual
+void LLFloaterWebContent::draw()
+{
+ // this is asychronous so we need to keep checking
+ getChildView( "back" )->setEnabled( mWebBrowser->canNavigateBack() );
+ getChildView( "forward" )->setEnabled( mWebBrowser->canNavigateForward() );
+
+ LLFloater::draw();
+}
+
+// virtual
+void LLFloaterWebContent::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)
+{
+ if(event == MEDIA_EVENT_LOCATION_CHANGED)
+ {
+ const std::string url = self->getLocation();
+
+ if ( url.length() )
+ mStatusBarText->setText( url );
+
+ set_current_url( url );
+ }
+ else if(event == MEDIA_EVENT_NAVIGATE_BEGIN)
+ {
+ // flags are sent with this event
+ getChildView("back")->setEnabled( self->getHistoryBackAvailable() );
+ getChildView("forward")->setEnabled( self->getHistoryForwardAvailable() );
+
+ // toggle visibility of these buttons based on browser state
+ getChildView("reload")->setVisible( false );
+ getChildView("stop")->setVisible( true );
+
+ // turn "on" progress bar now we're about to start loading
+ mStatusBarProgress->setVisible( true );
+ }
+ else if(event == MEDIA_EVENT_NAVIGATE_COMPLETE)
+ {
+ // flags are sent with this event
+ getChildView("back")->setEnabled( self->getHistoryBackAvailable() );
+ getChildView("forward")->setEnabled( self->getHistoryForwardAvailable() );
+
+ // toggle visibility of these buttons based on browser state
+ getChildView("reload")->setVisible( true );
+ getChildView("stop")->setVisible( false );
+
+ // turn "off" progress bar now we're loaded
+ mStatusBarProgress->setVisible( false );
+
+ // we populate the status bar with URLs as they change so clear it now we're done
+ const std::string end_str = "";
+ mStatusBarText->setText( end_str );
+
+ // decide if secure browsing icon should be displayed
+ std::string prefix = std::string("https://");
+ std::string test_prefix = mCurrentURL.substr(0, prefix.length());
+ LLStringUtil::toLower(test_prefix);
+ if(test_prefix == prefix)
+ {
+ mSecureLockIcon->setVisible(true);
+ }
+ else
+ {
+ mSecureLockIcon->setVisible(false);
+ }
+ }
+ else if(event == MEDIA_EVENT_CLOSE_REQUEST)
+ {
+ // The browser instance wants its window closed.
+ closeFloater();
+ }
+ else if(event == MEDIA_EVENT_GEOMETRY_CHANGE)
+ {
+ geometryChanged(self->getGeometryX(), self->getGeometryY(), self->getGeometryWidth(), self->getGeometryHeight());
+ }
+ else if(event == MEDIA_EVENT_STATUS_TEXT_CHANGED )
+ {
+ const std::string text = self->getStatusText();
+ if ( text.length() )
+ mStatusBarText->setText( text );
+ }
+ else if(event == MEDIA_EVENT_PROGRESS_UPDATED )
+ {
+ int percent = (int)self->getProgressPercent();
+ mStatusBarProgress->setValue( percent );
+ }
+ else if(event == MEDIA_EVENT_NAME_CHANGED )
+ {
+ std::string page_title = self->getMediaName();
+ // simulate browser behavior - title is empty, use the current URL
+ if ( page_title.length() > 0 )
+ setTitle( page_title );
+ else
+ setTitle( mCurrentURL );
+ }
+ else if(event == MEDIA_EVENT_LINK_HOVERED )
+ {
+ const std::string link = self->getHoverLink();
+ mStatusBarText->setText( link );
+ }
+}
+
+void LLFloaterWebContent::set_current_url(const std::string& url)
+{
+ mCurrentURL = url;
+
+ // serialize url history into the system URL History manager
+ LLURLHistory::removeURL("browser", mCurrentURL);
+ LLURLHistory::addURL("browser", mCurrentURL);
+
+ mAddressCombo->remove( mCurrentURL );
+ mAddressCombo->add( mCurrentURL );
+ mAddressCombo->selectByValue( mCurrentURL );
+}
+
+void LLFloaterWebContent::onClickForward()
+{
+ mWebBrowser->navigateForward();
+}
+
+void LLFloaterWebContent::onClickBack()
+{
+ mWebBrowser->navigateBack();
+}
+
+void LLFloaterWebContent::onClickReload()
+{
+
+ if( mWebBrowser->getMediaPlugin() )
+ {
+ bool ignore_cache = true;
+ mWebBrowser->getMediaPlugin()->browse_reload( ignore_cache );
+ }
+ else
+ {
+ mWebBrowser->navigateTo(mCurrentURL);
+ }
+}
+
+void LLFloaterWebContent::onClickStop()
+{
+ if( mWebBrowser->getMediaPlugin() )
+ mWebBrowser->getMediaPlugin()->browse_stop();
+
+ // still should happen when we catch the navigate complete event
+ // but sometimes (don't know why) that event isn't sent from Qt
+ // and we getto a point where the stop button stays active.
+ getChildView("reload")->setVisible( true );
+ getChildView("stop")->setVisible( false );
+}
+
+void LLFloaterWebContent::onEnterAddress()
+{
+ // make sure there is at least something there.
+ // (perhaps this test should be for minimum length of a URL)
+ std::string url = mAddressCombo->getValue().asString();
+ if ( url.length() > 0 )
+ {
+ mWebBrowser->navigateTo( url, "text/html");
+ };
+}
+
+void LLFloaterWebContent::onPopExternal()
+{
+ // make sure there is at least something there.
+ // (perhaps this test should be for minimum length of a URL)
+ std::string url = mAddressCombo->getValue().asString();
+ if ( url.length() > 0 )
+ {
+ LLWeb::loadURLExternal( url );
+ };
+}
diff --git a/indra/newview/llfloaterwebcontent.h b/indra/newview/llfloaterwebcontent.h
new file mode 100644
index 0000000000..ecc7e970d8
--- /dev/null
+++ b/indra/newview/llfloaterwebcontent.h
@@ -0,0 +1,82 @@
+/**
+ * @file llfloaterwebcontent.h
+ * @brief floater for displaying web content - e.g. profiles and search (eventually)
+ *
+ * $LicenseInfo:firstyear=2006&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_LLFLOATERWEBCONTENT_H
+#define LL_LLFLOATERWEBCONTENT_H
+
+#include "llfloater.h"
+#include "llmediactrl.h"
+
+class LLMediaCtrl;
+class LLComboBox;
+class LLTextBox;
+class LLProgressBar;
+class LLIconCtrl;
+
+class LLFloaterWebContent :
+ public LLFloater,
+ public LLViewerMediaObserver
+{
+public:
+ LOG_CLASS(LLFloaterWebContent);
+ LLFloaterWebContent(const LLSD& key);
+
+ void initializeURLHistory();
+
+ static void create(const std::string &url, const std::string& target, const std::string& uuid = LLStringUtil::null);
+
+ static void closeRequest(const std::string &uuid);
+ static void geometryChanged(const std::string &uuid, S32 x, S32 y, S32 width, S32 height);
+ void geometryChanged(S32 x, S32 y, S32 width, S32 height);
+
+ /* virtual */ BOOL postBuild();
+ /* virtual */ void onClose(bool app_quitting);
+ /* virtual */ void draw();
+
+ // inherited from LLViewerMediaObserver
+ /*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event);
+
+ void onClickBack();
+ void onClickForward();
+ void onClickReload();
+ void onClickStop();
+ void onEnterAddress();
+ void onPopExternal();
+
+private:
+ void open_media(const std::string& media_url, const std::string& target);
+ void set_current_url(const std::string& url);
+
+ LLMediaCtrl* mWebBrowser;
+ LLComboBox* mAddressCombo;
+ LLIconCtrl *mSecureLockIcon;
+ LLTextBox* mStatusBarText;
+ LLProgressBar* mStatusBarProgress;
+ std::string mCurrentURL;
+ std::string mUUID;
+};
+
+#endif // LL_LLFLOATERWEBCONTENT_H
diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp
index 7236894542..f8a4ce7ad0 100644
--- a/indra/newview/llfloaterworldmap.cpp
+++ b/indra/newview/llfloaterworldmap.cpp
@@ -72,8 +72,8 @@
#include "llweb.h"
#include "llslider.h"
#include "message.h"
-
#include "llwindow.h" // copyTextToClipboard()
+#include <algorithm>
//---------------------------------------------------------------------------
// Constants
@@ -86,6 +86,16 @@ static const F32 MAP_ZOOM_TIME = 0.2f;
// Currently (01/26/09), this value allows the whole grid to be visible in a 1024x1024 window.
static const S32 MAX_VISIBLE_REGIONS = 512;
+// It would be more logical to have this inside the method where it is used but to compile under gcc this
+// struct has to be here.
+struct SortRegionNames
+{
+ inline bool operator ()(std::pair <U64, LLSimInfo*> const& _left, std::pair <U64, LLSimInfo*> const& _right)
+ {
+ return(LLStringUtil::compareInsensitive(_left.second->getName(), _right.second->getName()) < 0);
+ }
+};
+
enum EPanDirection
{
PAN_UP,
@@ -106,32 +116,75 @@ class LLWorldMapHandler : public LLCommandHandler
{
public:
// requires trusted browser to trigger
- LLWorldMapHandler() : LLCommandHandler("worldmap", UNTRUSTED_THROTTLE) { }
-
+ LLWorldMapHandler() : LLCommandHandler("worldmap", UNTRUSTED_THROTTLE ) { }
+
bool handle(const LLSD& params, const LLSD& query_map,
LLMediaCtrl* web)
{
+ if (!LLUI::sSettingGroups["config"]->getBOOL("EnableWorldMap"))
+ {
+ LLNotificationsUtil::add("NoWorldMap", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit"));
+ return true;
+ }
+
if (params.size() == 0)
{
// support the secondlife:///app/worldmap SLapp
LLFloaterReg::showInstance("world_map", "center");
return true;
}
-
+
// support the secondlife:///app/worldmap/{LOCATION}/{COORDS} SLapp
const std::string region_name = LLURI::unescape(params[0].asString());
S32 x = (params.size() > 1) ? params[1].asInteger() : 128;
S32 y = (params.size() > 2) ? params[2].asInteger() : 128;
S32 z = (params.size() > 3) ? params[3].asInteger() : 0;
-
+
LLFloaterWorldMap::getInstance()->trackURL(region_name, x, y, z);
LLFloaterReg::showInstance("world_map", "center");
-
+
return true;
}
};
LLWorldMapHandler gWorldMapHandler;
+// SocialMap handler secondlife:///app/maptrackavatar/id
+class LLMapTrackAvatarHandler : public LLCommandHandler
+{
+public:
+ // requires trusted browser to trigger
+ LLMapTrackAvatarHandler() : LLCommandHandler("maptrackavatar", UNTRUSTED_THROTTLE)
+ {
+ }
+
+ bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web)
+ {
+ if (!LLUI::sSettingGroups["config"]->getBOOL("EnableWorldMap"))
+ {
+ LLNotificationsUtil::add("NoWorldMap", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit"));
+ return true;
+ }
+
+ //Make sure we have some parameters
+ if (params.size() == 0)
+ {
+ return false;
+ }
+
+ //Get the ID
+ LLUUID id;
+ if (!id.set( params[0], FALSE ))
+ {
+ return false;
+ }
+
+ LLFloaterWorldMap::getInstance()->avatarTrackFromSlapp( id );
+ LLFloaterReg::showInstance( "world_map", "center" );
+
+ return true;
+ }
+};
+LLMapTrackAvatarHandler gMapTrackAvatar;
LLFloaterWorldMap* gFloaterWorldMap = NULL;
@@ -142,7 +195,7 @@ public:
virtual ~LLMapInventoryObserver() {}
virtual void changed(U32 mask);
};
-
+
void LLMapInventoryObserver::changed(U32 mask)
{
// if there's a change we're interested in.
@@ -184,16 +237,16 @@ const LLUUID LLFloaterWorldMap::sHomeID( "10000000-0000-0000-0000-000000000001"
LLFloaterWorldMap::LLFloaterWorldMap(const LLSD& key)
: LLFloater(key),
- mInventory(NULL),
- mInventoryObserver(NULL),
- mFriendObserver(NULL),
- mCompletingRegionName(),
- mCompletingRegionPos(),
- mWaitingForTracker(FALSE),
- mIsClosing(FALSE),
- mSetToUserPosition(TRUE),
- mTrackedLocation(0,0,0),
- mTrackedStatus(LLTracker::TRACKING_NOTHING)
+mInventory(NULL),
+mInventoryObserver(NULL),
+mFriendObserver(NULL),
+mCompletingRegionName(),
+mCompletingRegionPos(),
+mWaitingForTracker(FALSE),
+mIsClosing(FALSE),
+mSetToUserPosition(TRUE),
+mTrackedLocation(0,0,0),
+mTrackedStatus(LLTracker::TRACKING_NOTHING)
{
gFloaterWorldMap = this;
@@ -210,7 +263,7 @@ LLFloaterWorldMap::LLFloaterWorldMap(const LLSD& key)
mCommitCallbackRegistrar.add("WMap.ShowAgent", boost::bind(&LLFloaterWorldMap::onShowAgentBtn, this));
mCommitCallbackRegistrar.add("WMap.Clear", boost::bind(&LLFloaterWorldMap::onClearBtn, this));
mCommitCallbackRegistrar.add("WMap.CopySLURL", boost::bind(&LLFloaterWorldMap::onCopySLURL, this));
-
+
gSavedSettings.getControl("PreferredMaturity")->getSignal()->connect(boost::bind(&LLFloaterWorldMap::onChangeMaturity, this));
}
@@ -223,32 +276,32 @@ void* LLFloaterWorldMap::createWorldMapView(void* data)
BOOL LLFloaterWorldMap::postBuild()
{
mPanel = getChild<LLPanel>("objects_mapview");
-
+
LLComboBox *avatar_combo = getChild<LLComboBox>("friend combo");
avatar_combo->selectFirstItem();
avatar_combo->setPrearrangeCallback( boost::bind(&LLFloaterWorldMap::onAvatarComboPrearrange, this) );
avatar_combo->setTextEntryCallback( boost::bind(&LLFloaterWorldMap::onComboTextEntry, this) );
-
+
LLSearchEditor *location_editor = getChild<LLSearchEditor>("location");
location_editor->setFocusChangedCallback(boost::bind(&LLFloaterWorldMap::onLocationFocusChanged, this, _1));
location_editor->setKeystrokeCallback( boost::bind(&LLFloaterWorldMap::onSearchTextEntry, this));
getChild<LLScrollListCtrl>("search_results")->setDoubleClickCallback( boost::bind(&LLFloaterWorldMap::onClickTeleportBtn, this));
-
+
LLComboBox *landmark_combo = getChild<LLComboBox>( "landmark combo");
landmark_combo->selectFirstItem();
landmark_combo->setPrearrangeCallback( boost::bind(&LLFloaterWorldMap::onLandmarkComboPrearrange, this) );
landmark_combo->setTextEntryCallback( boost::bind(&LLFloaterWorldMap::onComboTextEntry, this) );
-
+
mCurZoomVal = log(LLWorldMapView::sMapScale)/log(2.f);
getChild<LLUICtrl>("zoom slider")->setValue(LLWorldMapView::sMapScale);
-
+
setDefaultBtn(NULL);
-
+
mZoomTimer.stop();
-
+
onChangeMaturity();
-
+
return TRUE;
}
@@ -257,11 +310,11 @@ LLFloaterWorldMap::~LLFloaterWorldMap()
{
// All cleaned up by LLView destructor
mPanel = NULL;
-
+
// Inventory deletes all observers on shutdown
mInventory = NULL;
mInventoryObserver = NULL;
-
+
// avatar tracker will delete this for us.
mFriendObserver = NULL;
@@ -285,13 +338,13 @@ void LLFloaterWorldMap::onClose(bool app_quitting)
void LLFloaterWorldMap::onOpen(const LLSD& key)
{
bool center_on_target = (key.asString() == "center");
-
+
mIsClosing = FALSE;
-
+
LLWorldMapView* map_panel;
map_panel = (LLWorldMapView*)gFloaterWorldMap->mPanel;
map_panel->clearLastClick();
-
+
{
// reset pan on show, so it centers on you again
if (!center_on_target)
@@ -299,27 +352,27 @@ void LLFloaterWorldMap::onOpen(const LLSD& key)
LLWorldMapView::setPan(0, 0, TRUE);
}
map_panel->updateVisibleBlocks();
-
+
// Reload items as they may have changed
LLWorldMap::getInstance()->reloadItems();
-
+
// We may already have a bounding box for the regions of the world,
// so use that to adjust the view.
adjustZoomSliderBounds();
-
+
// Could be first show
//LLFirstUse::useMap();
-
+
// Start speculative download of landmarks
const LLUUID landmark_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK);
LLInventoryModelBackgroundFetch::instance().start(landmark_folder_id);
-
+
getChild<LLUICtrl>("location")->setFocus( TRUE);
gFocusMgr.triggerFocusFlash();
-
+
buildAvatarIDList();
buildLandmarkIDLists();
-
+
// If nothing is being tracked, set flag so the user position will be found
mSetToUserPosition = ( LLTracker::getTrackingStatus() == LLTracker::TRACKING_NOTHING );
}
@@ -356,7 +409,7 @@ BOOL LLFloaterWorldMap::handleScrollWheel(S32 x, S32 y, S32 clicks)
return TRUE;
}
}
-
+
return LLFloater::handleScrollWheel(x, y, clicks);
}
@@ -381,7 +434,7 @@ void LLFloaterWorldMap::draw()
bool agent_on_prelude = (regionp && regionp->isPrelude());
bool enable_go_home = gAgent.isGodlike() || !agent_on_prelude;
getChildView("Go Home")->setEnabled(enable_go_home);
-
+
updateLocation();
LLTracker::ETrackingStatus tracking_status = LLTracker::getTrackingStatus();
@@ -393,7 +446,7 @@ void LLFloaterWorldMap::draw()
{
getChild<LLUICtrl>("avatar_icon")->setColor( map_track_disabled_color);
}
-
+
if (LLTracker::TRACKING_LANDMARK == tracking_status)
{
getChild<LLUICtrl>("landmark_icon")->setColor( map_track_color);
@@ -402,7 +455,7 @@ void LLFloaterWorldMap::draw()
{
getChild<LLUICtrl>("landmark_icon")->setColor( map_track_disabled_color);
}
-
+
if (LLTracker::TRACKING_LOCATION == tracking_status)
{
getChild<LLUICtrl>("location_icon")->setColor( map_track_color);
@@ -422,21 +475,21 @@ void LLFloaterWorldMap::draw()
getChild<LLUICtrl>("location_icon")->setColor( map_track_disabled_color);
}
}
-
+
// check for completion of tracking data
if (mWaitingForTracker)
{
centerOnTarget(TRUE);
}
-
+
getChildView("Teleport")->setEnabled((BOOL)tracking_status);
-// getChildView("Clear")->setEnabled((BOOL)tracking_status);
+ // getChildView("Clear")->setEnabled((BOOL)tracking_status);
getChildView("Show Destination")->setEnabled((BOOL)tracking_status || LLWorldMap::getInstance()->isTracking());
getChildView("copy_slurl")->setEnabled((mSLURL.isValid()) );
-
+
setMouseOpaque(TRUE);
getDragHandle()->setMouseOpaque(TRUE);
-
+
//RN: snaps to zoom value because interpolation caused jitter in the text rendering
if (!mZoomTimer.getStarted() && mCurZoomVal != (F32)getChild<LLUICtrl>("zoom slider")->getValue().asReal())
{
@@ -451,7 +504,7 @@ void LLFloaterWorldMap::draw()
mCurZoomVal = lerp(mCurZoomVal, (F32)getChild<LLUICtrl>("zoom slider")->getValue().asReal(), interp);
F32 map_scale = 256.f*pow(2.f, mCurZoomVal);
LLWorldMapView::setScale( map_scale );
-
+
// Enable/disable checkboxes depending on the zoom level
// If above threshold level (i.e. low res) -> Disable all checkboxes
// If under threshold level (i.e. high res) -> Enable all checkboxes
@@ -477,7 +530,7 @@ void LLFloaterWorldMap::trackAvatar( const LLUUID& avatar_id, const std::string&
{
LLCtrlSelectionInterface *iface = childGetSelectionInterface("friend combo");
if (!iface) return;
-
+
buildAvatarIDList();
if(iface->setCurrentByID(avatar_id) || gAgent.isGodlike())
{
@@ -507,7 +560,7 @@ void LLFloaterWorldMap::trackLandmark( const LLUUID& landmark_item_id )
{
LLCtrlSelectionInterface *iface = childGetSelectionInterface("landmark combo");
if (!iface) return;
-
+
buildLandmarkIDLists();
BOOL found = FALSE;
S32 idx;
@@ -519,7 +572,7 @@ void LLFloaterWorldMap::trackLandmark( const LLUUID& landmark_item_id )
break;
}
}
-
+
if (found && iface->setCurrentByID( landmark_item_id ) )
{
LLUUID asset_id = mLandmarkAssetIDList.get( idx );
@@ -528,17 +581,17 @@ void LLFloaterWorldMap::trackLandmark( const LLUUID& landmark_item_id )
if (combo) name = combo->getSimple();
mTrackedStatus = LLTracker::TRACKING_LANDMARK;
LLTracker::trackLandmark(mLandmarkAssetIDList.get( idx ), // assetID
- mLandmarkItemIDList.get( idx ), // itemID
- name); // name
-
+ mLandmarkItemIDList.get( idx ), // itemID
+ name); // name
+
if( asset_id != sHomeID )
{
// start the download process
gLandmarkList.getAsset( asset_id);
}
-
+
// We have to download both region info and landmark data, so set busy. JC
-// getWindow()->incBusyCount();
+ // getWindow()->incBusyCount();
}
else
{
@@ -574,10 +627,10 @@ void LLFloaterWorldMap::trackLocation(const LLVector3d& pos_global)
S32 world_y = S32(pos_global.mdV[1] / 256);
LLWorldMapMessage::getInstance()->sendMapBlockRequest(world_x, world_y, world_x, world_y, true);
setDefaultBtn("");
-
+
// clicked on a non-region - turn off coord display
enableTeleportCoordsDisplay( false );
-
+
return;
}
if (sim_info->isDown())
@@ -588,33 +641,33 @@ void LLFloaterWorldMap::trackLocation(const LLVector3d& pos_global)
LLWorldMap::getInstance()->setTrackingInvalid();
LLTracker::stopTracking(NULL);
setDefaultBtn("");
-
+
// clicked on a down region - turn off coord display
enableTeleportCoordsDisplay( false );
-
+
return;
}
-
+
std::string sim_name = sim_info->getName();
F32 region_x = (F32)fmod( pos_global.mdV[VX], (F64)REGION_WIDTH_METERS );
F32 region_y = (F32)fmod( pos_global.mdV[VY], (F64)REGION_WIDTH_METERS );
std::string full_name = llformat("%s (%d, %d, %d)",
- sim_name.c_str(),
- llround(region_x),
- llround(region_y),
- llround((F32)pos_global.mdV[VZ]));
-
+ sim_name.c_str(),
+ llround(region_x),
+ llround(region_y),
+ llround((F32)pos_global.mdV[VZ]));
+
std::string tooltip("");
mTrackedStatus = LLTracker::TRACKING_LOCATION;
LLTracker::trackLocation(pos_global, full_name, tooltip);
LLWorldMap::getInstance()->cancelTracking(); // The floater is taking over the tracking
-
+
LLVector3d coord_pos = LLTracker::getTrackedPositionGlobal();
updateTeleportCoordsDisplay( coord_pos );
-
+
// we have a valid region - turn on coord display
enableTeleportCoordsDisplay( true );
-
+
setDefaultBtn("Teleport");
}
@@ -631,11 +684,11 @@ void LLFloaterWorldMap::updateTeleportCoordsDisplay( const LLVector3d& pos )
{
// if we're going to update their value, we should also enable them
enableTeleportCoordsDisplay( true );
-
+
// convert global specified position to a local one
F32 region_local_x = (F32)fmod( pos.mdV[VX], (F64)REGION_WIDTH_METERS );
F32 region_local_y = (F32)fmod( pos.mdV[VY], (F64)REGION_WIDTH_METERS );
- F32 region_local_z = (F32)fmod( pos.mdV[VZ], (F64)REGION_WIDTH_METERS );
+ F32 region_local_z = (F32)llclamp( pos.mdV[VZ], 0.0, (F64)REGION_HEIGHT_METERS );
// write in the values
childSetValue("teleport_coordinate_x", region_local_x );
@@ -646,16 +699,16 @@ void LLFloaterWorldMap::updateTeleportCoordsDisplay( const LLVector3d& pos )
void LLFloaterWorldMap::updateLocation()
{
bool gotSimName;
-
+
LLTracker::ETrackingStatus status = LLTracker::getTrackingStatus();
-
+
// These values may get updated by a message, so need to check them every frame
// The fields may be changed by the user, so only update them if the data changes
LLVector3d pos_global = LLTracker::getTrackedPositionGlobal();
if (pos_global.isExactlyZero())
{
LLVector3d agentPos = gAgent.getPositionGlobal();
-
+
// Set to avatar's current postion if nothing is selected
if ( status == LLTracker::TRACKING_NOTHING && mSetToUserPosition )
{
@@ -665,19 +718,19 @@ void LLFloaterWorldMap::updateLocation()
if ( gotSimName )
{
mSetToUserPosition = FALSE;
-
+
// Fill out the location field
getChild<LLUICtrl>("location")->setValue(agent_sim_name);
-
+
// update the coordinate display with location of avatar in region
updateTeleportCoordsDisplay( agentPos );
-
+
// Figure out where user is
// Set the current SLURL
mSLURL = LLSLURL(agent_sim_name, gAgent.getPositionGlobal());
}
}
-
+
return; // invalid location
}
std::string sim_name;
@@ -699,17 +752,17 @@ void LLFloaterWorldMap::updateLocation()
pos_global[2] = 200;
}
}
-
+
getChild<LLUICtrl>("location")->setValue(sim_name);
-
+
// refresh coordinate display to reflect where user clicked.
LLVector3d coord_pos = LLTracker::getTrackedPositionGlobal();
updateTeleportCoordsDisplay( coord_pos );
-
+
// simNameFromPosGlobal can fail, so don't give the user an invalid SLURL
if ( gotSimName )
{
- mSLURL = LLSLURL(sim_name, pos_global);
+ mSLURL = LLSLURL(sim_name, pos_global);
}
else
{ // Empty SLURL will disable the "Copy SLURL to clipboard" button
@@ -736,12 +789,12 @@ void LLFloaterWorldMap::trackURL(const std::string& region_name, S32 x_coord, S3
{
// fill in UI based on URL
gFloaterWorldMap->getChild<LLUICtrl>("location")->setValue(region_name);
-
+
// Save local coords to highlight position after region global
// position is returned.
gFloaterWorldMap->mCompletingRegionPos.set(
- (F32)x_coord, (F32)y_coord, (F32)z_coord);
-
+ (F32)x_coord, (F32)y_coord, (F32)z_coord);
+
// pass sim name to combo box
gFloaterWorldMap->mCompletingRegionName = region_name;
LLWorldMapMessage::getInstance()->sendNamedRegionRequest(region_name);
@@ -813,7 +866,7 @@ void LLFloaterWorldMap::buildAvatarIDList()
{
LLCtrlListInterface *list = childGetListInterface("friend combo");
if (!list) return;
-
+
// Delete all but the "None" entry
S32 list_size = list->getItemCount();
if (list_size > 1)
@@ -821,7 +874,7 @@ void LLFloaterWorldMap::buildAvatarIDList()
list->selectItemRange(1, -1);
list->operateOnSelection(LLCtrlListInterface::OP_DELETE);
}
-
+
// Get all of the calling cards for avatar that are currently online
LLCollectMappableBuddies collector;
LLAvatarTracker::instance().applyFunctor(collector);
@@ -833,7 +886,7 @@ void LLFloaterWorldMap::buildAvatarIDList()
{
list->addSimpleElement((*it).first, ADD_BOTTOM, (*it).second);
}
-
+
list->setCurrentByID( LLAvatarTracker::instance().getAvatarID() );
list->selectFirstItem();
}
@@ -843,7 +896,7 @@ void LLFloaterWorldMap::buildLandmarkIDLists()
{
LLCtrlListInterface *list = childGetListInterface("landmark combo");
if (!list) return;
-
+
// Delete all but the "None" entry
S32 list_size = list->getItemCount();
if (list_size > 1)
@@ -851,17 +904,17 @@ void LLFloaterWorldMap::buildLandmarkIDLists()
list->selectItemRange(1, -1);
list->operateOnSelection(LLCtrlListInterface::OP_DELETE);
}
-
+
mLandmarkItemIDList.reset();
mLandmarkAssetIDList.reset();
-
+
// Get all of the current landmarks
mLandmarkAssetIDList.put( LLUUID::null );
mLandmarkItemIDList.put( LLUUID::null );
-
+
mLandmarkAssetIDList.put( sHomeID );
mLandmarkItemIDList.put( sHomeID );
-
+
LLInventoryModel::cat_array_t cats;
LLInventoryModel::item_array_t items;
LLIsType is_landmark(LLAssetType::AT_LANDMARK);
@@ -870,20 +923,20 @@ void LLFloaterWorldMap::buildLandmarkIDLists()
items,
LLInventoryModel::EXCLUDE_TRASH,
is_landmark);
-
+
std::sort(items.begin(), items.end(), LLViewerInventoryItem::comparePointers());
S32 count = items.count();
for(S32 i = 0; i < count; ++i)
{
LLInventoryItem* item = items.get(i);
-
+
list->addSimpleElement(item->getName(), ADD_BOTTOM, item->getUUID());
-
+
mLandmarkAssetIDList.put( item->getAssetUUID() );
mLandmarkItemIDList.put( item->getUUID() );
}
-
+
list->selectFirstItem();
}
@@ -949,31 +1002,31 @@ void LLFloaterWorldMap::adjustZoomSliderBounds()
// Currently (01/26/09), this value allows the whole grid to be visible in a 1024x1024 window.
S32 world_width_regions = MAX_VISIBLE_REGIONS;
S32 world_height_regions = MAX_VISIBLE_REGIONS;
-
+
// Find how much space we have to display the world
LLWorldMapView* map_panel;
map_panel = (LLWorldMapView*)mPanel;
LLRect view_rect = map_panel->getRect();
-
+
// View size in pixels
S32 view_width = view_rect.getWidth();
S32 view_height = view_rect.getHeight();
-
+
// Pixels per region to display entire width/height
F32 width_pixels_per_region = (F32) view_width / (F32) world_width_regions;
F32 height_pixels_per_region = (F32) view_height / (F32) world_height_regions;
-
+
F32 pixels_per_region = llmin(width_pixels_per_region,
height_pixels_per_region);
-
+
// Round pixels per region to an even number of slider increments
S32 slider_units = llfloor(pixels_per_region / 0.2f);
pixels_per_region = slider_units * 0.2f;
-
+
// Make sure the zoom slider can be moved at least a little bit.
// Likewise, less than the increment pixels per region is just silly.
pixels_per_region = llclamp(pixels_per_region, 1.f, ZOOM_MAX);
-
+
F32 min_power = log(pixels_per_region/256.f)/log(2.f);
getChild<LLSlider>("zoom slider")->setMinValue(min_power);
@@ -997,19 +1050,19 @@ void LLFloaterWorldMap::onLandmarkComboPrearrange( )
{
return;
}
-
+
LLCtrlListInterface *list = childGetListInterface("landmark combo");
if (!list) return;
-
+
LLUUID current_choice = list->getCurrentID();
-
+
buildLandmarkIDLists();
-
+
if( current_choice.isNull() || !list->setCurrentByID( current_choice ) )
{
LLTracker::stopTracking(NULL);
}
-
+
}
void LLFloaterWorldMap::onComboTextEntry()
@@ -1033,18 +1086,18 @@ void LLFloaterWorldMap::onLandmarkComboCommit()
{
return;
}
-
+
LLCtrlListInterface *list = childGetListInterface("landmark combo");
if (!list) return;
-
+
LLUUID asset_id;
LLUUID item_id = list->getCurrentID();
-
+
LLTracker::stopTracking(NULL);
-
+
//RN: stopTracking() clears current combobox selection, need to reassert it here
list->setCurrentByID(item_id);
-
+
if( item_id.isNull() )
{
}
@@ -1068,7 +1121,7 @@ void LLFloaterWorldMap::onLandmarkComboCommit()
trackLandmark( item_id);
onShowTargetBtn();
-
+
// Reset to user postion if nothing is tracked
mSetToUserPosition = ( LLTracker::getTrackingStatus() == LLTracker::TRACKING_NOTHING );
}
@@ -1080,19 +1133,19 @@ void LLFloaterWorldMap::onAvatarComboPrearrange( )
{
return;
}
-
+
LLCtrlListInterface *list = childGetListInterface("friend combo");
if (!list) return;
-
+
LLUUID current_choice;
-
+
if( LLAvatarTracker::instance().haveTrackingInfo() )
{
current_choice = LLAvatarTracker::instance().getAvatarID();
}
-
+
buildAvatarIDList();
-
+
if( !list->setCurrentByID( current_choice ) || current_choice.isNull() )
{
LLTracker::stopTracking(NULL);
@@ -1105,10 +1158,10 @@ void LLFloaterWorldMap::onAvatarComboCommit()
{
return;
}
-
+
LLCtrlListInterface *list = childGetListInterface("friend combo");
if (!list) return;
-
+
const LLUUID& new_avatar_id = list->getCurrentID();
if (new_avatar_id.notNull())
{
@@ -1124,6 +1177,12 @@ void LLFloaterWorldMap::onAvatarComboCommit()
}
}
+void LLFloaterWorldMap::avatarTrackFromSlapp( const LLUUID& id )
+{
+ trackAvatar( id, "av" );
+ onShowTargetBtn();
+}
+
void LLFloaterWorldMap::onLocationFocusChanged( LLFocusableElement* focus )
{
updateSearchEnabled();
@@ -1148,13 +1207,13 @@ void LLFloaterWorldMap::onLocationCommit()
{
return;
}
-
+
clearLocationSelection(FALSE);
mCompletingRegionName = "";
mLastRegionName = "";
-
+
std::string str = getChild<LLUICtrl>("location")->getValue().asString();
-
+
// Trim any leading and trailing spaces in the search target
std::string saved_str = str;
LLStringUtil::trim( str );
@@ -1162,7 +1221,7 @@ void LLFloaterWorldMap::onLocationCommit()
{ // Set the value in the UI if any spaces were removed
getChild<LLUICtrl>("location")->setValue(str);
}
-
+
LLStringUtil::toLower(str);
mCompletingRegionName = str;
LLWorldMap::getInstance()->setTrackingCommit();
@@ -1183,13 +1242,13 @@ void LLFloaterWorldMap::onCoordinatesCommit()
{
return;
}
-
+
S32 x_coord = (S32)childGetValue("teleport_coordinate_x").asReal();
S32 y_coord = (S32)childGetValue("teleport_coordinate_y").asReal();
S32 z_coord = (S32)childGetValue("teleport_coordinate_z").asReal();
-
+
const std::string region_name = childGetValue("location").asString();
-
+
trackURL( region_name, x_coord, y_coord, z_coord );
}
@@ -1225,7 +1284,7 @@ void LLFloaterWorldMap::onCopySLURL()
LLSD args;
args["SLURL"] = mSLURL.getSLURLString();
-
+
LLNotificationsUtil::add("CopySLURL", args);
}
@@ -1246,26 +1305,26 @@ void LLFloaterWorldMap::centerOnTarget(BOOL animate)
else
{
// We've got the position finally, so we're no longer busy. JC
-// getWindow()->decBusyCount();
+ // getWindow()->decBusyCount();
pos_global = LLTracker::getTrackedPositionGlobal() - gAgentCamera.getCameraPositionGlobal();
}
}
else if(LLWorldMap::getInstance()->isTracking())
{
pos_global = LLWorldMap::getInstance()->getTrackedPositionGlobal() - gAgentCamera.getCameraPositionGlobal();;
-
-
-
+
+
+
}
else
{
// default behavior = center on agent
pos_global.clearVec();
}
-
+
LLWorldMapView::setPan( -llfloor((F32)(pos_global.mdV[VX] * (F64)LLWorldMapView::sMapScale / REGION_WIDTH_METERS)),
- -llfloor((F32)(pos_global.mdV[VY] * (F64)LLWorldMapView::sMapScale / REGION_WIDTH_METERS)),
- !animate);
+ -llfloor((F32)(pos_global.mdV[VY] * (F64)LLWorldMapView::sMapScale / REGION_WIDTH_METERS)),
+ !animate);
mWaitingForTracker = FALSE;
}
@@ -1273,7 +1332,7 @@ void LLFloaterWorldMap::centerOnTarget(BOOL animate)
void LLFloaterWorldMap::fly()
{
LLVector3d pos_global = LLTracker::getTrackedPositionGlobal();
-
+
// Start the autopilot and close the floater,
// so we can see where we're flying
if (!pos_global.isExactlyZero())
@@ -1294,7 +1353,7 @@ void LLFloaterWorldMap::teleport()
BOOL teleport_home = FALSE;
LLVector3d pos_global;
LLAvatarTracker& av_tracker = LLAvatarTracker::instance();
-
+
LLTracker::ETrackingStatus tracking_status = LLTracker::getTrackingStatus();
if (LLTracker::TRACKING_AVATAR == tracking_status
&& av_tracker.haveTrackingInfo() )
@@ -1317,10 +1376,10 @@ void LLFloaterWorldMap::teleport()
&& landmark->getRegionID(region_id))
{
LLLandmark::requestRegionHandle(
- gMessageSystem,
- gAgent.getRegionHost(),
- region_id,
- NULL);
+ gMessageSystem,
+ gAgent.getRegionHost(),
+ region_id,
+ NULL);
}
}
}
@@ -1332,7 +1391,7 @@ void LLFloaterWorldMap::teleport()
{
make_ui_sound("UISndInvalidOp");
}
-
+
// Do the teleport, which will also close the floater
if (teleport_home)
{
@@ -1367,7 +1426,7 @@ void LLFloaterWorldMap::teleportToLandmark()
{
BOOL has_destination = FALSE;
LLUUID destination_id; // Null means "home"
-
+
if( LLTracker::getTrackedLandmarkAssetID() == sHomeID )
{
has_destination = TRUE;
@@ -1388,14 +1447,14 @@ void LLFloaterWorldMap::teleportToLandmark()
if(landmark->getRegionID(region_id))
{
LLLandmark::requestRegionHandle(
- gMessageSystem,
- gAgent.getRegionHost(),
- region_id,
- NULL);
+ gMessageSystem,
+ gAgent.getRegionHost(),
+ region_id,
+ NULL);
}
}
}
-
+
if( has_destination )
{
gAgent.teleportViaLandmark( destination_id );
@@ -1428,22 +1487,25 @@ void LLFloaterWorldMap::updateSims(bool found_null_sim)
{
return;
}
-
+
LLScrollListCtrl *list = getChild<LLScrollListCtrl>("search_results");
list->operateOnAll(LLCtrlListInterface::OP_DELETE);
-
+
S32 name_length = mCompletingRegionName.length();
-
- LLSD match;
+ LLSD match;
+
S32 num_results = 0;
- std::map<U64, LLSimInfo*>::const_iterator it;
- for (it = LLWorldMap::getInstance()->getRegionMap().begin(); it != LLWorldMap::getInstance()->getRegionMap().end(); ++it)
+
+ std::vector<std::pair <U64, LLSimInfo*> > sim_info_vec(LLWorldMap::getInstance()->getRegionMap().begin(), LLWorldMap::getInstance()->getRegionMap().end());
+ std::sort(sim_info_vec.begin(), sim_info_vec.end(), SortRegionNames());
+
+ for (std::vector<std::pair <U64, LLSimInfo*> >::const_iterator it = sim_info_vec.begin(); it != sim_info_vec.end(); ++it)
{
LLSimInfo* info = it->second;
std::string sim_name_lower = info->getName();
LLStringUtil::toLower(sim_name_lower);
-
+
if (sim_name_lower.substr(0, name_length) == mCompletingRegionName)
{
if (sim_name_lower == mCompletingRegionName)
@@ -1459,12 +1521,12 @@ void LLFloaterWorldMap::updateSims(bool found_null_sim)
num_results++;
}
}
-
+
if (found_null_sim)
{
mCompletingRegionName = "";
}
-
+
// if match found, highlight it and go
if (!match.isUndefined())
{
@@ -1472,7 +1534,7 @@ void LLFloaterWorldMap::updateSims(bool found_null_sim)
getChild<LLUICtrl>("search_results")->setFocus(TRUE);
onCommitSearchResult();
}
-
+
// if we found nothing, say "none"
if (num_results == 0)
{
@@ -1486,7 +1548,7 @@ void LLFloaterWorldMap::onCommitSearchResult()
{
LLCtrlListInterface *list = childGetListInterface("search_results");
if (!list) return;
-
+
LLSD selected_value = list->getSelectedValue();
std::string sim_name = selected_value.asString();
if (sim_name.empty())
@@ -1494,19 +1556,19 @@ void LLFloaterWorldMap::onCommitSearchResult()
return;
}
LLStringUtil::toLower(sim_name);
-
+
std::map<U64, LLSimInfo*>::const_iterator it;
for (it = LLWorldMap::getInstance()->getRegionMap().begin(); it != LLWorldMap::getInstance()->getRegionMap().end(); ++it)
{
LLSimInfo* info = it->second;
-
+
if (info->isName(sim_name))
{
LLVector3d pos_global = info->getGlobalOrigin();
-
+
const F64 SIM_COORD_DEFAULT = 128.0;
LLVector3 pos_local(SIM_COORD_DEFAULT, SIM_COORD_DEFAULT, 0.0f);
-
+
// Did this value come from a trackURL() request?
if (!mCompletingRegionPos.isExactlyZero())
{
@@ -1516,14 +1578,14 @@ void LLFloaterWorldMap::onCommitSearchResult()
pos_global.mdV[VX] += (F64)pos_local.mV[VX];
pos_global.mdV[VY] += (F64)pos_local.mV[VY];
pos_global.mdV[VZ] = (F64)pos_local.mV[VZ];
-
+
getChild<LLUICtrl>("location")->setValue(sim_name);
trackLocation(pos_global);
setDefaultBtn("Teleport");
break;
}
}
-
+
onShowTargetBtn();
}
@@ -1531,15 +1593,15 @@ void LLFloaterWorldMap::onChangeMaturity()
{
bool can_access_mature = gAgent.canAccessMature();
bool can_access_adult = gAgent.canAccessAdult();
-
+
getChildView("events_mature_icon")->setVisible( can_access_mature);
getChildView("events_mature_label")->setVisible( can_access_mature);
getChildView("events_mature_chk")->setVisible( can_access_mature);
-
+
getChildView("events_adult_icon")->setVisible( can_access_adult);
getChildView("events_adult_label")->setVisible( can_access_adult);
getChildView("events_adult_chk")->setVisible( can_access_adult);
-
+
// disable mature / adult events.
if (!can_access_mature)
{
diff --git a/indra/newview/llfloaterworldmap.h b/indra/newview/llfloaterworldmap.h
index 1628a421ec..783d9f4819 100644
--- a/indra/newview/llfloaterworldmap.h
+++ b/indra/newview/llfloaterworldmap.h
@@ -106,6 +106,11 @@ public:
// teleport to the tracked item, if there is one
void teleport();
void onChangeMaturity();
+
+
+ //Slapp instigated avatar tracking
+ void avatarTrackFromSlapp( const LLUUID& id );
+
protected:
void onGoHome();
diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp
index c38cd4d090..3884b94b60 100644
--- a/indra/newview/llfolderview.cpp
+++ b/indra/newview/llfolderview.cpp
@@ -301,18 +301,6 @@ BOOL LLFolderView::canFocusChildren() const
return FALSE;
}
-void LLFolderView::checkTreeResortForModelChanged()
-{
- if (mSortOrder & LLInventoryFilter::SO_DATE && !(mSortOrder & LLInventoryFilter::SO_FOLDERS_BY_NAME))
- {
- // This is the case where something got added or removed. If we are date sorting
- // everything including folders, then we need to rebuild the whole tree.
- // Just set to something not SO_DATE to force the folder most resent date resort.
- mSortOrder = mSortOrder & ~LLInventoryFilter::SO_DATE;
- setSortOrder(mSortOrder | LLInventoryFilter::SO_DATE);
- }
-}
-
static LLFastTimer::DeclareTimer FTM_SORT("Sort Inventory");
void LLFolderView::setSortOrder(U32 order)
@@ -1854,31 +1842,9 @@ BOOL LLFolderView::handleRightMouseDown( S32 x, S32 y, MASK mask )
{
if (mCallbackRegistrar)
mCallbackRegistrar->pushScope();
- //menu->empty();
- const LLView::child_list_t *list = menu->getChildList();
-
- LLView::child_list_t::const_iterator menu_itor;
- for (menu_itor = list->begin(); menu_itor != list->end(); ++menu_itor)
- {
- (*menu_itor)->setVisible(FALSE);
- (*menu_itor)->pushVisible(TRUE);
- (*menu_itor)->setEnabled(TRUE);
- }
-
- // Successively filter out invalid options
- U32 flags = FIRST_SELECTED_ITEM;
- for (selected_items_t::iterator item_itor = mSelectedItems.begin();
- item_itor != mSelectedItems.end();
- ++item_itor)
- {
- LLFolderViewItem* selected_item = (*item_itor);
- selected_item->buildContextMenu(*menu, flags);
- flags = 0x0;
- }
+ updateMenuOptions(menu);
- addNoOptions(menu);
-
menu->updateParent(LLMenuGL::sMenuContainer);
LLMenuGL::showPopup(this, menu, x, y);
if (mCallbackRegistrar)
@@ -2365,6 +2331,45 @@ void LLFolderView::updateRenamerPosition()
}
}
+// Update visibility and availability (i.e. enabled/disabled) of context menu items.
+void LLFolderView::updateMenuOptions(LLMenuGL* menu)
+{
+ const LLView::child_list_t *list = menu->getChildList();
+
+ LLView::child_list_t::const_iterator menu_itor;
+ for (menu_itor = list->begin(); menu_itor != list->end(); ++menu_itor)
+ {
+ (*menu_itor)->setVisible(FALSE);
+ (*menu_itor)->pushVisible(TRUE);
+ (*menu_itor)->setEnabled(TRUE);
+ }
+
+ // Successively filter out invalid options
+
+ U32 flags = FIRST_SELECTED_ITEM;
+ for (selected_items_t::iterator item_itor = mSelectedItems.begin();
+ item_itor != mSelectedItems.end();
+ ++item_itor)
+ {
+ LLFolderViewItem* selected_item = (*item_itor);
+ selected_item->buildContextMenu(*menu, flags);
+ flags = 0x0;
+ }
+
+ addNoOptions(menu);
+}
+
+// Refresh the context menu (that is already shown).
+void LLFolderView::updateMenu()
+{
+ LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get();
+ if (menu && menu->getVisible())
+ {
+ updateMenuOptions(menu);
+ menu->needsArrange(); // update menu height if needed
+ }
+}
+
bool LLFolderView::selectFirstItem()
{
for (folders_t::iterator iter = mFolders.begin();
@@ -2429,6 +2434,7 @@ S32 LLFolderView::notify(const LLSD& info)
{
setFocus(true);
selectFirstItem();
+ scrollToShowSelection();
return 1;
}
@@ -2436,6 +2442,7 @@ S32 LLFolderView::notify(const LLSD& info)
{
setFocus(true);
selectLastItem();
+ scrollToShowSelection();
return 1;
}
}
diff --git a/indra/newview/llfolderview.h b/indra/newview/llfolderview.h
index afaac86b04..1464a058d8 100644
--- a/indra/newview/llfolderview.h
+++ b/indra/newview/llfolderview.h
@@ -101,7 +101,6 @@ public:
// FolderViews default to sort by name. This will change that,
// and resort the items if necessary.
void setSortOrder(U32 order);
- void checkTreeResortForModelChanged();
void setFilterPermMask(PermissionMask filter_perm_mask);
void setAllowMultiSelect(BOOL allow) { mAllowMultiSelect = allow; }
@@ -269,7 +268,10 @@ public:
virtual S32 notify(const LLSD& info) ;
bool useLabelSuffix() { return mUseLabelSuffix; }
+ void updateMenu();
+
private:
+ void updateMenuOptions(LLMenuGL* menu);
void updateRenamerPosition();
protected:
diff --git a/indra/newview/llfolderviewitem.cpp b/indra/newview/llfolderviewitem.cpp
index 3c36248c1f..e9d1ad3a9e 100644
--- a/indra/newview/llfolderviewitem.cpp
+++ b/indra/newview/llfolderviewitem.cpp
@@ -1835,7 +1835,7 @@ void LLFolderViewFolder::sortBy(U32 order)
return;
}
- // Propegate this change to sub folders
+ // Propagate this change to sub folders
for (folders_t::iterator iter = mFolders.begin();
iter != mFolders.end();)
{
diff --git a/indra/newview/llfolderviewitem.h b/indra/newview/llfolderviewitem.h
index 2006e094a8..fc941510ab 100644
--- a/indra/newview/llfolderviewitem.h
+++ b/indra/newview/llfolderviewitem.h
@@ -28,6 +28,7 @@
#include "llview.h"
#include "lldarray.h" // *TODO: Eliminate, forward declare
+#include "lluiimage.h"
class LLFontGL;
class LLFolderView;
diff --git a/indra/newview/llfriendcard.cpp b/indra/newview/llfriendcard.cpp
index e9f1e3bc22..11401d6c68 100644
--- a/indra/newview/llfriendcard.cpp
+++ b/indra/newview/llfriendcard.cpp
@@ -28,6 +28,7 @@
#include "llfriendcard.h"
+#include "llagent.h"
#include "llavatarnamecache.h"
#include "llinventory.h"
#include "llinventoryfunctions.h"
@@ -95,6 +96,36 @@ const LLUUID& get_folder_uuid(const LLUUID& parentFolderUUID, LLInventoryCollect
}
/**
+ * Class LLFindAgentCallingCard
+ *
+ * An inventory collector functor for checking that agent's own calling card
+ * exists within the Calling Cards category and its sub-folders.
+ */
+class LLFindAgentCallingCard : public LLInventoryCollectFunctor
+{
+public:
+ LLFindAgentCallingCard() : mIsAgentCallingCardFound(false) {}
+ virtual ~LLFindAgentCallingCard() {}
+ virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item);
+ bool isAgentCallingCardFound() { return mIsAgentCallingCardFound; }
+
+private:
+ bool mIsAgentCallingCardFound;
+};
+
+bool LLFindAgentCallingCard::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
+{
+ if (mIsAgentCallingCardFound) return true;
+
+ if (item && item->getType() == LLAssetType::AT_CALLINGCARD && item->getCreatorUUID() == gAgentID)
+ {
+ mIsAgentCallingCardFound = true;
+ }
+
+ return mIsAgentCallingCardFound;
+}
+
+/**
* Class for fetching initial friend cards data
*
* Implemented to fix an issue when Inventory folders are in incomplete state.
@@ -290,58 +321,6 @@ void LLFriendCardsManager::syncFriendCardsFolders()
boost::bind(&LLFriendCardsManager::ensureFriendsFolderExists, this));
}
-void LLFriendCardsManager::collectFriendsLists(folderid_buddies_map_t& folderBuddiesMap) const
-{
- folderBuddiesMap.clear();
-
- static bool syncronize_friends_folders = true;
- if (syncronize_friends_folders)
- {
- // Checks whether "Friends" and "Friends/All" folders exist in "Calling Cards" folder,
- // fetches their contents if needed and synchronizes it with buddies list.
- // If the folders are not found they are created.
- LLFriendCardsManager::instance().syncFriendCardsFolders();
- syncronize_friends_folders = false;
- }
-
-
- LLInventoryModel::cat_array_t* listFolders;
- LLInventoryModel::item_array_t* items;
-
- // get folders in the Friend folder. Items should be NULL due to Cards should be in lists.
- gInventory.getDirectDescendentsOf(findFriendFolderUUIDImpl(), listFolders, items);
-
- if (NULL == listFolders)
- return;
-
- LLInventoryModel::cat_array_t::const_iterator itCats; // to iterate Friend Lists (categories)
- LLInventoryModel::item_array_t::const_iterator itBuddy; // to iterate Buddies in each List
- LLInventoryModel::cat_array_t* fakeCatsArg;
- for (itCats = listFolders->begin(); itCats != listFolders->end(); ++itCats)
- {
- if (items)
- items->clear();
-
- // *HACK: Only Friends/All content will be shown for now
- // *TODO: Remove this hack, implement sorting if it will be needded by spec.
- if ((*itCats)->getUUID() != findFriendAllSubfolderUUIDImpl())
- continue;
-
- gInventory.getDirectDescendentsOf((*itCats)->getUUID(), fakeCatsArg, items);
-
- if (NULL == items)
- continue;
-
- uuid_vec_t buddyUUIDs;
- for (itBuddy = items->begin(); itBuddy != items->end(); ++itBuddy)
- {
- buddyUUIDs.push_back((*itBuddy)->getCreatorUUID());
- }
-
- folderBuddiesMap.insert(make_pair((*itCats)->getUUID(), buddyUUIDs));
- }
-}
-
/************************************************************************/
/* Private Methods */
@@ -499,21 +478,31 @@ void LLFriendCardsManager::syncFriendsFolder()
LLAvatarTracker::buddy_map_t all_buddies;
LLAvatarTracker::instance().copyBuddyList(all_buddies);
- // 1. Remove Friend Cards for non-friends
+ // 1. Check if own calling card exists
+ const LLUUID calling_cards_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD);
+
LLInventoryModel::cat_array_t cats;
LLInventoryModel::item_array_t items;
+ LLFindAgentCallingCard collector;
+ gInventory.collectDescendentsIf(calling_cards_folder_id, cats, items, LLInventoryModel::EXCLUDE_TRASH, collector);
- gInventory.collectDescendents(findFriendAllSubfolderUUIDImpl(), cats, items, LLInventoryModel::EXCLUDE_TRASH);
-
- LLInventoryModel::item_array_t::const_iterator it;
- for (it = items.begin(); it != items.end(); ++it)
+ // Create own calling card if it was not found in Friends/All folder
+ if (!collector.isAgentCallingCardFound())
{
- lldebugs << "Check if buddy is in list: " << (*it)->getName() << " " << (*it)->getCreatorUUID() << llendl;
- if (NULL == get_ptr_in_map(all_buddies, (*it)->getCreatorUUID()))
- {
- lldebugs << "NONEXISTS, so remove it" << llendl;
- removeFriendCardFromInventory((*it)->getCreatorUUID());
- }
+ LLAvatarName av_name;
+ LLAvatarNameCache::get( gAgentID, &av_name );
+
+ create_inventory_item(gAgentID,
+ gAgent.getSessionID(),
+ calling_cards_folder_id,
+ LLTransactionID::tnull,
+ av_name.getCompleteName(),
+ gAgentID.asString(),
+ LLAssetType::AT_CALLINGCARD,
+ LLInventoryType::IT_CALLINGCARD,
+ NOT_WEARABLE,
+ PERM_MOVE | PERM_TRANSFER,
+ NULL);
}
// 2. Add missing Friend Cards for friends
diff --git a/indra/newview/llfriendcard.h b/indra/newview/llfriendcard.h
index b7f0bada14..48a9f70079 100644
--- a/indra/newview/llfriendcard.h
+++ b/indra/newview/llfriendcard.h
@@ -79,19 +79,6 @@ public:
*/
void syncFriendCardsFolders();
- /*!
- * \brief
- * Collects folders' IDs with the buddies' IDs in the Inventory Calling Card/Friends folder.
- *
- * \param folderBuddiesMap
- * map into collected data will be put. It will be cleared before adding new data.
- *
- * Each item in the out map is a pair where first is an LLViewerInventoryCategory UUID,
- * second is a vector with UUID of Avatars from this folder.
- *
- */
- void collectFriendsLists(folderid_buddies_map_t& folderBuddiesMap) const;
-
private:
typedef boost::function<void()> callback_t;
diff --git a/indra/newview/llgesturemgr.cpp b/indra/newview/llgesturemgr.cpp
index f658287fb1..2f9856c650 100644
--- a/indra/newview/llgesturemgr.cpp
+++ b/indra/newview/llgesturemgr.cpp
@@ -33,8 +33,10 @@
#include <algorithm>
// library
+#include "llaudioengine.h"
#include "lldatapacker.h"
#include "llinventory.h"
+#include "llkeyframemotion.h"
#include "llmultigesture.h"
#include "llnotificationsutil.h"
#include "llstl.h"
@@ -526,6 +528,66 @@ void LLGestureMgr::playGesture(LLMultiGesture* gesture)
gesture->mPlaying = TRUE;
mPlaying.push_back(gesture);
+ // Load all needed assets to minimize the delays
+ // when gesture is playing.
+ for (std::vector<LLGestureStep*>::iterator steps_it = gesture->mSteps.begin();
+ steps_it != gesture->mSteps.end();
+ ++steps_it)
+ {
+ LLGestureStep* step = *steps_it;
+ switch(step->getType())
+ {
+ case STEP_ANIMATION:
+ {
+ LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step;
+ const LLUUID& anim_id = anim_step->mAnimAssetID;
+
+ // Don't request the animation if this step stops it or if it is already in Static VFS
+ if (!(anim_id.isNull()
+ || anim_step->mFlags & ANIM_FLAG_STOP
+ || gAssetStorage->hasLocalAsset(anim_id, LLAssetType::AT_ANIMATION)))
+ {
+ mLoadingAssets.insert(anim_id);
+
+ LLUUID* id = new LLUUID(gAgentID);
+ gAssetStorage->getAssetData(anim_id,
+ LLAssetType::AT_ANIMATION,
+ onAssetLoadComplete,
+ (void *)id,
+ TRUE);
+ }
+ break;
+ }
+ case STEP_SOUND:
+ {
+ LLGestureStepSound* sound_step = (LLGestureStepSound*)step;
+ const LLUUID& sound_id = sound_step->mSoundAssetID;
+ if (!(sound_id.isNull()
+ || gAssetStorage->hasLocalAsset(sound_id, LLAssetType::AT_SOUND)))
+ {
+ mLoadingAssets.insert(sound_id);
+
+ gAssetStorage->getAssetData(sound_id,
+ LLAssetType::AT_SOUND,
+ onAssetLoadComplete,
+ NULL,
+ TRUE);
+ }
+ break;
+ }
+ case STEP_CHAT:
+ case STEP_WAIT:
+ case STEP_EOF:
+ {
+ break;
+ }
+ default:
+ {
+ llwarns << "Unknown gesture step type: " << step->getType() << llendl;
+ }
+ }
+ }
+
// And get it going
stepGesture(gesture);
@@ -741,7 +803,7 @@ void LLGestureMgr::stepGesture(LLMultiGesture* gesture)
{
return;
}
- if (!isAgentAvatarValid()) return;
+ if (!isAgentAvatarValid() || hasLoadingAssets(gesture)) return;
// Of the ones that started playing, have any stopped?
@@ -1091,6 +1153,98 @@ void LLGestureMgr::onLoadComplete(LLVFS *vfs,
}
}
+// static
+void LLGestureMgr::onAssetLoadComplete(LLVFS *vfs,
+ const LLUUID& asset_uuid,
+ LLAssetType::EType type,
+ void* user_data, S32 status, LLExtStat ext_status)
+{
+ LLGestureMgr& self = LLGestureMgr::instance();
+
+ // Complete the asset loading process depending on the type and
+ // remove the asset id from pending downloads list.
+ switch(type)
+ {
+ case LLAssetType::AT_ANIMATION:
+ {
+ LLKeyframeMotion::onLoadComplete(vfs, asset_uuid, type, user_data, status, ext_status);
+
+ self.mLoadingAssets.erase(asset_uuid);
+
+ break;
+ }
+ case LLAssetType::AT_SOUND:
+ {
+ LLAudioEngine::assetCallback(vfs, asset_uuid, type, user_data, status, ext_status);
+
+ self.mLoadingAssets.erase(asset_uuid);
+
+ break;
+ }
+ default:
+ {
+ llwarns << "Unexpected asset type: " << type << llendl;
+
+ // We don't want to return from this callback without
+ // an animation or sound callback being fired
+ // and *user_data handled to avoid memory leaks.
+ llassert(type == LLAssetType::AT_ANIMATION || type == LLAssetType::AT_SOUND);
+ }
+ }
+}
+
+// static
+bool LLGestureMgr::hasLoadingAssets(LLMultiGesture* gesture)
+{
+ LLGestureMgr& self = LLGestureMgr::instance();
+
+ for (std::vector<LLGestureStep*>::iterator steps_it = gesture->mSteps.begin();
+ steps_it != gesture->mSteps.end();
+ ++steps_it)
+ {
+ LLGestureStep* step = *steps_it;
+ switch(step->getType())
+ {
+ case STEP_ANIMATION:
+ {
+ LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step;
+ const LLUUID& anim_id = anim_step->mAnimAssetID;
+
+ if (!(anim_id.isNull()
+ || anim_step->mFlags & ANIM_FLAG_STOP
+ || self.mLoadingAssets.find(anim_id) == self.mLoadingAssets.end()))
+ {
+ return true;
+ }
+ break;
+ }
+ case STEP_SOUND:
+ {
+ LLGestureStepSound* sound_step = (LLGestureStepSound*)step;
+ const LLUUID& sound_id = sound_step->mSoundAssetID;
+
+ if (!(sound_id.isNull()
+ || self.mLoadingAssets.find(sound_id) == self.mLoadingAssets.end()))
+ {
+ return true;
+ }
+ break;
+ }
+ case STEP_CHAT:
+ case STEP_WAIT:
+ case STEP_EOF:
+ {
+ break;
+ }
+ default:
+ {
+ llwarns << "Unknown gesture step type: " << step->getType() << llendl;
+ }
+ }
+ }
+
+ return false;
+}
void LLGestureMgr::stopGesture(LLMultiGesture* gesture)
{
diff --git a/indra/newview/llgesturemgr.h b/indra/newview/llgesturemgr.h
index b9935efeb3..5930841cbc 100644
--- a/indra/newview/llgesturemgr.h
+++ b/indra/newview/llgesturemgr.h
@@ -154,9 +154,20 @@ protected:
// Used by loadGesture
static void onLoadComplete(LLVFS *vfs,
- const LLUUID& asset_uuid,
- LLAssetType::EType type,
- void* user_data, S32 status, LLExtStat ext_status);
+ const LLUUID& asset_uuid,
+ LLAssetType::EType type,
+ void* user_data, S32 status, LLExtStat ext_status);
+
+ // Used by playGesture to load an asset file
+ // required to play a gesture step
+ static void onAssetLoadComplete(LLVFS *vfs,
+ const LLUUID& asset_uuid,
+ LLAssetType::EType type,
+ void* user_data, S32 status, LLExtStat ext_status);
+
+ // Checks whether all animation and sound assets
+ // needed to play a gesture are loaded.
+ static bool hasLoadingAssets(LLMultiGesture* gesture);
private:
// Active gestures.
@@ -172,6 +183,8 @@ private:
callback_map_t mCallbackMap;
std::vector<LLMultiGesture*> mPlaying;
BOOL mValid;
+
+ std::set<LLUUID> mLoadingAssets;
};
#endif
diff --git a/indra/newview/llgiveinventory.cpp b/indra/newview/llgiveinventory.cpp
index 260e15c714..30858871ec 100644
--- a/indra/newview/llgiveinventory.cpp
+++ b/indra/newview/llgiveinventory.cpp
@@ -128,7 +128,7 @@ bool LLGiveInventory::isInventoryGiveAcceptable(const LLInventoryItem* item)
switch(item->getType())
{
case LLAssetType::AT_OBJECT:
- if (gAgentAvatarp->isWearingAttachment(item->getUUID()))
+ if (get_is_item_worn(item->getUUID()))
{
acceptable = false;
}
@@ -139,7 +139,7 @@ bool LLGiveInventory::isInventoryGiveAcceptable(const LLInventoryItem* item)
BOOL copyable = false;
if (item->getPermissions().allowCopyBy(gAgentID)) copyable = true;
- if (!copyable && gAgentWearables.isWearingItem(item->getUUID()))
+ if (!copyable && get_is_item_worn(item->getUUID()))
{
acceptable = false;
}
@@ -311,6 +311,9 @@ void LLGiveInventory::logInventoryOffer(const LLUUID& to_agent, const LLUUID &im
std::string full_name;
if (gCacheName->getFullName(to_agent, full_name))
{
+ // Build a new format username or firstname_lastname for legacy names
+ // to use it for a history log filename.
+ full_name = LLCacheName::buildUsername(full_name);
LLIMModel::instance().logToFile(full_name, LLTrans::getString("SECOND_LIFE"), im_session_id, LLTrans::getString("inventory_item_offered-im"));
}
}
diff --git a/indra/newview/llglsandbox.cpp b/indra/newview/llglsandbox.cpp
index d43b3a5d6e..842911ecc0 100644
--- a/indra/newview/llglsandbox.cpp
+++ b/indra/newview/llglsandbox.cpp
@@ -663,35 +663,27 @@ void LLViewerParcelMgr::renderCollisionSegments(U8* segments, BOOL use_pass, LLV
x2 = x1 + PARCEL_GRID_STEP_METERS;
y2 = y1;
- if (gRenderForSelect)
- {
- LLColor4U color((U8)(GL_NAME_PARCEL_WALL >> 16), (U8)(GL_NAME_PARCEL_WALL >> 8), (U8)GL_NAME_PARCEL_WALL);
- gGL.color4ubv(color.mV);
- }
- else
- {
- dy = (pos_y - y1) + DIST_OFFSET;
-
- if (pos_x < x1)
- dx = pos_x - x1;
- else if (pos_x > x2)
- dx = pos_x - x2;
- else
- dx = 0;
+ dy = (pos_y - y1) + DIST_OFFSET;
- dist = dx*dx+dy*dy;
-
- if (dist < MIN_DIST_SQ)
- alpha = MAX_ALPHA;
- else if (dist > MAX_DIST_SQ)
- alpha = 0.0f;
- else
- alpha = 30/dist;
-
- alpha = llclamp(alpha, 0.0f, MAX_ALPHA);
-
- gGL.color4f(1.f, 1.f, 1.f, alpha);
- }
+ if (pos_x < x1)
+ dx = pos_x - x1;
+ else if (pos_x > x2)
+ dx = pos_x - x2;
+ else
+ dx = 0;
+
+ dist = dx*dx+dy*dy;
+
+ if (dist < MIN_DIST_SQ)
+ alpha = MAX_ALPHA;
+ else if (dist > MAX_DIST_SQ)
+ alpha = 0.0f;
+ else
+ alpha = 30/dist;
+
+ alpha = llclamp(alpha, 0.0f, MAX_ALPHA);
+
+ gGL.color4f(1.f, 1.f, 1.f, alpha);
if ((pos_y - y1) < 0) direction = SOUTH_MASK;
else direction = NORTH_MASK;
@@ -709,35 +701,27 @@ void LLViewerParcelMgr::renderCollisionSegments(U8* segments, BOOL use_pass, LLV
x2 = x1;
y2 = y1 + PARCEL_GRID_STEP_METERS;
- if (gRenderForSelect)
- {
- LLColor4U color((U8)(GL_NAME_PARCEL_WALL >> 16), (U8)(GL_NAME_PARCEL_WALL >> 8), (U8)GL_NAME_PARCEL_WALL);
- gGL.color4ubv(color.mV);
- }
+ dx = (pos_x - x1) + DIST_OFFSET;
+
+ if (pos_y < y1)
+ dy = pos_y - y1;
+ else if (pos_y > y2)
+ dy = pos_y - y2;
+ else
+ dy = 0;
+
+ dist = dx*dx+dy*dy;
+
+ if (dist < MIN_DIST_SQ)
+ alpha = MAX_ALPHA;
+ else if (dist > MAX_DIST_SQ)
+ alpha = 0.0f;
else
- {
- dx = (pos_x - x1) + DIST_OFFSET;
-
- if (pos_y < y1)
- dy = pos_y - y1;
- else if (pos_y > y2)
- dy = pos_y - y2;
- else
- dy = 0;
-
- dist = dx*dx+dy*dy;
-
- if (dist < MIN_DIST_SQ)
- alpha = MAX_ALPHA;
- else if (dist > MAX_DIST_SQ)
- alpha = 0.0f;
- else
- alpha = 30/dist;
-
- alpha = llclamp(alpha, 0.0f, MAX_ALPHA);
+ alpha = 30/dist;
+
+ alpha = llclamp(alpha, 0.0f, MAX_ALPHA);
- gGL.color4f(1.f, 1.f, 1.f, alpha);
- }
+ gGL.color4f(1.f, 1.f, 1.f, alpha);
if ((pos_x - x1) > 0) direction = WEST_MASK;
else direction = EAST_MASK;
diff --git a/indra/newview/llgroupactions.cpp b/indra/newview/llgroupactions.cpp
index 5393678a6b..97fa551441 100644
--- a/indra/newview/llgroupactions.cpp
+++ b/indra/newview/llgroupactions.cpp
@@ -40,10 +40,12 @@
#include "llsidetray.h"
#include "llstatusbar.h" // can_afford_transaction()
#include "llimfloater.h"
+#include "groupchatlistener.h"
//
// Globals
//
+static GroupChatListener sGroupChatListener;
class LLGroupHandler : public LLCommandHandler
{
@@ -53,6 +55,12 @@ public:
bool handle(const LLSD& tokens, const LLSD& query_map,
LLMediaCtrl* web)
{
+ if (!LLUI::sSettingGroups["config"]->getBOOL("EnableGroupInfo"))
+ {
+ LLNotificationsUtil::add("NoGroupInfo", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit"));
+ return true;
+ }
+
if (tokens.size() < 1)
{
return false;
@@ -314,10 +322,9 @@ void LLGroupActions::closeGroup(const LLUUID& group_id)
// static
-void LLGroupActions::startIM(const LLUUID& group_id)
+LLUUID LLGroupActions::startIM(const LLUUID& group_id)
{
- if (group_id.isNull())
- return;
+ if (group_id.isNull()) return LLUUID::null;
LLGroupData group_data;
if (gAgent.getGroupData(group_id, group_data))
@@ -331,12 +338,14 @@ void LLGroupActions::startIM(const LLUUID& group_id)
LLIMFloater::show(session_id);
}
make_ui_sound("UISndStartIM");
+ return session_id;
}
else
{
// this should never happen, as starting a group IM session
// relies on you belonging to the group and hence having the group data
make_ui_sound("UISndInvalidOp");
+ return LLUUID::null;
}
}
diff --git a/indra/newview/llgroupactions.h b/indra/newview/llgroupactions.h
index c52a25818b..3f9852f194 100644
--- a/indra/newview/llgroupactions.h
+++ b/indra/newview/llgroupactions.h
@@ -87,7 +87,7 @@ public:
/**
* Start group instant messaging session.
*/
- static void startIM(const LLUUID& group_id);
+ static LLUUID startIM(const LLUUID& group_id);
/**
* End group instant messaging session.
diff --git a/indra/newview/llgroupmgr.cpp b/indra/newview/llgroupmgr.cpp
index 7546c070ea..ce936a9924 100644
--- a/indra/newview/llgroupmgr.cpp
+++ b/indra/newview/llgroupmgr.cpp
@@ -52,6 +52,7 @@
#include <boost/regex.hpp>
#if LL_MSVC
+#pragma warning(push)
// disable boost::lexical_cast warning
#pragma warning (disable:4702)
#endif
diff --git a/indra/newview/llhints.cpp b/indra/newview/llhints.cpp
index 3f0deb98cd..e15862e2a4 100644
--- a/indra/newview/llhints.cpp
+++ b/indra/newview/llhints.cpp
@@ -33,6 +33,7 @@
#include "lltextbox.h"
#include "llviewerwindow.h"
#include "llviewercontrol.h"
+#include "lliconctrl.h"
#include "llsdparam.h"
class LLHintPopup : public LLPanel
@@ -80,7 +81,8 @@ public:
up_arrow,
right_arrow,
down_arrow,
- lower_left_arrow;
+ lower_left_arrow,
+ hint_image;
Optional<S32> left_arrow_offset,
up_arrow_offset,
@@ -96,6 +98,7 @@ public:
right_arrow("right_arrow"),
down_arrow("down_arrow"),
lower_left_arrow("lower_left_arrow"),
+ hint_image("hint_image"),
left_arrow_offset("left_arrow_offset"),
up_arrow_offset("up_arrow_offset"),
right_arrow_offset("right_arrow_offset"),
@@ -166,7 +169,15 @@ LLHintPopup::LLHintPopup(const LLHintPopup::Params& p)
mDirection = p.target_params.direction;
mTarget = p.target_params.target;
}
- buildFromFile( "panel_hint.xml", NULL, p);
+ if (p.hint_image.isProvided())
+ {
+ buildFromFile("panel_hint_image.xml", NULL, p);
+ getChild<LLIconCtrl>("hint_image")->setImage(p.hint_image());
+ }
+ else
+ {
+ buildFromFile( "panel_hint.xml", NULL, p);
+ }
}
BOOL LLHintPopup::postBuild()
@@ -180,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;
}
@@ -200,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/llhudeffectblob.cpp b/indra/newview/llhudeffectblob.cpp
new file mode 100644
index 0000000000..d8687eed8d
--- /dev/null
+++ b/indra/newview/llhudeffectblob.cpp
@@ -0,0 +1,90 @@
+/**
+ * @file llhudeffecttrail.cpp
+ * @brief LLHUDEffectSpiral class implementation
+ *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llhudeffectblob.h"
+
+#include "llagent.h"
+#include "llviewercamera.h"
+#include "llui.h"
+
+LLHUDEffectBlob::LLHUDEffectBlob(const U8 type)
+: LLHUDEffect(type),
+ mPixelSize(10)
+{
+ mTimer.start();
+ mImage = LLUI::getUIImage("Camera_Drag_Dot");
+}
+
+LLHUDEffectBlob::~LLHUDEffectBlob()
+{
+}
+
+void LLHUDEffectBlob::render()
+{
+ F32 time = mTimer.getElapsedTimeF32();
+ if (mDuration < time)
+ {
+ markDead();
+ }
+
+ LLVector3 pos_agent = gAgent.getPosAgentFromGlobal(mPositionGlobal);
+
+ LLVector3 pixel_up, pixel_right;
+
+ LLViewerCamera::instance().getPixelVectors(pos_agent, pixel_up, pixel_right);
+
+ LLGLSPipelineAlpha gls_pipeline_alpha;
+ gGL.getTexUnit(0)->bind(mImage->getImage());
+
+ LLColor4U color = mColor;
+ color.mV[VALPHA] = (U8)clamp_rescale(time, 0.f, mDuration, 255.f, 0.f);
+ gGL.color4ubv(color.mV);
+
+ { gGL.pushMatrix();
+ gGL.translatef(pos_agent.mV[0], pos_agent.mV[1], pos_agent.mV[2]);
+ LLVector3 u_scale = pixel_right * (F32)mPixelSize;
+ LLVector3 v_scale = pixel_up * (F32)mPixelSize;
+
+ { gGL.begin(LLRender::QUADS);
+ gGL.texCoord2f(0.f, 1.f);
+ gGL.vertex3fv((v_scale - u_scale).mV);
+ gGL.texCoord2f(0.f, 0.f);
+ gGL.vertex3fv((-v_scale - u_scale).mV);
+ gGL.texCoord2f(1.f, 0.f);
+ gGL.vertex3fv((-v_scale + u_scale).mV);
+ gGL.texCoord2f(1.f, 1.f);
+ gGL.vertex3fv((v_scale + u_scale).mV);
+ } gGL.end();
+
+ } gGL.popMatrix();
+}
+
+void LLHUDEffectBlob::renderForTimer()
+{
+}
+
diff --git a/indra/newview/llhudeffectblob.h b/indra/newview/llhudeffectblob.h
new file mode 100644
index 0000000000..f4c1691108
--- /dev/null
+++ b/indra/newview/llhudeffectblob.h
@@ -0,0 +1,52 @@
+/**
+ * @file llhudeffectblob.h
+ * @brief LLHUDEffectBlob class definition
+ *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLHUDEFFECTBLOB_H
+#define LL_LLHUDEFFECTBLOB_H
+
+#include "llhudeffect.h"
+#include "lluiimage.h"
+
+class LLHUDEffectBlob : public LLHUDEffect
+{
+public:
+ friend class LLHUDObject;
+
+ void setPixelSize(S32 pixels) { mPixelSize = pixels; }
+
+protected:
+ LLHUDEffectBlob(const U8 type);
+ ~LLHUDEffectBlob();
+
+ /*virtual*/ void render();
+ /*virtual*/ void renderForTimer();
+private:
+ S32 mPixelSize;
+ LLFrameTimer mTimer;
+ LLPointer<LLUIImage> mImage;
+};
+
+#endif // LL_LLHUDEFFECTBLOB_H
diff --git a/indra/newview/llhudeffectlookat.cpp b/indra/newview/llhudeffectlookat.cpp
index 8cf7d23f88..b380b3fe20 100644
--- a/indra/newview/llhudeffectlookat.cpp
+++ b/indra/newview/llhudeffectlookat.cpp
@@ -56,7 +56,7 @@ const S32 PKT_SIZE = 57;
// throttle
const F32 MAX_SENDS_PER_SEC = 4.f;
-const F32 MIN_DELTAPOS_FOR_UPDATE = 0.05f;
+const F32 MIN_DELTAPOS_FOR_UPDATE_SQUARED = 0.05f * 0.05f;
const F32 MIN_TARGET_OFFSET_SQUARED = 0.0001f;
@@ -416,7 +416,7 @@ BOOL LLHUDEffectLookAt::setLookAt(ELookAtType target_type, LLViewerObject *objec
BOOL lookAtChanged = (target_type != mTargetType) || (object != mTargetObject);
// lookat position has moved a certain amount and we haven't just sent an update
- lookAtChanged = lookAtChanged || ((dist_vec(position, mLastSentOffsetGlobal) > MIN_DELTAPOS_FOR_UPDATE) &&
+ lookAtChanged = lookAtChanged || ((dist_vec_squared(position, mLastSentOffsetGlobal) > MIN_DELTAPOS_FOR_UPDATE_SQUARED) &&
((current_time - mLastSendTime) > (1.f / MAX_SENDS_PER_SEC)));
if (lookAtChanged)
@@ -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/llhudeffectpointat.cpp b/indra/newview/llhudeffectpointat.cpp
index bfb0f150b3..28fe8e1c01 100644
--- a/indra/newview/llhudeffectpointat.cpp
+++ b/indra/newview/llhudeffectpointat.cpp
@@ -48,7 +48,7 @@ const S32 PKT_SIZE = 57;
// throttle
const F32 MAX_SENDS_PER_SEC = 4.f;
-const F32 MIN_DELTAPOS_FOR_UPDATE = 0.05f;
+const F32 MIN_DELTAPOS_FOR_UPDATE_SQUARED = 0.05f * 0.05f;
// timeouts
// can't use actual F32_MAX, because we add this to the current frametime
@@ -244,7 +244,7 @@ BOOL LLHUDEffectPointAt::setPointAt(EPointAtType target_type, LLViewerObject *ob
BOOL targetTypeChanged = (target_type != mTargetType) ||
(object != mTargetObject);
- BOOL targetPosChanged = (dist_vec(position, mLastSentOffsetGlobal) > MIN_DELTAPOS_FOR_UPDATE) &&
+ BOOL targetPosChanged = (dist_vec_squared(position, mLastSentOffsetGlobal) > MIN_DELTAPOS_FOR_UPDATE_SQUARED) &&
((current_time - mLastSendTime) > (1.f / MAX_SENDS_PER_SEC));
if (targetTypeChanged || targetPosChanged)
diff --git a/indra/newview/llhudicon.cpp b/indra/newview/llhudicon.cpp
index aea8c5928b..7e1025c41b 100644
--- a/indra/newview/llhudicon.cpp
+++ b/indra/newview/llhudicon.cpp
@@ -33,6 +33,7 @@
#include "llviewerobject.h"
#include "lldrawable.h"
+#include "llvector4a.h"
#include "llviewercamera.h"
#include "llviewertexture.h"
#include "llviewerwindow.h"
@@ -201,11 +202,6 @@ void LLHUDIcon::render()
renderIcon(FALSE);
}
-void LLHUDIcon::renderForSelect()
-{
- renderIcon(TRUE);
-}
-
BOOL LLHUDIcon::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, LLVector3* intersection)
{
if (mHidden)
@@ -260,21 +256,42 @@ BOOL LLHUDIcon::lineSegmentIntersect(const LLVector3& start, const LLVector3& en
LLVector3 x_scale = image_aspect * (F32)gViewerWindow->getWindowHeightScaled() * mScale * scale_factor * x_pixel_vec;
LLVector3 y_scale = (F32)gViewerWindow->getWindowHeightScaled() * mScale * scale_factor * y_pixel_vec;
- LLVector3 lower_left = icon_position - (x_scale * 0.5f);
- LLVector3 lower_right = icon_position + (x_scale * 0.5f);
- LLVector3 upper_left = icon_position - (x_scale * 0.5f) + y_scale;
- LLVector3 upper_right = icon_position + (x_scale * 0.5f) + y_scale;
+ LLVector4a x_scalea;
+ LLVector4a icon_positiona;
+ LLVector4a y_scalea;
-
- F32 t = 0.f;
- LLVector3 dir = end-start;
+ x_scalea.load3(x_scale.mV);
+ x_scalea.mul(0.5f);
+ y_scalea.load3(y_scale.mV);
+
+ icon_positiona.load3(icon_position.mV);
+
+ LLVector4a lower_left;
+ lower_left.setSub(icon_positiona, x_scalea);
+ LLVector4a lower_right;
+ lower_right.setAdd(icon_positiona, x_scalea);
+ LLVector4a upper_left;
+ upper_left.setAdd(lower_left, y_scalea);
+ LLVector4a upper_right;
+ upper_right.setAdd(lower_right, y_scalea);
+
+ LLVector4a enda;
+ enda.load3(end.mV);
+ LLVector4a starta;
+ starta.load3(start.mV);
+ LLVector4a dir;
+ dir.setSub(enda, starta);
+
+ F32 a,b,t;
- if (LLTriangleRayIntersect(upper_right, upper_left, lower_right, start, dir, NULL, NULL, &t, FALSE) ||
- LLTriangleRayIntersect(upper_left, lower_left, lower_right, start, dir, NULL, NULL, &t, FALSE))
+ if (LLTriangleRayIntersect(upper_right, upper_left, lower_right, starta, dir, a,b,t) ||
+ LLTriangleRayIntersect(upper_left, lower_left, lower_right, starta, dir, a,b,t))
{
if (intersection)
{
- *intersection = start + dir*t;
+ dir.mul(t);
+ starta.add(dir);
+ *intersection = LLVector3(starta.getF32ptr());
}
return TRUE;
}
diff --git a/indra/newview/llhudicon.h b/indra/newview/llhudicon.h
index 8d7b8d4288..644daa0299 100644
--- a/indra/newview/llhudicon.h
+++ b/indra/newview/llhudicon.h
@@ -52,7 +52,6 @@ friend class LLHUDObject;
public:
/*virtual*/ void render();
- /*virtual*/ void renderForSelect();
/*virtual*/ void markDead();
/*virtual*/ F32 getDistance() const { return mDistance; }
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/llhudnametag.cpp b/indra/newview/llhudnametag.cpp
index fc758569e4..82e1f2dfb5 100644
--- a/indra/newview/llhudnametag.cpp
+++ b/indra/newview/llhudnametag.cpp
@@ -146,24 +146,43 @@ BOOL LLHUDNameTag::lineSegmentIntersect(const LLVector3& start, const LLVector3&
mOffsetY = lltrunc(mHeight * ((mVertAlignment == ALIGN_VERT_CENTER) ? 0.5f : 1.f));
+ LLVector3 position = mPositionAgent;
+
+ if (mSourceObject)
+ { //get intersection of eye through mPositionAgent to plane of source object
+ //using this position keeps the camera from focusing on some seemingly random
+ //point several meters in front of the nametag
+ const LLVector3& p = mSourceObject->getPositionAgent();
+ const LLVector3& n = LLViewerCamera::getInstance()->getAtAxis();
+ const LLVector3& eye = LLViewerCamera::getInstance()->getOrigin();
+
+ LLVector3 ray = position-eye;
+ ray.normalize();
+
+ LLVector3 delta = p-position;
+ F32 dist = delta*n;
+ F32 dt = dist/(ray*n);
+ position += ray*dt;
+ }
+
// scale screen size of borders down
//RN: for now, text on hud objects is never occluded
LLVector3 x_pixel_vec;
LLVector3 y_pixel_vec;
- LLViewerCamera::getInstance()->getPixelVectors(mPositionAgent, y_pixel_vec, x_pixel_vec);
+ LLViewerCamera::getInstance()->getPixelVectors(position, y_pixel_vec, x_pixel_vec);
LLVector3 width_vec = mWidth * x_pixel_vec;
LLVector3 height_vec = mHeight * y_pixel_vec;
LLCoordGL screen_pos;
- LLViewerCamera::getInstance()->projectPosAgentToScreen(mPositionAgent, screen_pos, FALSE);
+ LLViewerCamera::getInstance()->projectPosAgentToScreen(position, screen_pos, FALSE);
LLVector2 screen_offset;
screen_offset = updateScreenPos(mPositionOffset);
- LLVector3 render_position = mPositionAgent
+ LLVector3 render_position = position
+ (x_pixel_vec * screen_offset.mV[VX])
+ (y_pixel_vec * screen_offset.mV[VY]);
@@ -197,10 +216,10 @@ BOOL LLHUDNameTag::lineSegmentIntersect(const LLVector3& start, const LLVector3&
}
LLVector3 dir = end-start;
- F32 t = 0.f;
+ F32 a, b, t;
- if (LLTriangleRayIntersect(v[0], v[1], v[2], start, dir, NULL, NULL, &t, FALSE) ||
- LLTriangleRayIntersect(v[2], v[3], v[0], start, dir, NULL, NULL, &t, FALSE) )
+ if (LLTriangleRayIntersect(v[0], v[1], v[2], start, dir, a, b, t, FALSE) ||
+ LLTriangleRayIntersect(v[2], v[3], v[0], start, dir, a, b, t, FALSE) )
{
if (t <= 1.f)
{
diff --git a/indra/newview/llhudobject.cpp b/indra/newview/llhudobject.cpp
index 09200ee5be..95d57d08d8 100644
--- a/indra/newview/llhudobject.cpp
+++ b/indra/newview/llhudobject.cpp
@@ -32,6 +32,7 @@
#include "llhudtext.h"
#include "llhudicon.h"
#include "llhudeffectbeam.h"
+#include "llhudeffectblob.h"
#include "llhudeffecttrail.h"
#include "llhudeffectlookat.h"
#include "llhudeffectpointat.h"
@@ -237,6 +238,9 @@ LLHUDEffect *LLHUDObject::addHUDEffect(const U8 type)
case LL_HUD_EFFECT_POINTAT:
hud_objectp = new LLHUDEffectPointAt(type);
break;
+ case LL_HUD_EFFECT_BLOB:
+ hud_objectp = new LLHUDEffectBlob(type);
+ break;
default:
llwarns << "Unknown type of hud effect:" << (U32) type << llendl;
}
@@ -284,27 +288,6 @@ void LLHUDObject::renderAll()
}
// static
-void LLHUDObject::renderAllForSelect()
-{
- LLHUDObject *hud_objp;
-
- hud_object_list_t::iterator object_it;
- for (object_it = sHUDObjects.begin(); object_it != sHUDObjects.end(); )
- {
- hud_object_list_t::iterator cur_it = object_it++;
- hud_objp = (*cur_it);
- if (hud_objp->getNumRefs() == 1)
- {
- sHUDObjects.erase(cur_it);
- }
- else if (hud_objp->isVisible())
- {
- hud_objp->renderForSelect();
- }
- }
-}
-
-// static
void LLHUDObject::renderAllForTimer()
{
LLHUDObject *hud_objp;
diff --git a/indra/newview/llhudobject.h b/indra/newview/llhudobject.h
index 4282ade34d..2f7a98c86c 100644
--- a/indra/newview/llhudobject.h
+++ b/indra/newview/llhudobject.h
@@ -95,7 +95,8 @@ public:
LL_HUD_EFFECT_LOOKAT,
LL_HUD_EFFECT_POINTAT,
LL_HUD_EFFECT_VOICE_VISUALIZER, // Ventrella
- LL_HUD_NAME_TAG
+ LL_HUD_NAME_TAG,
+ LL_HUD_EFFECT_BLOB
};
protected:
static void sortObjects();
@@ -104,7 +105,6 @@ protected:
~LLHUDObject();
virtual void render() = 0;
- virtual void renderForSelect() {};
virtual void renderForTimer() {};
protected:
diff --git a/indra/newview/llhudtext.cpp b/indra/newview/llhudtext.cpp
index 6a423e529a..24a876c59a 100644
--- a/indra/newview/llhudtext.cpp
+++ b/indra/newview/llhudtext.cpp
@@ -113,36 +113,21 @@ void LLHUDText::render()
if (!mOnHUDAttachment && sDisplayText)
{
LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
- renderText(FALSE);
+ renderText();
}
}
-void LLHUDText::renderForSelect()
-{
- if (!mOnHUDAttachment)
- {
- LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
- renderText(TRUE);
- }
-}
-
-void LLHUDText::renderText(BOOL for_select)
+void LLHUDText::renderText()
{
if (!mVisible || mHidden)
{
return;
}
- // don't pick text
- if (for_select)
- {
- return;
- }
-
gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
- LLGLState gls_blend(GL_BLEND, for_select ? FALSE : TRUE);
- LLGLState gls_alpha(GL_ALPHA_TEST, for_select ? FALSE : TRUE);
+ LLGLState gls_blend(GL_BLEND, TRUE);
+ LLGLState gls_alpha(GL_ALPHA_TEST, TRUE);
LLColor4 shadow_color(0.f, 0.f, 0.f, 1.f);
F32 alpha_factor = 1.f;
@@ -209,9 +194,6 @@ void LLHUDText::renderText(BOOL for_select)
mRadius = (width_vec + height_vec).magVec() * 0.5f;
- LLCoordGL screen_pos;
- LLViewerCamera::getInstance()->projectPosAgentToScreen(mPositionAgent, screen_pos, FALSE);
-
LLVector2 screen_offset;
screen_offset = mPositionOffset;
@@ -594,7 +576,7 @@ void LLHUDText::renderAllHUD()
for (text_it = sVisibleHUDTextObjects.begin(); text_it != sVisibleHUDTextObjects.end(); ++text_it)
{
- (*text_it)->renderText(FALSE);
+ (*text_it)->renderText();
}
}
diff --git a/indra/newview/llhudtext.h b/indra/newview/llhudtext.h
index f05ee4d594..36015d51f0 100644
--- a/indra/newview/llhudtext.h
+++ b/indra/newview/llhudtext.h
@@ -128,8 +128,7 @@ protected:
LLHUDText(const U8 type);
/*virtual*/ void render();
- /*virtual*/ void renderForSelect();
- void renderText(BOOL for_select);
+ void renderText();
static void updateAll();
S32 getMaxLines();
diff --git a/indra/newview/llimfloater.cpp b/indra/newview/llimfloater.cpp
index e000abda2a..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) );
@@ -470,7 +473,7 @@ LLIMFloater* LLIMFloater::show(const LLUUID& session_id)
}
//static
-bool LLIMFloater::resetAllowedRectPadding(const LLSD& newvalue)
+bool LLIMFloater::resetAllowedRectPadding()
{
//reset allowed rect right padding if "SidebarCameraMovement" option
//or sidebar state changed
@@ -482,10 +485,10 @@ void LLIMFloater::getAllowedRect(LLRect& rect)
{
if (sAllowedRectRightPadding == RECT_PADDING_NOT_INIT) //wasn't initialized
{
- gSavedSettings.getControl("SidebarCameraMovement")->getSignal()->connect(boost::bind(&LLIMFloater::resetAllowedRectPadding, _2));
+ gSavedSettings.getControl("SidebarCameraMovement")->getSignal()->connect(boost::bind(&LLIMFloater::resetAllowedRectPadding));
LLSideTray* side_bar = LLSideTray::getInstance();
- side_bar->getCollapseSignal().connect(boost::bind(&LLIMFloater::resetAllowedRectPadding, _2));
+ side_bar->setVisibleWidthChangeCallback(boost::bind(&LLIMFloater::resetAllowedRectPadding));
sAllowedRectRightPadding = RECT_PADDING_NEED_RECALC;
}
@@ -500,10 +503,7 @@ void LLIMFloater::getAllowedRect(LLRect& rect)
if (gSavedSettings.getBOOL("SidebarCameraMovement") == FALSE)
{
- LLSideTray* side_bar = LLSideTray::getInstance();
-
- if (side_bar->getVisible() && !side_bar->getCollapsed())
- sAllowedRectRightPadding += side_bar->getRect().getWidth();
+ sAllowedRectRightPadding += LLSideTray::getInstance()->getVisibleWidth();
}
}
rect.mRight -= sAllowedRectRightPadding;
@@ -680,8 +680,6 @@ void LLIMFloater::updateMessages()
if (messages.size())
{
-// LLUIColor chat_color = LLUIColorTable::instance().getColor("IMChatColor");
-
LLSD chat_args;
chat_args["use_plain_text_chat_history"] = use_plain_text_chat_history;
@@ -896,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)
@@ -904,6 +903,7 @@ void LLIMFloater::processChatHistoryStyleUpdate(const LLSD& newvalue)
if (floater)
{
floater->updateChatHistoryStyle();
+ floater->mInputEditor->setFont(font);
}
}
diff --git a/indra/newview/llimfloater.h b/indra/newview/llimfloater.h
index e80e45e64a..5158f6c1f7 100644
--- a/indra/newview/llimfloater.h
+++ b/indra/newview/llimfloater.h
@@ -156,7 +156,7 @@ private:
static void closeHiddenIMToasts();
- static bool resetAllowedRectPadding(const LLSD& newvalue);
+ static bool resetAllowedRectPadding();
//need to keep this static for performance issues
static S32 sAllowedRectRightPadding;
diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp
index 02a693b9a0..4de6976534 100644
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -131,6 +131,20 @@ void toast_callback(const LLSD& msg){
return;
}
+ // *NOTE Skip toasting if the user disable it in preferences/debug settings ~Alexandrea
+ LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(
+ msg["session_id"]);
+ if (!gSavedSettings.getBOOL("EnableGroupChatPopups")
+ && session->isGroupSessionType())
+ {
+ return;
+ }
+ if (!gSavedSettings.getBOOL("EnableIMChatPopups")
+ && !session->isGroupSessionType())
+ {
+ return;
+ }
+
// Skip toasting if we have open window of IM with this session id
LLIMFloater* open_im_floater = LLIMFloater::findInstance(msg["session_id"]);
if (open_im_floater && open_im_floater->getVisible())
@@ -181,7 +195,7 @@ LLIMModel::LLIMSession::LLIMSession(const LLUUID& session_id, const std::string&
// set P2P type by default
mSessionType = P2P_SESSION;
- if (IM_NOTHING_SPECIAL == type || IM_SESSION_P2P_INVITE == type)
+ if (IM_NOTHING_SPECIAL == mType || IM_SESSION_P2P_INVITE == mType)
{
mVoiceChannel = new LLVoiceChannelP2P(session_id, name, other_participant_id);
mOtherParticipantIsAvatar = LLVoiceClient::getInstance()->isParticipantAvatar(mSessionID);
@@ -235,7 +249,7 @@ LLIMModel::LLIMSession::LLIMSession(const LLUUID& session_id, const std::string&
new LLSessionTimeoutTimer(mSessionID, SESSION_INITIALIZATION_TIMEOUT);
}
- if (IM_NOTHING_SPECIAL == type)
+ if (IM_NOTHING_SPECIAL == mType)
{
mCallBackEnabled = LLVoiceClient::getInstance()->isSessionCallBackPossible(mSessionID);
mTextIMPossible = LLVoiceClient::getInstance()->isSessionTextIMPossible(mSessionID);
@@ -255,19 +269,37 @@ LLIMModel::LLIMSession::LLIMSession(const LLUUID& session_id, const std::string&
// Localizing name of ad-hoc session. STORM-153
// Changing name should happen here- after the history file was created, so that
// history files have consistent (English) names in different locales.
- if (isAdHocSessionType() && IM_SESSION_INVITE == type)
+ if (isAdHocSessionType() && IM_SESSION_INVITE == mType)
{
- LLAvatarNameCache::get(mOtherParticipantID,
- boost::bind(&LLIMModel::LLIMSession::onAdHocNameCache,
+ LLAvatarNameCache::get(mOtherParticipantID,
+ boost::bind(&LLIMModel::LLIMSession::onAdHocNameCache,
this, _2));
}
}
void LLIMModel::LLIMSession::onAdHocNameCache(const LLAvatarName& av_name)
{
+ if (av_name.mIsTemporaryName)
+ {
+ S32 separator_index = mName.rfind(" ");
+ std::string name = mName.substr(0, separator_index);
+ ++separator_index;
+ std::string conference_word = mName.substr(separator_index, mName.length());
+
+ // additional check that session name is what we expected
+ if ("Conference" == conference_word)
+ {
LLStringUtil::format_map_t args;
- args["[AGENT_NAME]"] = av_name.getCompleteName();
+ args["[AGENT_NAME]"] = name;
LLTrans::findString(mName, "conference-title-incoming", args);
+ }
+ }
+ else
+ {
+ LLStringUtil::format_map_t args;
+ args["[AGENT_NAME]"] = av_name.getCompleteName();
+ LLTrans::findString(mName, "conference-title-incoming", args);
+ }
}
void LLIMModel::LLIMSession::onVoiceChannelStateChanged(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state, const LLVoiceChannel::EDirection& direction)
@@ -521,43 +553,52 @@ bool LLIMModel::LLIMSession::isOtherParticipantAvaline()
return !mOtherParticipantIsAvatar;
}
-void LLIMModel::LLIMSession::onAvatarNameCache(const LLUUID& avatar_id, const LLAvatarName& av_name)
-{
- if (av_name.mLegacyFirstName.empty())
- {
- // if mLegacyFirstName is empty it means display names is off and the
- // data came from the gCacheName, mDisplayName will be the legacy name
- mHistoryFileName = LLCacheName::cleanFullName(av_name.mDisplayName);
- }
- else
- {
- mHistoryFileName = LLCacheName::cleanFullName(av_name.getLegacyName());
- }
-}
-
void LLIMModel::LLIMSession::buildHistoryFileName()
{
mHistoryFileName = mName;
-
+
//ad-hoc requires sophisticated chat history saving schemes
if (isAdHoc())
{
- //in case of outgoing ad-hoc sessions
+ /* in case of outgoing ad-hoc sessions we need to make specilized names
+ * if this naming system is ever changed then the filtering definitions in
+ * lllogchat.cpp need to be change acordingly so that the filtering for the
+ * date stamp code introduced in STORM-102 will work properly and not add
+ * a date stamp to the Ad-hoc conferences.
+ */
if (mInitialTargetIDs.size())
{
std::set<LLUUID> sorted_uuids(mInitialTargetIDs.begin(), mInitialTargetIDs.end());
mHistoryFileName = mName + " hash" + generateHash(sorted_uuids);
- return;
}
-
- //in case of incoming ad-hoc sessions
- mHistoryFileName = mName + " " + LLLogChat::timestamp(true) + " " + mSessionID.asString().substr(0, 4);
+ else
+ {
+ //in case of incoming ad-hoc sessions
+ mHistoryFileName = mName + " " + LLLogChat::timestamp(true) + " " + mSessionID.asString().substr(0, 4);
+ }
}
-
- // look up username to use as the log name
- if (isP2P())
+ else if (isP2P()) // look up username to use as the log name
{
- LLAvatarNameCache::get(mOtherParticipantID, boost::bind(&LLIMModel::LLIMSession::onAvatarNameCache, this, _1, _2));
+ LLAvatarName av_name;
+ // For outgoing sessions we already have a cached name
+ // so no need for a callback in LLAvatarNameCache::get()
+ if (LLAvatarNameCache::get(mOtherParticipantID, &av_name))
+ {
+ if (av_name.mUsername.empty())
+ {
+ // Display names are off, use mDisplayName which will be the legacy name
+ mHistoryFileName = LLCacheName::buildUsername(av_name.mDisplayName);
+ }
+ else
+ {
+ mHistoryFileName = av_name.mUsername;
+ }
+ }
+ else
+ {
+ // Incoming P2P sessions include a name that we can use to build a history file name
+ mHistoryFileName = LLCacheName::buildUsername(mName);
+ }
}
}
@@ -579,7 +620,6 @@ std::string LLIMModel::LLIMSession::generateHash(const std::set<LLUUID>& sorted_
return participants_md5_hash.asString();
}
-
void LLIMModel::processSessionInitializedReply(const LLUUID& old_session_id, const LLUUID& new_session_id)
{
LLIMSession* session = findIMSession(old_session_id);
@@ -762,11 +802,6 @@ bool LLIMModel::logToFile(const std::string& file_name, const std::string& from,
}
}
-bool LLIMModel::logToFile(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, const std::string& utf8_text)
-{
- return logToFile(LLIMModel::getInstance()->getHistoryFileName(session_id), from, from_id, utf8_text);
-}
-
bool LLIMModel::proccessOnlineOfflineNotification(
const LLUUID& session_id,
const std::string& utf8_text)
@@ -820,8 +855,11 @@ LLIMModel::LLIMSession* LLIMModel::addMessageSilently(const LLUUID& session_id,
}
addToHistory(session_id, from_name, from_id, utf8_text);
- if (log2file) logToFile(session_id, from_name, from_id, utf8_text);
-
+ if (log2file)
+ {
+ logToFile(getHistoryFileName(session_id), from_name, from_id, utf8_text);
+ }
+
session->mNumUnread++;
//update count of unread messages from real participant
@@ -1064,17 +1102,27 @@ void LLIMModel::sendMessage(const std::string& utf8_text,
if( session == 0)//??? shouldn't really happen
{
LLRecentPeople::instance().add(other_participant_id);
+ return;
}
- else
+ // IM_SESSION_INVITE means that this is an Ad-hoc incoming chat
+ // (it can be also Group chat but it is checked above)
+ // In this case mInitialTargetIDs contains Ad-hoc session ID and it should not be added
+ // to Recent People to prevent showing of an item with (???)(???). See EXT-8246.
+ // Concrete participants will be added into this list once they sent message in chat.
+ if (IM_SESSION_INVITE == dialog) return;
+
+ if (IM_SESSION_CONFERENCE_START == dialog) // outgoing ad-hoc session
{
- // IM_SESSION_INVITE means that this is an Ad-hoc incoming chat
- // (it can be also Group chat but it is checked above)
- // In this case mInitialTargetIDs contains Ad-hoc session ID and it should not be added
- // to Recent People to prevent showing of an item with (???)(???). See EXT-8246.
- // Concrete participants will be added into this list once they sent message in chat.
- if (IM_SESSION_INVITE == dialog) return;
- // Add only online members to recent (EXT-8658)
- addSpeakersToRecent(im_session_id);
+ // Add only online members of conference to recent list (EXT-8658)
+ addSpeakersToRecent(im_session_id);
+ }
+ else // outgoing P2P session
+ {
+ // Add the recepient of the session.
+ if (!session->mInitialTargetIDs.empty())
+ {
+ LLRecentPeople::instance().add(*(session->mInitialTargetIDs.begin()));
+ }
}
}
}
@@ -2061,7 +2109,7 @@ void LLIncomingCallDialog::onOpen(const LLSD& key)
void LLIncomingCallDialog::onAccept(void* user_data)
{
LLIncomingCallDialog* self = (LLIncomingCallDialog*)user_data;
- self->processCallResponse(0);
+ processCallResponse(0, self->mPayload);
self->closeFloater();
}
@@ -2069,7 +2117,7 @@ void LLIncomingCallDialog::onAccept(void* user_data)
void LLIncomingCallDialog::onReject(void* user_data)
{
LLIncomingCallDialog* self = (LLIncomingCallDialog*)user_data;
- self->processCallResponse(1);
+ processCallResponse(1, self->mPayload);
self->closeFloater();
}
@@ -2077,20 +2125,21 @@ void LLIncomingCallDialog::onReject(void* user_data)
void LLIncomingCallDialog::onStartIM(void* user_data)
{
LLIncomingCallDialog* self = (LLIncomingCallDialog*)user_data;
- self->processCallResponse(2);
+ processCallResponse(2, self->mPayload);
self->closeFloater();
}
-void LLIncomingCallDialog::processCallResponse(S32 response)
+// static
+void LLIncomingCallDialog::processCallResponse(S32 response, const LLSD &payload)
{
if (!gIMMgr || gDisconnected)
return;
- LLUUID session_id = mPayload["session_id"].asUUID();
- LLUUID caller_id = mPayload["caller_id"].asUUID();
- std::string session_name = mPayload["session_name"].asString();
- EInstantMessage type = (EInstantMessage)mPayload["type"].asInteger();
- LLIMMgr::EInvitationType inv_type = (LLIMMgr::EInvitationType)mPayload["inv_type"].asInteger();
+ LLUUID session_id = payload["session_id"].asUUID();
+ LLUUID caller_id = payload["caller_id"].asUUID();
+ std::string session_name = payload["session_name"].asString();
+ EInstantMessage type = (EInstantMessage)payload["type"].asInteger();
+ LLIMMgr::EInvitationType inv_type = (LLIMMgr::EInvitationType)payload["inv_type"].asInteger();
bool voice = true;
switch(response)
{
@@ -2107,8 +2156,8 @@ void LLIncomingCallDialog::processCallResponse(S32 response)
session_id = gIMMgr->addP2PSession(
session_name,
caller_id,
- mPayload["session_handle"].asString(),
- mPayload["session_uri"].asString());
+ payload["session_handle"].asString(),
+ payload["session_uri"].asString());
if (voice)
{
@@ -2142,7 +2191,7 @@ void LLIncomingCallDialog::processCallResponse(S32 response)
LLAvatarName av_name;
if (LLAvatarNameCache::get(caller_id, &av_name))
{
- correct_session_name = av_name.mDisplayName + " (" + av_name.mUsername + ")";
+ correct_session_name = av_name.getCompleteName();
correct_session_name.append(ADHOC_NAME_SUFFIX);
}
}
@@ -2172,10 +2221,10 @@ void LLIncomingCallDialog::processCallResponse(S32 response)
inv_type));
// send notification message to the corresponding chat
- if (mPayload["notify_box_type"].asString() == "VoiceInviteGroup" || mPayload["notify_box_type"].asString() == "VoiceInviteAdHoc")
+ if (payload["notify_box_type"].asString() == "VoiceInviteGroup" || payload["notify_box_type"].asString() == "VoiceInviteAdHoc")
{
LLStringUtil::format_map_t string_args;
- string_args["[NAME]"] = mPayload["caller_name"].asString();
+ string_args["[NAME]"] = payload["caller_name"].asString();
std::string message = LLTrans::getString("name_started_call", string_args);
LLIMModel::getInstance()->addMessageSilently(session_id, SYSTEM_FROM, LLUUID::null, message);
}
@@ -2192,7 +2241,7 @@ void LLIncomingCallDialog::processCallResponse(S32 response)
{
if(LLVoiceClient::getInstance())
{
- std::string s = mPayload["session_handle"].asString();
+ std::string s = payload["session_handle"].asString();
LLVoiceClient::getInstance()->declineInvite(s);
}
}
@@ -2421,6 +2470,7 @@ void LLIMMgr::addSystemMessage(const LLUUID& session_id, const std::string& mess
std::string session_name;
// since we select user to share item with - his name is already in cache
gCacheName->getFullName(args["user_id"], session_name);
+ session_name = LLCacheName::buildUsername(session_name);
LLIMModel::instance().logToFile(session_name, SYSTEM_FROM, LLUUID::null, message.getString());
}
}
@@ -2599,16 +2649,19 @@ void LLIMMgr::inviteToSession(
std::string question_type = "VoiceInviteQuestionDefault";
BOOL ad_hoc_invite = FALSE;
+ BOOL voice_invite = FALSE;
if(type == IM_SESSION_P2P_INVITE)
{
//P2P is different...they only have voice invitations
notify_box_type = "VoiceInviteP2P";
+ voice_invite = TRUE;
}
else if ( gAgent.isInGroup(session_id) )
{
//only really old school groups have voice invitations
notify_box_type = "VoiceInviteGroup";
question_type = "VoiceInviteQuestionGroup";
+ voice_invite = TRUE;
}
else if ( inv_type == INVITATION_TYPE_VOICE )
{
@@ -2616,6 +2669,7 @@ void LLIMMgr::inviteToSession(
//and a voice ad-hoc
notify_box_type = "VoiceInviteAdHoc";
ad_hoc_invite = TRUE;
+ voice_invite = TRUE;
}
else if ( inv_type == INVITATION_TYPE_IMMEDIATE )
{
@@ -2639,23 +2693,21 @@ void LLIMMgr::inviteToSession(
if (channelp && channelp->callStarted())
{
// you have already started a call to the other user, so just accept the invite
- LLNotifications::instance().forceResponse(LLNotification::Params("VoiceInviteP2P").payload(payload), 0);
+ LLIncomingCallDialog::processCallResponse(0, payload);
return;
}
- if (type == IM_SESSION_P2P_INVITE || ad_hoc_invite)
+ if (voice_invite)
{
- // is the inviter a friend?
- if (LLAvatarTracker::instance().getBuddyInfo(caller_id) == NULL)
+ if ( // if we are rejecting group calls
+ (gSavedSettings.getBOOL("VoiceCallsRejectGroup") && notify_box_type == "VoiceInviteGroup") ||
+ // or we're rejecting non-friend voice calls and this isn't a friend
+ (gSavedSettings.getBOOL("VoiceCallsFriendsOnly") && (LLAvatarTracker::instance().getBuddyInfo(caller_id) == NULL))
+ )
{
- // if not, and we are ignoring voice invites from non-friends
- // then silently decline
- if (gSavedSettings.getBOOL("VoiceCallsFriendsOnly"))
- {
- // invite not from a friend, so decline
- LLNotifications::instance().forceResponse(LLNotification::Params("VoiceInviteP2P").payload(payload), 1);
- return;
- }
+ // silently decline the call
+ LLIncomingCallDialog::processCallResponse(1, payload);
+ return;
}
}
@@ -2670,6 +2722,15 @@ void LLIMMgr::inviteToSession(
{
LLFloaterReg::showInstance("incoming_call", payload, FALSE);
}
+
+ // Add the caller to the Recent List here (at this point
+ // "incoming_call" floater is shown and the recipient can
+ // reject the call), because even if a recipient will reject
+ // the call, the caller should be added to the recent list
+ // anyway. STORM-507.
+ if(type == IM_SESSION_P2P_INVITE)
+ LLRecentPeople::instance().add(caller_id);
+
mPendingInvitations[session_id.asString()] = LLSD();
}
}
@@ -3125,10 +3186,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();
@@ -3205,11 +3262,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/llimview.h b/indra/newview/llimview.h
index 650d329e18..0ee56c8070 100644
--- a/indra/newview/llimview.h
+++ b/indra/newview/llimview.h
@@ -62,7 +62,7 @@ class LLIMModel : public LLSingleton<LLIMModel>
{
public:
- struct LLIMSession
+ struct LLIMSession : public boost::signals2::trackable
{
typedef enum e_session_type
{ // for now we have 4 predefined types for a session
@@ -98,13 +98,6 @@ public:
/** ad-hoc sessions involve sophisticated chat history file naming schemes */
void buildHistoryFileName();
- void onAvatarNameCache(const LLUUID& avatar_id, const LLAvatarName& av_name);
-
- void onAdHocNameCache(const LLAvatarName& av_name);
-
- //*TODO make private
- static std::string generateHash(const std::set<LLUUID>& sorted_uuids);
-
LLUUID mSessionID;
std::string mName;
EInstantMessage mType;
@@ -139,6 +132,11 @@ public:
//if IM session is created for a voice call
bool mStartedAsIMCall;
+
+ private:
+ void onAdHocNameCache(const LLAvatarName& av_name);
+
+ static std::string generateHash(const std::set<LLUUID>& sorted_uuids);
};
@@ -293,12 +291,7 @@ private:
/**
* Add message to a list of message associated with session specified by session_id
*/
- bool addToHistory(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, const std::string& utf8_text);
-
- /**
- * Save an IM message into a file
- */
- bool logToFile(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, const std::string& utf8_text);
+ bool addToHistory(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, const std::string& utf8_text);
};
class LLIMSessionObserver
@@ -542,6 +535,7 @@ public:
static void onReject(void* user_data);
static void onStartIM(void* user_data);
+ static void processCallResponse(S32 response, const LLSD& payload);
private:
void setCallerName(const std::string& ui_title,
const std::string& ui_label,
@@ -551,7 +545,6 @@ private:
const std::string& call_type);
/*virtual*/ void onLifetimeExpired();
- void processCallResponse(S32 response);
};
class LLOutgoingCallDialog : public LLCallDialog
diff --git a/indra/newview/llinspectavatar.cpp b/indra/newview/llinspectavatar.cpp
index 29dcb2c4d3..17d0b0ffbb 100644
--- a/indra/newview/llinspectavatar.cpp
+++ b/indra/newview/llinspectavatar.cpp
@@ -47,12 +47,14 @@
#include "llvoiceclient.h"
#include "llviewerobjectlist.h"
#include "lltransientfloatermgr.h"
+#include "llnotificationsutil.h"
// Linden libraries
#include "llfloater.h"
#include "llfloaterreg.h"
#include "llmenubutton.h"
#include "lltextbox.h"
+#include "lltoggleablemenu.h"
#include "lltooltip.h" // positionViewNearMouse()
#include "lltrans.h"
#include "lluictrl.h"
@@ -125,16 +127,20 @@ private:
void onClickReport();
void onClickFreeze();
void onClickEject();
+ void onClickKick();
+ void onClickCSR();
void onClickZoomIn();
void onClickFindOnMap();
bool onVisibleFindOnMap();
- bool onVisibleFreezeEject();
+ bool onVisibleEject();
+ bool onVisibleFreeze();
bool onVisibleZoomIn();
void onClickMuteVolume();
void onVolumeChange(const LLSD& data);
bool enableMute();
bool enableUnmute();
bool enableTeleportOffer();
+ bool godModeEnabled();
// Is used to determine if "Add friend" option should be enabled in gear menu
bool isNotFriend();
@@ -213,20 +219,21 @@ LLInspectAvatar::LLInspectAvatar(const LLSD& sd)
mCommitCallbackRegistrar.add("InspectAvatar.Pay", boost::bind(&LLInspectAvatar::onClickPay, this));
mCommitCallbackRegistrar.add("InspectAvatar.Share", boost::bind(&LLInspectAvatar::onClickShare, this));
mCommitCallbackRegistrar.add("InspectAvatar.ToggleMute", boost::bind(&LLInspectAvatar::onToggleMute, this));
- mCommitCallbackRegistrar.add("InspectAvatar.Freeze",
- boost::bind(&LLInspectAvatar::onClickFreeze, this));
- mCommitCallbackRegistrar.add("InspectAvatar.Eject",
- boost::bind(&LLInspectAvatar::onClickEject, this));
+ mCommitCallbackRegistrar.add("InspectAvatar.Freeze", boost::bind(&LLInspectAvatar::onClickFreeze, this));
+ mCommitCallbackRegistrar.add("InspectAvatar.Eject", boost::bind(&LLInspectAvatar::onClickEject, this));
+ mCommitCallbackRegistrar.add("InspectAvatar.Kick", boost::bind(&LLInspectAvatar::onClickKick, this));
+ mCommitCallbackRegistrar.add("InspectAvatar.CSR", boost::bind(&LLInspectAvatar::onClickCSR, this));
mCommitCallbackRegistrar.add("InspectAvatar.Report", boost::bind(&LLInspectAvatar::onClickReport, this));
mCommitCallbackRegistrar.add("InspectAvatar.FindOnMap", boost::bind(&LLInspectAvatar::onClickFindOnMap, this));
mCommitCallbackRegistrar.add("InspectAvatar.ZoomIn", boost::bind(&LLInspectAvatar::onClickZoomIn, this));
mCommitCallbackRegistrar.add("InspectAvatar.DisableVoice", boost::bind(&LLInspectAvatar::toggleSelectedVoice, this, false));
mCommitCallbackRegistrar.add("InspectAvatar.EnableVoice", boost::bind(&LLInspectAvatar::toggleSelectedVoice, this, true));
+
+ mEnableCallbackRegistrar.add("InspectAvatar.EnableGod", boost::bind(&LLInspectAvatar::godModeEnabled, this));
mEnableCallbackRegistrar.add("InspectAvatar.VisibleFindOnMap", boost::bind(&LLInspectAvatar::onVisibleFindOnMap, this));
- mEnableCallbackRegistrar.add("InspectAvatar.VisibleFreezeEject",
- boost::bind(&LLInspectAvatar::onVisibleFreezeEject, this));
- mEnableCallbackRegistrar.add("InspectAvatar.VisibleZoomIn",
- boost::bind(&LLInspectAvatar::onVisibleZoomIn, this));
+ mEnableCallbackRegistrar.add("InspectAvatar.VisibleEject", boost::bind(&LLInspectAvatar::onVisibleEject, this));
+ mEnableCallbackRegistrar.add("InspectAvatar.VisibleFreeze", boost::bind(&LLInspectAvatar::onVisibleFreeze, this));
+ mEnableCallbackRegistrar.add("InspectAvatar.VisibleZoomIn", boost::bind(&LLInspectAvatar::onVisibleZoomIn, this));
mEnableCallbackRegistrar.add("InspectAvatar.Gear.Enable", boost::bind(&LLInspectAvatar::isNotFriend, this));
mEnableCallbackRegistrar.add("InspectAvatar.Gear.EnableCall", boost::bind(&LLAvatarActions::canCall));
mEnableCallbackRegistrar.add("InspectAvatar.Gear.EnableTeleportOffer", boost::bind(&LLInspectAvatar::enableTeleportOffer, this));
@@ -402,8 +409,8 @@ void LLInspectAvatar::processAvatarData(LLAvatarData* data)
// if neither the gear menu or self gear menu are open
void LLInspectAvatar::onMouseLeave(S32 x, S32 y, MASK mask)
{
- LLMenuGL* gear_menu = getChild<LLMenuButton>("gear_btn")->getMenu();
- LLMenuGL* gear_menu_self = getChild<LLMenuButton>("gear_self_btn")->getMenu();
+ LLToggleableMenu* gear_menu = getChild<LLMenuButton>("gear_btn")->getMenu();
+ LLToggleableMenu* gear_menu_self = getChild<LLMenuButton>("gear_self_btn")->getMenu();
if ( gear_menu && gear_menu->getVisible() &&
gear_menu_self && gear_menu_self->getVisible() )
{
@@ -655,11 +662,18 @@ bool LLInspectAvatar::onVisibleFindOnMap()
return gAgent.isGodlike() || is_agent_mappable(mAvatarID);
}
-bool LLInspectAvatar::onVisibleFreezeEject()
+bool LLInspectAvatar::onVisibleEject()
{
return enable_freeze_eject( LLSD(mAvatarID) );
}
+bool LLInspectAvatar::onVisibleFreeze()
+{
+ // either user is a god and can do long distance freeze
+ // or check for target proximity and permissions
+ return gAgent.isGodlike() || enable_freeze_eject(LLSD(mAvatarID));
+}
+
bool LLInspectAvatar::onVisibleZoomIn()
{
return gObjectList.findObject(mAvatarID);
@@ -703,7 +717,7 @@ void LLInspectAvatar::onClickShare()
void LLInspectAvatar::onToggleMute()
{
- LLMute mute(mAvatarID, mAvatarName.getLegacyName(), LLMute::AGENT);
+ LLMute mute(mAvatarID, mAvatarName.mDisplayName, LLMute::AGENT);
if (LLMuteList::getInstance()->isMuted(mute.mID, mute.mName))
{
@@ -724,9 +738,41 @@ void LLInspectAvatar::onClickReport()
closeFloater();
}
+bool godlike_freeze(const LLSD& notification, const LLSD& response)
+{
+ LLUUID avatar_id = notification["payload"]["avatar_id"].asUUID();
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+
+ switch (option)
+ {
+ case 0:
+ LLAvatarActions::freeze(avatar_id);
+ break;
+ case 1:
+ LLAvatarActions::unfreeze(avatar_id);
+ break;
+ default:
+ break;
+ }
+
+ return false;
+}
+
void LLInspectAvatar::onClickFreeze()
{
- handle_avatar_freeze( LLSD(mAvatarID) );
+ if (gAgent.isGodlike())
+ {
+ // use godlike freeze-at-a-distance, with confirmation
+ LLNotificationsUtil::add("FreezeAvatar",
+ LLSD(),
+ LLSD().with("avatar_id", mAvatarID),
+ godlike_freeze);
+ }
+ else
+ {
+ // use default "local" version of freezing that requires avatar to be in range
+ handle_avatar_freeze( LLSD(mAvatarID) );
+ }
closeFloater();
}
@@ -736,6 +782,20 @@ void LLInspectAvatar::onClickEject()
closeFloater();
}
+void LLInspectAvatar::onClickKick()
+{
+ LLAvatarActions::kick(mAvatarID);
+ closeFloater();
+}
+
+void LLInspectAvatar::onClickCSR()
+{
+ std::string name;
+ gCacheName->getFullName(mAvatarID, name);
+ LLAvatarActions::csr(mAvatarID, name);
+ closeFloater();
+}
+
void LLInspectAvatar::onClickZoomIn()
{
handle_zoom_to_object(mAvatarID);
@@ -784,6 +844,11 @@ bool LLInspectAvatar::enableTeleportOffer()
return LLAvatarActions::canOfferTeleport(mAvatarID);
}
+bool LLInspectAvatar::godModeEnabled()
+{
+ return gAgent.isGodlike();
+}
+
//////////////////////////////////////////////////////////////////////////////
// LLInspectAvatarUtil
//////////////////////////////////////////////////////////////////////////////
diff --git a/indra/newview/llinspectobject.cpp b/indra/newview/llinspectobject.cpp
index 532ffca4be..ee076f68ea 100644
--- a/indra/newview/llinspectobject.cpp
+++ b/indra/newview/llinspectobject.cpp
@@ -47,6 +47,7 @@
#include "llsafehandle.h"
#include "llsidetray.h"
#include "lltextbox.h" // for description truncation
+#include "lltoggleablemenu.h"
#include "lltrans.h"
#include "llui.h" // positionViewNearMouse()
#include "lluictrl.h"
@@ -568,7 +569,7 @@ void LLInspectObject::updateSecureBrowsing()
// if the gear menu is not open
void LLInspectObject::onMouseLeave(S32 x, S32 y, MASK mask)
{
- LLMenuGL* gear_menu = getChild<LLMenuButton>("gear_btn")->getMenu();
+ LLToggleableMenu* gear_menu = getChild<LLMenuButton>("gear_btn")->getMenu();
if ( gear_menu && gear_menu->getVisible() )
{
return;
diff --git a/indra/newview/llinspecttoast.cpp b/indra/newview/llinspecttoast.cpp
index 58b3f0309f..d7b82667d1 100644
--- a/indra/newview/llinspecttoast.cpp
+++ b/indra/newview/llinspecttoast.cpp
@@ -46,6 +46,7 @@ public:
virtual ~LLInspectToast();
/*virtual*/ void onOpen(const LLSD& notification_id);
+ /*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask);
private:
void onToastDestroy(LLToast * toast);
@@ -73,6 +74,7 @@ LLInspectToast::~LLInspectToast()
LLTransientFloaterMgr::getInstance()->removeControlView(this);
}
+// virtual
void LLInspectToast::onOpen(const LLSD& notification_id)
{
LLInspect::onOpen(notification_id);
@@ -103,6 +105,15 @@ void LLInspectToast::onOpen(const LLSD& notification_id)
LLUI::positionViewNearMouse(this);
}
+// virtual
+BOOL LLInspectToast::handleToolTip(S32 x, S32 y, MASK mask)
+{
+ // We don't like the way LLInspect handles tooltips
+ // (black tooltips look weird),
+ // so force using the default implementation (STORM-511).
+ return LLFloater::handleToolTip(x, y, mask);
+}
+
void LLInspectToast::onToastDestroy(LLToast * toast)
{
closeFloater(false);
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index b15dcd993a..86c8a1a9b5 100644
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -104,6 +104,7 @@ void remove_inventory_category_from_avatar_step2( BOOL proceed, LLUUID category_
bool move_task_inventory_callback(const LLSD& notification, const LLSD& response, LLMoveInv*);
bool confirm_attachment_rez(const LLSD& notification, const LLSD& response);
void teleport_via_landmark(const LLUUID& asset_id);
+static BOOL can_move_to_outfit(LLInventoryItem* inv_item, BOOL move_is_into_current_outfit);
// +=================================================+
// | LLInvFVBridge |
@@ -916,6 +917,14 @@ LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type,
// Only should happen for broken links.
new_listener = new LLLinkItemBridge(inventory, root, uuid);
break;
+ case LLAssetType::AT_MESH:
+ if(!(inv_type == LLInventoryType::IT_MESH))
+ {
+ llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl;
+ }
+ new_listener = new LLMeshBridge(inventory, root, uuid);
+ break;
+
default:
llinfos << "Unhandled asset type (llassetstorage.h): "
<< (S32)asset_type << llendl;
@@ -1643,16 +1652,19 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
const BOOL is_agent_inventory = (model->getCategory(inv_cat->getUUID()) != NULL)
&& (LLToolDragAndDrop::SOURCE_AGENT == source);
+ const LLUUID &current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false);
+ const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id);
+
BOOL accept = FALSE;
if (is_agent_inventory)
{
const LLUUID &cat_id = inv_cat->getUUID();
const LLUUID &trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH, false);
- const LLUUID &current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false);
+ const LLUUID &landmarks_id = model->findCategoryUUIDForType(LLFolderType::FT_LANDMARK, false);
const BOOL move_is_into_trash = (mUUID == trash_id) || model->isObjectDescendentOf(mUUID, trash_id);
const BOOL move_is_into_outfit = getCategory() && (getCategory()->getPreferredType() == LLFolderType::FT_OUTFIT);
- const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id);
+ const BOOL move_is_into_landmarks = (mUUID == landmarks_id) || model->isObjectDescendentOf(mUUID, landmarks_id);
//--------------------------------------------------------------------------------
// Determine if folder can be moved.
@@ -1690,6 +1702,21 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
}
}
}
+ if (move_is_into_landmarks)
+ {
+ for (S32 i=0; i < descendent_items.count(); ++i)
+ {
+ LLViewerInventoryItem* item = descendent_items[i];
+
+ // Don't move anything except landmarks and categories into Landmarks folder.
+ // We use getType() instead of getActua;Type() to allow links to landmarks and folders.
+ if (LLAssetType::AT_LANDMARK != item->getType() && LLAssetType::AT_CATEGORY != item->getType())
+ {
+ is_movable = FALSE;
+ break; // It's generally movable, but not into Landmarks.
+ }
+ }
+ }
//
//--------------------------------------------------------------------------------
@@ -1777,6 +1804,17 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
LLUUID category_id = mUUID;
accept = move_inv_category_world_to_agent(object_id, category_id, drop);
}
+ else if (LLToolDragAndDrop::SOURCE_LIBRARY == source)
+ {
+ // Accept folders that contain complete outfits.
+ accept = move_is_into_current_outfit && LLAppearanceMgr::instance().getCanMakeFolderIntoOutfit(inv_cat->getUUID());
+
+ if (accept && drop)
+ {
+ LLAppearanceMgr::instance().wearInventoryCategory(inv_cat, true, false);
+ }
+ }
+
return accept;
}
@@ -2236,6 +2274,9 @@ LLUIImagePtr LLFolderBridge::getIcon() const
LLUIImagePtr LLFolderBridge::getIcon(LLFolderType::EType preferred_type)
{
return LLUI::getUIImage(LLViewerFolderType::lookupIconName(preferred_type, FALSE));
+ /*case LLAssetType::AT_MESH:
+ control = "inv_folder_mesh.tga";
+ break;*/
}
LLUIImagePtr LLFolderBridge::getOpenIcon() const
@@ -2312,6 +2353,10 @@ void LLFolderBridge::pasteFromClipboard()
LLInventoryModel* model = getInventoryModel();
if(model && isClipboardPasteable())
{
+ const LLUUID &current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false);
+ const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id);
+ const BOOL move_is_into_outfit = (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT);
+
const LLUUID parent_id(mUUID);
LLDynamicArray<LLUUID> objects;
@@ -2324,7 +2369,14 @@ void LLFolderBridge::pasteFromClipboard()
LLInventoryItem *item = model->getItem(item_id);
if (item)
{
- if(LLInventoryClipboard::instance().isCutMode())
+ if (move_is_into_current_outfit || move_is_into_outfit)
+ {
+ if (can_move_to_outfit(item, move_is_into_current_outfit))
+ {
+ dropToOutfit(item, move_is_into_current_outfit);
+ }
+ }
+ else if(LLInventoryClipboard::instance().isCutMode())
{
// move_inventory_item() is not enough,
//we have to update inventory locally too
@@ -2352,9 +2404,13 @@ void LLFolderBridge::pasteFromClipboard()
void LLFolderBridge::pasteLinkFromClipboard()
{
- const LLInventoryModel* model = getInventoryModel();
+ LLInventoryModel* model = getInventoryModel();
if(model)
{
+ const LLUUID &current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false);
+ const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id);
+ const BOOL move_is_into_outfit = (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT);
+
const LLUUID parent_id(mUUID);
LLDynamicArray<LLUUID> objects;
@@ -2364,7 +2420,15 @@ void LLFolderBridge::pasteLinkFromClipboard()
++iter)
{
const LLUUID &object_id = (*iter);
- if (LLInventoryCategory *cat = model->getCategory(object_id))
+ if (move_is_into_current_outfit || move_is_into_outfit)
+ {
+ LLInventoryItem *item = model->getItem(object_id);
+ if (item && can_move_to_outfit(item, move_is_into_current_outfit))
+ {
+ dropToOutfit(item, move_is_into_current_outfit);
+ }
+ }
+ else if (LLInventoryCategory *cat = model->getCategory(object_id))
{
const std::string empty_description = "";
link_inventory_item(
@@ -2661,6 +2725,8 @@ BOOL LLFolderBridge::dragOrDrop(MASK mask, BOOL drop,
EDragAndDropType cargo_type,
void* cargo_data)
{
+ LLInventoryItem* inv_item = (LLInventoryItem*)cargo_data;
+
//llinfos << "LLFolderBridge::dragOrDrop()" << llendl;
BOOL accept = FALSE;
switch(cargo_type)
@@ -2670,15 +2736,31 @@ BOOL LLFolderBridge::dragOrDrop(MASK mask, BOOL drop,
case DAD_CALLINGCARD:
case DAD_LANDMARK:
case DAD_SCRIPT:
+ case DAD_CLOTHING:
case DAD_OBJECT:
case DAD_NOTECARD:
- case DAD_CLOTHING:
case DAD_BODYPART:
case DAD_ANIMATION:
case DAD_GESTURE:
+ case DAD_MESH:
+ accept = dragItemIntoFolder(inv_item, drop);
+ break;
case DAD_LINK:
- accept = dragItemIntoFolder((LLInventoryItem*)cargo_data,
- drop);
+ // DAD_LINK type might mean one of two asset types: AT_LINK or AT_LINK_FOLDER.
+ // If we have an item of AT_LINK_FOLDER type we should process the linked
+ // category being dragged or dropped into folder.
+ if (inv_item && LLAssetType::AT_LINK_FOLDER == inv_item->getActualType())
+ {
+ LLInventoryCategory* linked_category = gInventory.getCategory(inv_item->getLinkedUUID());
+ if (linked_category)
+ {
+ accept = dragCategoryIntoFolder((LLInventoryCategory*)linked_category, drop);
+ }
+ }
+ else
+ {
+ accept = dragItemIntoFolder(inv_item, drop);
+ }
break;
case DAD_CATEGORY:
if (LLFriendCardsManager::instance().isAnyFriendCategory(mUUID))
@@ -2690,7 +2772,11 @@ BOOL LLFolderBridge::dragOrDrop(MASK mask, BOOL drop,
accept = dragCategoryIntoFolder((LLInventoryCategory*)cargo_data, drop);
}
break;
+ case DAD_ROOT_CATEGORY:
+ case DAD_NONE:
+ break;
default:
+ llwarns << "Unhandled cargo type for drag&drop " << cargo_type << llendl;
break;
}
return accept;
@@ -2862,6 +2948,7 @@ static BOOL can_move_to_outfit(LLInventoryItem* inv_item, BOOL move_is_into_curr
{
if ((inv_item->getInventoryType() != LLInventoryType::IT_WEARABLE) &&
(inv_item->getInventoryType() != LLInventoryType::IT_GESTURE) &&
+ (inv_item->getInventoryType() != LLInventoryType::IT_ATTACHMENT) &&
(inv_item->getInventoryType() != LLInventoryType::IT_OBJECT))
{
return FALSE;
@@ -2875,6 +2962,24 @@ static BOOL can_move_to_outfit(LLInventoryItem* inv_item, BOOL move_is_into_curr
return TRUE;
}
+// Returns TRUE if item is a landmark or a link to a landmark
+// and can be moved to Favorites or Landmarks folder.
+static BOOL can_move_to_landmarks(LLInventoryItem* inv_item)
+{
+ // Need to get the linked item to know its type because LLInventoryItem::getType()
+ // returns actual type AT_LINK for links, not the asset type of a linked item.
+ if (LLAssetType::AT_LINK == inv_item->getType())
+ {
+ LLInventoryItem* linked_item = gInventory.getItem(inv_item->getLinkedUUID());
+ if (linked_item)
+ {
+ return LLAssetType::AT_LANDMARK == linked_item->getType();
+ }
+ }
+
+ return LLAssetType::AT_LANDMARK == inv_item->getType();
+}
+
void LLFolderBridge::dropToFavorites(LLInventoryItem* inv_item)
{
// use callback to rearrange favorite landmarks after adding
@@ -2931,9 +3036,12 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
const LLUUID &current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false);
const LLUUID &favorites_id = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE, false);
+ const LLUUID &landmarks_id = model->findCategoryUUIDForType(LLFolderType::FT_LANDMARK, false);
const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id);
+ const BOOL move_is_into_favorites = (mUUID == favorites_id);
const BOOL move_is_into_outfit = (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT);
+ const BOOL move_is_into_landmarks = (mUUID == landmarks_id) || model->isObjectDescendentOf(mUUID, landmarks_id);
LLToolDragAndDrop::ESource source = LLToolDragAndDrop::getInstance()->getSource();
BOOL accept = FALSE;
@@ -2944,7 +3052,6 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
const BOOL move_is_into_trash = (mUUID == trash_id) || model->isObjectDescendentOf(mUUID, trash_id);
const BOOL move_is_outof_current_outfit = LLAppearanceMgr::instance().getIsInCOF(inv_item->getUUID());
- const BOOL folder_allows_reorder = (mUUID == favorites_id);
//--------------------------------------------------------------------------------
// Determine if item can be moved.
@@ -2990,12 +3097,16 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
if (!is_movable)
accept = FALSE;
- if ((mUUID == inv_item->getParentUUID()) && !folder_allows_reorder)
+ if ((mUUID == inv_item->getParentUUID()) && !move_is_into_favorites)
accept = FALSE;
if (move_is_into_current_outfit || move_is_into_outfit)
{
accept = can_move_to_outfit(inv_item, move_is_into_current_outfit);
}
+ else if (move_is_into_favorites || move_is_into_landmarks)
+ {
+ accept = can_move_to_landmarks(inv_item);
+ }
if(accept && drop)
{
@@ -3021,8 +3132,8 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
//
// REORDER
- // (only reorder the item)
- if ((mUUID == inv_item->getParentUUID()) && folder_allows_reorder)
+ // (only reorder the item in Favorites folder)
+ if ((mUUID == inv_item->getParentUUID()) && move_is_into_favorites)
{
LLInventoryPanel* panel = dynamic_cast<LLInventoryPanel*>(mInventoryPanel.get());
LLFolderViewItem* itemp = panel ? panel->getRootFolder()->getDraggingOverItem() : NULL;
@@ -3036,7 +3147,7 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
// FAVORITES folder
// (copy the item)
- else if (favorites_id == mUUID)
+ else if (move_is_into_favorites)
{
dropToFavorites(inv_item);
}
@@ -3101,6 +3212,13 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
{
accept = FALSE;
}
+ // Don't allow to move a single item to Favorites or Landmarks
+ // if it is not a landmark or a link to a landmark.
+ else if ((move_is_into_favorites || move_is_into_landmarks)
+ && !can_move_to_landmarks(inv_item))
+ {
+ accept = FALSE;
+ }
if(drop && accept)
{
@@ -3128,7 +3246,10 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
}
else if(LLToolDragAndDrop::SOURCE_NOTECARD == source)
{
- accept = TRUE;
+ // Don't allow placing an original item from a notecard to Current Outfit or an outfit folder
+ // because they must contain only links to wearable items.
+ accept = !(move_is_into_current_outfit || move_is_into_outfit);
+
if(drop)
{
copy_inventory_from_notecard(LLToolDragAndDrop::getInstance()->getObjectID(),
@@ -3146,12 +3267,18 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
{
accept = can_move_to_outfit(inv_item, move_is_into_current_outfit);
}
+ // Don't allow to move a single item to Favorites or Landmarks
+ // if it is not a landmark or a link to a landmark.
+ else if (move_is_into_favorites || move_is_into_landmarks)
+ {
+ accept = can_move_to_landmarks(inv_item);
+ }
if (accept && drop)
{
// FAVORITES folder
// (copy the item)
- if (favorites_id == mUUID)
+ if (move_is_into_favorites)
{
dropToFavorites(inv_item);
}
@@ -3641,6 +3768,7 @@ BOOL LLCallingCardBridge::dragOrDrop(MASK mask, BOOL drop,
case DAD_BODYPART:
case DAD_ANIMATION:
case DAD_GESTURE:
+ case DAD_MESH:
{
LLInventoryItem* inv_item = (LLInventoryItem*)cargo_data;
const LLPermissions& perm = inv_item->getPermissions();
@@ -4563,10 +4691,18 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
else
{
items.push_back(std::string("Wearable And Object Wear"));
- items.push_back(std::string("Wearable Add"));
disabled_items.push_back(std::string("Take Off"));
disabled_items.push_back(std::string("Wearable Edit"));
}
+
+ if (LLWearableType::getAllowMultiwear(mWearableType))
+ {
+ items.push_back(std::string("Wearable Add"));
+ if (gAgentWearables.getWearableCount(mWearableType) >= LLAgentWearables::MAX_CLOTHING_PER_TYPE)
+ {
+ disabled_items.push_back(std::string("Wearable Add"));
+ }
+ }
break;
default:
break;
@@ -4809,6 +4945,7 @@ void LLWearableBridge::removeFromAvatar()
}
}
+
// +=================================================+
// | LLLinkItemBridge |
// +=================================================+
@@ -4839,6 +4976,63 @@ void LLLinkItemBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
}
// +=================================================+
+// | LLMeshBridge |
+// +=================================================+
+
+LLUIImagePtr LLMeshBridge::getIcon() const
+{
+ return LLInventoryIcon::getIcon(LLAssetType::AT_MESH, LLInventoryType::IT_MESH, 0, FALSE);
+}
+
+void LLMeshBridge::openItem()
+{
+ LLViewerInventoryItem* item = getItem();
+
+ if (item)
+ {
+ // open mesh
+ }
+}
+
+void LLMeshBridge::previewItem()
+{
+ LLViewerInventoryItem* item = getItem();
+ if(item)
+ {
+ // preview mesh
+ }
+}
+
+
+void LLMeshBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
+{
+ lldebugs << "LLMeshBridge::buildContextMenu()" << llendl;
+ std::vector<std::string> items;
+ std::vector<std::string> disabled_items;
+
+ if(isItemInTrash())
+ {
+ items.push_back(std::string("Purge Item"));
+ if (!isItemRemovable())
+ {
+ disabled_items.push_back(std::string("Purge Item"));
+ }
+
+ items.push_back(std::string("Restore Item"));
+ }
+ else
+ {
+ items.push_back(std::string("Properties"));
+
+ getClipboardEntries(true, items, disabled_items, flags);
+ }
+
+
+ hide_context_entries(menu, items, disabled_items);
+}
+
+
+// +=================================================+
// | LLLinkBridge |
// +=================================================+
// For broken folder links.
@@ -5144,6 +5338,7 @@ public:
{
wearOnAvatar();
}
+
virtual ~LLWearableBridgeAction(){}
protected:
LLWearableBridgeAction(const LLUUID& id,LLInventoryModel* model) : LLInvFVBridgeAction(id,model) {}
@@ -5236,11 +5431,6 @@ void LLRecentItemsFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
menuentry_vec_t disabled_items, items = getMenuItems();
- items.erase(std::remove(items.begin(), items.end(), std::string("New Body Parts")), items.end());
- items.erase(std::remove(items.begin(), items.end(), std::string("New Clothes")), items.end());
- items.erase(std::remove(items.begin(), items.end(), std::string("New Note")), items.end());
- items.erase(std::remove(items.begin(), items.end(), std::string("New Gesture")), items.end());
- items.erase(std::remove(items.begin(), items.end(), std::string("New Script")), items.end());
items.erase(std::remove(items.begin(), items.end(), std::string("New Folder")), items.end());
hide_context_entries(menu, items, disabled_items);
diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h
index 5ac328dcef..1e849c8812 100644
--- a/indra/newview/llinventorybridge.h
+++ b/indra/newview/llinventorybridge.h
@@ -41,6 +41,7 @@ class LLMenuGL;
class LLCallingCardObserver;
class LLViewerJointAttachment;
+
typedef std::vector<std::string> menuentry_vec_t;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -523,6 +524,24 @@ protected:
static std::string sPrefix;
};
+
+class LLMeshBridge : public LLItemBridge
+{
+ friend class LLInvFVBridge;
+public:
+ virtual LLUIImagePtr getIcon() const;
+ virtual void openItem();
+ virtual void previewItem();
+ virtual void buildContextMenu(LLMenuGL& menu, U32 flags);
+
+protected:
+ LLMeshBridge(LLInventoryPanel* inventory,
+ LLFolderView* root,
+ const LLUUID& uuid) :
+ LLItemBridge(inventory, root, uuid) {}
+};
+
+
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLInvFVBridgeAction
//
@@ -553,13 +572,23 @@ protected:
LLInventoryModel* mModel;
};
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Recent Inventory Panel related classes
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class LLMeshBridgeAction: public LLInvFVBridgeAction
+{
+ friend class LLInvFVBridgeAction;
+public:
+ virtual void doIt() ;
+ virtual ~LLMeshBridgeAction(){}
+protected:
+ LLMeshBridgeAction(const LLUUID& id,LLInventoryModel* model):LLInvFVBridgeAction(id,model){}
+
+};
+
+
// Overridden version of the Inventory-Folder-View-Bridge for Folders
class LLRecentItemsFolderBridge : public LLFolderBridge
{
+ friend class LLInvFVBridgeAction;
public:
// Creates context menu for Folders related to Recent Inventory Panel.
// Uses base logic and than removes from visible items "New..." menu items.
diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp
index ef4774a06d..dee15a1efd 100644
--- a/indra/newview/llinventoryfilter.cpp
+++ b/indra/newview/llinventoryfilter.cpp
@@ -393,18 +393,22 @@ void LLInventoryFilter::setFilterUUID(const LLUUID& object_id)
void LLInventoryFilter::setFilterSubString(const std::string& string)
{
- if (mFilterSubString != string)
+ std::string filter_sub_string_new = string;
+ mFilterSubStringOrig = string;
+ LLStringUtil::trimHead(filter_sub_string_new);
+ LLStringUtil::toUpper(filter_sub_string_new);
+
+ if (mFilterSubString != filter_sub_string_new)
{
// hitting BACKSPACE, for example
- const BOOL less_restrictive = mFilterSubString.size() >= string.size() && !mFilterSubString.substr(0, string.size()).compare(string);
+ const BOOL less_restrictive = mFilterSubString.size() >= filter_sub_string_new.size()
+ && !mFilterSubString.substr(0, filter_sub_string_new.size()).compare(filter_sub_string_new);
// appending new characters
- const BOOL more_restrictive = mFilterSubString.size() < string.size() && !string.substr(0, mFilterSubString.size()).compare(mFilterSubString);
+ const BOOL more_restrictive = mFilterSubString.size() < filter_sub_string_new.size()
+ && !filter_sub_string_new.substr(0, mFilterSubString.size()).compare(mFilterSubString);
- mFilterSubStringOrig = string;
- LLStringUtil::trimHead(mFilterSubStringOrig);
- mFilterSubString = mFilterSubStringOrig;
- LLStringUtil::toUpper(mFilterSubString);
+ mFilterSubString = filter_sub_string_new;
if (less_restrictive)
{
setModified(FILTER_LESS_RESTRICTIVE);
@@ -506,9 +510,15 @@ void LLInventoryFilter::setHoursAgo(U32 hours)
{
if (mFilterOps.mHoursAgo != hours)
{
+ bool are_date_limits_valid = mFilterOps.mMinDate == time_min() && mFilterOps.mMaxDate == time_max();
+
+ bool is_increasing = hours > mFilterOps.mHoursAgo;
+ bool is_increasing_from_zero = is_increasing && !mFilterOps.mHoursAgo;
+
// *NOTE: need to cache last filter time, in case filter goes stale
- BOOL less_restrictive = (mFilterOps.mMinDate == time_min() && mFilterOps.mMaxDate == time_max() && hours > mFilterOps.mHoursAgo);
- BOOL more_restrictive = (mFilterOps.mMinDate == time_min() && mFilterOps.mMaxDate == time_max() && hours <= mFilterOps.mHoursAgo);
+ BOOL less_restrictive = (are_date_limits_valid && ((is_increasing && mFilterOps.mHoursAgo)) || !hours);
+ BOOL more_restrictive = (are_date_limits_valid && (!is_increasing && hours) || is_increasing_from_zero);
+
mFilterOps.mHoursAgo = hours;
mFilterOps.mMinDate = time_min();
mFilterOps.mMaxDate = time_max();
diff --git a/indra/newview/llinventoryfilter.h b/indra/newview/llinventoryfilter.h
index f488b2ed1b..39e6f797a2 100644
--- a/indra/newview/llinventoryfilter.h
+++ b/indra/newview/llinventoryfilter.h
@@ -66,10 +66,13 @@ public:
FILTERLINK_ONLY_LINKS // only show links
};
- // REFACTOR: Change this to an enum.
- static const U32 SO_DATE = 1;
- static const U32 SO_FOLDERS_BY_NAME = 2;
- static const U32 SO_SYSTEM_FOLDERS_TO_TOP = 4;
+ enum ESortOrderType
+ {
+ SO_NAME = 0, // Sort inventory by name
+ SO_DATE = 0x1, // Sort inventory by date
+ SO_FOLDERS_BY_NAME = 0x1 << 1, // Force folder sort by name
+ SO_SYSTEM_FOLDERS_TO_TOP = 0x1 << 2 // Force system folders to be on top
+ };
LLInventoryFilter(const std::string& name);
virtual ~LLInventoryFilter();
diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp
index f3d9639dee..db3b968730 100644
--- a/indra/newview/llinventoryfunctions.cpp
+++ b/indra/newview/llinventoryfunctions.cpp
@@ -483,16 +483,10 @@ bool LLInventoryCollectFunctor::itemTransferCommonlyAllowed(const LLInventoryIte
switch(item->getType())
{
- case LLAssetType::AT_CALLINGCARD:
- return false;
- break;
case LLAssetType::AT_OBJECT:
- if (isAgentAvatarValid() && !gAgentAvatarp->isWearingAttachment(item->getUUID()))
- return true;
- break;
case LLAssetType::AT_BODYPART:
case LLAssetType::AT_CLOTHING:
- if(!gAgentWearables.isWearingItem(item->getUUID()))
+ if (!get_is_item_worn(item->getUUID()))
return true;
break;
default:
@@ -689,6 +683,12 @@ bool LLFindWearablesEx::operator()(LLInventoryCategory* cat, LLInventoryItem* it
return false;
}
+ // Skip broken links.
+ if (vitem->getIsBrokenLink())
+ {
+ return false;
+ }
+
return (bool) get_is_item_worn(item->getUUID()) == mIsWorn;
}
@@ -853,3 +853,4 @@ void LLOpenFoldersWithSelection::doFolder(LLFolderViewFolder* folder)
folder->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP);
}
}
+
diff --git a/indra/newview/llinventoryicon.cpp b/indra/newview/llinventoryicon.cpp
index 7216d61e7f..34734d57c5 100644
--- a/indra/newview/llinventoryicon.cpp
+++ b/indra/newview/llinventoryicon.cpp
@@ -50,7 +50,7 @@ public:
LLIconDictionary::LLIconDictionary()
{
addEntry(LLInventoryIcon::ICONNAME_TEXTURE, new IconEntry("Inv_Texture"));
- addEntry(LLInventoryIcon::ICONNAME_SOUND, new IconEntry("Inv_Texture"));
+ addEntry(LLInventoryIcon::ICONNAME_SOUND, new IconEntry("Inv_Sound"));
addEntry(LLInventoryIcon::ICONNAME_CALLINGCARD_ONLINE, new IconEntry("Inv_CallingCard"));
addEntry(LLInventoryIcon::ICONNAME_CALLINGCARD_OFFLINE, new IconEntry("Inv_CallingCard"));
addEntry(LLInventoryIcon::ICONNAME_LANDMARK, new IconEntry("Inv_Landmark"));
@@ -82,8 +82,11 @@ LLIconDictionary::LLIconDictionary()
addEntry(LLInventoryIcon::ICONNAME_ANIMATION, new IconEntry("Inv_Animation"));
addEntry(LLInventoryIcon::ICONNAME_GESTURE, new IconEntry("Inv_Gesture"));
+ addEntry(LLInventoryIcon::ICONNAME_CLOTHING_PHYSICS, new IconEntry("Inv_Physics"));
+
addEntry(LLInventoryIcon::ICONNAME_LINKITEM, new IconEntry("Inv_LinkItem"));
- addEntry(LLInventoryIcon::ICONNAME_LINKFOLDER, new IconEntry("Inv_LinkItem"));
+ addEntry(LLInventoryIcon::ICONNAME_LINKFOLDER, new IconEntry("Inv_LinkFolder"));
+ addEntry(LLInventoryIcon::ICONNAME_MESH, new IconEntry("Inv_Mesh"));
addEntry(LLInventoryIcon::ICONNAME_INVALID, new IconEntry("Inv_Invalid"));
@@ -157,6 +160,8 @@ const std::string& LLInventoryIcon::getIconName(LLAssetType::EType asset_type,
case LLAssetType::AT_OBJECT:
idx = ICONNAME_OBJECT;
break;
+ case LLAssetType::AT_MESH:
+ idx = ICONNAME_MESH;
default:
break;
}
diff --git a/indra/newview/llinventoryicon.h b/indra/newview/llinventoryicon.h
index 9a2cc08095..c7e2998a20 100644
--- a/indra/newview/llinventoryicon.h
+++ b/indra/newview/llinventoryicon.h
@@ -66,12 +66,15 @@ public:
ICONNAME_CLOTHING_SKIRT,
ICONNAME_CLOTHING_ALPHA,
ICONNAME_CLOTHING_TATTOO,
-
+
ICONNAME_ANIMATION,
ICONNAME_GESTURE,
+
+ ICONNAME_CLOTHING_PHYSICS,
ICONNAME_LINKITEM,
ICONNAME_LINKFOLDER,
+ ICONNAME_MESH,
ICONNAME_INVALID,
ICONNAME_COUNT,
diff --git a/indra/newview/llinventoryitemslist.h b/indra/newview/llinventoryitemslist.h
index 86e11dff17..b183a2052d 100644
--- a/indra/newview/llinventoryitemslist.h
+++ b/indra/newview/llinventoryitemslist.h
@@ -38,7 +38,6 @@ class LLViewerInventoryItem;
class LLInventoryItemsList : public LLFlatListViewEx
{
- LOG_CLASS(LLInventoryItemsList);
public:
struct Params : public LLInitParam::Block<Params, LLFlatListViewEx::Params>
{
diff --git a/indra/newview/llinventorylistitem.cpp b/indra/newview/llinventorylistitem.cpp
index 225d0288a9..3e0849a795 100644
--- a/indra/newview/llinventorylistitem.cpp
+++ b/indra/newview/llinventorylistitem.cpp
@@ -97,7 +97,8 @@ void LLPanelInventoryListItemBase::draw()
LLRect separator_rect = getLocalRect();
separator_rect.mTop = separator_rect.mBottom;
separator_rect.mBottom -= mSeparatorImage->getHeight();
- mSeparatorImage->draw(separator_rect);
+ F32 alpha = getCurrentTransparency();
+ mSeparatorImage->draw(separator_rect, UI_VERTEX_COLOR % alpha);
}
LLPanel::draw();
diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp
index 53835f0166..b5180854ef 100644
--- a/indra/newview/llinventorymodel.cpp
+++ b/indra/newview/llinventorymodel.cpp
@@ -631,6 +631,12 @@ U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item)
return mask;
}
+ // We're hiding mesh types
+ if (item->getType() == LLAssetType::AT_MESH)
+ {
+ return mask;
+ }
+
LLViewerInventoryItem* old_item = getItem(item->getUUID());
LLPointer<LLViewerInventoryItem> new_item;
if(old_item)
@@ -1059,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)
{
@@ -1081,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);
@@ -1187,7 +1184,7 @@ void LLInventoryModel::fetchInventoryResponder::result(const LLSD& content)
{
changes |= gInventory.updateItem(*it);
}
- gInventory.notifyObservers("fetchinventory");
+ gInventory.notifyObservers();
gViewerWindow->getWindow()->decBusyCount();
}
@@ -1196,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
@@ -1272,6 +1269,12 @@ void LLInventoryModel::addCategory(LLViewerInventoryCategory* category)
//llinfos << "LLInventoryModel::addCategory()" << llendl;
if(category)
{
+ // We aren't displaying the Meshes folder
+ if (category->mPreferredType == LLFolderType::FT_MESH)
+ {
+ return;
+ }
+
// try to localize default names first. See EXT-8319, EXT-7051.
category->localizeName();
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 eab8f187a7..7b1ff102e7 100644
--- a/indra/newview/llinventorymodelbackgroundfetch.cpp
+++ b/indra/newview/llinventorymodelbackgroundfetch.cpp
@@ -181,8 +181,8 @@ void LLInventoryModelBackgroundFetch::backgroundFetch()
if (mBackgroundFetchActive && gAgent.getRegion())
{
// If we'll be using the capability, we'll be sending batches and the background thing isn't as important.
- std::string url = gAgent.getRegion()->getCapability("WebFetchInventoryDescendents");
- if (!url.empty())
+ std::string url = gAgent.getRegion()->getCapability("FetchInventoryDescendents2");
+ if (gSavedSettings.getBOOL("UseHTTPInventory") && !url.empty())
{
bulkFetch(url);
return;
@@ -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
@@ -604,7 +604,7 @@ void LLInventoryModelBackgroundFetch::bulkFetch(std::string url)
}
if (body_lib["folders"].size())
{
- std::string url_lib = gAgent.getRegion()->getCapability("FetchLibDescendents");
+ std::string url_lib = gAgent.getRegion()->getCapability("FetchLibDescendents2");
LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(body_lib, recursive_cats);
LLHTTPClient::post(url_lib, body_lib, fetcher, 300.0);
diff --git a/indra/newview/llinventoryobserver.cpp b/indra/newview/llinventoryobserver.cpp
index 91ff8c7867..6bf19e346d 100644
--- a/indra/newview/llinventoryobserver.cpp
+++ b/indra/newview/llinventoryobserver.cpp
@@ -203,8 +203,8 @@ void fetch_items_from_llsd(const LLSD& items_llsd)
{
if (!items_llsd.size() || gDisconnected) return;
LLSD body;
- body[0]["cap_name"] = "FetchInventory";
- body[1]["cap_name"] = "FetchLib";
+ body[0]["cap_name"] = "FetchInventory2";
+ body[1]["cap_name"] = "FetchLib2";
for (S32 i=0; i<items_llsd.size();i++)
{
if (items_llsd[i]["owner_id"].asString() == gAgent.getID().asString())
@@ -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/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp
index 50adae09c0..1dcb91ad4d 100644
--- a/indra/newview/llinventorypanel.cpp
+++ b/indra/newview/llinventorypanel.cpp
@@ -60,6 +60,7 @@ static const LLInventoryFVBridgeBuilder INVENTORY_BRIDGE_BUILDER;
//
// Bridge to support knowing when the inventory has changed.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
class LLInventoryPanelObserver : public LLInventoryObserver
{
public:
@@ -73,9 +74,57 @@ protected:
LLInventoryPanel* mIP;
};
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Class LLInvPanelComplObserver
+//
+// Calls specified callback when all specified items become complete.
+//
+// Usage:
+// observer = new LLInvPanelComplObserver(boost::bind(onComplete));
+// inventory->addObserver(observer);
+// observer->reset(); // (optional)
+// observer->watchItem(incomplete_item1_id);
+// observer->watchItem(incomplete_item2_id);
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+class LLInvPanelComplObserver : public LLInventoryCompletionObserver
+{
+public:
+ typedef boost::function<void()> callback_t;
+
+ LLInvPanelComplObserver(callback_t cb)
+ : mCallback(cb)
+ {
+ }
+
+ void reset();
+
+private:
+ /*virtual*/ void done();
+
+ /// Called when all the items are complete.
+ callback_t mCallback;
+};
+
+void LLInvPanelComplObserver::reset()
+{
+ mIncomplete.clear();
+ mComplete.clear();
+}
+
+void LLInvPanelComplObserver::done()
+{
+ mCallback();
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Class LLInventoryPanel
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
LLInventoryPanel::LLInventoryPanel(const LLInventoryPanel::Params& p) :
LLPanel(p),
mInventoryObserver(NULL),
+ mCompletionObserver(NULL),
mFolderRoot(NULL),
mScroller(NULL),
mSortOrderSetting(p.sort_order_setting),
@@ -152,6 +201,9 @@ void LLInventoryPanel::initFromParams(const LLInventoryPanel::Params& params)
mInventoryObserver = new LLInventoryPanelObserver(this);
mInventory->addObserver(mInventoryObserver);
+ mCompletionObserver = new LLInvPanelComplObserver(boost::bind(&LLInventoryPanel::onItemsCompletion, this));
+ mInventory->addObserver(mCompletionObserver);
+
// Build view of inventory if we need default full hierarchy and inventory ready,
// otherwise wait for idle callback.
if (mBuildDefaultHierarchy && mInventory->isInventoryUsable() && !mViewsInitialized)
@@ -189,7 +241,10 @@ LLInventoryPanel::~LLInventoryPanel()
// LLView destructor will take care of the sub-views.
mInventory->removeObserver(mInventoryObserver);
+ mInventory->removeObserver(mCompletionObserver);
delete mInventoryObserver;
+ delete mCompletionObserver;
+
mScroller = NULL;
}
@@ -290,7 +345,10 @@ void LLInventoryPanel::modelChanged(U32 mask)
const LLUUID& item_id = (*items_iter);
const LLInventoryObject* model_item = model->getObject(item_id);
LLFolderViewItem* view_item = mFolderRoot->getItemByID(item_id);
- LLFolderViewFolder* view_folder = mFolderRoot->getFolderByID(item_id);
+
+ // LLFolderViewFolder is derived from LLFolderViewItem so dynamic_cast from item
+ // to folder is the fast way to get a folder without searching through folders tree.
+ LLFolderViewFolder* view_folder = dynamic_cast<LLFolderViewFolder*>(view_item);
//////////////////////////////
// LABEL Operation
@@ -651,6 +709,11 @@ void LLInventoryPanel::openStartFolderOrMyInventory()
}
}
+void LLInventoryPanel::onItemsCompletion()
+{
+ if (mFolderRoot) mFolderRoot->updateMenu();
+}
+
void LLInventoryPanel::openSelected()
{
LLFolderViewItem* folder_item = mFolderRoot->getCurSelectedItem();
@@ -754,6 +817,19 @@ void LLInventoryPanel::clearSelection()
void LLInventoryPanel::onSelectionChange(const std::deque<LLFolderViewItem*>& items, BOOL user_action)
{
+ // Schedule updating the folder view context menu when all selected items become complete (STORM-373).
+ mCompletionObserver->reset();
+ for (std::deque<LLFolderViewItem*>::const_iterator it = items.begin(); it != items.end(); ++it)
+ {
+ LLUUID id = (*it)->getListener()->getUUID();
+ LLViewerInventoryItem* inv_item = mInventory->getItem(id);
+
+ if (inv_item && !inv_item->isFinished())
+ {
+ mCompletionObserver->watchItem(id);
+ }
+ }
+
LLFolderView* fv = getRootFolder();
if (fv->needsAutoRename()) // auto-selecting a new user-created asset and preparing to rename
{
@@ -918,6 +994,8 @@ LLInventoryPanel* LLInventoryPanel::getActiveInventoryPanel(BOOL auto_open)
{
S32 z_min = S32_MAX;
LLInventoryPanel* res = NULL;
+ LLFloater* active_inv_floaterp = NULL;
+
// A. If the inventory side panel is open, use that preferably.
if (is_inventorysp_active())
{
@@ -938,6 +1016,7 @@ LLInventoryPanel* LLInventoryPanel::getActiveInventoryPanel(BOOL auto_open)
{
res = inventorySP->getActivePanel();
z_min = gFloaterView->getZOrder(inv_floater);
+ active_inv_floaterp = inv_floater;
}
else
{
@@ -957,10 +1036,19 @@ LLInventoryPanel* LLInventoryPanel::getActiveInventoryPanel(BOOL auto_open)
{
res = iv->getPanel();
z_min = z_order;
+ active_inv_floaterp = iv;
}
}
}
- if (res) return res;
+
+ if (res)
+ {
+ // Make sure the floater is not minimized (STORM-438).
+ if (active_inv_floaterp && active_inv_floaterp->isMinimized())
+ active_inv_floaterp->setMinimized(FALSE);
+
+ return res;
+ }
// C. If no panels are open and we don't want to force open a panel, then just abort out.
if (!auto_open) return NULL;
diff --git a/indra/newview/llinventorypanel.h b/indra/newview/llinventorypanel.h
index 6545fc0d5e..9da9f7d8ba 100644
--- a/indra/newview/llinventorypanel.h
+++ b/indra/newview/llinventorypanel.h
@@ -52,6 +52,7 @@ class LLIconCtrl;
class LLSaveFolderState;
class LLFilterEditor;
class LLTabContainer;
+class LLInvPanelComplObserver;
class LLInventoryPanel : public LLPanel
{
@@ -167,9 +168,11 @@ public:
protected:
void openStartFolderOrMyInventory(); // open the first level of inventory
+ void onItemsCompletion(); // called when selected items are complete
LLInventoryModel* mInventory;
LLInventoryObserver* mInventoryObserver;
+ LLInvPanelComplObserver* mCompletionObserver;
BOOL mAllowMultiSelect;
BOOL mShowItemLinkOverlays; // Shows link graphic over inventory item icons
diff --git a/indra/newview/lllistcontextmenu.cpp b/indra/newview/lllistcontextmenu.cpp
index ea744072d2..6421ab42bf 100644
--- a/indra/newview/lllistcontextmenu.cpp
+++ b/indra/newview/lllistcontextmenu.cpp
@@ -36,7 +36,6 @@
#include "llviewermenu.h" // for LLViewerMenuHolderGL
LLListContextMenu::LLListContextMenu()
-: mMenu(NULL)
{
}
@@ -51,23 +50,22 @@ LLListContextMenu::~LLListContextMenu()
// of mMenu has already been deleted except of using LLHandle. EXT-4762.
if (!mMenuHandle.isDead())
{
- mMenu->die();
- mMenu = NULL;
+ mMenuHandle.get()->die();
}
}
void LLListContextMenu::show(LLView* spawning_view, const uuid_vec_t& uuids, S32 x, S32 y)
{
- if (mMenu)
+ LLContextMenu* menup = mMenuHandle.get();
+ if (menup)
{
//preventing parent (menu holder) from deleting already "dead" context menus on exit
- LLView* parent = mMenu->getParent();
+ LLView* parent = menup->getParent();
if (parent)
{
- parent->removeChild(mMenu);
+ parent->removeChild(menup);
}
- delete mMenu;
- mMenu = NULL;
+ delete menup;
mUUIDs.clear();
}
@@ -79,23 +77,23 @@ void LLListContextMenu::show(LLView* spawning_view, const uuid_vec_t& uuids, S32
mUUIDs.resize(uuids.size());
std::copy(uuids.begin(), uuids.end(), mUUIDs.begin());
- mMenu = createMenu();
- if (!mMenu)
+ menup = createMenu();
+ if (!menup)
{
llwarns << "Context menu creation failed" << llendl;
return;
}
- mMenuHandle = mMenu->getHandle();
- mMenu->show(x, y);
- LLMenuGL::showPopup(spawning_view, mMenu, x, y);
+ mMenuHandle = menup->getHandle();
+ menup->show(x, y);
+ LLMenuGL::showPopup(spawning_view, menup, x, y);
}
void LLListContextMenu::hide()
{
- if(mMenu)
+ if(mMenuHandle.get())
{
- mMenu->hide();
+ mMenuHandle.get()->hide();
}
}
diff --git a/indra/newview/lllistcontextmenu.h b/indra/newview/lllistcontextmenu.h
index 5dedc30b0c..fabd68ee20 100644
--- a/indra/newview/lllistcontextmenu.h
+++ b/indra/newview/lllistcontextmenu.h
@@ -71,8 +71,7 @@ protected:
static void handleMultiple(functor_t functor, const uuid_vec_t& ids);
uuid_vec_t mUUIDs;
- LLContextMenu* mMenu;
- LLHandle<LLView> mMenuHandle;
+ LLHandle<LLContextMenu> mMenuHandle;
};
#endif // LL_LLLISTCONTEXTMENU_H
diff --git a/indra/newview/lllocationhistory.h b/indra/newview/lllocationhistory.h
index 188fbf1f9b..9fef42c5df 100644
--- a/indra/newview/lllocationhistory.h
+++ b/indra/newview/lllocationhistory.h
@@ -33,6 +33,7 @@
#include <string>
#include <map>
#include <boost/function.hpp>
+#include <boost/signals2.hpp>
class LLSD;
/**
diff --git a/indra/newview/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp
index 1527f8f4c9..5c65dcec34 100644
--- a/indra/newview/lllocationinputctrl.cpp
+++ b/indra/newview/lllocationinputctrl.cpp
@@ -211,7 +211,6 @@ LLLocationInputCtrl::LLLocationInputCtrl(const LLLocationInputCtrl::Params& p)
{
// Lets replace default LLLineEditor with LLLocationLineEditor
// to make needed escaping while copying and cutting url
- this->removeChild(mTextEntry);
delete mTextEntry;
// Can't access old mTextEntry fields as they are protected, so lets build new params
@@ -547,6 +546,10 @@ void LLLocationInputCtrl::onFocusLost()
{
LLUICtrl::onFocusLost();
refreshLocation();
+
+ // Setting cursor to 0 to show the left edge of the text. See STORM-370.
+ mTextEntry->setCursor(0);
+
if(mTextEntry->hasSelection()){
mTextEntry->deselect();
}
diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp
index 8c70b1e973..efc4e23838 100644
--- a/indra/newview/lllogchat.cpp
+++ b/indra/newview/lllogchat.cpp
@@ -32,6 +32,7 @@
#include "lltrans.h"
#include "llviewercontrol.h"
+#include "lldiriterator.h"
#include "llinstantmessage.h"
#include "llsingleton.h" // for LLSingleton
@@ -41,6 +42,7 @@
#include <boost/regex/v4/match_results.hpp>
#if LL_MSVC
+#pragma warning(push)
// disable warning about boost::lexical_cast unreachable code
// when it fails to parse the string
#pragma warning (disable:4702)
@@ -89,6 +91,16 @@ const static boost::regex TIMESTAMP_AND_STUFF("^(\\[\\d{4}/\\d{1,2}/\\d{1,2}\\s+
*/
const static boost::regex NAME_AND_TEXT("([^:]+[:]{1})?(\\s*)(.*)");
+/**
+ * These are recognizers for matching the names of ad-hoc conferences when generating the log file name
+ * On invited side, an ad-hoc is named like "<first name> <last name> Conference 2010/11/19 03:43 f0f4"
+ * On initiating side, an ad-hoc is named like Ad-hoc Conference hash<hash>"
+ * If the naming system for ad-hoc conferences are change in LLIMModel::LLIMSession::buildHistoryFileName()
+ * then these definition need to be adjusted as well.
+ */
+const static boost::regex INBOUND_CONFERENCE("^[a-zA-Z]{1,31} [a-zA-Z]{1,31} Conference [0-9]{4}/[0-9]{2}/[0-9]{2} [0-9]{2}:[0-9]{2} [0-9a-f]{4}");
+const static boost::regex OUTBOUND_CONFERENCE("^Ad-hoc Conference hash[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}");
+
//is used to parse complex object names like "Xstreet SL Terminal v2.2.5 st"
const static std::string NAME_TEXT_DIVIDER(": ");
@@ -182,15 +194,43 @@ private:
//static
std::string LLLogChat::makeLogFileName(std::string filename)
{
+ /**
+ * Testing for in bound and out bound ad-hoc file names
+ * if it is then skip date stamping.
+ **/
+ //LL_INFOS("") << "Befor:" << filename << LL_ENDL;/* uncomment if you want to verify step, delete on commit */
+ boost::match_results<std::string::const_iterator> matches;
+ bool inboundConf = boost::regex_match(filename, matches, INBOUND_CONFERENCE);
+ bool outboundConf = boost::regex_match(filename, matches, OUTBOUND_CONFERENCE);
+ if (!(inboundConf || outboundConf))
+ {
+ if( gSavedPerAccountSettings.getBOOL("LogFileNamewithDate") )
+ {
+ time_t now;
+ time(&now);
+ char dbuffer[20]; /* Flawfinder: ignore */
+ if (filename == "chat")
+ {
+ strftime(dbuffer, 20, "-%Y-%m-%d", localtime(&now));
+ }
+ else
+ {
+ strftime(dbuffer, 20, "-%Y-%m", localtime(&now));
+ }
+ filename += dbuffer;
+ }
+ }
+ //LL_INFOS("") << "After:" << filename << LL_ENDL;/* uncomment if you want to verify step, delete on commit */
filename = cleanFileName(filename);
filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_ACCOUNT_CHAT_LOGS,filename);
filename += ".txt";
+ //LL_INFOS("") << "Full:" << filename << LL_ENDL;/* uncomment if you want to verify step, delete on commit */
return filename;
}
std::string LLLogChat::cleanFileName(std::string filename)
{
- std::string invalidChars = "\"\'\\/?*:<>|";
+ std::string invalidChars = "\"\'\\/?*:.<>|";
std::string::size_type position = filename.find_first_of(invalidChars);
while (position != filename.npos)
{
@@ -354,10 +394,19 @@ void LLLogChat::loadAllHistory(const std::string& file_name, std::list<LLSD>& me
llwarns << "Session name is Empty!" << llendl;
return ;
}
-
- LLFILE* fptr = LLFile::fopen(makeLogFileName(file_name), "r"); /*Flawfinder: ignore*/
- if (!fptr) return; //No previous conversation with this name.
-
+ //LL_INFOS("") << "Loading:" << file_name << LL_ENDL;/* uncomment if you want to verify step, delete on commit */
+ //LL_INFOS("") << "Current:" << makeLogFileName(file_name) << LL_ENDL;/* uncomment if you want to verify step, delete on commit */
+ LLFILE* fptr = LLFile::fopen(makeLogFileName(file_name), "r");/*Flawfinder: ignore*/
+ if (!fptr)
+ {
+ fptr = LLFile::fopen(oldLogFileName(file_name), "r");/*Flawfinder: ignore*/
+ if (!fptr)
+ {
+ if (!fptr) return; //No previous conversation with this name.
+ }
+ }
+
+ //LL_INFOS("") << "Reading:" << file_name << LL_ENDL;
char buffer[LOG_RECALL_SIZE]; /*Flawfinder: ignore*/
char *bptr;
S32 len;
@@ -544,3 +593,33 @@ bool LLChatLogParser::parse(std::string& raw, LLSD& im)
im[IM_TEXT] = name_and_text[IDX_TEXT];
return true; //parsed name and message text, maybe have a timestamp too
}
+std::string LLLogChat::oldLogFileName(std::string filename)
+{
+ std::string scanResult;
+ std::string directory = gDirUtilp->getPerAccountChatLogsDir();/* get Users log directory */
+ directory += gDirUtilp->getDirDelimiter();/* add final OS dependent delimiter */
+ filename=cleanFileName(filename);/* lest make shure the file name has no invalad charecters befor making the pattern */
+ std::string pattern = (filename+(( filename == "chat" ) ? "-???\?-?\?-??.txt" : "-???\?-??.txt"));/* create search pattern*/
+ //LL_INFOS("") << "Checking:" << directory << " for " << pattern << LL_ENDL;/* uncomment if you want to verify step, delete on commit */
+ std::vector<std::string> allfiles;
+
+ LLDirIterator iter(directory, pattern);
+ while (iter.next(scanResult))
+ {
+ //LL_INFOS("") << "Found :" << scanResult << LL_ENDL;
+ allfiles.push_back(scanResult);
+ }
+
+ if (allfiles.size() == 0) // if no result from date search, return generic filename
+ {
+ scanResult = directory + filename + ".txt";
+ }
+ else
+ {
+ std::sort(allfiles.begin(), allfiles.end());
+ scanResult = directory + allfiles.back();
+ // thisfile is now the most recent version of the file.
+ }
+ //LL_INFOS("") << "Reading:" << scanResult << LL_ENDL;/* uncomment if you want to verify step, delete on commit */
+ return scanResult;
+}
diff --git a/indra/newview/lllogchat.h b/indra/newview/lllogchat.h
index 6958d56311..27752452c9 100644
--- a/indra/newview/lllogchat.h
+++ b/indra/newview/lllogchat.h
@@ -41,6 +41,10 @@ public:
};
static std::string timestamp(bool withdate = false);
static std::string makeLogFileName(std::string(filename));
+ /**
+ *Add functions to get old and non date stamped file names when needed
+ */
+ static std::string oldLogFileName(std::string(filename));
static void saveHistory(const std::string& filename,
const std::string& from,
const LLUUID& from_id,
diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp
index 029e700c4c..00de6a86e1 100644
--- a/indra/newview/lllogininstance.cpp
+++ b/indra/newview/lllogininstance.cpp
@@ -42,40 +42,450 @@
// newview
#include "llviewernetwork.h"
#include "llviewercontrol.h"
+#include "llversioninfo.h"
#include "llslurl.h"
#include "llstartup.h"
#include "llfloaterreg.h"
#include "llnotifications.h"
#include "llwindow.h"
#include "llviewerwindow.h"
+#include "llprogressview.h"
#if LL_LINUX || LL_SOLARIS
#include "lltrans.h"
#endif
#include "llsecapi.h"
#include "llstartup.h"
#include "llmachineid.h"
+#include "llupdaterservice.h"
+#include "llevents.h"
+#include "llnotificationsutil.h"
+#include "llappviewer.h"
+
+#include <boost/scoped_ptr.hpp>
+#include <sstream>
+
+class LLLoginInstance::Disposable {
+public:
+ virtual ~Disposable() {}
+};
+
+namespace {
+ class MandatoryUpdateMachine:
+ public LLLoginInstance::Disposable
+ {
+ public:
+ MandatoryUpdateMachine(LLLoginInstance & loginInstance, LLUpdaterService & updaterService);
+
+ void start(void);
+
+ private:
+ class State;
+ class CheckingForUpdate;
+ class Error;
+ class ReadyToInstall;
+ class StartingUpdaterService;
+ class WaitingForDownload;
+
+ LLLoginInstance & mLoginInstance;
+ boost::scoped_ptr<State> mState;
+ LLUpdaterService & mUpdaterService;
+
+ void setCurrentState(State * newState);
+ };
+
+
+ class MandatoryUpdateMachine::State {
+ public:
+ virtual ~State() {}
+ virtual void enter(void) {}
+ virtual void exit(void) {}
+ };
+
+
+ class MandatoryUpdateMachine::CheckingForUpdate:
+ public MandatoryUpdateMachine::State
+ {
+ public:
+ CheckingForUpdate(MandatoryUpdateMachine & machine);
+
+ virtual void enter(void);
+ virtual void exit(void);
+
+ private:
+ LLTempBoundListener mConnection;
+ MandatoryUpdateMachine & mMachine;
+ LLProgressView * mProgressView;
+
+ bool onEvent(LLSD const & event);
+ };
+
+
+ class MandatoryUpdateMachine::Error:
+ public MandatoryUpdateMachine::State
+ {
+ public:
+ Error(MandatoryUpdateMachine & machine);
+
+ virtual void enter(void);
+ virtual void exit(void);
+ void onButtonClicked(const LLSD &, const LLSD &);
+
+ private:
+ MandatoryUpdateMachine & mMachine;
+ };
+
+
+ class MandatoryUpdateMachine::ReadyToInstall:
+ public MandatoryUpdateMachine::State
+ {
+ public:
+ ReadyToInstall(MandatoryUpdateMachine & machine);
+
+ virtual void enter(void);
+ virtual void exit(void);
+
+ private:
+ MandatoryUpdateMachine & mMachine;
+ };
+
+
+ class MandatoryUpdateMachine::StartingUpdaterService:
+ public MandatoryUpdateMachine::State
+ {
+ public:
+ StartingUpdaterService(MandatoryUpdateMachine & machine);
+
+ virtual void enter(void);
+ virtual void exit(void);
+ void onButtonClicked(const LLSD & uiform, const LLSD & result);
+ private:
+ MandatoryUpdateMachine & mMachine;
+ };
+
+
+ class MandatoryUpdateMachine::WaitingForDownload:
+ public MandatoryUpdateMachine::State
+ {
+ public:
+ WaitingForDownload(MandatoryUpdateMachine & machine);
+
+ virtual void enter(void);
+ virtual void exit(void);
+
+ private:
+ LLTempBoundListener mConnection;
+ MandatoryUpdateMachine & mMachine;
+ LLProgressView * mProgressView;
+
+ bool onEvent(LLSD const & event);
+ };
+}
static const char * const TOS_REPLY_PUMP = "lllogininstance_tos_callback";
static const char * const TOS_LISTENER_NAME = "lllogininstance_tos";
std::string construct_start_string();
+
+
+// MandatoryUpdateMachine
+//-----------------------------------------------------------------------------
+
+
+MandatoryUpdateMachine::MandatoryUpdateMachine(LLLoginInstance & loginInstance, LLUpdaterService & updaterService):
+ mLoginInstance(loginInstance),
+ mUpdaterService(updaterService)
+{
+ ; // No op.
+}
+
+
+void MandatoryUpdateMachine::start(void)
+{
+ llinfos << "starting manditory update machine" << llendl;
+
+ if(mUpdaterService.isChecking()) {
+ switch(mUpdaterService.getState()) {
+ case LLUpdaterService::UP_TO_DATE:
+ mUpdaterService.stopChecking();
+ mUpdaterService.startChecking();
+ // Fall through.
+ case LLUpdaterService::INITIAL:
+ case LLUpdaterService::CHECKING_FOR_UPDATE:
+ setCurrentState(new CheckingForUpdate(*this));
+ break;
+ case LLUpdaterService::TEMPORARY_ERROR:
+ setCurrentState(new Error(*this));
+ break;
+ case LLUpdaterService::DOWNLOADING:
+ setCurrentState(new WaitingForDownload(*this));
+ break;
+ case LLUpdaterService::TERMINAL:
+ if(LLUpdaterService::updateReadyToInstall()) {
+ setCurrentState(new ReadyToInstall(*this));
+ } else {
+ setCurrentState(new Error(*this));
+ }
+ break;
+ case LLUpdaterService::FAILURE:
+ setCurrentState(new Error(*this));
+ break;
+ default:
+ llassert(!"unpossible case");
+ break;
+ }
+ } else {
+ setCurrentState(new StartingUpdaterService(*this));
+ }
+}
+
+
+void MandatoryUpdateMachine::setCurrentState(State * newStatePointer)
+{
+ {
+ boost::scoped_ptr<State> newState(newStatePointer);
+ if(mState != 0) mState->exit();
+ mState.swap(newState);
+
+ // Old state will be deleted on exit from this block before the new state
+ // is entered.
+ }
+ if(mState != 0) mState->enter();
+}
+
+
+
+// MandatoryUpdateMachine::CheckingForUpdate
+//-----------------------------------------------------------------------------
+
+
+MandatoryUpdateMachine::CheckingForUpdate::CheckingForUpdate(MandatoryUpdateMachine & machine):
+ mMachine(machine)
+{
+ ; // No op.
+}
+
+
+void MandatoryUpdateMachine::CheckingForUpdate::enter(void)
+{
+ llinfos << "entering checking for update" << llendl;
+
+ mProgressView = gViewerWindow->getProgressView();
+ mProgressView->setMessage("Looking for update...");
+ mProgressView->setText("There is a required update for your Second Life installation.");
+ mProgressView->setPercent(0);
+ mProgressView->setVisible(true);
+ mConnection = LLEventPumps::instance().obtain(LLUpdaterService::pumpName()).
+ listen("MandatoryUpdateMachine::CheckingForUpdate", boost::bind(&MandatoryUpdateMachine::CheckingForUpdate::onEvent, this, _1));
+}
+
+
+void MandatoryUpdateMachine::CheckingForUpdate::exit(void)
+{
+}
+
+
+bool MandatoryUpdateMachine::CheckingForUpdate::onEvent(LLSD const & event)
+{
+ if(event["type"].asInteger() == LLUpdaterService::STATE_CHANGE) {
+ switch(event["state"].asInteger()) {
+ case LLUpdaterService::DOWNLOADING:
+ mMachine.setCurrentState(new WaitingForDownload(mMachine));
+ break;
+ case LLUpdaterService::TEMPORARY_ERROR:
+ case LLUpdaterService::UP_TO_DATE:
+ case LLUpdaterService::TERMINAL:
+ case LLUpdaterService::FAILURE:
+ mProgressView->setVisible(false);
+ mMachine.setCurrentState(new Error(mMachine));
+ break;
+ case LLUpdaterService::INSTALLING:
+ llassert(!"can't possibly be installing");
+ break;
+ default:
+ break;
+ }
+ } else {
+ ; // Ignore.
+ }
+
+ return false;
+}
+
+
+
+// MandatoryUpdateMachine::Error
+//-----------------------------------------------------------------------------
+
+
+MandatoryUpdateMachine::Error::Error(MandatoryUpdateMachine & machine):
+ mMachine(machine)
+{
+ ; // No op.
+}
+
+
+void MandatoryUpdateMachine::Error::enter(void)
+{
+ llinfos << "entering error" << llendl;
+ LLNotificationsUtil::add("FailedRequiredUpdateInstall", LLSD(), LLSD(), boost::bind(&MandatoryUpdateMachine::Error::onButtonClicked, this, _1, _2));
+}
+
+
+void MandatoryUpdateMachine::Error::exit(void)
+{
+ LLAppViewer::instance()->forceQuit();
+}
+
+
+void MandatoryUpdateMachine::Error::onButtonClicked(const LLSD &, const LLSD &)
+{
+ mMachine.setCurrentState(0);
+}
+
+
+
+// MandatoryUpdateMachine::ReadyToInstall
+//-----------------------------------------------------------------------------
+
+
+MandatoryUpdateMachine::ReadyToInstall::ReadyToInstall(MandatoryUpdateMachine & machine):
+ mMachine(machine)
+{
+ ; // No op.
+}
+
+
+void MandatoryUpdateMachine::ReadyToInstall::enter(void)
+{
+ llinfos << "entering ready to install" << llendl;
+ // Open update ready dialog.
+}
+
+
+void MandatoryUpdateMachine::ReadyToInstall::exit(void)
+{
+ // Restart viewer.
+}
+
+
+
+// MandatoryUpdateMachine::StartingUpdaterService
+//-----------------------------------------------------------------------------
+
+
+MandatoryUpdateMachine::StartingUpdaterService::StartingUpdaterService(MandatoryUpdateMachine & machine):
+ mMachine(machine)
+{
+ ; // No op.
+}
+
+
+void MandatoryUpdateMachine::StartingUpdaterService::enter(void)
+{
+ llinfos << "entering start update service" << llendl;
+ LLNotificationsUtil::add("UpdaterServiceNotRunning", LLSD(), LLSD(), boost::bind(&MandatoryUpdateMachine::StartingUpdaterService::onButtonClicked, this, _1, _2));
+}
+
+
+void MandatoryUpdateMachine::StartingUpdaterService::exit(void)
+{
+ ; // No op.
+}
+
+
+void MandatoryUpdateMachine::StartingUpdaterService::onButtonClicked(const LLSD & uiform, const LLSD & result)
+{
+ if(result["OK_okcancelbuttons"].asBoolean()) {
+ mMachine.mUpdaterService.startChecking(false);
+ mMachine.setCurrentState(new CheckingForUpdate(mMachine));
+ } else {
+ LLAppViewer::instance()->forceQuit();
+ }
+}
+
+
+
+// MandatoryUpdateMachine::WaitingForDownload
+//-----------------------------------------------------------------------------
+
+
+MandatoryUpdateMachine::WaitingForDownload::WaitingForDownload(MandatoryUpdateMachine & machine):
+ mMachine(machine),
+ mProgressView(0)
+{
+ ; // No op.
+}
+
+
+void MandatoryUpdateMachine::WaitingForDownload::enter(void)
+{
+ llinfos << "entering waiting for download" << llendl;
+ mProgressView = gViewerWindow->getProgressView();
+ mProgressView->setMessage("Downloading update...");
+ std::ostringstream stream;
+ stream << "There is a required update for your Second Life installation." << std::endl <<
+ "Version " << mMachine.mUpdaterService.updatedVersion();
+ mProgressView->setText(stream.str());
+ mProgressView->setPercent(0);
+ mProgressView->setVisible(true);
+ mConnection = LLEventPumps::instance().obtain(LLUpdaterService::pumpName()).
+ listen("MandatoryUpdateMachine::CheckingForUpdate", boost::bind(&MandatoryUpdateMachine::WaitingForDownload::onEvent, this, _1));
+}
+
+
+void MandatoryUpdateMachine::WaitingForDownload::exit(void)
+{
+ mProgressView->setVisible(false);
+}
+
+
+bool MandatoryUpdateMachine::WaitingForDownload::onEvent(LLSD const & event)
+{
+ switch(event["type"].asInteger()) {
+ case LLUpdaterService::DOWNLOAD_COMPLETE:
+ mMachine.setCurrentState(new ReadyToInstall(mMachine));
+ break;
+ case LLUpdaterService::DOWNLOAD_ERROR:
+ mMachine.setCurrentState(new Error(mMachine));
+ break;
+ case LLUpdaterService::PROGRESS: {
+ double downloadSize = event["download_size"].asReal();
+ double bytesDownloaded = event["bytes_downloaded"].asReal();
+ mProgressView->setPercent(100. * bytesDownloaded / downloadSize);
+ break;
+ }
+ default:
+ break;
+ }
+
+ return false;
+}
+
+
+
+// LLLoginInstance
+//-----------------------------------------------------------------------------
+
+
LLLoginInstance::LLLoginInstance() :
mLoginModule(new LLLogin()),
mNotifications(NULL),
mLoginState("offline"),
- mUserInteraction(true),
mSkipOptionalUpdate(false),
mAttemptComplete(false),
mTransferRate(0.0f),
- mDispatcher("LLLoginInstance", "change")
+ mDispatcher("LLLoginInstance", "change"),
+ mUpdaterService(0)
{
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()
@@ -148,7 +558,20 @@ void LLLoginInstance::constructAuthParams(LLPointer<LLCredential> user_credentia
requested_options.append("buddy-list");
requested_options.append("newuser-config");
requested_options.append("ui-config");
+
+ //send this info to login.cgi for stats gathering
+ //since viewerstats isn't reliable enough
+ if (gSavedSettings.getString("SessionSettingsFile").empty())
+ {
+ requested_options.append("advanced-mode");
+ }
+ else
+ {
+ requested_options.append("basic-mode");
+ }
+
#endif
+ requested_options.append("max-agent-groups");
requested_options.append("map-server-url");
requested_options.append("voice-config");
requested_options.append("tutorial_setting");
@@ -181,9 +604,11 @@ void LLLoginInstance::constructAuthParams(LLPointer<LLCredential> user_credentia
request_params["read_critical"] = false; // handleTOSResponse
request_params["last_exec_event"] = mLastExecEvent;
request_params["mac"] = hashed_unique_id_string;
- request_params["version"] = gCurrentVersion; // Includes channel name
- request_params["channel"] = gSavedSettings.getString("VersionChannelName");
+ request_params["version"] = LLVersionInfo::getChannelAndVersion(); // Includes channel name
+ request_params["channel"] = LLVersionInfo::getChannel();
request_params["id0"] = mSerialNumber;
+ request_params["host_id"] = gSavedSettings.getString("HostID");
+ request_params["extended_errors"] = true; // request message_id and message_args
mRequestData.clear();
mRequestData["method"] = "login_to_simulator";
@@ -215,11 +640,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;
}
@@ -230,64 +651,57 @@ void LLLoginInstance::handleLoginFailure(const LLSD& event)
LLSD response = event["data"];
std::string reason_response = response["reason"].asString();
std::string message_response = response["message"].asString();
- if(mUserInteraction)
+ // For the cases of critical message or TOS agreement,
+ // start the TOS dialog. The dialog response will be handled
+ // by the LLLoginInstance::handleTOSResponse() callback.
+ // The callback intiates the login attempt next step, either
+ // to reconnect or to end the attempt in failure.
+ if(reason_response == "tos")
{
- // For the cases of critical message or TOS agreement,
- // start the TOS dialog. The dialog response will be handled
- // by the LLLoginInstance::handleTOSResponse() callback.
- // The callback intiates the login attempt next step, either
- // to reconnect or to end the attempt in failure.
- if(reason_response == "tos")
- {
- LLSD data(LLSD::emptyMap());
- data["message"] = message_response;
- data["reply_pump"] = TOS_REPLY_PUMP;
- gViewerWindow->setShowProgress(FALSE);
- LLFloaterReg::showInstance("message_tos", data);
- LLEventPumps::instance().obtain(TOS_REPLY_PUMP)
- .listen(TOS_LISTENER_NAME,
- boost::bind(&LLLoginInstance::handleTOSResponse,
- this, _1, "agree_to_tos"));
- }
- else if(reason_response == "critical")
- {
- LLSD data(LLSD::emptyMap());
- data["message"] = message_response;
- data["reply_pump"] = TOS_REPLY_PUMP;
- if(response.has("error_code"))
- {
- data["error_code"] = response["error_code"];
- }
- if(response.has("certificate"))
- {
- data["certificate"] = response["certificate"];
- }
-
- gViewerWindow->setShowProgress(FALSE);
- LLFloaterReg::showInstance("message_critical", data);
- LLEventPumps::instance().obtain(TOS_REPLY_PUMP)
- .listen(TOS_LISTENER_NAME,
- boost::bind(&LLLoginInstance::handleTOSResponse,
- this, _1, "read_critical"));
- }
- else if(reason_response == "update" || gSavedSettings.getBOOL("ForceMandatoryUpdate"))
+ LLSD data(LLSD::emptyMap());
+ data["message"] = message_response;
+ data["reply_pump"] = TOS_REPLY_PUMP;
+ gViewerWindow->setShowProgress(FALSE);
+ LLFloaterReg::showInstance("message_tos", data);
+ LLEventPumps::instance().obtain(TOS_REPLY_PUMP)
+ .listen(TOS_LISTENER_NAME,
+ boost::bind(&LLLoginInstance::handleTOSResponse,
+ this, _1, "agree_to_tos"));
+ }
+ else if(reason_response == "critical")
+ {
+ LLSD data(LLSD::emptyMap());
+ data["message"] = message_response;
+ data["reply_pump"] = TOS_REPLY_PUMP;
+ if(response.has("error_code"))
{
- gSavedSettings.setBOOL("ForceMandatoryUpdate", FALSE);
- updateApp(true, message_response);
+ data["error_code"] = response["error_code"];
}
- else if(reason_response == "optional")
+ if(response.has("certificate"))
{
- updateApp(false, message_response);
+ data["certificate"] = response["certificate"];
}
- else
- {
- attemptComplete();
- }
+
+ gViewerWindow->setShowProgress(FALSE);
+ LLFloaterReg::showInstance("message_critical", data);
+ LLEventPumps::instance().obtain(TOS_REPLY_PUMP)
+ .listen(TOS_LISTENER_NAME,
+ boost::bind(&LLLoginInstance::handleTOSResponse,
+ this, _1, "read_critical"));
}
- else // no user interaction
+ else if(reason_response == "update" || gSavedSettings.getBOOL("ForceMandatoryUpdate"))
{
- attemptComplete();
+ gSavedSettings.setBOOL("ForceMandatoryUpdate", FALSE);
+ updateApp(true, message_response);
+ }
+ else if(reason_response == "optional")
+ {
+ updateApp(false, message_response);
}
+ else
+ {
+ attemptComplete();
+ }
}
void LLLoginInstance::handleLoginSuccess(const LLSD& event)
@@ -351,6 +765,15 @@ bool LLLoginInstance::handleTOSResponse(bool accepted, const std::string& key)
void LLLoginInstance::updateApp(bool mandatory, const std::string& auth_msg)
{
+ if(mandatory)
+ {
+ gViewerWindow->setShowProgress(false);
+ MandatoryUpdateMachine * machine = new MandatoryUpdateMachine(*this, *mUpdaterService);
+ mUpdateStateMachine.reset(machine);
+ machine->start();
+ return;
+ }
+
// store off config state, as we might quit soon
gSavedSettings.saveToFile(gSavedSettings.getString("ClientSettingsFile"), TRUE);
LLUIColorTable::instance().saveUserSettings();
diff --git a/indra/newview/lllogininstance.h b/indra/newview/lllogininstance.h
index 159e05046c..8b53431219 100644
--- a/indra/newview/lllogininstance.h
+++ b/indra/newview/lllogininstance.h
@@ -34,12 +34,15 @@
class LLLogin;
class LLEventStream;
class LLNotificationsInterface;
+class LLUpdaterService;
// This class hosts the login module and is used to
// negotiate user authentication attempts.
class LLLoginInstance : public LLSingleton<LLLoginInstance>
{
public:
+ class Disposable;
+
LLLoginInstance();
~LLLoginInstance();
@@ -58,12 +61,6 @@ public:
// Only valid when authSuccess == true.
const F64 getLastTransferRateBPS() { return mTransferRate; }
- // Set whether this class will drive user interaction.
- // If not, login failures like 'need tos agreement' will
- // end the login attempt.
- void setUserInteraction(bool state) { mUserInteraction = state; }
- bool getUserInteraction() { return mUserInteraction; }
-
// Whether to tell login to skip optional update request.
// False by default.
void setSkipOptionalUpdate(bool state) { mSkipOptionalUpdate = state; }
@@ -75,6 +72,7 @@ public:
typedef boost::function<void()> UpdaterLauncherCallback;
void setUpdaterLauncher(const UpdaterLauncherCallback& ulc) { mUpdaterLauncher = ulc; }
+ void setUpdaterService(LLUpdaterService * updaterService) { mUpdaterService = updaterService; }
private:
void constructAuthParams(LLPointer<LLCredential> user_credentials);
void updateApp(bool mandatory, const std::string& message);
@@ -96,7 +94,6 @@ private:
std::string mLoginState;
LLSD mRequestData;
LLSD mResponseData;
- bool mUserInteraction;
bool mSkipOptionalUpdate;
bool mAttemptComplete;
F64 mTransferRate;
@@ -104,6 +101,8 @@ private:
int mLastExecEvent;
UpdaterLauncherCallback mUpdaterLauncher;
LLEventDispatcher mDispatcher;
+ LLUpdaterService * mUpdaterService;
+ boost::scoped_ptr<Disposable> mUpdateStateMachine;
};
#endif
diff --git a/indra/newview/llmainlooprepeater.cpp b/indra/newview/llmainlooprepeater.cpp
new file mode 100644
index 0000000000..5c020e6d98
--- /dev/null
+++ b/indra/newview/llmainlooprepeater.cpp
@@ -0,0 +1,88 @@
+/**
+ * @file llmachineid.cpp
+ * @brief retrieves unique machine ids
+ *
+ * $LicenseInfo:firstyear=2009&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 "llapr.h"
+#include "llevents.h"
+#include "llmainlooprepeater.h"
+
+
+
+// LLMainLoopRepeater
+//-----------------------------------------------------------------------------
+
+
+LLMainLoopRepeater::LLMainLoopRepeater(void):
+ mQueue(0)
+{
+ ; // No op.
+}
+
+
+void LLMainLoopRepeater::start(void)
+{
+ if(mQueue != 0) return;
+
+ mQueue = new LLThreadSafeQueue<LLSD>(gAPRPoolp, 1024);
+ mMainLoopConnection = LLEventPumps::instance().
+ obtain("mainloop").listen(LLEventPump::inventName(), boost::bind(&LLMainLoopRepeater::onMainLoop, this, _1));
+ mRepeaterConnection = LLEventPumps::instance().
+ obtain("mainlooprepeater").listen(LLEventPump::inventName(), boost::bind(&LLMainLoopRepeater::onMessage, this, _1));
+}
+
+
+void LLMainLoopRepeater::stop(void)
+{
+ mMainLoopConnection.release();
+ mRepeaterConnection.release();
+
+ delete mQueue;
+ mQueue = 0;
+}
+
+
+bool LLMainLoopRepeater::onMainLoop(LLSD const &)
+{
+ LLSD message;
+ while(mQueue->tryPopBack(message)) {
+ std::string pump = message["pump"].asString();
+ if(pump.length() == 0 ) continue; // No pump.
+ LLEventPumps::instance().obtain(pump).post(message["payload"]);
+ }
+ return false;
+}
+
+
+bool LLMainLoopRepeater::onMessage(LLSD const & event)
+{
+ try {
+ mQueue->pushFront(event);
+ } catch(LLThreadSafeQueueError & e) {
+ llwarns << "could not repeat message (" << e.what() << ")" <<
+ event.asString() << LL_ENDL;
+ }
+ return false;
+}
diff --git a/indra/newview/llmainlooprepeater.h b/indra/newview/llmainlooprepeater.h
new file mode 100644
index 0000000000..f84c0ca94c
--- /dev/null
+++ b/indra/newview/llmainlooprepeater.h
@@ -0,0 +1,65 @@
+/**
+ * @file llmainlooprepeater.h
+ * @brief a service for repeating messages on the main loop.
+ *
+ * $LicenseInfo:firstyear=2010&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_LLMAINLOOPREPEATER_H
+#define LL_LLMAINLOOPREPEATER_H
+
+
+#include "llsd.h"
+#include "llthreadsafequeue.h"
+
+
+//
+// A service which creates the pump 'mainlooprepeater' to which any thread can
+// post a message that will be re-posted on the main loop.
+//
+// The posted message should contain two map elements: pump and payload. The
+// pump value is a string naming the pump to which the message should be
+// re-posted. The payload value is what will be posted to the designated pump.
+//
+class LLMainLoopRepeater:
+ public LLSingleton<LLMainLoopRepeater>
+{
+public:
+ LLMainLoopRepeater(void);
+
+ // Start the repeater service.
+ void start(void);
+
+ // Stop the repeater service.
+ void stop(void);
+
+private:
+ LLTempBoundListener mMainLoopConnection;
+ LLTempBoundListener mRepeaterConnection;
+ LLThreadSafeQueue<LLSD> * mQueue;
+
+ bool onMainLoop(LLSD const &);
+ bool onMessage(LLSD const & event);
+};
+
+
+#endif
diff --git a/indra/newview/llmaniprotate.cpp b/indra/newview/llmaniprotate.cpp
index 43a16f8ed8..6ee095475f 100644
--- a/indra/newview/llmaniprotate.cpp
+++ b/indra/newview/llmaniprotate.cpp
@@ -901,32 +901,32 @@ void LLManipRotate::renderSnapGuides()
{
if (i == 0)
{
- renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Forward") : LLTrans::getString("East"), LLColor4::white);
+ renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Direction_Forward") : LLTrans::getString("Direction_East"), LLColor4::white);
}
else if (i == 16)
{
if (constraint_axis.mV[VZ] > 0.f)
{
- renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Left") : LLTrans::getString("North"), LLColor4::white);
+ renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Direction_Left") : LLTrans::getString("Direction_North"), LLColor4::white);
}
else
{
- renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Right") : LLTrans::getString("South"), LLColor4::white);
+ renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Direction_Right") : LLTrans::getString("Direction_South"), LLColor4::white);
}
}
else if (i == 32)
{
- renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Back") : LLTrans::getString("West"), LLColor4::white);
+ renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Direction_Back") : LLTrans::getString("Direction_West"), LLColor4::white);
}
else
{
if (constraint_axis.mV[VZ] > 0.f)
{
- renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Right") : LLTrans::getString("South"), LLColor4::white);
+ renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Direction_Right") : LLTrans::getString("Direction_South"), LLColor4::white);
}
else
{
- renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Left") : LLTrans::getString("North"), LLColor4::white);
+ renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Direction_Left") : LLTrans::getString("Direction_North"), LLColor4::white);
}
}
}
@@ -934,32 +934,32 @@ void LLManipRotate::renderSnapGuides()
{
if (i == 0)
{
- renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Left") : LLTrans::getString("North"), LLColor4::white);
+ renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Direction_Left") : LLTrans::getString("Direction_North"), LLColor4::white);
}
else if (i == 16)
{
if (constraint_axis.mV[VX] > 0.f)
{
- renderTickText(text_point, LLTrans::getString("Up"), LLColor4::white);
+ renderTickText(text_point, LLTrans::getString("Direction_Up"), LLColor4::white);
}
else
{
- renderTickText(text_point, LLTrans::getString("Down"), LLColor4::white);
+ renderTickText(text_point, LLTrans::getString("Direction_Down"), LLColor4::white);
}
}
else if (i == 32)
{
- renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Right") : LLTrans::getString("South"), LLColor4::white);
+ renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Direction_Right") : LLTrans::getString("Direction_South"), LLColor4::white);
}
else
{
if (constraint_axis.mV[VX] > 0.f)
{
- renderTickText(text_point, LLTrans::getString("Down"), LLColor4::white);
+ renderTickText(text_point, LLTrans::getString("Direction_Down"), LLColor4::white);
}
else
{
- renderTickText(text_point, LLTrans::getString("Up"), LLColor4::white);
+ renderTickText(text_point, LLTrans::getString("Direction_Up"), LLColor4::white);
}
}
}
@@ -967,32 +967,32 @@ void LLManipRotate::renderSnapGuides()
{
if (i == 0)
{
- renderTickText(text_point, LLTrans::getString("Up"), LLColor4::white);
+ renderTickText(text_point, LLTrans::getString("Direction_Up"), LLColor4::white);
}
else if (i == 16)
{
if (constraint_axis.mV[VY] > 0.f)
{
- renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Forward") : LLTrans::getString("East"), LLColor4::white);
+ renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Direction_Forward") : LLTrans::getString("Direction_East"), LLColor4::white);
}
else
{
- renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Back") : LLTrans::getString("West"), LLColor4::white);
+ renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Direction_Back") : LLTrans::getString("Direction_West"), LLColor4::white);
}
}
else if (i == 32)
{
- renderTickText(text_point, LLTrans::getString("Down"), LLColor4::white);
+ renderTickText(text_point, LLTrans::getString("Direction_Down"), LLColor4::white);
}
else
{
if (constraint_axis.mV[VY] > 0.f)
{
- renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Back") : LLTrans::getString("West"), LLColor4::white);
+ renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Direction_Back") : LLTrans::getString("Direction_West"), LLColor4::white);
}
else
{
- renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Forward") : LLTrans::getString("East"), LLColor4::white);
+ renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Direction_Forward") : LLTrans::getString("Direction_East"), LLColor4::white);
}
}
}
@@ -1127,7 +1127,7 @@ BOOL LLManipRotate::updateVisiblity()
if (gSavedSettings.getBOOL("LimitSelectDistance"))
{
F32 max_select_distance = gSavedSettings.getF32("MaxSelectDistance");
- if (dist_vec(gAgent.getPositionAgent(), center) > max_select_distance)
+ if (dist_vec_squared(gAgent.getPositionAgent(), center) > (max_select_distance * max_select_distance))
{
visible = FALSE;
}
diff --git a/indra/newview/llmanipscale.cpp b/indra/newview/llmanipscale.cpp
index 060677f9f3..738d82e732 100644
--- a/indra/newview/llmanipscale.cpp
+++ b/indra/newview/llmanipscale.cpp
@@ -52,6 +52,7 @@
#include "llui.h"
#include "llviewercamera.h"
#include "llviewerobject.h"
+#include "llviewerregion.h"
#include "llviewerwindow.h"
#include "llhudrender.h"
#include "llworld.h"
@@ -85,6 +86,22 @@ const LLManip::EManipPart MANIPULATOR_IDS[NUM_MANIPULATORS] =
};
+F32 get_default_max_prim_scale(bool is_flora)
+{
+ // a bit of a hack, but if it's foilage, we don't want to use the
+ // new larger scale which would result in giant trees and grass
+ if (gSavedSettings.getBOOL("MeshEnabled") &&
+ gAgent.getRegion() &&
+ !gAgent.getRegion()->getCapability("GetMesh").empty() &&
+ !is_flora)
+ {
+ return DEFAULT_MAX_PRIM_SCALE;
+ }
+ else
+ {
+ return DEFAULT_MAX_PRIM_SCALE_NO_MESH;
+ }
+}
// static
void LLManipScale::setUniform(BOOL b)
@@ -217,8 +234,6 @@ void LLManipScale::render()
LLVector3 center_agent = gAgent.getPosAgentFromGlobal(LLSelectMgr::getInstance()->getSelectionCenterGlobal());
- F32 range;
- F32 range_from_agent;
if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
{
mBoxHandleSize = BOX_HANDLE_BASE_SIZE * BOX_HANDLE_BASE_FACTOR / (F32) LLViewerCamera::getInstance()->getViewHeightInPixels();
@@ -226,25 +241,25 @@ void LLManipScale::render()
}
else
{
- range = dist_vec(gAgentCamera.getCameraPositionAgent(), center_agent);
- range_from_agent = dist_vec(gAgent.getPositionAgent(), center_agent);
+ F32 range_squared = dist_vec_squared(gAgentCamera.getCameraPositionAgent(), center_agent);
+ F32 range_from_agent_squared = dist_vec_squared(gAgent.getPositionAgent(), center_agent);
// Don't draw manip if object too far away
if (gSavedSettings.getBOOL("LimitSelectDistance"))
{
F32 max_select_distance = gSavedSettings.getF32("MaxSelectDistance");
- if (range_from_agent > max_select_distance)
+ if (range_from_agent_squared > max_select_distance * max_select_distance)
{
return;
}
}
- if (range > 0.001f)
+ if (range_squared > 0.001f * 0.001f)
{
// range != zero
F32 fraction_of_fov = BOX_HANDLE_BASE_SIZE / (F32) LLViewerCamera::getInstance()->getViewHeightInPixels();
F32 apparent_angle = fraction_of_fov * LLViewerCamera::getInstance()->getView(); // radians
- mBoxHandleSize = range * tan(apparent_angle) * BOX_HANDLE_BASE_FACTOR;
+ mBoxHandleSize = (F32) sqrtf(range_squared) * tan(apparent_angle) * BOX_HANDLE_BASE_FACTOR;
}
else
{
@@ -950,8 +965,8 @@ void LLManipScale::dragCorner( S32 x, S32 y )
mInSnapRegime = FALSE;
}
- F32 max_scale_factor = DEFAULT_MAX_PRIM_SCALE / MIN_PRIM_SCALE;
- F32 min_scale_factor = MIN_PRIM_SCALE / DEFAULT_MAX_PRIM_SCALE;
+ F32 max_scale_factor = get_default_max_prim_scale() / MIN_PRIM_SCALE;
+ F32 min_scale_factor = MIN_PRIM_SCALE / get_default_max_prim_scale();
// find max and min scale factors that will make biggest object hit max absolute scale and smallest object hit min absolute scale
for (LLObjectSelection::iterator iter = mObjectSelection->begin();
@@ -963,7 +978,7 @@ void LLManipScale::dragCorner( S32 x, S32 y )
{
const LLVector3& scale = selectNode->mSavedScale;
- F32 cur_max_scale_factor = llmin( DEFAULT_MAX_PRIM_SCALE / scale.mV[VX], DEFAULT_MAX_PRIM_SCALE / scale.mV[VY], DEFAULT_MAX_PRIM_SCALE / scale.mV[VZ] );
+ F32 cur_max_scale_factor = llmin( get_default_max_prim_scale(LLPickInfo::isFlora(cur)) / scale.mV[VX], get_default_max_prim_scale(LLPickInfo::isFlora(cur)) / scale.mV[VY], get_default_max_prim_scale(LLPickInfo::isFlora(cur)) / scale.mV[VZ] );
max_scale_factor = llmin( max_scale_factor, cur_max_scale_factor );
F32 cur_min_scale_factor = llmax( MIN_PRIM_SCALE / scale.mV[VX], MIN_PRIM_SCALE / scale.mV[VY], MIN_PRIM_SCALE / scale.mV[VZ] );
@@ -1260,7 +1275,7 @@ void LLManipScale::stretchFace( const LLVector3& drag_start_agent, const LLVecto
F32 denom = axis * dir_local;
F32 desired_delta_size = is_approx_zero(denom) ? 0.f : (delta_local_mag / denom); // in meters
- F32 desired_scale = llclamp(selectNode->mSavedScale.mV[axis_index] + desired_delta_size, MIN_PRIM_SCALE, DEFAULT_MAX_PRIM_SCALE);
+ F32 desired_scale = llclamp(selectNode->mSavedScale.mV[axis_index] + desired_delta_size, MIN_PRIM_SCALE, get_default_max_prim_scale(LLPickInfo::isFlora(cur)));
// propagate scale constraint back to position offset
desired_delta_size = desired_scale - selectNode->mSavedScale.mV[axis_index]; // propagate constraint back to position
@@ -1960,7 +1975,7 @@ F32 LLManipScale::partToMaxScale( S32 part, const LLBBox &bbox ) const
max_extent = bbox_extents.mV[i];
}
}
- max_scale_factor = bbox_extents.magVec() * DEFAULT_MAX_PRIM_SCALE / max_extent;
+ max_scale_factor = bbox_extents.magVec() * get_default_max_prim_scale() / max_extent;
if (getUniform())
{
@@ -1975,7 +1990,7 @@ F32 LLManipScale::partToMinScale( S32 part, const LLBBox &bbox ) const
{
LLVector3 bbox_extents = unitVectorToLocalBBoxExtent( partToUnitVector( part ), bbox );
bbox_extents.abs();
- F32 min_extent = DEFAULT_MAX_PRIM_SCALE;
+ F32 min_extent = get_default_max_prim_scale();
for (U32 i = VX; i <= VZ; i++)
{
if (bbox_extents.mV[i] > 0.f && bbox_extents.mV[i] < min_extent)
diff --git a/indra/newview/llmanipscale.h b/indra/newview/llmanipscale.h
index 5559f557c0..5cb8898fd0 100644
--- a/indra/newview/llmanipscale.h
+++ b/indra/newview/llmanipscale.h
@@ -39,6 +39,9 @@
#include "llviewerobject.h"
#include "llbbox.h"
+
+F32 get_default_max_prim_scale(bool is_flora = false);
+
class LLToolComposite;
class LLColor4;
diff --git a/indra/newview/llmaniptranslate.cpp b/indra/newview/llmaniptranslate.cpp
index 5eb3b789f2..f871df0c36 100644
--- a/indra/newview/llmaniptranslate.cpp
+++ b/indra/newview/llmaniptranslate.cpp
@@ -726,7 +726,7 @@ BOOL LLManipTranslate::handleHover(S32 x, S32 y, MASK mask)
LLVector3d new_position_global = selectNode->mSavedPositionGlobal + clamped_relative_move;
// Don't let object centers go too far underground
- F64 min_height = LLWorld::getInstance()->getMinAllowedZ(object);
+ F64 min_height = LLWorld::getInstance()->getMinAllowedZ(object, object->getPositionGlobal());
if (new_position_global.mdV[VZ] < min_height)
{
new_position_global.mdV[VZ] = min_height;
diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp
index e84c9152b1..b3ad9efeb2 100644
--- a/indra/newview/llmediactrl.cpp
+++ b/indra/newview/llmediactrl.cpp
@@ -25,7 +25,7 @@
*/
#include "llviewerprecompiledheaders.h"
-
+#include "lltooltip.h"
#include "llmediactrl.h"
@@ -44,6 +44,7 @@
#include "llslurl.h"
#include "lluictrlfactory.h" // LLDefaultChildRegistry
#include "llkeyboard.h"
+#include "llviewermenu.h"
// linden library includes
#include "llfocusmgr.h"
@@ -54,6 +55,10 @@
#include "llbutton.h"
#include "llcheckboxctrl.h"
#include "llnotifications.h"
+#include "lllineeditor.h"
+#include "llfloatermediabrowser.h"
+#include "llfloaterwebcontent.h"
+#include "llwindowshade.h"
extern BOOL gRestoreGL;
@@ -63,14 +68,15 @@ LLMediaCtrl::Params::Params()
: start_url("start_url"),
border_visible("border_visible", true),
ignore_ui_scale("ignore_ui_scale", true),
- hide_loading("hide_loading", false),
decouple_texture_size("decouple_texture_size", false),
texture_width("texture_width", 1024),
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)
+ trusted_content("trusted_content", false),
+ focus_on_click("focus_on_click", true)
{
tab_stop(false);
}
@@ -86,18 +92,20 @@ LLMediaCtrl::LLMediaCtrl( const Params& p) :
mIgnoreUIScale( true ),
mAlwaysRefresh( false ),
mMediaSource( 0 ),
- mTakeFocusOnClick( true ),
+ mTakeFocusOnClick( p.focus_on_click ),
mCurrentNavUrl( "" ),
mStretchToFill( true ),
mMaintainAspectRatio ( true ),
- mHideLoading (false),
- mHidingInitialLoad (false),
mDecoupleTextureSize ( false ),
mTextureWidth ( 1024 ),
mTextureHeight ( 1024 ),
mClearCache(false),
mHomePageMimeType(p.initial_mime_type),
- mTrusted(p.trusted_content)
+ mErrorPageURL(p.error_page_url),
+ mTrusted(p.trusted_content),
+ mWindowShade(NULL),
+ mHoverTextChanged(false),
+ mContextMenu(NULL)
{
{
LLColor4 color = p.caret_color().get();
@@ -110,8 +118,6 @@ LLMediaCtrl::LLMediaCtrl( const Params& p) :
setBorderVisible(p.border_visible);
- mHideLoading = p.hide_loading;
-
setDecoupleTextureSize(p.decouple_texture_size);
setTextureSize(p.texture_width, p.texture_height);
@@ -126,7 +132,7 @@ LLMediaCtrl::LLMediaCtrl( const Params& p) :
setTextureSize(screen_width, screen_height);
}
- mMediaTextureID.generate();
+ mMediaTextureID = getKey();
// We don't need to create the media source up front anymore unless we have a non-empty home URL to navigate to.
if(!mHomePageUrl.empty())
@@ -140,11 +146,8 @@ LLMediaCtrl::LLMediaCtrl( const Params& p) :
// addChild( mBorder );
}
-////////////////////////////////////////////////////////////////////////////////
-// note: this is now a singleton and destruction happens via initClass() now
LLMediaCtrl::~LLMediaCtrl()
{
-
if (mMediaSource)
{
mMediaSource->remObserver( this );
@@ -181,6 +184,13 @@ BOOL LLMediaCtrl::handleHover( S32 x, S32 y, MASK mask )
mMediaSource->mouseMove(x, y, mask);
gViewerWindow->setCursor(mMediaSource->getLastSetCursor());
}
+
+ // TODO: Is this the right way to handle hover text changes driven by the plugin?
+ if(mHoverTextChanged)
+ {
+ mHoverTextChanged = false;
+ handleToolTip(x, y, mask);
+ }
return TRUE;
}
@@ -197,6 +207,35 @@ BOOL LLMediaCtrl::handleScrollWheel( S32 x, S32 y, S32 clicks )
}
////////////////////////////////////////////////////////////////////////////////
+// virtual
+BOOL LLMediaCtrl::handleToolTip(S32 x, S32 y, MASK mask)
+{
+ std::string hover_text;
+
+ if (mMediaSource && mMediaSource->hasMedia())
+ hover_text = mMediaSource->getMediaPlugin()->getHoverText();
+
+ if(hover_text.empty())
+ {
+ return FALSE;
+ }
+ else
+ {
+ S32 screen_x, screen_y;
+
+ localPointToScreen(x, y, &screen_x, &screen_y);
+ LLRect sticky_rect_screen;
+ sticky_rect_screen.setCenterAndSize(screen_x, screen_y, 20, 20);
+
+ LLToolTipMgr::instance().show(LLToolTip::Params()
+ .message(hover_text)
+ .sticky_rect(sticky_rect_screen));
+ }
+
+ return TRUE;
+}
+
+////////////////////////////////////////////////////////////////////////////////
//
BOOL LLMediaCtrl::handleMouseUp( S32 x, S32 y, MASK mask )
{
@@ -206,14 +245,6 @@ BOOL LLMediaCtrl::handleMouseUp( S32 x, S32 y, MASK mask )
if (mMediaSource)
{
mMediaSource->mouseUp(x, y, mask);
-
- // *HACK: LLMediaImplLLMozLib automatically takes focus on mouseup,
- // in addition to the onFocusReceived() call below. Undo this. JC
- if (!mTakeFocusOnClick)
- {
- mMediaSource->focus(false);
- gViewerWindow->focusClient();
- }
}
gFocusMgr.setMouseCapture( NULL );
@@ -271,10 +302,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 );
@@ -283,6 +316,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;
}
@@ -345,85 +384,8 @@ void LLMediaCtrl::onFocusLost()
//
BOOL LLMediaCtrl::postBuild ()
{
- LLLayoutStack::Params layout_p;
- layout_p.name = "notification_stack";
- layout_p.rect = LLRect(0,getLocalRect().mTop,getLocalRect().mRight, 30);
- layout_p.follows.flags = FOLLOWS_ALL;
- layout_p.mouse_opaque = false;
- layout_p.orientation = "vertical";
-
- LLLayoutStack* stackp = LLUICtrlFactory::create<LLLayoutStack>(layout_p);
- addChild(stackp);
-
- LLLayoutPanel::Params panel_p;
- panel_p.rect = LLRect(0, 30, 800, 0);
- panel_p.min_height = 30;
- panel_p.name = "notification_area";
- panel_p.visible = false;
- panel_p.user_resize = false;
- panel_p.background_visible = true;
- panel_p.bg_alpha_image.name = "Yellow_Gradient";
- panel_p.auto_resize = false;
- LLLayoutPanel* notification_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p);
- stackp->addChild(notification_panel);
-
- panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>();
- panel_p.auto_resize = true;
- panel_p.mouse_opaque = false;
- LLLayoutPanel* dummy_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p);
- stackp->addChild(dummy_panel);
-
- layout_p = LLUICtrlFactory::getDefaultParams<LLLayoutStack>();
- layout_p.rect = LLRect(0, 30, 800, 0);
- layout_p.follows.flags = FOLLOWS_ALL;
- layout_p.orientation = "horizontal";
- stackp = LLUICtrlFactory::create<LLLayoutStack>(layout_p);
- notification_panel->addChild(stackp);
-
- panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>();
- panel_p.rect.height = 30;
- LLLayoutPanel* panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p);
- stackp->addChild(panel);
-
- LLIconCtrl::Params icon_p;
- icon_p.name = "notification_icon";
- icon_p.rect = LLRect(5, 23, 21, 8);
- panel->addChild(LLUICtrlFactory::create<LLIconCtrl>(icon_p));
-
- LLTextBox::Params text_p;
- text_p.rect = LLRect(31, 20, 430, 0);
- text_p.text_color = LLColor4::black;
- text_p.font = LLFontGL::getFontSansSerif();
- text_p.font.style = "BOLD";
- text_p.name = "notification_text";
- text_p.use_ellipses = true;
- panel->addChild(LLUICtrlFactory::create<LLTextBox>(text_p));
-
- panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>();
- panel_p.auto_resize = false;
- panel_p.user_resize = false;
- panel_p.name="form_elements";
- panel_p.rect = LLRect(0, 30, 130, 0);
- LLLayoutPanel* form_elements_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p);
- stackp->addChild(form_elements_panel);
-
- panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>();
- panel_p.auto_resize = false;
- panel_p.user_resize = false;
- panel_p.rect = LLRect(0, 30, 25, 0);
- LLLayoutPanel* close_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p);
- stackp->addChild(close_panel);
-
- LLButton::Params button_p;
- button_p.name = "close_notification";
- button_p.rect = LLRect(5, 23, 21, 7);
- button_p.image_color=LLUIColorTable::instance().getColor("DkGray_66");
- button_p.image_unselected.name="Icon_Close_Foreground";
- button_p.image_selected.name="Icon_Close_Press";
- button_p.click_callback.function = boost::bind(&LLMediaCtrl::onCloseNotification, this);
-
- close_panel->addChild(LLUICtrlFactory::create<LLButton>(button_p));
-
+ 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;
}
@@ -432,13 +394,15 @@ BOOL LLMediaCtrl::postBuild ()
//
BOOL LLMediaCtrl::handleKeyHere( KEY key, MASK mask )
{
- if (LLPanel::handleKeyHere(key, mask)) return TRUE;
BOOL result = FALSE;
if (mMediaSource)
{
result = mMediaSource->handleKeyHere(key, mask);
}
+
+ if ( ! result )
+ result = LLPanel::handleKeyHere(key, mask);
return result;
}
@@ -458,7 +422,6 @@ void LLMediaCtrl::handleVisibilityChange ( BOOL new_visibility )
//
BOOL LLMediaCtrl::handleUnicodeCharHere(llwchar uni_char)
{
- if (LLPanel::handleUnicodeCharHere(uni_char)) return TRUE;
BOOL result = FALSE;
if (mMediaSource)
@@ -466,6 +429,9 @@ BOOL LLMediaCtrl::handleUnicodeCharHere(llwchar uni_char)
result = mMediaSource->handleUnicodeCharHere(uni_char);
}
+ if ( ! result )
+ result = LLPanel::handleUnicodeCharHere(uni_char);
+
return result;
}
@@ -545,22 +511,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)
@@ -668,6 +618,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)
@@ -719,11 +679,6 @@ bool LLMediaCtrl::ensureMediaSourceExists()
mMediaSource->clearCache();
mClearCache = false;
}
-
- if(mHideLoading)
- {
- mHidingInitialLoad = true;
- }
}
else
{
@@ -791,11 +746,11 @@ void LLMediaCtrl::draw()
}
}
- if(mHidingInitialLoad)
- {
- // If we're hiding loading, don't draw at all.
- draw_media = false;
- }
+// if(mHidingInitialLoad)
+// {
+// // If we're hiding loading, don't draw at all.
+// draw_media = false;
+// }
bool background_visible = isBackgroundVisible();
bool background_opaque = isBackgroundOpaque();
@@ -921,11 +876,6 @@ void LLMediaCtrl::draw()
if ( mBorder && mBorder->getVisible() )
mBorder->setKeyboardFocusHighlight( gFocusMgr.childHasKeyboardFocus( this ) );
- if (mCurNotification && !mCurNotification->isActive())
- {
- hideNotification();
- }
-
LLPanel::draw();
// Restore the previous values
@@ -1023,6 +973,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;
@@ -1033,7 +993,7 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)
LLNotification::Params notify_params;
notify_params.name = "PopupAttempt";
- notify_params.payload = LLSD().with("target", target).with("url", url).with("uuid", uuid).with("media_id", getKey());
+ notify_params.payload = LLSD().with("target", target).with("url", url).with("uuid", uuid).with("media_id", mMediaTextureID);
notify_params.functor.function = boost::bind(&LLMediaCtrl::onPopup, this, _1, _2);
if (mTrusted)
@@ -1088,6 +1048,31 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)
LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_GEOMETRY_CHANGE, uuid is " << self->getClickUUID() << LL_ENDL;
}
break;
+
+ case MEDIA_EVENT_AUTH_REQUEST:
+ {
+ LLNotification::Params auth_request_params;
+ auth_request_params.name = "AuthRequest";
+
+ // pass in host name and realm for site (may be zero length but will always exist)
+ LLSD args;
+ LLURL raw_url( self->getAuthURL().c_str() );
+ args["HOST_NAME"] = raw_url.getAuthority();
+ args["REALM"] = self->getAuthRealm();
+ auth_request_params.substitutions = args;
+
+ auth_request_params.payload = LLSD().with("media_id", mMediaTextureID);
+ auth_request_params.functor.function = boost::bind(&LLViewerMedia::onAuthSubmit, _1, _2);
+ LLNotifications::instance().add(auth_request_params);
+ };
+ break;
+
+ case MEDIA_EVENT_LINK_HOVERED:
+ {
+ LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_LINK_HOVERED, hover text is: " << self->getHoverText() << LL_ENDL;
+ mHoverTextChanged = true;
+ };
+ break;
};
// chain all events to any potential observers of this object.
@@ -1105,109 +1090,85 @@ void LLMediaCtrl::onPopup(const LLSD& notification, const LLSD& response)
{
if (response["open"])
{
- LLWeb::loadURL(notification["payload"]["url"], notification["payload"]["target"], notification["payload"]["uuid"]);
+ // name of default floater to open
+ std::string floater_name = "media_browser";
+
+ // look for parent floater name
+ if ( gFloaterView )
+ {
+ if ( gFloaterView->getParentFloater(this) )
+ {
+ floater_name = gFloaterView->getParentFloater(this)->getInstanceName();
+ }
+ else
+ {
+ lldebugs << "No gFloaterView->getParentFloater(this) for onPopuup()" << llendl;
+ };
+ }
+ else
+ {
+ lldebugs << "No gFloaterView for onPopuup()" << llendl;
+ };
+
+ // (for now) open web content floater if that's our parent, otherwise, open the current media floater
+ // (this will change soon)
+ if ( floater_name == "web_content" )
+ {
+ LLWeb::loadWebURL(notification["payload"]["url"], notification["payload"]["target"], notification["payload"]["uuid"]);
+ }
+ else
+ {
+ LLWeb::loadURL(notification["payload"]["url"], notification["payload"]["target"], notification["payload"]["uuid"]);
+ }
}
else
{
// Make sure the opening instance knows its window open request was denied, so it can clean things up.
LLViewerMedia::proxyWindowClosed(notification["payload"]["uuid"]);
}
-
}
-void LLMediaCtrl::onCloseNotification()
-{
- LLNotifications::instance().cancel(mCurNotification);
-}
-
-void LLMediaCtrl::onClickIgnore(LLUICtrl* ctrl)
+void LLMediaCtrl::showNotification(LLNotificationPtr notify)
{
- bool check = ctrl->getValue().asBoolean();
- if (mCurNotification && mCurNotification->getForm()->getIgnoreType() == LLNotificationForm::IGNORE_SHOW_AGAIN)
+ delete mWindowShade;
+
+ LLWindowShade::Params params;
+ params.name = "notification_shade";
+ params.rect = getLocalRect();
+ params.follows.flags = FOLLOWS_ALL;
+ params.notification = notify;
+ params.modal = true;
+ //HACK: don't hardcode this
+ if (notify->getIcon() == "Popup_Caution")
{
- // question was "show again" so invert value to get "ignore"
- check = !check;
+ params.bg_image.name = "Yellow_Gradient";
+ params.text_color = LLColor4::black;
}
- mCurNotification->setIgnored(check);
-}
-
-void LLMediaCtrl::onClickNotificationButton(const std::string& name)
-{
- if (!mCurNotification) return;
-
- LLSD response = mCurNotification->getResponseTemplate();
- response[name] = true;
-
- mCurNotification->respond(response);
-}
-
-void LLMediaCtrl::showNotification(LLNotificationPtr notify)
-{
- mCurNotification = notify;
-
- // add popup here
- LLSD payload = notify->getPayload();
-
- LLNotificationFormPtr formp = notify->getForm();
- LLLayoutPanel& panel = getChildRef<LLLayoutPanel>("notification_area");
- panel.setVisible(true);
- panel.getChild<LLUICtrl>("notification_icon")->setValue(notify->getIcon());
- panel.getChild<LLUICtrl>("notification_text")->setValue(notify->getMessage());
- panel.getChild<LLUICtrl>("notification_text")->setToolTip(notify->getMessage());
- LLNotificationForm::EIgnoreType ignore_type = formp->getIgnoreType();
- LLLayoutPanel& form_elements = panel.getChildRef<LLLayoutPanel>("form_elements");
- form_elements.deleteAllChildren();
-
- const S32 FORM_PADDING_HORIZONTAL = 10;
- const S32 FORM_PADDING_VERTICAL = 3;
- S32 cur_x = FORM_PADDING_HORIZONTAL;
-
- if (ignore_type != LLNotificationForm::IGNORE_NO)
+ else
+ //HACK: another one since XUI doesn't support what we need right now
+ if (notify->getName() == "AuthRequest")
{
- LLCheckBoxCtrl::Params checkbox_p;
- checkbox_p.name = "ignore_check";
- checkbox_p.rect = LLRect(cur_x, form_elements.getRect().getHeight() - FORM_PADDING_VERTICAL, cur_x, FORM_PADDING_VERTICAL);
- checkbox_p.label = formp->getIgnoreMessage();
- checkbox_p.label_text.text_color = LLColor4::black;
- checkbox_p.commit_callback.function = boost::bind(&LLMediaCtrl::onClickIgnore, this, _1);
- checkbox_p.initial_value = formp->getIgnored();
-
- LLCheckBoxCtrl* check = LLUICtrlFactory::create<LLCheckBoxCtrl>(checkbox_p);
- check->setRect(check->getBoundingRect());
- form_elements.addChild(check);
- cur_x = check->getRect().mRight + FORM_PADDING_HORIZONTAL;
+ params.bg_image.name = "Yellow_Gradient";
+ params.text_color = LLColor4::black;
+ params.can_close = false;
}
-
- for (S32 i = 0; i < formp->getNumElements(); i++)
+ else
{
- LLSD form_element = formp->getElement(i);
- if (form_element["type"].asString() == "button")
- {
- LLButton::Params button_p;
- button_p.name = form_element["name"];
- button_p.label = form_element["text"];
- button_p.rect = LLRect(cur_x, form_elements.getRect().getHeight() - FORM_PADDING_VERTICAL, cur_x, FORM_PADDING_VERTICAL);
- button_p.click_callback.function = boost::bind(&LLMediaCtrl::onClickNotificationButton, this, form_element["name"].asString());
- button_p.auto_resize = true;
-
- LLButton* button = LLUICtrlFactory::create<LLButton>(button_p);
- button->autoResize();
- form_elements.addChild(button);
-
- cur_x = button->getRect().mRight + FORM_PADDING_HORIZONTAL;
- }
+ //HACK: make this a property of the notification itself, "cancellable"
+ params.can_close = false;
+ params.text_color.control = "LabelTextColor";
}
+ mWindowShade = LLUICtrlFactory::create<LLWindowShade>(params);
- form_elements.reshape(cur_x, form_elements.getRect().getHeight());
-
- //LLWeb::loadURL(payload["url"], payload["target"]);
+ addChild(mWindowShade);
+ mWindowShade->show();
}
void LLMediaCtrl::hideNotification()
{
- LLLayoutPanel& panel = getChildRef<LLLayoutPanel>("notification_area");
- panel.setVisible(FALSE);
-
- mCurNotification.reset();
+ if (mWindowShade)
+ {
+ mWindowShade->hide();
+ }
}
diff --git a/indra/newview/llmediactrl.h b/indra/newview/llmediactrl.h
index 65dfbbff78..28666e620f 100644
--- a/indra/newview/llmediactrl.h
+++ b/indra/newview/llmediactrl.h
@@ -34,6 +34,7 @@
class LLViewBorder;
class LLUICtrlFactory;
+class LLContextMenu;
////////////////////////////////////////////////////////////////////////////////
//
@@ -53,7 +54,8 @@ public:
ignore_ui_scale,
hide_loading,
decouple_texture_size,
- trusted_content;
+ trusted_content,
+ focus_on_click;
Optional<S32> texture_width,
texture_height;
@@ -62,6 +64,7 @@ public:
Optional<std::string> initial_mime_type;
Optional<std::string> media_id;
+ Optional<std::string> error_page_url;
Params();
};
@@ -89,6 +92,7 @@ public:
virtual BOOL handleRightMouseUp(S32 x, S32 y, MASK mask);
virtual BOOL handleDoubleClick( S32 x, S32 y, MASK mask );
virtual BOOL handleScrollWheel( S32 x, S32 y, S32 clicks );
+ virtual BOOL handleToolTip(S32 x, S32 y, MASK mask);
// navigation
void navigateTo( std::string url_in, std::string mime_type = "");
@@ -111,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();
@@ -167,9 +170,6 @@ public:
private:
void onVisibilityChange ( const LLSD& new_visibility );
void onPopup(const LLSD& notification, const LLSD& response);
- void onCloseNotification();
- void onClickNotificationButton(const std::string& name);
- void onClickIgnore(LLUICtrl* ctrl);
const S32 mTextureDepthBytes;
LLUUID mMediaTextureID;
@@ -180,6 +180,7 @@ public:
std::string mHomePageUrl;
std::string mHomePageMimeType;
std::string mCurrentNavUrl;
+ std::string mErrorPageURL;
std::string mTarget;
bool mIgnoreUIScale;
bool mAlwaysRefresh;
@@ -193,7 +194,9 @@ public:
S32 mTextureWidth;
S32 mTextureHeight;
bool mClearCache;
- boost::shared_ptr<class LLNotification> mCurNotification;
+ class LLWindowShade* mWindowShade;
+ bool mHoverTextChanged;
+ LLContextMenu* mContextMenu;
};
#endif // LL_LLMediaCtrl_H
diff --git a/indra/newview/llmemoryview.cpp b/indra/newview/llmemoryview.cpp
index 9a244e2562..7e9c3c84a7 100644
--- a/indra/newview/llmemoryview.cpp
+++ b/indra/newview/llmemoryview.cpp
@@ -37,9 +37,11 @@
#include <sstream>
#include <boost/algorithm/string/split.hpp>
+#include "llmemory.h"
LLMemoryView::LLMemoryView(const LLMemoryView::Params& p)
: LLView(p),
+ mPaused(FALSE),
//mDelay(120),
mAlloc(NULL)
{
@@ -59,6 +61,7 @@ BOOL LLMemoryView::handleMouseDown(S32 x, S32 y, MASK mask)
}
else
{
+ mPaused = !mPaused;
}
return TRUE;
}
@@ -148,13 +151,14 @@ void LLMemoryView::draw()
// cut off lines on bottom
U32 max_lines = U32((height - 2 * line_height) / line_height);
- std::vector<LLWString>::const_iterator end = mLines.end();
+ y_pos = height - MARGIN_AMT - line_height;
+ y_off = 0.f;
+
+#if !MEM_TRACK_MEM
+ std::vector<LLWString>::const_iterator end = mLines.end();
if(mLines.size() > max_lines) {
end = mLines.begin() + max_lines;
}
-
- y_pos = height - MARGIN_AMT - line_height;
- y_off = 0.f;
for (std::vector<LLWString>::const_iterator i = mLines.begin(); i != end; ++i)
{
font->render(*i, 0, MARGIN_AMT, y_pos - y_off,
@@ -169,6 +173,47 @@ void LLMemoryView::draw()
y_off += line_height;
}
+#else
+ LLMemTracker::getInstance()->preDraw(mPaused) ;
+
+ {
+ F32 x_pos = MARGIN_AMT ;
+ U32 lines = 0 ;
+ const char* str = LLMemTracker::getInstance()->getNextLine() ;
+ while(str != NULL)
+ {
+ lines++ ;
+ font->renderUTF8(str, 0, x_pos, y_pos - y_off,
+ LLColor4::white,
+ LLFontGL::LEFT,
+ LLFontGL::BASELINE,
+ LLFontGL::NORMAL,
+ LLFontGL::DROP_SHADOW,
+ S32_MAX,
+ target_width,
+ NULL, FALSE);
+
+ str = LLMemTracker::getInstance()->getNextLine() ;
+ y_off += line_height;
+
+ if(lines >= max_lines)
+ {
+ lines = 0 ;
+ x_pos += 512.f ;
+ if(x_pos + 512.f > target_width)
+ {
+ break ;
+ }
+
+ y_pos = height - MARGIN_AMT - line_height;
+ y_off = 0.f;
+ }
+ }
+ }
+
+ LLMemTracker::getInstance()->postDraw() ;
+#endif
+
#if MEM_TRACK_TYPE
S32 left, top, right, bottom;
diff --git a/indra/newview/llmemoryview.h b/indra/newview/llmemoryview.h
index 24ea058279..9bdc59ab10 100644
--- a/indra/newview/llmemoryview.h
+++ b/indra/newview/llmemoryview.h
@@ -55,6 +55,7 @@ public:
private:
std::vector<LLWString> mLines;
LLAllocator* mAlloc;
+ BOOL mPaused ;
};
diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp
new file mode 100644
index 0000000000..0a1eadf4d0
--- /dev/null
+++ b/indra/newview/llmeshrepository.cpp
@@ -0,0 +1,3807 @@
+/**
+ * @file llmeshrepository.cpp
+ * @brief Mesh repository implementation.
+ *
+ * $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 "apr_pools.h"
+#include "apr_dso.h"
+#include "llhttpstatuscodes.h"
+#include "llmeshrepository.h"
+
+#include "llagent.h"
+#include "llappviewer.h"
+#include "llbufferstream.h"
+#include "llcurl.h"
+#include "lldatapacker.h"
+#include "llfasttimer.h"
+#include "llfloatermodelpreview.h"
+#include "llfloaterperms.h"
+#include "lleconomy.h"
+#include "llimagej2c.h"
+#include "llhost.h"
+#include "llnotificationsutil.h"
+#include "llsd.h"
+#include "llsdutil_math.h"
+#include "llsdserialize.h"
+#include "llthread.h"
+#include "llvfile.h"
+#include "llviewercontrol.h"
+#include "llviewermenufile.h"
+#include "llviewerobjectlist.h"
+#include "llviewerregion.h"
+#include "llviewertexturelist.h"
+#include "llvolume.h"
+#include "llvolumemgr.h"
+#include "llvovolume.h"
+#include "llworld.h"
+#include "material_codes.h"
+#include "pipeline.h"
+#include "llinventorymodel.h"
+#include "llfoldertype.h"
+
+#ifndef LL_WINDOWS
+#include "netdb.h"
+#endif
+
+#include <queue>
+
+LLFastTimer::DeclareTimer FTM_MESH_UPDATE("Mesh Update");
+LLFastTimer::DeclareTimer FTM_LOAD_MESH("Load Mesh");
+
+LLMeshRepository gMeshRepo;
+
+const U32 MAX_MESH_REQUESTS_PER_SECOND = 100;
+
+U32 LLMeshRepository::sBytesReceived = 0;
+U32 LLMeshRepository::sHTTPRequestCount = 0;
+U32 LLMeshRepository::sHTTPRetryCount = 0;
+U32 LLMeshRepository::sCacheBytesRead = 0;
+U32 LLMeshRepository::sCacheBytesWritten = 0;
+U32 LLMeshRepository::sPeakKbps = 0;
+
+
+const U32 MAX_TEXTURE_UPLOAD_RETRIES = 5;
+
+std::string header_lod[] =
+{
+ "lowest_lod",
+ "low_lod",
+ "medium_lod",
+ "high_lod"
+};
+
+
+//get the number of bytes resident in memory for given volume
+U32 get_volume_memory_size(const LLVolume* volume)
+{
+ U32 indices = 0;
+ U32 vertices = 0;
+
+ for (U32 i = 0; i < volume->getNumVolumeFaces(); ++i)
+ {
+ const LLVolumeFace& face = volume->getVolumeFace(i);
+ indices += face.mNumIndices;
+ vertices += face.mNumVertices;
+ }
+
+
+ return indices*2+vertices*11+sizeof(LLVolume)+sizeof(LLVolumeFace)*volume->getNumVolumeFaces();
+}
+
+void get_vertex_buffer_from_mesh(LLCDMeshData& mesh, LLModel::PhysicsMesh& res, F32 scale = 1.f)
+{
+ res.mPositions.clear();
+ res.mNormals.clear();
+
+ const F32* v = mesh.mVertexBase;
+
+ if (mesh.mIndexType == LLCDMeshData::INT_16)
+ {
+ U16* idx = (U16*) mesh.mIndexBase;
+ for (S32 j = 0; j < mesh.mNumTriangles; ++j)
+ {
+ F32* mp0 = (F32*) ((U8*)v+idx[0]*mesh.mVertexStrideBytes);
+ F32* mp1 = (F32*) ((U8*)v+idx[1]*mesh.mVertexStrideBytes);
+ F32* mp2 = (F32*) ((U8*)v+idx[2]*mesh.mVertexStrideBytes);
+
+ idx = (U16*) (((U8*)idx)+mesh.mIndexStrideBytes);
+
+ LLVector3 v0(mp0);
+ LLVector3 v1(mp1);
+ LLVector3 v2(mp2);
+
+ LLVector3 n = (v1-v0)%(v2-v0);
+ n.normalize();
+
+ res.mPositions.push_back(v0*scale);
+ res.mPositions.push_back(v1*scale);
+ res.mPositions.push_back(v2*scale);
+
+ res.mNormals.push_back(n);
+ res.mNormals.push_back(n);
+ res.mNormals.push_back(n);
+ }
+ }
+ else
+ {
+ U32* idx = (U32*) mesh.mIndexBase;
+ for (S32 j = 0; j < mesh.mNumTriangles; ++j)
+ {
+ F32* mp0 = (F32*) ((U8*)v+idx[0]*mesh.mVertexStrideBytes);
+ F32* mp1 = (F32*) ((U8*)v+idx[1]*mesh.mVertexStrideBytes);
+ F32* mp2 = (F32*) ((U8*)v+idx[2]*mesh.mVertexStrideBytes);
+
+ idx = (U32*) (((U8*)idx)+mesh.mIndexStrideBytes);
+
+ LLVector3 v0(mp0);
+ LLVector3 v1(mp1);
+ LLVector3 v2(mp2);
+
+ LLVector3 n = (v1-v0)%(v2-v0);
+ n.normalize();
+
+ res.mPositions.push_back(v0*scale);
+ res.mPositions.push_back(v1*scale);
+ res.mPositions.push_back(v2*scale);
+
+ res.mNormals.push_back(n);
+ res.mNormals.push_back(n);
+ res.mNormals.push_back(n);
+ }
+ }
+}
+
+S32 LLMeshRepoThread::sActiveHeaderRequests = 0;
+S32 LLMeshRepoThread::sActiveLODRequests = 0;
+U32 LLMeshRepoThread::sMaxConcurrentRequests = 1;
+
+
+class LLTextureCostResponder : public LLCurl::Responder
+{
+public:
+ LLTextureUploadData mData;
+ LLMeshUploadThread* mThread;
+
+ LLTextureCostResponder(LLTextureUploadData data, LLMeshUploadThread* thread)
+ : mData(data), mThread(thread)
+ {
+
+ }
+
+ virtual void completed(U32 status, const std::string& reason, const LLSD& content)
+ {
+ mThread->mPendingConfirmations--;
+ if (isGoodStatus(status))
+ {
+ mThread->priceResult(mData, content);
+ }
+ else
+ {
+ llwarns << status << ": " << reason << llendl;
+
+ if (mData.mRetries < MAX_TEXTURE_UPLOAD_RETRIES)
+ {
+ llwarns << "Retrying. (" << ++mData.mRetries << ")" << llendl;
+
+ if (status == 499 || status == 500)
+ {
+ mThread->uploadTexture(mData);
+ }
+ else
+ {
+ llerrs << "Unhandled status " << status << llendl;
+ }
+ }
+ else
+ {
+ llwarns << "Giving up after " << mData.mRetries << " retries." << llendl;
+ }
+ }
+ }
+};
+
+class LLTextureUploadResponder : public LLCurl::Responder
+{
+public:
+ LLTextureUploadData mData;
+ LLMeshUploadThread* mThread;
+
+ LLTextureUploadResponder(LLTextureUploadData data, LLMeshUploadThread* thread)
+ : mData(data), mThread(thread)
+ {
+ }
+
+ virtual void completed(U32 status, const std::string& reason, const LLSD& content)
+ {
+ mThread->mPendingUploads--;
+ if (isGoodStatus(status))
+ {
+ mData.mUUID = content["new_asset"].asUUID();
+ gMeshRepo.updateInventory(LLMeshRepository::inventory_data(mData.mPostData, content));
+ mThread->onTextureUploaded(mData);
+ }
+ else
+ {
+ llwarns << status << ": " << reason << llendl;
+ llwarns << "Retrying. (" << ++mData.mRetries << ")" << llendl;
+
+ if (status == 404)
+ {
+ mThread->uploadTexture(mData);
+ }
+ else if (status == 499)
+ {
+ mThread->mConfirmedTextureQ.push(mData);
+ }
+ else
+ {
+ llerrs << "Unhandled status " << status << llendl;
+ }
+ }
+ }
+};
+
+class LLMeshCostResponder : public LLCurl::Responder
+{
+public:
+ LLMeshUploadData mData;
+ LLMeshUploadThread* mThread;
+
+ LLMeshCostResponder(LLMeshUploadData data, LLMeshUploadThread* thread)
+ : mData(data), mThread(thread)
+ {
+
+ }
+
+ virtual void completed(U32 status, const std::string& reason, const LLSD& content)
+ {
+ mThread->mPendingConfirmations--;
+
+ if (isGoodStatus(status))
+ {
+ mThread->priceResult(mData, content);
+ }
+ else
+ {
+ llwarns << status << ": " << reason << llendl;
+
+ if (status == HTTP_INTERNAL_ERROR)
+ {
+ llwarns << "Retrying. (" << ++mData.mRetries << ")" << llendl;
+ mThread->uploadModel(mData);
+ }
+ else if (status == HTTP_BAD_REQUEST)
+ {
+ llwarns << "Status 400 received from server, giving up." << llendl;
+ }
+ else if (status == HTTP_NOT_FOUND)
+ {
+ llwarns <<"Status 404 received, server is disconnected, giving up." << llendl ;
+ }
+ else
+ {
+ llerrs << "Unhandled status " << status << llendl;
+ }
+ }
+ }
+};
+
+class LLMeshUploadResponder : public LLCurl::Responder
+{
+public:
+ LLMeshUploadData mData;
+ LLMeshUploadThread* mThread;
+
+ LLMeshUploadResponder(LLMeshUploadData data, LLMeshUploadThread* thread)
+ : mData(data), mThread(thread)
+ {
+ }
+
+ virtual void completed(U32 status, const std::string& reason, const LLSD& content)
+ {
+ mThread->mPendingUploads--;
+ if (isGoodStatus(status))
+ {
+ mData.mUUID = content["new_asset"].asUUID();
+ if (mData.mUUID.isNull())
+ {
+ LLSD args;
+ std::string message = content["error"]["message"];
+ std::string identifier = content["error"]["identifier"];
+ std::string invalidity_identifier = content["error"]["invalidity_identifier"];
+
+ args["MESSAGE"] = message;
+ args["IDENTIFIER"] = identifier;
+ args["INVALIDITY_IDENTIFIER"] = invalidity_identifier;
+ args["LABEL"] = mData.mBaseModel->mLabel;
+
+ gMeshRepo.uploadError(args);
+ }
+ else
+ {
+ gMeshRepo.updateInventory(LLMeshRepository::inventory_data(mData.mPostData, content));
+ mThread->onModelUploaded(mData);
+ }
+ }
+ else
+ {
+ llwarns << status << ": " << reason << llendl;
+ llwarns << "Retrying. (" << ++mData.mRetries << ")" << llendl;
+
+ if (status == 404)
+ {
+ mThread->uploadModel(mData);
+ }
+ else if (status == 499)
+ {
+ mThread->mConfirmedQ.push(mData);
+ }
+ else if (status != 500)
+ { //drop internal server errors on the floor, otherwise grab
+ llerrs << "Unhandled status " << status << llendl;
+ }
+ }
+ }
+};
+
+
+class LLMeshHeaderResponder : public LLCurl::Responder
+{
+public:
+ LLVolumeParams mMeshParams;
+
+ LLMeshHeaderResponder(const LLVolumeParams& mesh_params)
+ : mMeshParams(mesh_params)
+ {
+ }
+
+ virtual void completedRaw(U32 status, const std::string& reason,
+ const LLChannelDescriptors& channels,
+ const LLIOPipe::buffer_ptr_t& buffer);
+
+};
+
+class LLMeshLODResponder : public LLCurl::Responder
+{
+public:
+ LLVolumeParams mMeshParams;
+ S32 mLOD;
+ U32 mRequestedBytes;
+ U32 mOffset;
+
+ LLMeshLODResponder(const LLVolumeParams& mesh_params, S32 lod, U32 offset, U32 requested_bytes)
+ : mMeshParams(mesh_params), mLOD(lod), mOffset(offset), mRequestedBytes(requested_bytes)
+ {
+ }
+
+ virtual void completedRaw(U32 status, const std::string& reason,
+ const LLChannelDescriptors& channels,
+ const LLIOPipe::buffer_ptr_t& buffer);
+
+};
+
+class LLMeshSkinInfoResponder : public LLCurl::Responder
+{
+public:
+ LLUUID mMeshID;
+ U32 mRequestedBytes;
+ U32 mOffset;
+
+ LLMeshSkinInfoResponder(const LLUUID& id, U32 offset, U32 size)
+ : mMeshID(id), mRequestedBytes(size), mOffset(offset)
+ {
+ }
+
+ virtual void completedRaw(U32 status, const std::string& reason,
+ const LLChannelDescriptors& channels,
+ const LLIOPipe::buffer_ptr_t& buffer);
+
+};
+
+class LLMeshDecompositionResponder : public LLCurl::Responder
+{
+public:
+ LLUUID mMeshID;
+ U32 mRequestedBytes;
+ U32 mOffset;
+
+ LLMeshDecompositionResponder(const LLUUID& id, U32 offset, U32 size)
+ : mMeshID(id), mRequestedBytes(size), mOffset(offset)
+ {
+ }
+
+ virtual void completedRaw(U32 status, const std::string& reason,
+ const LLChannelDescriptors& channels,
+ const LLIOPipe::buffer_ptr_t& buffer);
+
+};
+
+class LLMeshPhysicsShapeResponder : public LLCurl::Responder
+{
+public:
+ LLUUID mMeshID;
+ U32 mRequestedBytes;
+ U32 mOffset;
+
+ LLMeshPhysicsShapeResponder(const LLUUID& id, U32 offset, U32 size)
+ : mMeshID(id), mRequestedBytes(size), mOffset(offset)
+ {
+ }
+
+ virtual void completedRaw(U32 status, const std::string& reason,
+ const LLChannelDescriptors& channels,
+ const LLIOPipe::buffer_ptr_t& buffer);
+
+};
+
+class LLModelObjectUploadResponder: public LLCurl::Responder
+{
+ LLSD mObjectAsset;
+ LLMeshUploadThread* mThread;
+
+public:
+ LLModelObjectUploadResponder(LLMeshUploadThread* thread, const LLSD& object_asset):
+ mThread(thread),
+ mObjectAsset(object_asset)
+ {
+ }
+
+ virtual void completedRaw(U32 status, const std::string& reason,
+ const LLChannelDescriptors& channels,
+ const LLIOPipe::buffer_ptr_t& buffer)
+ {
+ assert_main_thread();
+
+ llinfos << "completed" << llendl;
+ mThread->mPendingUploads--;
+ mThread->mFinished = true;
+ }
+};
+
+class LLWholeModelFeeResponder: public LLCurl::Responder
+{
+ LLMeshUploadThread* mThread;
+public:
+ LLWholeModelFeeResponder(LLMeshUploadThread* thread):
+ mThread(thread)
+ {
+ }
+ virtual void completedRaw(U32 status, const std::string& reason,
+ const LLChannelDescriptors& channels,
+ const LLIOPipe::buffer_ptr_t& buffer)
+ {
+ assert_main_thread();
+ llinfos << "completed" << llendl;
+ mThread->mPendingUploads--;
+ }
+
+};
+
+LLMeshRepoThread::LLMeshRepoThread()
+: LLThread("mesh repo", NULL)
+{
+ mWaiting = false;
+ mMutex = new LLMutex(NULL);
+ mHeaderMutex = new LLMutex(NULL);
+ mSignal = new LLCondition(NULL);
+}
+
+LLMeshRepoThread::~LLMeshRepoThread()
+{
+ delete mMutex;
+ mMutex = NULL;
+ delete mHeaderMutex;
+ mHeaderMutex = NULL;
+ delete mSignal;
+ mSignal = NULL;
+}
+
+void LLMeshRepoThread::run()
+{
+ mCurlRequest = new LLCurlRequest();
+ LLCDResult res = LLConvexDecomposition::initThread();
+ if (res != LLCD_OK)
+ {
+ llwarns << "convex decomposition unable to be loaded" << llendl;
+ }
+
+ while (!LLApp::isQuitting())
+ {
+ mWaiting = true;
+ mSignal->wait();
+ mWaiting = false;
+
+ if (!LLApp::isQuitting())
+ {
+ static U32 count = 0;
+
+ static F32 last_hundred = gFrameTimeSeconds;
+
+ if (gFrameTimeSeconds - last_hundred > 1.f)
+ { //a second has gone by, clear count
+ last_hundred = gFrameTimeSeconds;
+ count = 0;
+ }
+
+ // NOTE: throttling intentionally favors LOD requests over header requests
+
+ while (!mLODReqQ.empty() && count < MAX_MESH_REQUESTS_PER_SECOND && sActiveLODRequests < sMaxConcurrentRequests)
+ {
+ {
+ mMutex->lock();
+ LODRequest req = mLODReqQ.front();
+ mLODReqQ.pop();
+ mMutex->unlock();
+ if (fetchMeshLOD(req.mMeshParams, req.mLOD))
+ {
+ count++;
+ }
+ }
+ }
+
+ while (!mHeaderReqQ.empty() && count < MAX_MESH_REQUESTS_PER_SECOND && sActiveHeaderRequests < sMaxConcurrentRequests)
+ {
+ {
+ mMutex->lock();
+ HeaderRequest req = mHeaderReqQ.front();
+ mHeaderReqQ.pop();
+ mMutex->unlock();
+ if (fetchMeshHeader(req.mMeshParams))
+ {
+ count++;
+ }
+ }
+ }
+
+ { //mSkinRequests is protected by mSignal
+ std::set<LLUUID> incomplete;
+ for (std::set<LLUUID>::iterator iter = mSkinRequests.begin(); iter != mSkinRequests.end(); ++iter)
+ {
+ LLUUID mesh_id = *iter;
+ if (!fetchMeshSkinInfo(mesh_id))
+ {
+ incomplete.insert(mesh_id);
+ }
+ }
+ mSkinRequests = incomplete;
+ }
+
+ { //mDecompositionRequests is protected by mSignal
+ std::set<LLUUID> incomplete;
+ for (std::set<LLUUID>::iterator iter = mDecompositionRequests.begin(); iter != mDecompositionRequests.end(); ++iter)
+ {
+ LLUUID mesh_id = *iter;
+ if (!fetchMeshDecomposition(mesh_id))
+ {
+ incomplete.insert(mesh_id);
+ }
+ }
+ mDecompositionRequests = incomplete;
+ }
+
+ { //mPhysicsShapeRequests is protected by mSignal
+ std::set<LLUUID> incomplete;
+ for (std::set<LLUUID>::iterator iter = mPhysicsShapeRequests.begin(); iter != mPhysicsShapeRequests.end(); ++iter)
+ {
+ LLUUID mesh_id = *iter;
+ if (!fetchMeshPhysicsShape(mesh_id))
+ {
+ incomplete.insert(mesh_id);
+ }
+ }
+ mPhysicsShapeRequests = incomplete;
+ }
+
+ mCurlRequest->process();
+ }
+ }
+
+ if (mSignal->isLocked())
+ { //make sure to let go of the mutex associated with the given signal before shutting down
+ mSignal->unlock();
+ }
+
+ res = LLConvexDecomposition::quitThread();
+ if (res != LLCD_OK)
+ {
+ llwarns << "convex decomposition unable to be quit" << llendl;
+ }
+
+ delete mCurlRequest;
+ mCurlRequest = NULL;
+}
+
+void LLMeshRepoThread::loadMeshSkinInfo(const LLUUID& mesh_id)
+{ //protected by mSignal, no locking needed here
+ mSkinRequests.insert(mesh_id);
+}
+
+void LLMeshRepoThread::loadMeshDecomposition(const LLUUID& mesh_id)
+{ //protected by mSignal, no locking needed here
+ mDecompositionRequests.insert(mesh_id);
+}
+
+void LLMeshRepoThread::loadMeshPhysicsShape(const LLUUID& mesh_id)
+{ //protected by mSignal, no locking needed here
+ mPhysicsShapeRequests.insert(mesh_id);
+}
+
+
+void LLMeshRepoThread::loadMeshLOD(const LLVolumeParams& mesh_params, S32 lod)
+{ //protected by mSignal, no locking needed here
+
+ mesh_header_map::iterator iter = mMeshHeader.find(mesh_params.getSculptID());
+ if (iter != mMeshHeader.end())
+ { //if we have the header, request LOD byte range
+ LODRequest req(mesh_params, lod);
+ {
+ LLMutexLock lock(mMutex);
+ mLODReqQ.push(req);
+ }
+ }
+ else
+ {
+ HeaderRequest req(mesh_params);
+
+ pending_lod_map::iterator pending = mPendingLOD.find(mesh_params);
+
+ if (pending != mPendingLOD.end())
+ { //append this lod request to existing header request
+ pending->second.push_back(lod);
+ if (pending->second.size() > 4)
+ {
+ llerrs << "WTF?" << llendl;
+ }
+ }
+ else
+ { //if no header request is pending, fetch header
+ LLMutexLock lock(mMutex);
+ mHeaderReqQ.push(req);
+ mPendingLOD[mesh_params].push_back(lod);
+ }
+ }
+}
+
+//static
+std::string LLMeshRepoThread::constructUrl(LLUUID mesh_id)
+{
+ std::string http_url;
+
+ if (gAgent.getRegion())
+ {
+ http_url = gMeshRepo.mGetMeshCapability;
+ }
+
+ if (!http_url.empty())
+ {
+ http_url += "/?mesh_id=";
+ http_url += mesh_id.asString().c_str();
+ }
+ else
+ {
+ llwarns << "Current region does not have GetMesh capability! Cannot load " << mesh_id << ".mesh" << llendl;
+ }
+
+ return http_url;
+}
+
+bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id)
+{ //protected by mMutex
+ mHeaderMutex->lock();
+
+ if (mMeshHeader.find(mesh_id) == mMeshHeader.end())
+ { //we have no header info for this mesh, do nothing
+ mHeaderMutex->unlock();
+ return false;
+ }
+
+ U32 header_size = mMeshHeaderSize[mesh_id];
+
+ if (header_size > 0)
+ {
+ S32 offset = header_size + mMeshHeader[mesh_id]["skin"]["offset"].asInteger();
+ S32 size = mMeshHeader[mesh_id]["skin"]["size"].asInteger();
+
+ mHeaderMutex->unlock();
+
+ if (offset >= 0 && size > 0)
+ {
+ //check VFS for mesh skin info
+ LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH);
+ if (file.getSize() >= offset+size)
+ {
+ LLMeshRepository::sCacheBytesRead += size;
+ file.seek(offset);
+ U8* buffer = new U8[size];
+ file.read(buffer, size);
+
+ //make sure buffer isn't all 0's (reserved block but not written)
+ bool zero = true;
+ for (S32 i = 0; i < llmin(size, 1024) && zero; ++i)
+ {
+ zero = buffer[i] > 0 ? false : true;
+ }
+
+ if (!zero)
+ { //attempt to parse
+ if (skinInfoReceived(mesh_id, buffer, size))
+ {
+ delete[] buffer;
+ return true;
+ }
+ }
+
+ delete[] buffer;
+ }
+
+ //reading from VFS failed for whatever reason, fetch from sim
+ std::vector<std::string> headers;
+ headers.push_back("Accept: application/octet-stream");
+
+ std::string http_url = constructUrl(mesh_id);
+ if (!http_url.empty())
+ {
+ ++sActiveLODRequests;
+ LLMeshRepository::sHTTPRequestCount++;
+ mCurlRequest->getByteRange(constructUrl(mesh_id), headers, offset, size,
+ new LLMeshSkinInfoResponder(mesh_id, offset, size));
+ }
+ }
+ }
+ else
+ {
+ mHeaderMutex->unlock();
+ }
+
+ //early out was not hit, effectively fetched
+ return true;
+}
+
+bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id)
+{ //protected by mMutex
+ mHeaderMutex->lock();
+
+ if (mMeshHeader.find(mesh_id) == mMeshHeader.end())
+ { //we have no header info for this mesh, do nothing
+ mHeaderMutex->unlock();
+ return false;
+ }
+
+ U32 header_size = mMeshHeaderSize[mesh_id];
+
+ if (header_size > 0)
+ {
+ S32 offset = header_size + mMeshHeader[mesh_id]["decomposition"]["offset"].asInteger();
+ S32 size = mMeshHeader[mesh_id]["decomposition"]["size"].asInteger();
+
+ mHeaderMutex->unlock();
+
+ if (offset >= 0 && size > 0)
+ {
+ //check VFS for mesh skin info
+ LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH);
+ if (file.getSize() >= offset+size)
+ {
+ LLMeshRepository::sCacheBytesRead += size;
+ file.seek(offset);
+ U8* buffer = new U8[size];
+ file.read(buffer, size);
+
+ //make sure buffer isn't all 0's (reserved block but not written)
+ bool zero = true;
+ for (S32 i = 0; i < llmin(size, 1024) && zero; ++i)
+ {
+ zero = buffer[i] > 0 ? false : true;
+ }
+
+ if (!zero)
+ { //attempt to parse
+ if (decompositionReceived(mesh_id, buffer, size))
+ {
+ delete[] buffer;
+ return true;
+ }
+ }
+
+ delete[] buffer;
+ }
+
+ //reading from VFS failed for whatever reason, fetch from sim
+ std::vector<std::string> headers;
+ headers.push_back("Accept: application/octet-stream");
+
+ std::string http_url = constructUrl(mesh_id);
+ if (!http_url.empty())
+ {
+ ++sActiveLODRequests;
+ LLMeshRepository::sHTTPRequestCount++;
+ mCurlRequest->getByteRange(http_url, headers, offset, size,
+ new LLMeshDecompositionResponder(mesh_id, offset, size));
+ }
+ }
+ }
+ else
+ {
+ mHeaderMutex->unlock();
+ }
+
+ //early out was not hit, effectively fetched
+ return true;
+}
+
+bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id)
+{ //protected by mMutex
+ mHeaderMutex->lock();
+
+ if (mMeshHeader.find(mesh_id) == mMeshHeader.end())
+ { //we have no header info for this mesh, do nothing
+ mHeaderMutex->unlock();
+ return false;
+ }
+
+ U32 header_size = mMeshHeaderSize[mesh_id];
+
+ if (header_size > 0)
+ {
+ S32 offset = header_size + mMeshHeader[mesh_id]["physics_shape"]["offset"].asInteger();
+ S32 size = mMeshHeader[mesh_id]["physics_shape"]["size"].asInteger();
+
+ mHeaderMutex->unlock();
+
+ if (offset >= 0 && size > 0)
+ {
+ //check VFS for mesh physics shape info
+ LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH);
+ if (file.getSize() >= offset+size)
+ {
+ LLMeshRepository::sCacheBytesRead += size;
+ file.seek(offset);
+ U8* buffer = new U8[size];
+ file.read(buffer, size);
+
+ //make sure buffer isn't all 0's (reserved block but not written)
+ bool zero = true;
+ for (S32 i = 0; i < llmin(size, 1024) && zero; ++i)
+ {
+ zero = buffer[i] > 0 ? false : true;
+ }
+
+ if (!zero)
+ { //attempt to parse
+ if (physicsShapeReceived(mesh_id, buffer, size))
+ {
+ delete[] buffer;
+ return true;
+ }
+ }
+
+ delete[] buffer;
+ }
+
+ //reading from VFS failed for whatever reason, fetch from sim
+ std::vector<std::string> headers;
+ headers.push_back("Accept: application/octet-stream");
+
+ std::string http_url = constructUrl(mesh_id);
+ if (!http_url.empty())
+ {
+ ++sActiveLODRequests;
+ LLMeshRepository::sHTTPRequestCount++;
+ mCurlRequest->getByteRange(http_url, headers, offset, size,
+ new LLMeshPhysicsShapeResponder(mesh_id, offset, size));
+ }
+ }
+ else
+ { //no physics shape whatsoever, report back NULL
+ physicsShapeReceived(mesh_id, NULL, 0);
+ }
+ }
+ else
+ {
+ mHeaderMutex->unlock();
+ }
+
+ //early out was not hit, effectively fetched
+ return true;
+}
+
+bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params)
+{
+ bool retval = false;
+
+ {
+ //look for mesh in asset in vfs
+ LLVFile file(gVFS, mesh_params.getSculptID(), LLAssetType::AT_MESH);
+
+ S32 size = file.getSize();
+
+ if (size > 0)
+ {
+ U8 buffer[1024];
+ S32 bytes = llmin(size, 1024);
+ LLMeshRepository::sCacheBytesRead += bytes;
+ file.read(buffer, bytes);
+ if (headerReceived(mesh_params, buffer, bytes))
+ { //did not do an HTTP request, return false
+ return false;
+ }
+ }
+ }
+
+ //either cache entry doesn't exist or is corrupt, request header from simulator
+
+ std::vector<std::string> headers;
+ headers.push_back("Accept: application/octet-stream");
+
+ std::string http_url = constructUrl(mesh_params.getSculptID());
+ if (!http_url.empty())
+ {
+ ++sActiveHeaderRequests;
+ retval = true;
+ //grab first 4KB if we're going to bother with a fetch. Cache will prevent future fetches if a full mesh fits
+ //within the first 4KB
+ LLMeshRepository::sHTTPRequestCount++;
+ mCurlRequest->getByteRange(http_url, headers, 0, 4096, new LLMeshHeaderResponder(mesh_params));
+ }
+
+ return retval;
+}
+
+bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod)
+{ //protected by mMutex
+ mHeaderMutex->lock();
+
+ bool retval = false;
+
+ LLUUID mesh_id = mesh_params.getSculptID();
+
+ U32 header_size = mMeshHeaderSize[mesh_id];
+
+ if (header_size > 0)
+ {
+ S32 offset = header_size + mMeshHeader[mesh_id][header_lod[lod]]["offset"].asInteger();
+ S32 size = mMeshHeader[mesh_id][header_lod[lod]]["size"].asInteger();
+ mHeaderMutex->unlock();
+ if (offset >= 0 && size > 0)
+ {
+
+ //check VFS for mesh asset
+ LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH);
+ if (file.getSize() >= offset+size)
+ {
+ LLMeshRepository::sCacheBytesRead += size;
+ file.seek(offset);
+ U8* buffer = new U8[size];
+ file.read(buffer, size);
+
+ //make sure buffer isn't all 0's (reserved block but not written)
+ bool zero = true;
+ for (S32 i = 0; i < llmin(size, 1024) && zero; ++i)
+ {
+ zero = buffer[i] > 0 ? false : true;
+ }
+
+ if (!zero)
+ { //attempt to parse
+ if (lodReceived(mesh_params, lod, buffer, size))
+ {
+ delete[] buffer;
+ return false;
+ }
+ }
+
+ delete[] buffer;
+ }
+
+ //reading from VFS failed for whatever reason, fetch from sim
+ std::vector<std::string> headers;
+ headers.push_back("Accept: application/octet-stream");
+
+ std::string http_url = constructUrl(mesh_id);
+ if (!http_url.empty())
+ {
+ ++sActiveLODRequests;
+ retval = true;
+ LLMeshRepository::sHTTPRequestCount++;
+ mCurlRequest->getByteRange(constructUrl(mesh_id), headers, offset, size,
+ new LLMeshLODResponder(mesh_params, lod, offset, size));
+ }
+ else
+ {
+ mUnavailableQ.push(LODRequest(mesh_params, lod));
+ }
+ }
+ else
+ {
+ mUnavailableQ.push(LODRequest(mesh_params, lod));
+ }
+ }
+ else
+ {
+ mHeaderMutex->unlock();
+ }
+
+ return retval;
+}
+
+bool LLMeshRepoThread::headerReceived(const LLVolumeParams& mesh_params, U8* data, S32 data_size)
+{
+ LLSD header;
+
+ U32 header_size = 0;
+ if (data_size > 0)
+ {
+ std::string res_str((char*) data, data_size);
+
+ std::string deprecated_header("<? LLSD/Binary ?>");
+
+ if (res_str.substr(0, deprecated_header.size()) == deprecated_header)
+ {
+ res_str = res_str.substr(deprecated_header.size()+1, data_size);
+ header_size = deprecated_header.size()+1;
+ }
+ data_size = res_str.size();
+
+ std::istringstream stream(res_str);
+
+ if (!LLSDSerialize::fromBinary(header, stream, data_size))
+ {
+ llwarns << "Mesh header parse error. Not a valid mesh asset!" << llendl;
+ return false;
+ }
+
+ header_size += stream.tellg();
+ }
+ else
+ {
+ llinfos
+ << "Marking header as non-existent, will not retry." << llendl;
+ header["404"] = 1;
+ }
+
+ {
+ U32 cost = gMeshRepo.calcResourceCost(header);
+
+ LLUUID mesh_id = mesh_params.getSculptID();
+
+ mHeaderMutex->lock();
+ mMeshHeaderSize[mesh_id] = header_size;
+ mMeshHeader[mesh_id] = header;
+ mMeshResourceCost[mesh_id] = cost;
+ mHeaderMutex->unlock();
+
+ //check for pending requests
+ pending_lod_map::iterator iter = mPendingLOD.find(mesh_params);
+ if (iter != mPendingLOD.end())
+ {
+ LLMutexLock lock(mMutex);
+ for (U32 i = 0; i < iter->second.size(); ++i)
+ {
+ LODRequest req(mesh_params, iter->second[i]);
+ mLODReqQ.push(req);
+ }
+ }
+ mPendingLOD.erase(iter);
+ }
+
+ return true;
+}
+
+bool LLMeshRepoThread::lodReceived(const LLVolumeParams& mesh_params, S32 lod, U8* data, S32 data_size)
+{
+ LLVolume* volume = new LLVolume(mesh_params, LLVolumeLODGroup::getVolumeScaleFromDetail(lod));
+ std::string mesh_string((char*) data, data_size);
+ std::istringstream stream(mesh_string);
+
+ if (volume->unpackVolumeFaces(stream, data_size))
+ {
+ LoadedMesh mesh(volume, mesh_params, lod);
+ if (volume->getNumFaces() > 0)
+ {
+ LLMutexLock lock(mMutex);
+ mLoadedQ.push(mesh);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool LLMeshRepoThread::skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 data_size)
+{
+ LLSD skin;
+
+ if (data_size > 0)
+ {
+ std::string res_str((char*) data, data_size);
+
+ std::istringstream stream(res_str);
+
+ if (!unzip_llsd(skin, stream, data_size))
+ {
+ llwarns << "Mesh skin info parse error. Not a valid mesh asset!" << llendl;
+ return false;
+ }
+ }
+
+ {
+ LLMeshSkinInfo info(skin);
+ info.mMeshID = mesh_id;
+
+ //llinfos<<"info pelvis offset"<<info.mPelvisOffset<<llendl;
+ mSkinInfoQ.push(info);
+ }
+
+ return true;
+}
+
+bool LLMeshRepoThread::decompositionReceived(const LLUUID& mesh_id, U8* data, S32 data_size)
+{
+ LLSD decomp;
+
+ if (data_size > 0)
+ {
+ std::string res_str((char*) data, data_size);
+
+ std::istringstream stream(res_str);
+
+ if (!unzip_llsd(decomp, stream, data_size))
+ {
+ llwarns << "Mesh decomposition parse error. Not a valid mesh asset!" << llendl;
+ return false;
+ }
+ }
+
+ {
+ LLModel::Decomposition* d = new LLModel::Decomposition(decomp);
+ d->mMeshID = mesh_id;
+ mDecompositionQ.push(d);
+ }
+
+ return true;
+}
+
+bool LLMeshRepoThread::physicsShapeReceived(const LLUUID& mesh_id, U8* data, S32 data_size)
+{
+ LLSD physics_shape;
+
+ LLModel::Decomposition* d = new LLModel::Decomposition();
+ d->mMeshID = mesh_id;
+
+ if (data == NULL)
+ { //no data, no physics shape exists
+ d->mPhysicsShapeMesh.clear();
+ }
+ else
+ {
+ LLVolumeParams volume_params;
+ volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
+ volume_params.setSculptID(mesh_id, LL_SCULPT_TYPE_MESH);
+ LLPointer<LLVolume> volume = new LLVolume(volume_params,0);
+ std::string mesh_string((char*) data, data_size);
+ std::istringstream stream(mesh_string);
+
+ if (volume->unpackVolumeFaces(stream, data_size))
+ {
+ //load volume faces into decomposition buffer
+ S32 vertex_count = 0;
+ S32 index_count = 0;
+
+ for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
+ {
+ const LLVolumeFace& face = volume->getVolumeFace(i);
+ vertex_count += face.mNumVertices;
+ index_count += face.mNumIndices;
+ }
+
+ d->mPhysicsShapeMesh.clear();
+
+ std::vector<LLVector3>& pos = d->mPhysicsShapeMesh.mPositions;
+ std::vector<LLVector3>& norm = d->mPhysicsShapeMesh.mNormals;
+
+ for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
+ {
+ const LLVolumeFace& face = volume->getVolumeFace(i);
+
+ for (S32 i = 0; i < face.mNumIndices; ++i)
+ {
+ U16 idx = face.mIndices[i];
+
+ pos.push_back(LLVector3(face.mPositions[idx].getF32ptr()));
+ norm.push_back(LLVector3(face.mNormals[idx].getF32ptr()));
+ }
+ }
+ }
+ }
+
+ mDecompositionQ.push(d);
+ return true;
+}
+
+LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data, LLVector3& scale, bool upload_textures,
+ bool upload_skin, bool upload_joints)
+: LLThread("mesh upload"),
+ mDiscarded(FALSE)
+{
+ mInstanceList = data;
+ mUploadTextures = upload_textures;
+ mUploadSkin = upload_skin;
+ mUploadJoints = upload_joints;
+ mMutex = new LLMutex(NULL);
+ mCurlRequest = NULL;
+ mPendingConfirmations = 0;
+ mPendingUploads = 0;
+ mPendingCost = 0;
+ mFinished = false;
+ mOrigin = gAgent.getPositionAgent();
+ mHost = gAgent.getRegionHost();
+
+ mUploadObjectAssetCapability = gAgent.getRegion()->getCapability("UploadObjectAsset");
+ mNewInventoryCapability = gAgent.getRegion()->getCapability("NewFileAgentInventoryVariablePrice");
+ mWholeModelUploadCapability = gAgent.getRegion()->getCapability("NewFileAgentInventory");
+
+ mOrigin += gAgent.getAtAxis() * scale.magVec();
+}
+
+LLMeshUploadThread::~LLMeshUploadThread()
+{
+
+}
+
+LLMeshUploadThread::DecompRequest::DecompRequest(LLModel* mdl, LLModel* base_model, LLMeshUploadThread* thread)
+{
+ mStage = "single_hull";
+ mModel = mdl;
+ mDecompID = &mdl->mDecompID;
+ mBaseModel = base_model;
+ mThread = thread;
+
+ //copy out positions and indices
+ if (mdl)
+ {
+ U16 index_offset = 0;
+
+ mPositions.clear();
+ mIndices.clear();
+
+ //queue up vertex positions and indices
+ for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i)
+ {
+ const LLVolumeFace& face = mdl->getVolumeFace(i);
+ if (mPositions.size() + face.mNumVertices > 65535)
+ {
+ continue;
+ }
+
+ for (U32 j = 0; j < face.mNumVertices; ++j)
+ {
+ mPositions.push_back(LLVector3(face.mPositions[j].getF32ptr()));
+ }
+
+ for (U32 j = 0; j < face.mNumIndices; ++j)
+ {
+ mIndices.push_back(face.mIndices[j]+index_offset);
+ }
+
+ index_offset += face.mNumVertices;
+ }
+ }
+
+ mThread->mFinalDecomp = this;
+ mThread->mPhysicsComplete = false;
+}
+
+void LLMeshUploadThread::DecompRequest::completed()
+{
+ if (mThread->mFinalDecomp == this)
+ {
+ mThread->mPhysicsComplete = true;
+ }
+
+ if (mHull.size() != 1)
+ {
+ llerrs << "WTF?" << llendl;
+ }
+
+ mThread->mHullMap[mBaseModel] = mHull[0];
+}
+
+//called in the main thread.
+void LLMeshUploadThread::preStart()
+{
+ //build map of LLModel refs to instances for callbacks
+ for (instance_list::iterator iter = mInstanceList.begin(); iter != mInstanceList.end(); ++iter)
+ {
+ mInstance[iter->mModel].push_back(*iter);
+ }
+}
+
+void LLMeshUploadThread::discard()
+{
+ LLMutexLock lock(mMutex) ;
+ mDiscarded = TRUE ;
+}
+
+BOOL LLMeshUploadThread::isDiscarded()
+{
+ LLMutexLock lock(mMutex) ;
+ return mDiscarded ;
+}
+
+void LLMeshUploadThread::run()
+{
+ if (gSavedSettings.getBOOL("MeshUseWholeModelUpload"))
+ {
+ doWholeModelUpload();
+ }
+ else
+ {
+ doIterativeUpload();
+ }
+}
+
+#if 0
+void dumpLLSDToFile(LLSD& content, std::string& filename)
+{
+ std::ofstream of(filename);
+ LLSDSerialize::toPrettyXML(content,of);
+}
+#endif
+
+void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures)
+{
+ // TODO where do textures go?
+
+ LLSD result;
+
+ result["folder_id"] = gInventory.findCategoryUUIDForType(LLFolderType::FT_OBJECT);
+ result["asset_type"] = "mesh";
+ result["inventory_type"] = "object";
+ result["name"] = "your name here";
+ result["description"] = "your description here";
+
+ // TODO "optional" fields from the spec
+
+ LLSD res;
+ res["mesh_list"] = LLSD::emptyArray();
+ res["texture_list"] = LLSD::emptyArray();
+ S32 mesh_num = 0;
+ S32 texture_num = 0;
+
+ std::set<LLViewerTexture* > textures;
+
+ for (instance_map::iterator iter = mInstance.begin(); iter != mInstance.end(); ++iter)
+ {
+ LLMeshUploadData data;
+ data.mBaseModel = iter->first;
+
+ LLModelInstance& instance = *(iter->second.begin());
+
+ for (S32 i = 0; i < 5; i++)
+ {
+ data.mModel[i] = instance.mLOD[i];
+ }
+
+ std::stringstream ostr;
+
+ LLModel::Decomposition& decomp =
+ data.mModel[LLModel::LOD_PHYSICS].notNull() ?
+ data.mModel[LLModel::LOD_PHYSICS]->mPhysics :
+ data.mBaseModel->mPhysics;
+
+ decomp.mBaseHull = mHullMap[data.mBaseModel];
+
+ LLSD mesh_header = LLModel::writeModel(
+ ostr,
+ data.mModel[LLModel::LOD_PHYSICS],
+ data.mModel[LLModel::LOD_HIGH],
+ data.mModel[LLModel::LOD_MEDIUM],
+ data.mModel[LLModel::LOD_LOW],
+ data.mModel[LLModel::LOD_IMPOSTOR],
+ decomp,
+ mUploadSkin,
+ mUploadJoints);
+
+ data.mAssetData = ostr.str();
+
+ LLSD mesh_entry;
+
+ LLVector3 pos, scale;
+ LLQuaternion rot;
+ LLMatrix4 transformation = instance.mTransform;
+ decomposeMeshMatrix(transformation,pos,rot,scale);
+
+ mesh_entry["childpos"] = ll_sd_from_vector3(pos);
+ mesh_entry["childrot"] = ll_sd_from_quaternion(rot);
+ mesh_entry["scale"] = ll_sd_from_vector3(scale);
+
+ // TODO should be binary.
+ std::string str = ostr.str();
+ mesh_entry["mesh_data"] = LLSD::Binary(str.begin(),str.end());
+
+ res["mesh_list"][mesh_num] = mesh_entry;
+
+ // TODO how do textures in the list map to textures in the meshes?
+ if (mUploadTextures)
+ {
+ for (std::vector<LLImportMaterial>::iterator material_iter = instance.mMaterial.begin();
+ material_iter != instance.mMaterial.end(); ++material_iter)
+ {
+
+ if (textures.find(material_iter->mDiffuseMap.get()) == textures.end())
+ {
+ textures.insert(material_iter->mDiffuseMap.get());
+
+ std::stringstream ostr;
+ if (include_textures) // otherwise data is blank.
+ {
+ LLTextureUploadData data(material_iter->mDiffuseMap.get(), material_iter->mDiffuseMapLabel);
+ if (!data.mTexture->isRawImageValid())
+ {
+ data.mTexture->reloadRawImage(data.mTexture->getDiscardLevel());
+ }
+
+ LLPointer<LLImageJ2C> upload_file =
+ LLViewerTextureList::convertToUploadFile(data.mTexture->getRawImage());
+ ostr.write((const char*) upload_file->getData(), upload_file->getDataSize());
+ }
+ LLSD texture_entry;
+ texture_entry["texture_data"] = ostr.str();
+ res["texture_list"][texture_num] = texture_entry;
+ texture_num++;
+ }
+ }
+ }
+
+ mesh_num++;
+ }
+
+ result["asset_resources"] = res;
+#if 0
+ std::string name("whole_model.xml");
+ dumpLLSDToFile(result,name);
+#endif
+
+ dest = result;
+}
+
+void LLMeshUploadThread::doWholeModelUpload()
+{
+ mCurlRequest = new LLCurlRequest();
+
+ // Queue up models for hull generation (viewer-side)
+ for (instance_map::iterator iter = mInstance.begin(); iter != mInstance.end(); ++iter)
+ {
+ LLMeshUploadData data;
+ data.mBaseModel = iter->first;
+
+ LLModelInstance& instance = *(iter->second.begin());
+
+ for (S32 i = 0; i < 5; i++)
+ {
+ data.mModel[i] = instance.mLOD[i];
+ }
+
+ //queue up models for hull generation
+ LLModel* physics = NULL;
+
+ if (data.mModel[LLModel::LOD_PHYSICS].notNull())
+ {
+ physics = data.mModel[LLModel::LOD_PHYSICS];
+ }
+ else if (data.mModel[LLModel::LOD_MEDIUM].notNull())
+ {
+ physics = data.mModel[LLModel::LOD_MEDIUM];
+ }
+ else
+ {
+ physics = data.mModel[LLModel::LOD_HIGH];
+ }
+
+ if (!physics)
+ {
+ llerrs << "WTF?" << llendl;
+ }
+
+ DecompRequest* request = new DecompRequest(physics, data.mBaseModel, this);
+ gMeshRepo.mDecompThread->submitRequest(request);
+ }
+
+ while (!mPhysicsComplete)
+ {
+ apr_sleep(100);
+ }
+
+ bool do_include_textures = false; // not needed for initial cost/validation check.
+ LLSD model_data;
+ wholeModelToLLSD(model_data, do_include_textures);
+
+ mPendingUploads++;
+ LLCurlRequest::headers_t headers;
+ mCurlRequest->post(mWholeModelUploadCapability, headers, model_data.asString(),
+ new LLWholeModelFeeResponder(this));
+
+ // Currently a no-op.
+ mFinished = true;
+}
+
+void LLMeshUploadThread::doIterativeUpload()
+{
+ if(isDiscarded())
+ {
+ mFinished = true;
+ return ;
+ }
+
+ mCurlRequest = new LLCurlRequest();
+
+ std::set<LLViewerTexture* > textures;
+
+ //populate upload queue with relevant models
+ for (instance_map::iterator iter = mInstance.begin(); iter != mInstance.end(); ++iter)
+ {
+ LLMeshUploadData data;
+ data.mBaseModel = iter->first;
+
+ LLModelInstance& instance = *(iter->second.begin());
+
+ for (S32 i = 0; i < 5; i++)
+ {
+ data.mModel[i] = instance.mLOD[i];
+ }
+
+ uploadModel(data);
+
+ if (mUploadTextures)
+ {
+ for (std::vector<LLImportMaterial>::iterator material_iter = instance.mMaterial.begin();
+ material_iter != instance.mMaterial.end(); ++material_iter)
+ {
+
+ if (textures.find(material_iter->mDiffuseMap.get()) == textures.end())
+ {
+ textures.insert(material_iter->mDiffuseMap.get());
+
+ LLTextureUploadData data(material_iter->mDiffuseMap.get(), material_iter->mDiffuseMapLabel);
+ uploadTexture(data);
+ }
+ }
+ }
+
+ //queue up models for hull generation
+ DecompRequest* request = new DecompRequest(data.mModel[LLModel::LOD_HIGH], data.mBaseModel, this);
+ gMeshRepo.mDecompThread->submitRequest(request);
+ }
+
+ while (!mPhysicsComplete)
+ {
+ apr_sleep(100);
+ }
+
+ //upload textures
+ bool done = false;
+ do
+ {
+ if (!mTextureQ.empty())
+ {
+ sendCostRequest(mTextureQ.front());
+ mTextureQ.pop();
+ }
+
+ if (!mConfirmedTextureQ.empty())
+ {
+ doUploadTexture(mConfirmedTextureQ.front());
+ mConfirmedTextureQ.pop();
+ }
+
+ mCurlRequest->process();
+
+ done = mTextureQ.empty() && mConfirmedTextureQ.empty();
+ }
+ while (!done || mCurlRequest->getQueued() > 0);
+
+ LLSD object_asset;
+ object_asset["objects"] = LLSD::emptyArray();
+
+ done = false;
+ do
+ {
+ static S32 count = 0;
+ static F32 last_hundred = gFrameTimeSeconds;
+ if (gFrameTimeSeconds - last_hundred > 1.f)
+ {
+ last_hundred = gFrameTimeSeconds;
+ count = 0;
+ }
+
+ //how many requests to push before calling process
+ const S32 PUSH_PER_PROCESS = 32;
+
+ S32 tcount = llmin(count+PUSH_PER_PROCESS, 100);
+
+ while (!mUploadQ.empty() && count < tcount)
+ { //send any pending upload requests
+ mMutex->lock();
+ LLMeshUploadData data = mUploadQ.front();
+ mUploadQ.pop();
+ mMutex->unlock();
+ sendCostRequest(data);
+ count++;
+ }
+
+ tcount = llmin(count+PUSH_PER_PROCESS, 100);
+
+ while (!mConfirmedQ.empty() && count < tcount)
+ { //process any meshes that have been confirmed for upload
+ LLMeshUploadData& data = mConfirmedQ.front();
+ doUploadModel(data);
+ mConfirmedQ.pop();
+ count++;
+ }
+
+ tcount = llmin(count+PUSH_PER_PROCESS, 100);
+
+ while (!mInstanceQ.empty() && count < tcount && !isDiscarded())
+ { //create any objects waiting for upload
+ count++;
+ object_asset["objects"].append(createObject(mInstanceQ.front()));
+ mInstanceQ.pop();
+ }
+
+ mCurlRequest->process();
+
+ done = isDiscarded() || (mInstanceQ.empty() && mConfirmedQ.empty() && mUploadQ.empty());
+ }
+ while (!done || mCurlRequest->getQueued() > 0);
+
+ delete mCurlRequest;
+ mCurlRequest = NULL;
+
+ // now upload the object asset
+ std::string url = mUploadObjectAssetCapability;
+
+ if (object_asset["objects"][0].has("permissions"))
+ { //copy permissions from first available object to be used for coalesced object
+ object_asset["permissions"] = object_asset["objects"][0]["permissions"];
+ }
+
+ if(!isDiscarded())
+ {
+ mPendingUploads++;
+ LLHTTPClient::post(url, object_asset, new LLModelObjectUploadResponder(this,object_asset));
+ }
+ else
+ {
+ mFinished = true;
+ }
+}
+
+void LLMeshUploadThread::uploadModel(LLMeshUploadData& data)
+{ //called from arbitrary thread
+ {
+ LLMutexLock lock(mMutex);
+ mUploadQ.push(data);
+ }
+}
+
+void LLMeshUploadThread::uploadTexture(LLTextureUploadData& data)
+{ //called from mesh upload thread
+ mTextureQ.push(data);
+}
+
+
+static LLFastTimer::DeclareTimer FTM_NOTIFY_MESH_LOADED("Notify Loaded");
+static LLFastTimer::DeclareTimer FTM_NOTIFY_MESH_UNAVAILABLE("Notify Unavailable");
+
+void LLMeshRepoThread::notifyLoadedMeshes()
+{
+ while (!mLoadedQ.empty())
+ {
+ mMutex->lock();
+ LoadedMesh mesh = mLoadedQ.front();
+ mLoadedQ.pop();
+ mMutex->unlock();
+
+ if (mesh.mVolume && mesh.mVolume->getNumVolumeFaces() > 0)
+ {
+ gMeshRepo.notifyMeshLoaded(mesh.mMeshParams, mesh.mVolume);
+ }
+ else
+ {
+ gMeshRepo.notifyMeshUnavailable(mesh.mMeshParams,
+ LLVolumeLODGroup::getVolumeDetailFromScale(mesh.mVolume->getDetail()));
+ }
+ }
+
+ while (!mUnavailableQ.empty())
+ {
+ mMutex->lock();
+ LODRequest req = mUnavailableQ.front();
+ mUnavailableQ.pop();
+ mMutex->unlock();
+
+ gMeshRepo.notifyMeshUnavailable(req.mMeshParams, req.mLOD);
+ }
+
+ while (!mSkinInfoQ.empty())
+ {
+ gMeshRepo.notifySkinInfoReceived(mSkinInfoQ.front());
+ mSkinInfoQ.pop();
+ }
+
+ while (!mDecompositionQ.empty())
+ {
+ gMeshRepo.notifyDecompositionReceived(mDecompositionQ.front());
+ mDecompositionQ.pop();
+ }
+}
+
+S32 LLMeshRepoThread::getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lod)
+{ //only ever called from main thread
+ LLMutexLock lock(mHeaderMutex);
+ mesh_header_map::iterator iter = mMeshHeader.find(mesh_params.getSculptID());
+
+ if (iter != mMeshHeader.end())
+ {
+ LLSD& header = iter->second;
+
+ return LLMeshRepository::getActualMeshLOD(header, lod);
+ }
+
+ return lod;
+}
+
+//static
+S32 LLMeshRepository::getActualMeshLOD(LLSD& header, S32 lod)
+{
+ lod = llclamp(lod, 0, 3);
+
+ if (header.has("404"))
+ {
+ return -1;
+ }
+
+ if (header[header_lod[lod]]["size"].asInteger() > 0)
+ {
+ return lod;
+ }
+
+ //search down to find the next available lower lod
+ for (S32 i = lod-1; i >= 0; --i)
+ {
+ if (header[header_lod[i]]["size"].asInteger() > 0)
+ {
+ return i;
+ }
+ }
+
+ //search up to find then ext available higher lod
+ for (S32 i = lod+1; i < 4; ++i)
+ {
+ if (header[header_lod[i]]["size"].asInteger() > 0)
+ {
+ return i;
+ }
+ }
+
+ //header exists and no good lod found, treat as 404
+ header["404"] = 1;
+ return -1;
+}
+
+U32 LLMeshRepoThread::getResourceCost(const LLUUID& mesh_id)
+{
+ LLMutexLock lock(mHeaderMutex);
+
+ std::map<LLUUID, U32>::iterator iter = mMeshResourceCost.find(mesh_id);
+ if (iter != mMeshResourceCost.end())
+ {
+ return iter->second;
+ }
+
+ return 0;
+}
+
+void LLMeshRepository::cacheOutgoingMesh(LLMeshUploadData& data, LLSD& header)
+{
+ mThread->mMeshHeader[data.mUUID] = header;
+
+ // we cache the mesh for default parameters
+ LLVolumeParams volume_params;
+ volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
+ volume_params.setSculptID(data.mUUID, LL_SCULPT_TYPE_MESH);
+
+ for (U32 i = 0; i < 4; i++)
+ {
+ if (data.mModel[i].notNull())
+ {
+ LLPointer<LLVolume> volume = new LLVolume(volume_params, LLVolumeLODGroup::getVolumeScaleFromDetail(i));
+ volume->copyVolumeFaces(data.mModel[i]);
+ }
+ }
+
+}
+
+void LLMeshLODResponder::completedRaw(U32 status, const std::string& reason,
+ const LLChannelDescriptors& channels,
+ const LLIOPipe::buffer_ptr_t& buffer)
+{
+
+ LLMeshRepoThread::sActiveLODRequests--;
+ S32 data_size = buffer->countAfter(channels.in(), NULL);
+
+ if (status < 200 || status > 400)
+ {
+ llwarns << status << ": " << reason << llendl;
+ }
+
+ if (data_size < mRequestedBytes)
+ {
+ if (status == 499 || status == 503)
+ { //timeout or service unavailable, try again
+ LLMeshRepository::sHTTPRetryCount++;
+ gMeshRepo.mThread->loadMeshLOD(mMeshParams, mLOD);
+ }
+ else
+ {
+ llwarns << "Unhandled status " << status << llendl;
+ }
+ return;
+ }
+
+ LLMeshRepository::sBytesReceived += mRequestedBytes;
+
+ U8* data = NULL;
+
+ if (data_size > 0)
+ {
+ data = new U8[data_size];
+ buffer->readAfter(channels.in(), NULL, data, data_size);
+ }
+
+ if (gMeshRepo.mThread->lodReceived(mMeshParams, mLOD, data, data_size))
+ {
+ //good fetch from sim, write to VFS for caching
+ LLVFile file(gVFS, mMeshParams.getSculptID(), LLAssetType::AT_MESH, LLVFile::WRITE);
+
+ S32 offset = mOffset;
+ S32 size = mRequestedBytes;
+
+ if (file.getSize() >= offset+size)
+ {
+ file.seek(offset);
+ file.write(data, size);
+ LLMeshRepository::sCacheBytesWritten += size;
+ }
+ }
+
+ delete [] data;
+}
+
+void LLMeshSkinInfoResponder::completedRaw(U32 status, const std::string& reason,
+ const LLChannelDescriptors& channels,
+ const LLIOPipe::buffer_ptr_t& buffer)
+{
+ S32 data_size = buffer->countAfter(channels.in(), NULL);
+
+ if (status < 200 || status > 400)
+ {
+ llwarns << status << ": " << reason << llendl;
+ }
+
+ if (data_size < mRequestedBytes)
+ {
+ if (status == 499 || status == 503)
+ { //timeout or service unavailable, try again
+ LLMeshRepository::sHTTPRetryCount++;
+ gMeshRepo.mThread->loadMeshSkinInfo(mMeshID);
+ }
+ else
+ {
+ llwarns << "Unhandled status " << status << llendl;
+ }
+ return;
+ }
+
+ LLMeshRepository::sBytesReceived += mRequestedBytes;
+
+ U8* data = NULL;
+
+ if (data_size > 0)
+ {
+ data = new U8[data_size];
+ buffer->readAfter(channels.in(), NULL, data, data_size);
+ }
+
+ if (gMeshRepo.mThread->skinInfoReceived(mMeshID, data, data_size))
+ {
+ //good fetch from sim, write to VFS for caching
+ LLVFile file(gVFS, mMeshID, LLAssetType::AT_MESH, LLVFile::WRITE);
+
+ S32 offset = mOffset;
+ S32 size = mRequestedBytes;
+
+ if (file.getSize() >= offset+size)
+ {
+ LLMeshRepository::sCacheBytesWritten += size;
+ file.seek(offset);
+ file.write(data, size);
+ }
+ }
+
+ delete [] data;
+}
+
+void LLMeshDecompositionResponder::completedRaw(U32 status, const std::string& reason,
+ const LLChannelDescriptors& channels,
+ const LLIOPipe::buffer_ptr_t& buffer)
+{
+ S32 data_size = buffer->countAfter(channels.in(), NULL);
+
+ if (status < 200 || status > 400)
+ {
+ llwarns << status << ": " << reason << llendl;
+ }
+
+ if (data_size < mRequestedBytes)
+ {
+ if (status == 499 || status == 503)
+ { //timeout or service unavailable, try again
+ LLMeshRepository::sHTTPRetryCount++;
+ gMeshRepo.mThread->loadMeshDecomposition(mMeshID);
+ }
+ else
+ {
+ llwarns << "Unhandled status " << status << llendl;
+ }
+ return;
+ }
+
+ LLMeshRepository::sBytesReceived += mRequestedBytes;
+
+ U8* data = NULL;
+
+ if (data_size > 0)
+ {
+ data = new U8[data_size];
+ buffer->readAfter(channels.in(), NULL, data, data_size);
+ }
+
+ if (gMeshRepo.mThread->decompositionReceived(mMeshID, data, data_size))
+ {
+ //good fetch from sim, write to VFS for caching
+ LLVFile file(gVFS, mMeshID, LLAssetType::AT_MESH, LLVFile::WRITE);
+
+ S32 offset = mOffset;
+ S32 size = mRequestedBytes;
+
+ if (file.getSize() >= offset+size)
+ {
+ LLMeshRepository::sCacheBytesWritten += size;
+ file.seek(offset);
+ file.write(data, size);
+ }
+ }
+
+ delete [] data;
+}
+
+void LLMeshPhysicsShapeResponder::completedRaw(U32 status, const std::string& reason,
+ const LLChannelDescriptors& channels,
+ const LLIOPipe::buffer_ptr_t& buffer)
+{
+ S32 data_size = buffer->countAfter(channels.in(), NULL);
+
+ if (status < 200 || status > 400)
+ {
+ llwarns << status << ": " << reason << llendl;
+ }
+
+ if (data_size < mRequestedBytes)
+ {
+ if (status == 499 || status == 503)
+ { //timeout or service unavailable, try again
+ LLMeshRepository::sHTTPRetryCount++;
+ gMeshRepo.mThread->loadMeshPhysicsShape(mMeshID);
+ }
+ else
+ {
+ llwarns << "Unhandled status " << status << llendl;
+ }
+ return;
+ }
+
+ LLMeshRepository::sBytesReceived += mRequestedBytes;
+
+ U8* data = NULL;
+
+ if (data_size > 0)
+ {
+ data = new U8[data_size];
+ buffer->readAfter(channels.in(), NULL, data, data_size);
+ }
+
+ if (gMeshRepo.mThread->physicsShapeReceived(mMeshID, data, data_size))
+ {
+ //good fetch from sim, write to VFS for caching
+ LLVFile file(gVFS, mMeshID, LLAssetType::AT_MESH, LLVFile::WRITE);
+
+ S32 offset = mOffset;
+ S32 size = mRequestedBytes;
+
+ if (file.getSize() >= offset+size)
+ {
+ LLMeshRepository::sCacheBytesWritten += size;
+ file.seek(offset);
+ file.write(data, size);
+ }
+ }
+
+ delete [] data;
+}
+
+void LLMeshHeaderResponder::completedRaw(U32 status, const std::string& reason,
+ const LLChannelDescriptors& channels,
+ const LLIOPipe::buffer_ptr_t& buffer)
+{
+ LLMeshRepoThread::sActiveHeaderRequests--;
+ if (status < 200 || status > 400)
+ {
+ //llwarns
+ // << "Header responder failed with status: "
+ // << status << ": " << reason << llendl;
+
+ // 503 (service unavailable) or 499 (timeout)
+ // can be due to server load and can be retried
+
+ // TODO*: Add maximum retry logic, exponential backoff
+ // and (somewhat more optional than the others) retries
+ // again after some set period of time
+ if (status == 503 || status == 499)
+ { //retry
+ LLMeshRepository::sHTTPRetryCount++;
+ LLMeshRepoThread::HeaderRequest req(mMeshParams);
+ LLMutexLock lock(gMeshRepo.mThread->mMutex);
+ gMeshRepo.mThread->mHeaderReqQ.push(req);
+
+ return;
+ }
+ }
+
+ S32 data_size = buffer->countAfter(channels.in(), NULL);
+
+ U8* data = NULL;
+
+ if (data_size > 0)
+ {
+ data = new U8[data_size];
+ buffer->readAfter(channels.in(), NULL, data, data_size);
+ }
+
+ LLMeshRepository::sBytesReceived += llmin(data_size, 4096);
+
+ if (!gMeshRepo.mThread->headerReceived(mMeshParams, data, data_size))
+ {
+ llwarns
+ << "Unable to parse mesh header: "
+ << status << ": " << reason << llendl;
+ }
+ else if (data && data_size > 0)
+ {
+ //header was successfully retrieved from sim, cache in vfs
+ LLUUID mesh_id = mMeshParams.getSculptID();
+ LLSD header = gMeshRepo.mThread->mMeshHeader[mesh_id];
+
+ std::stringstream str;
+
+ S32 lod_bytes = 0;
+
+ for (U32 i = 0; i < LLModel::LOD_PHYSICS; ++i)
+ { //figure out how many bytes we'll need to reserve in the file
+ std::string lod_name = header_lod[i];
+ lod_bytes = llmax(lod_bytes, header[lod_name]["offset"].asInteger()+header[lod_name]["size"].asInteger());
+ }
+
+ //just in case skin info or decomposition is at the end of the file (which it shouldn't be)
+ lod_bytes = llmax(lod_bytes, header["skin"]["offset"].asInteger() + header["skin"]["size"].asInteger());
+ lod_bytes = llmax(lod_bytes, header["decomposition"]["offset"].asInteger() + header["decomposition"]["size"].asInteger());
+
+ S32 header_bytes = (S32) gMeshRepo.mThread->mMeshHeaderSize[mesh_id];
+ S32 bytes = lod_bytes + header_bytes;
+
+
+ //it's possible for the remote asset to have more data than is needed for the local cache
+ //only allocate as much space in the VFS as is needed for the local cache
+ data_size = llmin(data_size, bytes);
+
+ LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH, LLVFile::WRITE);
+ if (file.getMaxSize() >= bytes || file.setMaxSize(bytes))
+ {
+ LLMeshRepository::sCacheBytesWritten += data_size;
+
+ file.write((const U8*) data, data_size);
+
+ //zero out the rest of the file
+ U8 block[4096];
+ memset(block, 0, 4096);
+
+ while (bytes-file.tell() > 4096)
+ {
+ file.write(block, 4096);
+ }
+
+ S32 remaining = bytes-file.tell();
+
+ if (remaining < 0 || remaining > 4096)
+ {
+ llerrs << "Bad padding of mesh asset cache entry." << llendl;
+ }
+
+ if (remaining > 0)
+ {
+ file.write(block, remaining);
+ }
+ }
+ }
+
+ delete [] data;
+}
+
+
+LLMeshRepository::LLMeshRepository()
+: mMeshMutex(NULL),
+ mMeshThreadCount(0),
+ mThread(NULL)
+{
+
+}
+
+void LLMeshRepository::init()
+{
+ mMeshMutex = new LLMutex(NULL);
+
+ LLConvexDecomposition::getInstance()->initSystem();
+
+ mDecompThread = new LLPhysicsDecomp();
+ mDecompThread->start();
+
+ while (!mDecompThread->mInited)
+ { //wait for physics decomp thread to init
+ apr_sleep(100);
+ }
+
+
+
+ mThread = new LLMeshRepoThread();
+ mThread->start();
+}
+
+void LLMeshRepository::shutdown()
+{
+ llinfos << "Shutting down mesh repository." << llendl;
+
+ for (U32 i = 0; i < mUploads.size(); ++i)
+ {
+ llinfos << "Discard the pending mesh uploads " << llendl;
+ mUploads[i]->discard() ; //discard the uploading requests.
+ }
+
+ mThread->mSignal->signal();
+
+ while (!mThread->isStopped())
+ {
+ apr_sleep(10);
+ }
+ delete mThread;
+ mThread = NULL;
+
+ for (U32 i = 0; i < mUploads.size(); ++i)
+ {
+ llinfos << "Waiting for pending mesh upload " << i << "/" << mUploads.size() << llendl;
+ while (!mUploads[i]->isStopped())
+ {
+ apr_sleep(10);
+ }
+ delete mUploads[i];
+ }
+
+ mUploads.clear();
+
+ delete mMeshMutex;
+ mMeshMutex = NULL;
+
+ llinfos << "Shutting down decomposition system." << llendl;
+
+ if (mDecompThread)
+ {
+ mDecompThread->shutdown();
+ delete mDecompThread;
+ mDecompThread = NULL;
+ }
+
+ LLConvexDecomposition::quitSystem();
+}
+
+//called in the main thread.
+S32 LLMeshRepository::update()
+{
+ if(mUploadWaitList.empty())
+ {
+ return 0 ;
+ }
+
+ S32 size = mUploadWaitList.size() ;
+ for (S32 i = 0; i < size; ++i)
+ {
+ mUploads.push_back(mUploadWaitList[i]);
+ mUploadWaitList[i]->preStart() ;
+ mUploadWaitList[i]->start() ;
+ }
+ mUploadWaitList.clear() ;
+
+ return size ;
+}
+
+S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_params, S32 detail, S32 last_lod)
+{
+ if (detail < 0 || detail > 4)
+ {
+ return detail;
+ }
+
+ LLFastTimer t(FTM_LOAD_MESH);
+
+ {
+ LLMutexLock lock(mMeshMutex);
+ //add volume to list of loading meshes
+ mesh_load_map::iterator iter = mLoadingMeshes[detail].find(mesh_params);
+ if (iter != mLoadingMeshes[detail].end())
+ { //request pending for this mesh, append volume id to list
+ iter->second.insert(vobj->getID());
+ }
+ else
+ {
+ //first request for this mesh
+ mLoadingMeshes[detail][mesh_params].insert(vobj->getID());
+ mPendingRequests.push_back(LLMeshRepoThread::LODRequest(mesh_params, detail));
+ }
+ }
+
+ //do a quick search to see if we can't display something while we wait for this mesh to load
+ LLVolume* volume = vobj->getVolume();
+
+ if (volume)
+ {
+ if (volume->getNumVolumeFaces() == 0 && !volume->isTetrahedron())
+ {
+ volume->makeTetrahedron();
+ }
+
+ LLVolumeParams params = volume->getParams();
+
+ LLVolumeLODGroup* group = LLPrimitive::getVolumeManager()->getGroup(params);
+
+ if (group)
+ {
+ //first, see if last_lod is available (don't transition down to avoid funny popping a la SH-641)
+ if (last_lod >= 0)
+ {
+ LLVolume* lod = group->refLOD(last_lod);
+ if (lod && !lod->isTetrahedron() && lod->getNumVolumeFaces() > 0)
+ {
+ group->derefLOD(lod);
+ return last_lod;
+ }
+ group->derefLOD(lod);
+ }
+
+ //next, see what the next lowest LOD available might be
+ for (S32 i = detail-1; i >= 0; --i)
+ {
+ LLVolume* lod = group->refLOD(i);
+ if (lod && !lod->isTetrahedron() && lod->getNumVolumeFaces() > 0)
+ {
+ group->derefLOD(lod);
+ return i;
+ }
+
+ group->derefLOD(lod);
+ }
+
+ //no lower LOD is a available, is a higher lod available?
+ for (S32 i = detail+1; i < 4; ++i)
+ {
+ LLVolume* lod = group->refLOD(i);
+ if (lod && !lod->isTetrahedron() && lod->getNumVolumeFaces() > 0)
+ {
+ group->derefLOD(lod);
+ return i;
+ }
+
+ group->derefLOD(lod);
+ }
+ }
+ else
+ {
+ llerrs << "WTF?" << llendl;
+ }
+ }
+
+ return detail;
+}
+
+static LLFastTimer::DeclareTimer FTM_START_MESH_THREAD("Start Thread");
+static LLFastTimer::DeclareTimer FTM_LOAD_MESH_LOD("Load LOD");
+static LLFastTimer::DeclareTimer FTM_MESH_LOCK1("Lock 1");
+static LLFastTimer::DeclareTimer FTM_MESH_LOCK2("Lock 2");
+
+void LLMeshRepository::notifyLoadedMeshes()
+{ //called from main thread
+
+ LLMeshRepoThread::sMaxConcurrentRequests = gSavedSettings.getU32("MeshMaxConcurrentRequests");
+
+ //clean up completed upload threads
+ for (std::vector<LLMeshUploadThread*>::iterator iter = mUploads.begin(); iter != mUploads.end(); )
+ {
+ LLMeshUploadThread* thread = *iter;
+
+ if (thread->isStopped() && thread->finished())
+ {
+ iter = mUploads.erase(iter);
+ delete thread;
+ }
+ else
+ {
+ ++iter;
+ }
+ }
+
+ //update inventory
+ if (!mInventoryQ.empty())
+ {
+ LLMutexLock lock(mMeshMutex);
+ while (!mInventoryQ.empty())
+ {
+ inventory_data& data = mInventoryQ.front();
+
+ LLAssetType::EType asset_type = LLAssetType::lookup(data.mPostData["asset_type"].asString());
+ LLInventoryType::EType inventory_type = LLInventoryType::lookup(data.mPostData["inventory_type"].asString());
+
+ on_new_single_inventory_upload_complete(
+ asset_type,
+ inventory_type,
+ data.mPostData["asset_type"].asString(),
+ data.mPostData["folder_id"].asUUID(),
+ data.mPostData["name"],
+ data.mPostData["description"],
+ data.mResponse,
+ 0);
+
+ mInventoryQ.pop();
+ }
+ }
+
+ //call completed callbacks on finished decompositions
+ mDecompThread->notifyCompleted();
+
+ if (!mThread->mWaiting)
+ { //curl thread is churning, wait for it to go idle
+ return;
+ }
+
+ static std::string region_name("never name a region this");
+
+ if (gAgent.getRegion())
+ { //update capability url
+ if (gAgent.getRegion()->getName() != region_name && gAgent.getRegion()->capabilitiesReceived())
+ {
+ region_name = gAgent.getRegion()->getName();
+
+ mGetMeshCapability = gAgent.getRegion()->getCapability("GetMesh");
+ }
+ }
+
+ LLFastTimer t(FTM_MESH_UPDATE);
+
+ {
+ LLFastTimer t(FTM_MESH_LOCK1);
+ mMeshMutex->lock();
+ }
+
+ {
+ LLFastTimer t(FTM_MESH_LOCK2);
+ mThread->mMutex->lock();
+ }
+
+ //popup queued error messages from background threads
+ while (!mUploadErrorQ.empty())
+ {
+ LLNotificationsUtil::add("MeshUploadError", mUploadErrorQ.front());
+ mUploadErrorQ.pop();
+ }
+
+ S32 push_count = LLMeshRepoThread::sMaxConcurrentRequests-(LLMeshRepoThread::sActiveHeaderRequests+LLMeshRepoThread::sActiveLODRequests);
+
+ if (push_count > 0)
+ {
+ //calculate "score" for pending requests
+
+ //create score map
+ std::map<LLUUID, F32> score_map;
+
+ for (U32 i = 0; i < 4; ++i)
+ {
+ for (mesh_load_map::iterator iter = mLoadingMeshes[i].begin(); iter != mLoadingMeshes[i].end(); ++iter)
+ {
+ F32 max_score = 0.f;
+ for (std::set<LLUUID>::iterator obj_iter = iter->second.begin(); obj_iter != iter->second.end(); ++obj_iter)
+ {
+ LLViewerObject* object = gObjectList.findObject(*obj_iter);
+
+ if (object)
+ {
+ LLDrawable* drawable = object->mDrawable;
+ if (drawable)
+ {
+ F32 cur_score = drawable->getRadius()/llmax(drawable->mDistanceWRTCamera, 1.f);
+ max_score = llmax(max_score, cur_score);
+ }
+ }
+ }
+
+ score_map[iter->first.getSculptID()] = max_score;
+ }
+ }
+
+ //set "score" for pending requests
+ for (std::vector<LLMeshRepoThread::LODRequest>::iterator iter = mPendingRequests.begin(); iter != mPendingRequests.end(); ++iter)
+ {
+ iter->mScore = score_map[iter->mMeshParams.getSculptID()];
+ }
+
+ //sort by "score"
+ std::sort(mPendingRequests.begin(), mPendingRequests.end(), LLMeshRepoThread::CompareScoreGreater());
+
+ while (!mPendingRequests.empty() && push_count > 0)
+ {
+ LLFastTimer t(FTM_LOAD_MESH_LOD);
+ LLMeshRepoThread::LODRequest& request = mPendingRequests.front();
+ mThread->loadMeshLOD(request.mMeshParams, request.mLOD);
+ mPendingRequests.erase(mPendingRequests.begin());
+ push_count--;
+ }
+ }
+
+ //send skin info requests
+ while (!mPendingSkinRequests.empty())
+ {
+ mThread->loadMeshSkinInfo(mPendingSkinRequests.front());
+ mPendingSkinRequests.pop();
+ }
+
+ //send decomposition requests
+ while (!mPendingDecompositionRequests.empty())
+ {
+ mThread->loadMeshDecomposition(mPendingDecompositionRequests.front());
+ mPendingDecompositionRequests.pop();
+ }
+
+ //send physics shapes decomposition requests
+ while (!mPendingPhysicsShapeRequests.empty())
+ {
+ mThread->loadMeshPhysicsShape(mPendingPhysicsShapeRequests.front());
+ mPendingPhysicsShapeRequests.pop();
+ }
+
+ mThread->notifyLoadedMeshes();
+
+ mThread->mMutex->unlock();
+ mMeshMutex->unlock();
+
+ mThread->mSignal->signal();
+}
+
+void LLMeshRepository::notifySkinInfoReceived(LLMeshSkinInfo& info)
+{
+ mSkinMap[info.mMeshID] = info;
+ mLoadingSkins.erase(info.mMeshID);
+}
+
+void LLMeshRepository::notifyDecompositionReceived(LLModel::Decomposition* decomp)
+{
+ decomposition_map::iterator iter = mDecompositionMap.find(decomp->mMeshID);
+ if (iter == mDecompositionMap.end())
+ { //just insert decomp into map
+ mDecompositionMap[decomp->mMeshID] = decomp;
+ }
+ else
+ { //merge decomp with existing entry
+ iter->second->merge(decomp);
+ delete decomp;
+ }
+
+ mLoadingDecompositions.erase(decomp->mMeshID);
+}
+
+void LLMeshRepository::notifyMeshLoaded(const LLVolumeParams& mesh_params, LLVolume* volume)
+{ //called from main thread
+ S32 detail = LLVolumeLODGroup::getVolumeDetailFromScale(volume->getDetail());
+
+ //get list of objects waiting to be notified this mesh is loaded
+ mesh_load_map::iterator obj_iter = mLoadingMeshes[detail].find(mesh_params);
+
+ if (volume && obj_iter != mLoadingMeshes[detail].end())
+ {
+ //make sure target volume is still valid
+ if (volume->getNumVolumeFaces() <= 0)
+ {
+ llwarns << "Mesh loading returned empty volume." << llendl;
+ volume->makeTetrahedron();
+ }
+
+ { //update system volume
+ LLVolume* sys_volume = LLPrimitive::getVolumeManager()->refVolume(mesh_params, detail);
+ if (sys_volume)
+ {
+ sys_volume->copyVolumeFaces(volume);
+ LLPrimitive::getVolumeManager()->unrefVolume(sys_volume);
+ }
+ else
+ {
+ llwarns << "Couldn't find system volume for given mesh." << llendl;
+ }
+ }
+
+ //notify waiting LLVOVolume instances that their requested mesh is available
+ for (std::set<LLUUID>::iterator vobj_iter = obj_iter->second.begin(); vobj_iter != obj_iter->second.end(); ++vobj_iter)
+ {
+ LLVOVolume* vobj = (LLVOVolume*) gObjectList.findObject(*vobj_iter);
+ if (vobj)
+ {
+ vobj->notifyMeshLoaded();
+ }
+ }
+
+ mLoadingMeshes[detail].erase(mesh_params);
+ }
+}
+
+void LLMeshRepository::notifyMeshUnavailable(const LLVolumeParams& mesh_params, S32 lod)
+{ //called from main thread
+ //get list of objects waiting to be notified this mesh is loaded
+ mesh_load_map::iterator obj_iter = mLoadingMeshes[lod].find(mesh_params);
+
+ F32 detail = LLVolumeLODGroup::getVolumeScaleFromDetail(lod);
+
+ if (obj_iter != mLoadingMeshes[lod].end())
+ {
+ for (std::set<LLUUID>::iterator vobj_iter = obj_iter->second.begin(); vobj_iter != obj_iter->second.end(); ++vobj_iter)
+ {
+ LLVOVolume* vobj = (LLVOVolume*) gObjectList.findObject(*vobj_iter);
+ if (vobj)
+ {
+ LLVolume* obj_volume = vobj->getVolume();
+
+ if (obj_volume &&
+ obj_volume->getDetail() == detail &&
+ obj_volume->getParams() == mesh_params)
+ { //should force volume to find most appropriate LOD
+ vobj->setVolume(obj_volume->getParams(), lod);
+ }
+ }
+ }
+
+ mLoadingMeshes[lod].erase(mesh_params);
+ }
+}
+
+S32 LLMeshRepository::getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lod)
+{
+ return mThread->getActualMeshLOD(mesh_params, lod);
+}
+
+U32 LLMeshRepository::calcResourceCost(LLSD& header)
+{
+ U32 bytes = 0;
+
+ for (U32 i = 0; i < 4; i++)
+ {
+ bytes += header[header_lod[i]]["size"].asInteger();
+ }
+
+ bytes += header["skin"]["size"].asInteger();
+
+ return bytes/4096 + 1;
+}
+
+U32 LLMeshRepository::getResourceCost(const LLUUID& mesh_id)
+{
+ return mThread->getResourceCost(mesh_id);
+}
+
+const LLMeshSkinInfo* LLMeshRepository::getSkinInfo(const LLUUID& mesh_id)
+{
+ if (mesh_id.notNull())
+ {
+ skin_map::iterator iter = mSkinMap.find(mesh_id);
+ if (iter != mSkinMap.end())
+ {
+ return &(iter->second);
+ }
+
+ //no skin info known about given mesh, try to fetch it
+ {
+ LLMutexLock lock(mMeshMutex);
+ //add volume to list of loading meshes
+ std::set<LLUUID>::iterator iter = mLoadingSkins.find(mesh_id);
+ if (iter == mLoadingSkins.end())
+ { //no request pending for this skin info
+ mLoadingSkins.insert(mesh_id);
+ mPendingSkinRequests.push(mesh_id);
+ }
+ }
+ }
+
+ return NULL;
+}
+
+void LLMeshRepository::fetchPhysicsShape(const LLUUID& mesh_id)
+{
+ if (mesh_id.notNull())
+ {
+ LLModel::Decomposition* decomp = NULL;
+ decomposition_map::iterator iter = mDecompositionMap.find(mesh_id);
+ if (iter != mDecompositionMap.end())
+ {
+ decomp = iter->second;
+ }
+
+ //decomposition block hasn't been fetched yet
+ if (!decomp || decomp->mPhysicsShapeMesh.empty())
+ {
+ LLMutexLock lock(mMeshMutex);
+ //add volume to list of loading meshes
+ std::set<LLUUID>::iterator iter = mLoadingPhysicsShapes.find(mesh_id);
+ if (iter == mLoadingPhysicsShapes.end())
+ { //no request pending for this skin info
+ mLoadingPhysicsShapes.insert(mesh_id);
+ mPendingPhysicsShapeRequests.push(mesh_id);
+ }
+ }
+ }
+
+}
+
+LLModel::Decomposition* LLMeshRepository::getDecomposition(const LLUUID& mesh_id)
+{
+ LLModel::Decomposition* ret = NULL;
+
+ if (mesh_id.notNull())
+ {
+ decomposition_map::iterator iter = mDecompositionMap.find(mesh_id);
+ if (iter != mDecompositionMap.end())
+ {
+ ret = iter->second;
+ }
+
+ //decomposition block hasn't been fetched yet
+ if (!ret || ret->mBaseHullMesh.empty())
+ {
+ LLMutexLock lock(mMeshMutex);
+ //add volume to list of loading meshes
+ std::set<LLUUID>::iterator iter = mLoadingDecompositions.find(mesh_id);
+ if (iter == mLoadingDecompositions.end())
+ { //no request pending for this skin info
+ mLoadingDecompositions.insert(mesh_id);
+ mPendingDecompositionRequests.push(mesh_id);
+ }
+ }
+ }
+
+ return ret;
+}
+
+void LLMeshRepository::buildHull(const LLVolumeParams& params, S32 detail)
+{
+ LLVolume* volume = LLPrimitive::sVolumeManager->refVolume(params, detail);
+
+ if (!volume->mHullPoints)
+ {
+ //all default params
+ //execute first stage
+ //set simplify mode to retain
+ //set retain percentage to zero
+ //run second stage
+ }
+
+ LLPrimitive::sVolumeManager->unrefVolume(volume);
+}
+
+bool LLMeshRepository::hasPhysicsShape(const LLUUID& mesh_id)
+{
+ LLSD mesh = mThread->getMeshHeader(mesh_id);
+ return mesh.has("physics_shape") && mesh["physics_shape"].has("size") && (mesh["physics_shape"]["size"].asInteger() > 0);
+}
+
+LLSD& LLMeshRepository::getMeshHeader(const LLUUID& mesh_id)
+{
+ return mThread->getMeshHeader(mesh_id);
+}
+
+LLSD& LLMeshRepoThread::getMeshHeader(const LLUUID& mesh_id)
+{
+ static LLSD dummy_ret;
+ if (mesh_id.notNull())
+ {
+ LLMutexLock lock(mHeaderMutex);
+ mesh_header_map::iterator iter = mMeshHeader.find(mesh_id);
+ if (iter != mMeshHeader.end())
+ {
+ return iter->second;
+ }
+ }
+
+ return dummy_ret;
+}
+
+
+void LLMeshRepository::uploadModel(std::vector<LLModelInstance>& data, LLVector3& scale, bool upload_textures,
+ bool upload_skin, bool upload_joints)
+{
+ LLMeshUploadThread* thread = new LLMeshUploadThread(data, scale, upload_textures, upload_skin, upload_joints);
+ mUploadWaitList.push_back(thread);
+}
+
+S32 LLMeshRepository::getMeshSize(const LLUUID& mesh_id, S32 lod)
+{
+ if (mThread)
+ {
+ LLMeshRepoThread::mesh_header_map::iterator iter = mThread->mMeshHeader.find(mesh_id);
+ if (iter != mThread->mMeshHeader.end())
+ {
+ LLSD& header = iter->second;
+
+ if (header.has("404"))
+ {
+ return -1;
+ }
+
+ S32 size = header[header_lod[lod]]["size"].asInteger();
+ return size;
+ }
+
+ }
+
+ return -1;
+
+}
+
+void LLMeshUploadThread::sendCostRequest(LLMeshUploadData& data)
+{
+ if(isDiscarded())
+ {
+ return ;
+ }
+
+ //write model file to memory buffer
+ std::stringstream ostr;
+
+ LLModel::Decomposition& decomp =
+ data.mModel[LLModel::LOD_PHYSICS].notNull() ?
+ data.mModel[LLModel::LOD_PHYSICS]->mPhysics :
+ data.mBaseModel->mPhysics;
+
+ LLSD header = LLModel::writeModel(
+ ostr,
+ data.mModel[LLModel::LOD_PHYSICS],
+ data.mModel[LLModel::LOD_HIGH],
+ data.mModel[LLModel::LOD_MEDIUM],
+ data.mModel[LLModel::LOD_LOW],
+ data.mModel[LLModel::LOD_IMPOSTOR],
+ decomp,
+ mUploadSkin,
+ mUploadJoints,
+ true);
+
+ std::string desc = data.mBaseModel->mLabel;
+
+ // Grab the total vertex count of the model
+ // along with other information for the "asset_resources" map
+ // to send to the server.
+ LLSD asset_resources = LLSD::emptyMap();
+
+
+ std::string url = mNewInventoryCapability;
+
+ if (!url.empty())
+ {
+ LLSD body = generate_new_resource_upload_capability_body(
+ LLAssetType::AT_MESH,
+ desc,
+ desc,
+ LLFolderType::FT_MESH,
+ LLInventoryType::IT_MESH,
+ LLFloaterPerms::getNextOwnerPerms(),
+ LLFloaterPerms::getGroupPerms(),
+ LLFloaterPerms::getEveryonePerms());
+
+ body["asset_resources"] = asset_resources;
+
+ mPendingConfirmations++;
+ LLCurlRequest::headers_t headers;
+
+ data.mPostData = body;
+
+ mCurlRequest->post(url, headers, body, new LLMeshCostResponder(data, this));
+ }
+}
+
+void LLMeshUploadThread::sendCostRequest(LLTextureUploadData& data)
+{
+ if(isDiscarded())
+ {
+ return ;
+ }
+
+ if (data.mTexture && data.mTexture->getDiscardLevel() >= 0)
+ {
+ LLSD asset_resources = LLSD::emptyMap();
+
+ std::string url = mNewInventoryCapability;
+
+ if (!url.empty())
+ {
+ LLSD body = generate_new_resource_upload_capability_body(
+ LLAssetType::AT_TEXTURE,
+ data.mLabel,
+ data.mLabel,
+ LLFolderType::FT_TEXTURE,
+ LLInventoryType::IT_TEXTURE,
+ LLFloaterPerms::getNextOwnerPerms(),
+ LLFloaterPerms::getGroupPerms(),
+ LLFloaterPerms::getEveryonePerms());
+
+ body["asset_resources"] = asset_resources;
+
+ mPendingConfirmations++;
+ LLCurlRequest::headers_t headers;
+
+ data.mPostData = body;
+ mCurlRequest->post(url, headers, body, new LLTextureCostResponder(data, this));
+ }
+ }
+}
+
+
+void LLMeshUploadThread::doUploadModel(LLMeshUploadData& data)
+{
+ if(isDiscarded())
+ {
+ return ;
+ }
+
+ if (!data.mRSVP.empty())
+ {
+ std::stringstream ostr;
+
+ LLModel::Decomposition& decomp =
+ data.mModel[LLModel::LOD_PHYSICS].notNull() ?
+ data.mModel[LLModel::LOD_PHYSICS]->mPhysics :
+ data.mBaseModel->mPhysics;
+
+ decomp.mBaseHull = mHullMap[data.mBaseModel];
+
+ LLModel::writeModel(
+ ostr,
+ data.mModel[LLModel::LOD_PHYSICS],
+ data.mModel[LLModel::LOD_HIGH],
+ data.mModel[LLModel::LOD_MEDIUM],
+ data.mModel[LLModel::LOD_LOW],
+ data.mModel[LLModel::LOD_IMPOSTOR],
+ decomp,
+ mUploadSkin,
+ mUploadJoints);
+
+ data.mAssetData = ostr.str();
+
+ LLCurlRequest::headers_t headers;
+ mPendingUploads++;
+
+ mCurlRequest->post(data.mRSVP, headers, data.mAssetData, new LLMeshUploadResponder(data, this));
+ }
+}
+
+void LLMeshUploadThread::doUploadTexture(LLTextureUploadData& data)
+{
+ if(isDiscarded())
+ {
+ return ;
+ }
+
+ if (!data.mRSVP.empty())
+ {
+ std::stringstream ostr;
+
+ if (!data.mTexture->isRawImageValid())
+ {
+ data.mTexture->reloadRawImage(data.mTexture->getDiscardLevel());
+ }
+
+ LLPointer<LLImageJ2C> upload_file = LLViewerTextureList::convertToUploadFile(data.mTexture->getRawImage());
+
+ ostr.write((const char*) upload_file->getData(), upload_file->getDataSize());
+
+ data.mAssetData = ostr.str();
+
+ LLCurlRequest::headers_t headers;
+ mPendingUploads++;
+
+ mCurlRequest->post(data.mRSVP, headers, data.mAssetData, new LLTextureUploadResponder(data, this));
+ }
+}
+
+
+void LLMeshUploadThread::onModelUploaded(LLMeshUploadData& data)
+{
+ createObjects(data);
+}
+
+void LLMeshUploadThread::onTextureUploaded(LLTextureUploadData& data)
+{
+ mTextureMap[data.mTexture] = data;
+}
+
+
+void LLMeshUploadThread::createObjects(LLMeshUploadData& data)
+{
+ instance_list& instances = mInstance[data.mBaseModel];
+
+ for (instance_list::iterator iter = instances.begin(); iter != instances.end(); ++iter)
+ { //create prims that reference given mesh
+ LLModelInstance& instance = *iter;
+ instance.mMeshID = data.mUUID;
+ mInstanceQ.push(instance);
+ }
+}
+
+void LLMeshUploadThread::decomposeMeshMatrix(LLMatrix4& transformation,
+ LLVector3& result_pos,
+ LLQuaternion& result_rot,
+ LLVector3& result_scale)
+{
+ // check for reflection
+ BOOL reflected = (transformation.determinant() < 0);
+
+ // compute position
+ LLVector3 position = LLVector3(0, 0, 0) * transformation;
+
+ // compute scale
+ LLVector3 x_transformed = LLVector3(1, 0, 0) * transformation - position;
+ LLVector3 y_transformed = LLVector3(0, 1, 0) * transformation - position;
+ LLVector3 z_transformed = LLVector3(0, 0, 1) * transformation - position;
+ F32 x_length = x_transformed.normalize();
+ F32 y_length = y_transformed.normalize();
+ F32 z_length = z_transformed.normalize();
+ LLVector3 scale = LLVector3(x_length, y_length, z_length);
+
+ // adjust for "reflected" geometry
+ LLVector3 x_transformed_reflected = x_transformed;
+ if (reflected)
+ {
+ x_transformed_reflected *= -1.0;
+ }
+
+ // compute rotation
+ LLMatrix3 rotation_matrix;
+ rotation_matrix.setRows(x_transformed_reflected, y_transformed, z_transformed);
+ LLQuaternion quat_rotation = rotation_matrix.quaternion();
+ quat_rotation.normalize(); // the rotation_matrix might not have been orthoginal. make it so here.
+ LLVector3 euler_rotation;
+ quat_rotation.getEulerAngles(&euler_rotation.mV[VX], &euler_rotation.mV[VY], &euler_rotation.mV[VZ]);
+
+ result_pos = position + mOrigin;
+ result_scale = scale;
+ result_rot = quat_rotation;
+}
+
+
+LLSD LLMeshUploadThread::createObject(LLModelInstance& instance)
+{
+ LLMatrix4 transformation = instance.mTransform;
+
+ if (instance.mMeshID.isNull())
+ {
+ llerrs << "WTF?" << llendl;
+ }
+
+ // check for reflection
+ BOOL reflected = (transformation.determinant() < 0);
+
+ // compute position
+ LLVector3 position = LLVector3(0, 0, 0) * transformation;
+
+ // compute scale
+ LLVector3 x_transformed = LLVector3(1, 0, 0) * transformation - position;
+ LLVector3 y_transformed = LLVector3(0, 1, 0) * transformation - position;
+ LLVector3 z_transformed = LLVector3(0, 0, 1) * transformation - position;
+ F32 x_length = x_transformed.normalize();
+ F32 y_length = y_transformed.normalize();
+ F32 z_length = z_transformed.normalize();
+ LLVector3 scale = LLVector3(x_length, y_length, z_length);
+
+ // adjust for "reflected" geometry
+ LLVector3 x_transformed_reflected = x_transformed;
+ if (reflected)
+ {
+ x_transformed_reflected *= -1.0;
+ }
+
+ // compute rotation
+ LLMatrix3 rotation_matrix;
+ rotation_matrix.setRows(x_transformed_reflected, y_transformed, z_transformed);
+ LLQuaternion quat_rotation = rotation_matrix.quaternion();
+ quat_rotation.normalize(); // the rotation_matrix might not have been orthoginal. make it so here.
+ LLVector3 euler_rotation;
+ quat_rotation.getEulerAngles(&euler_rotation.mV[VX], &euler_rotation.mV[VY], &euler_rotation.mV[VZ]);
+
+ //
+ // build parameter block to construct this prim
+ //
+
+ LLSD object_params;
+
+ // create prim
+
+ // set volume params
+ U8 sculpt_type = LL_SCULPT_TYPE_MESH;
+ if (reflected)
+ {
+ sculpt_type |= LL_SCULPT_FLAG_MIRROR;
+ }
+ LLVolumeParams volume_params;
+ volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE );
+ volume_params.setBeginAndEndS( 0.f, 1.f );
+ volume_params.setBeginAndEndT( 0.f, 1.f );
+ volume_params.setRatio ( 1, 1 );
+ volume_params.setShear ( 0, 0 );
+ volume_params.setSculptID(instance.mMeshID, sculpt_type);
+ object_params["shape"] = volume_params.asLLSD();
+
+ object_params["material"] = LL_MCODE_WOOD;
+
+ object_params["group-id"] = gAgent.getGroupID();
+ object_params["pos"] = ll_sd_from_vector3(position + mOrigin);
+ object_params["rotation"] = ll_sd_from_quaternion(quat_rotation);
+ object_params["scale"] = ll_sd_from_vector3(scale);
+ object_params["name"] = instance.mLabel;
+
+ // load material from dae file
+ object_params["facelist"] = LLSD::emptyArray();
+ for (S32 i = 0; i < instance.mMaterial.size(); i++)
+ {
+ LLTextureEntry te;
+ LLImportMaterial& mat = instance.mMaterial[i];
+
+ te.setColor(mat.mDiffuseColor);
+
+ LLUUID diffuse_id = mTextureMap[mat.mDiffuseMap].mUUID;
+
+ if (diffuse_id.notNull())
+ {
+ te.setID(diffuse_id);
+ }
+ else
+ {
+ te.setID(LLUUID("5748decc-f629-461c-9a36-a35a221fe21f")); // blank texture
+ }
+
+ te.setFullbright(mat.mFullbright);
+
+ object_params["facelist"][i] = te.asLLSD();
+ }
+
+ // set extra parameters
+ LLSculptParams sculpt_params;
+ sculpt_params.setSculptTexture(instance.mMeshID);
+ sculpt_params.setSculptType(sculpt_type);
+ U8 buffer[MAX_OBJECT_PARAMS_SIZE+1];
+ LLDataPackerBinaryBuffer dp(buffer, MAX_OBJECT_PARAMS_SIZE);
+ sculpt_params.pack(dp);
+ std::vector<U8> v(dp.getCurrentSize());
+ memcpy(&v[0], buffer, dp.getCurrentSize());
+ LLSD extra_parameter;
+ extra_parameter["extra_parameter"] = sculpt_params.mType;
+ extra_parameter["param_data"] = v;
+ object_params["extra_parameters"].append(extra_parameter);
+
+ LLPermissions perm;
+ perm.setOwnerAndGroup(gAgent.getID(), gAgent.getID(), LLUUID::null, false);
+ perm.setCreator(gAgent.getID());
+
+ perm.initMasks(PERM_ITEM_UNRESTRICTED | PERM_MOVE, //base
+ PERM_ITEM_UNRESTRICTED | PERM_MOVE, //owner
+ LLFloaterPerms::getEveryonePerms(),
+ LLFloaterPerms::getGroupPerms(),
+ LLFloaterPerms::getNextOwnerPerms());
+
+ object_params["permissions"] = ll_create_sd_from_permissions(perm);
+
+ object_params["physics_shape_type"] = (U8)(LLViewerObject::PHYSICS_SHAPE_CONVEX_HULL);
+
+ return object_params;
+}
+
+void LLMeshUploadThread::priceResult(LLMeshUploadData& data, const LLSD& content)
+{
+ mPendingCost += content["upload_price"].asInteger();
+ data.mRSVP = content["rsvp"].asString();
+
+ mConfirmedQ.push(data);
+}
+
+void LLMeshUploadThread::priceResult(LLTextureUploadData& data, const LLSD& content)
+{
+ mPendingCost += content["upload_price"].asInteger();
+ data.mRSVP = content["rsvp"].asString();
+
+ mConfirmedTextureQ.push(data);
+}
+
+
+bool LLImportMaterial::operator<(const LLImportMaterial &rhs) const
+{
+ if (mDiffuseMap != rhs.mDiffuseMap)
+ {
+ return mDiffuseMap < rhs.mDiffuseMap;
+ }
+
+ if (mDiffuseMapFilename != rhs.mDiffuseMapFilename)
+ {
+ return mDiffuseMapFilename < rhs.mDiffuseMapFilename;
+ }
+
+ if (mDiffuseMapLabel != rhs.mDiffuseMapLabel)
+ {
+ return mDiffuseMapLabel < rhs.mDiffuseMapLabel;
+ }
+
+ if (mDiffuseColor != rhs.mDiffuseColor)
+ {
+ return mDiffuseColor < rhs.mDiffuseColor;
+ }
+
+ return mFullbright < rhs.mFullbright;
+}
+
+
+void LLMeshRepository::updateInventory(inventory_data data)
+{
+ LLMutexLock lock(mMeshMutex);
+ mInventoryQ.push(data);
+}
+
+void LLMeshRepository::uploadError(LLSD& args)
+{
+ LLMutexLock lock(mMeshMutex);
+ mUploadErrorQ.push(args);
+}
+
+//static
+F32 LLMeshRepository::getStreamingCost(LLSD& header, F32 radius, S32* bytes, S32* bytes_visible, S32 lod)
+{
+ F32 dlowest = llmin(radius/0.03f, 256.f);
+ F32 dlow = llmin(radius/0.06f, 256.f);
+ F32 dmid = llmin(radius/0.24f, 256.f);
+
+ F32 bytes_lowest = header["lowest_lod"]["size"].asReal()/1024.f;
+ F32 bytes_low = header["low_lod"]["size"].asReal()/1024.f;
+ F32 bytes_mid = header["medium_lod"]["size"].asReal()/1024.f;
+ F32 bytes_high = header["high_lod"]["size"].asReal()/1024.f;
+
+ if (bytes)
+ {
+ *bytes = 0;
+ *bytes += header["lowest_lod"]["size"].asInteger();
+ *bytes += header["low_lod"]["size"].asInteger();
+ *bytes += header["medium_lod"]["size"].asInteger();
+ *bytes += header["high_lod"]["size"].asInteger();
+ }
+
+
+ if (bytes_visible)
+ {
+ lod = LLMeshRepository::getActualMeshLOD(header, lod);
+ if (lod >= 0 && lod <= 3)
+ {
+ *bytes_visible = header[header_lod[lod]]["size"].asInteger();
+ }
+ }
+
+ if (bytes_high == 0.f)
+ {
+ return 0.f;
+ }
+
+ if (bytes_mid == 0.f)
+ {
+ bytes_mid = bytes_high;
+ }
+
+ if (bytes_low == 0.f)
+ {
+ bytes_low = bytes_mid;
+ }
+
+ if (bytes_lowest == 0.f)
+ {
+ bytes_lowest = bytes_low;
+ }
+
+ F32 max_area = 65536.f;
+ F32 min_area = 1.f;
+
+ F32 high_area = llmin(F_PI*dmid*dmid, max_area);
+ F32 mid_area = llmin(F_PI*dlow*dlow, max_area);
+ F32 low_area = llmin(F_PI*dlowest*dlowest, max_area);
+ F32 lowest_area = max_area;
+
+ lowest_area -= low_area;
+ low_area -= mid_area;
+ mid_area -= high_area;
+
+ high_area = llclamp(high_area, min_area, max_area);
+ mid_area = llclamp(mid_area, min_area, max_area);
+ low_area = llclamp(low_area, min_area, max_area);
+ lowest_area = llclamp(lowest_area, min_area, max_area);
+
+ F32 total_area = high_area + mid_area + low_area + lowest_area;
+ high_area /= total_area;
+ mid_area /= total_area;
+ low_area /= total_area;
+ lowest_area /= total_area;
+
+ F32 weighted_avg = bytes_high*high_area +
+ bytes_mid*mid_area +
+ bytes_low*low_area +
+ bytes_lowest*lowest_area;
+
+ return weighted_avg * gSavedSettings.getF32("MeshStreamingCostScaler");
+}
+
+
+LLPhysicsDecomp::LLPhysicsDecomp()
+: LLThread("Physics Decomp")
+{
+ mInited = false;
+ mQuitting = false;
+ mDone = false;
+
+ mSignal = new LLCondition(NULL);
+ mMutex = new LLMutex(NULL);
+}
+
+LLPhysicsDecomp::~LLPhysicsDecomp()
+{
+ shutdown();
+
+ delete mSignal;
+ mSignal = NULL;
+ delete mMutex;
+ mMutex = NULL;
+}
+
+void LLPhysicsDecomp::shutdown()
+{
+ if (mSignal)
+ {
+ mQuitting = true;
+ mSignal->signal();
+
+ while (!isStopped())
+ {
+ apr_sleep(10);
+ }
+ }
+}
+
+void LLPhysicsDecomp::submitRequest(LLPhysicsDecomp::Request* request)
+{
+ LLMutexLock lock(mMutex);
+ mRequestQ.push(request);
+ mSignal->signal();
+}
+
+//static
+S32 LLPhysicsDecomp::llcdCallback(const char* status, S32 p1, S32 p2)
+{
+ if (gMeshRepo.mDecompThread && gMeshRepo.mDecompThread->mCurRequest.notNull())
+ {
+ return gMeshRepo.mDecompThread->mCurRequest->statusCallback(status, p1, p2);
+ }
+
+ return 1;
+}
+
+void LLPhysicsDecomp::setMeshData(LLCDMeshData& mesh)
+{
+ mesh.mVertexBase = mCurRequest->mPositions[0].mV;
+ mesh.mVertexStrideBytes = 12;
+ mesh.mNumVertices = mCurRequest->mPositions.size();
+
+ mesh.mIndexType = LLCDMeshData::INT_16;
+ mesh.mIndexBase = &(mCurRequest->mIndices[0]);
+ mesh.mIndexStrideBytes = 6;
+
+ mesh.mNumTriangles = mCurRequest->mIndices.size()/3;
+
+ LLCDResult ret = LLCD_OK;
+ if (LLConvexDecomposition::getInstance() != NULL)
+ {
+ ret = LLConvexDecomposition::getInstance()->setMeshData(&mesh);
+ }
+
+ if (ret)
+ {
+ llerrs << "Convex Decomposition thread valid but could not set mesh data" << llendl;
+ }
+}
+
+void LLPhysicsDecomp::doDecomposition()
+{
+ LLCDMeshData mesh;
+ S32 stage = mStageID[mCurRequest->mStage];
+
+ //load data intoLLCD
+ if (stage == 0)
+ {
+ setMeshData(mesh);
+ }
+
+ //build parameter map
+ std::map<std::string, const LLCDParam*> param_map;
+
+ static const LLCDParam* params = NULL;
+ static S32 param_count = 0;
+ if (!params)
+ {
+ param_count = LLConvexDecomposition::getInstance()->getParameters(&params);
+ }
+
+ for (S32 i = 0; i < param_count; ++i)
+ {
+ param_map[params[i].mName] = params+i;
+ }
+
+ //set parameter values
+ for (decomp_params::iterator iter = mCurRequest->mParams.begin(); iter != mCurRequest->mParams.end(); ++iter)
+ {
+ const std::string& name = iter->first;
+ const LLSD& value = iter->second;
+
+ const LLCDParam* param = param_map[name];
+
+ if (param == NULL)
+ { //couldn't find valid parameter
+ continue;
+ }
+
+ U32 ret = LLCD_OK;
+
+ if (param->mType == LLCDParam::LLCD_FLOAT)
+ {
+ ret = LLConvexDecomposition::getInstance()->setParam(param->mName, (F32) value.asReal());
+ }
+ else if (param->mType == LLCDParam::LLCD_INTEGER ||
+ param->mType == LLCDParam::LLCD_ENUM)
+ {
+ ret = LLConvexDecomposition::getInstance()->setParam(param->mName, value.asInteger());
+ }
+ else if (param->mType == LLCDParam::LLCD_BOOLEAN)
+ {
+ ret = LLConvexDecomposition::getInstance()->setParam(param->mName, value.asBoolean());
+ }
+
+ if (ret)
+ {
+ llerrs << "WTF?" << llendl;
+ }
+ }
+
+ mCurRequest->setStatusMessage("Executing.");
+
+ LLCDResult ret = LLCD_OK;
+
+ if (LLConvexDecomposition::getInstance() != NULL)
+ {
+ ret = LLConvexDecomposition::getInstance()->executeStage(stage);
+ }
+
+ if (ret)
+ {
+ llwarns << "Convex Decomposition thread valid but could not execute stage " << stage << llendl;
+ LLMutexLock lock(mMutex);
+
+ mCurRequest->mHull.clear();
+ mCurRequest->mHullMesh.clear();
+
+ mCurRequest->setStatusMessage("FAIL");
+
+ completeCurrent();
+ }
+ else
+ {
+ mCurRequest->setStatusMessage("Reading results");
+
+ S32 num_hulls =0;
+ if (LLConvexDecomposition::getInstance() != NULL)
+ {
+ num_hulls = LLConvexDecomposition::getInstance()->getNumHullsFromStage(stage);
+ }
+
+ mMutex->lock();
+ mCurRequest->mHull.clear();
+ mCurRequest->mHull.resize(num_hulls);
+
+ mCurRequest->mHullMesh.clear();
+ mCurRequest->mHullMesh.resize(num_hulls);
+ mMutex->unlock();
+
+ for (S32 i = 0; i < num_hulls; ++i)
+ {
+ std::vector<LLVector3> p;
+ LLCDHull hull;
+ // if LLConvexDecomposition is a stub, num_hulls should have been set to 0 above, and we should not reach this code
+ LLConvexDecomposition::getInstance()->getHullFromStage(stage, i, &hull);
+
+ const F32* v = hull.mVertexBase;
+
+ for (S32 j = 0; j < hull.mNumVertices; ++j)
+ {
+ LLVector3 vert(v[0], v[1], v[2]);
+ p.push_back(vert);
+ v = (F32*) (((U8*) v) + hull.mVertexStrideBytes);
+ }
+
+ LLCDMeshData mesh;
+ // if LLConvexDecomposition is a stub, num_hulls should have been set to 0 above, and we should not reach this code
+ LLConvexDecomposition::getInstance()->getMeshFromStage(stage, i, &mesh);
+
+ get_vertex_buffer_from_mesh(mesh, mCurRequest->mHullMesh[i]);
+
+ mMutex->lock();
+ mCurRequest->mHull[i] = p;
+ mMutex->unlock();
+ }
+
+ {
+ LLMutexLock lock(mMutex);
+
+ mCurRequest->setStatusMessage("FAIL");
+ completeCurrent();
+ }
+ }
+}
+
+void LLPhysicsDecomp::completeCurrent()
+{
+ LLMutexLock lock(mMutex);
+ mCompletedQ.push(mCurRequest);
+ mCurRequest = NULL;
+}
+
+void LLPhysicsDecomp::notifyCompleted()
+{
+ if (!mCompletedQ.empty())
+ {
+ LLMutexLock lock(mMutex);
+ while (!mCompletedQ.empty())
+ {
+ Request* req = mCompletedQ.front();
+ req->completed();
+ mCompletedQ.pop();
+ }
+ }
+}
+
+
+void make_box(LLPhysicsDecomp::Request * request)
+{
+ LLVector3 min,max;
+ min = request->mPositions[0];
+ max = min;
+
+ for (U32 i = 0; i < request->mPositions.size(); ++i)
+ {
+ update_min_max(min, max, request->mPositions[i]);
+ }
+
+ request->mHull.clear();
+
+ LLModel::hull box;
+ box.push_back(LLVector3(min[0],min[1],min[2]));
+ box.push_back(LLVector3(max[0],min[1],min[2]));
+ box.push_back(LLVector3(min[0],max[1],min[2]));
+ box.push_back(LLVector3(max[0],max[1],min[2]));
+ box.push_back(LLVector3(min[0],min[1],max[2]));
+ box.push_back(LLVector3(max[0],min[1],max[2]));
+ box.push_back(LLVector3(min[0],max[1],max[2]));
+ box.push_back(LLVector3(max[0],max[1],max[2]));
+
+ request->mHull.push_back(box);
+}
+
+
+void LLPhysicsDecomp::doDecompositionSingleHull()
+{
+ LLCDMeshData mesh;
+
+ setMeshData(mesh);
+
+
+ //set all parameters to default
+ std::map<std::string, const LLCDParam*> param_map;
+
+ static const LLCDParam* params = NULL;
+ static S32 param_count = 0;
+
+ if (!params)
+ {
+ param_count = LLConvexDecomposition::getInstance()->getParameters(&params);
+ }
+
+ LLConvexDecomposition* decomp = LLConvexDecomposition::getInstance();
+
+ for (S32 i = 0; i < param_count; ++i)
+ {
+ decomp->setParam(params[i].mName, params[i].mDefault.mIntOrEnumValue);
+ }
+
+ const S32 STAGE_DECOMPOSE = mStageID["Decompose"];
+ const S32 STAGE_SIMPLIFY = mStageID["Simplify"];
+ const S32 DECOMP_PREVIEW = 0;
+ const S32 SIMPLIFY_RETAIN = 0;
+
+ decomp->setParam("Decompose Quality", DECOMP_PREVIEW);
+ decomp->setParam("Simplify Method", SIMPLIFY_RETAIN);
+ decomp->setParam("Retain%", 0.f);
+
+ LLCDResult ret = LLCD_OK;
+ ret = decomp->executeStage(STAGE_DECOMPOSE);
+
+ if (ret)
+ {
+ llwarns << "Could not execute decomposition stage when attempting to create single hull." << llendl;
+ make_box(mCurRequest);
+ }
+ else
+ {
+ ret = decomp->executeStage(STAGE_SIMPLIFY);
+
+ if (ret)
+ {
+ llwarns << "Could not execute simiplification stage when attempting to create single hull." << llendl;
+ make_box(mCurRequest);
+ }
+ else
+ {
+ S32 num_hulls =0;
+ if (LLConvexDecomposition::getInstance() != NULL)
+ {
+ num_hulls = LLConvexDecomposition::getInstance()->getNumHullsFromStage(STAGE_SIMPLIFY);
+ }
+
+ mMutex->lock();
+ mCurRequest->mHull.clear();
+ mCurRequest->mHull.resize(num_hulls);
+ mCurRequest->mHullMesh.clear();
+ mMutex->unlock();
+
+ for (S32 i = 0; i < num_hulls; ++i)
+ {
+ std::vector<LLVector3> p;
+ LLCDHull hull;
+ // if LLConvexDecomposition is a stub, num_hulls should have been set to 0 above, and we should not reach this code
+ LLConvexDecomposition::getInstance()->getHullFromStage(STAGE_SIMPLIFY, i, &hull);
+
+ const F32* v = hull.mVertexBase;
+
+ for (S32 j = 0; j < hull.mNumVertices; ++j)
+ {
+ LLVector3 vert(v[0], v[1], v[2]);
+ p.push_back(vert);
+ v = (F32*) (((U8*) v) + hull.mVertexStrideBytes);
+ }
+
+ mMutex->lock();
+ mCurRequest->mHull[i] = p;
+ mMutex->unlock();
+ }
+ }
+ }
+
+
+ {
+ completeCurrent();
+
+ }
+}
+
+
+void LLPhysicsDecomp::run()
+{
+ LLConvexDecomposition* decomp = LLConvexDecomposition::getInstance();
+ decomp->initThread();
+ mInited = true;
+
+ static const LLCDStageData* stages = NULL;
+ static S32 num_stages = 0;
+
+ if (!stages)
+ {
+ num_stages = decomp->getStages(&stages);
+ }
+
+ for (S32 i = 0; i < num_stages; i++)
+ {
+ mStageID[stages[i].mName] = i;
+ }
+
+ while (!mQuitting)
+ {
+ mSignal->wait();
+ while (!mQuitting && !mRequestQ.empty())
+ {
+ {
+ LLMutexLock lock(mMutex);
+ mCurRequest = mRequestQ.front();
+ mRequestQ.pop();
+ }
+
+ S32& id = *(mCurRequest->mDecompID);
+ if (id == -1)
+ {
+ decomp->genDecomposition(id);
+ }
+ decomp->bindDecomposition(id);
+
+ if (mCurRequest->mStage == "single_hull")
+ {
+ doDecompositionSingleHull();
+ }
+ else
+ {
+ doDecomposition();
+ }
+ }
+ }
+
+ decomp->quitThread();
+
+ if (mSignal->isLocked())
+ { //let go of mSignal's associated mutex
+ mSignal->unlock();
+ }
+
+ mDone = true;
+}
+
+void LLPhysicsDecomp::Request::setStatusMessage(const std::string& msg)
+{
+ mStatusMessage = msg;
+}
+
+LLModelInstance::LLModelInstance(LLSD& data)
+{
+ mLocalMeshID = data["mesh_id"].asInteger();
+ mLabel = data["label"].asString();
+ mTransform.setValue(data["transform"]);
+
+ for (U32 i = 0; i < data["material"].size(); ++i)
+ {
+ mMaterial.push_back(LLImportMaterial(data["material"][i]));
+ }
+}
+
+
+LLSD LLModelInstance::asLLSD()
+{
+ LLSD ret;
+
+ ret["mesh_id"] = mModel->mLocalID;
+ ret["label"] = mLabel;
+ ret["transform"] = mTransform.getValue();
+
+ for (U32 i = 0; i < mMaterial.size(); ++i)
+ {
+ ret["material"][i] = mMaterial[i].asLLSD();
+ }
+
+ return ret;
+}
+
+LLImportMaterial::LLImportMaterial(LLSD& data)
+{
+ mDiffuseMapFilename = data["diffuse"]["filename"].asString();
+ mDiffuseMapLabel = data["diffuse"]["label"].asString();
+ mDiffuseColor.setValue(data["diffuse"]["color"]);
+ mFullbright = data["fullbright"].asBoolean();
+}
+
+
+LLSD LLImportMaterial::asLLSD()
+{
+ LLSD ret;
+
+ ret["diffuse"]["filename"] = mDiffuseMapFilename;
+ ret["diffuse"]["label"] = mDiffuseMapLabel;
+ ret["diffuse"]["color"] = mDiffuseColor.getValue();
+ ret["fullbright"] = mFullbright;
+
+ return ret;
+}
+
+void LLMeshRepository::buildPhysicsMesh(LLModel::Decomposition& decomp)
+{
+ decomp.mMesh.resize(decomp.mHull.size());
+
+ for (U32 i = 0; i < decomp.mHull.size(); ++i)
+ {
+ LLCDHull hull;
+ hull.mNumVertices = decomp.mHull[i].size();
+ hull.mVertexBase = decomp.mHull[i][0].mV;
+ hull.mVertexStrideBytes = 12;
+
+ LLCDMeshData mesh;
+ LLCDResult res = LLCD_OK;
+ if (LLConvexDecomposition::getInstance() != NULL)
+ {
+ res = LLConvexDecomposition::getInstance()->getMeshFromHull(&hull, &mesh);
+ }
+ if (res == LLCD_OK)
+ {
+ get_vertex_buffer_from_mesh(mesh, decomp.mMesh[i]);
+ }
+ }
+
+ if (!decomp.mBaseHull.empty() && decomp.mBaseHullMesh.empty())
+ { //get mesh for base hull
+ LLCDHull hull;
+ hull.mNumVertices = decomp.mBaseHull.size();
+ hull.mVertexBase = decomp.mBaseHull[0].mV;
+ hull.mVertexStrideBytes = 12;
+
+ LLCDMeshData mesh;
+ LLCDResult res = LLCD_OK;
+ if (LLConvexDecomposition::getInstance() != NULL)
+ {
+ res = LLConvexDecomposition::getInstance()->getMeshFromHull(&hull, &mesh);
+ }
+ if (res == LLCD_OK)
+ {
+ get_vertex_buffer_from_mesh(mesh, decomp.mBaseHullMesh);
+ }
+ }
+}
diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h
new file mode 100644
index 0000000000..802e3e1aba
--- /dev/null
+++ b/indra/newview/llmeshrepository.h
@@ -0,0 +1,551 @@
+/**
+ * @file llmeshrepository.h
+ * @brief Client-side repository of mesh assets.
+ *
+ * $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_MESH_REPOSITORY_H
+#define LL_MESH_REPOSITORY_H
+
+#include "llassettype.h"
+#include "llmodel.h"
+#include "lluuid.h"
+#include "llviewertexture.h"
+#include "llvolume.h"
+
+#define LLCONVEXDECOMPINTER_STATIC 1
+
+#include "llconvexdecomposition.h"
+
+class LLVOVolume;
+class LLMeshResponder;
+class LLCurlRequest;
+class LLMutex;
+class LLCondition;
+class LLVFS;
+class LLMeshRepository;
+
+class LLMeshUploadData
+{
+public:
+ LLPointer<LLModel> mBaseModel;
+ LLPointer<LLModel> mModel[5];
+ LLUUID mUUID;
+ U32 mRetries;
+ std::string mRSVP;
+ std::string mAssetData;
+ LLSD mPostData;
+
+ LLMeshUploadData()
+ {
+ mRetries = 0;
+ }
+};
+
+class LLTextureUploadData
+{
+public:
+ LLViewerFetchedTexture* mTexture;
+ LLUUID mUUID;
+ std::string mRSVP;
+ std::string mLabel;
+ U32 mRetries;
+ std::string mAssetData;
+ LLSD mPostData;
+
+ LLTextureUploadData()
+ {
+ mRetries = 0;
+ }
+
+ LLTextureUploadData(LLViewerFetchedTexture* texture, std::string& label)
+ : mTexture(texture), mLabel(label)
+ {
+ mRetries = 0;
+ }
+};
+
+class LLImportMaterial
+{
+public:
+ LLPointer<LLViewerFetchedTexture> mDiffuseMap;
+ std::string mDiffuseMapFilename;
+ std::string mDiffuseMapLabel;
+ LLColor4 mDiffuseColor;
+ bool mFullbright;
+
+ bool operator<(const LLImportMaterial &params) const;
+
+ LLImportMaterial()
+ : mFullbright(false)
+ {
+ mDiffuseColor.set(1,1,1,1);
+ }
+
+ LLImportMaterial(LLSD& data);
+
+ LLSD asLLSD();
+};
+
+class LLModelInstance
+{
+public:
+ LLPointer<LLModel> mModel;
+ LLPointer<LLModel> mLOD[5];
+
+ std::string mLabel;
+
+ LLUUID mMeshID;
+ S32 mLocalMeshID;
+
+ LLMatrix4 mTransform;
+ std::vector<LLImportMaterial> mMaterial;
+
+ LLModelInstance(LLModel* model, const std::string& label, LLMatrix4& transform, std::vector<LLImportMaterial>& materials)
+ : mModel(model), mLabel(label), mTransform(transform), mMaterial(materials)
+ {
+ mLocalMeshID = -1;
+ }
+
+ LLModelInstance(LLSD& data);
+
+ LLSD asLLSD();
+};
+
+class LLPhysicsDecomp : public LLThread
+{
+public:
+
+ typedef std::map<std::string, LLSD> decomp_params;
+
+ class Request : public LLRefCount
+ {
+ public:
+ //input params
+ S32* mDecompID;
+ std::string mStage;
+ std::vector<LLVector3> mPositions;
+ std::vector<U16> mIndices;
+ decomp_params mParams;
+
+ //output state
+ std::string mStatusMessage;
+ std::vector<LLModel::PhysicsMesh> mHullMesh;
+ LLModel::convex_hull_decomposition mHull;
+
+ //status message callback, called from decomposition thread
+ virtual S32 statusCallback(const char* status, S32 p1, S32 p2) = 0;
+
+ //completed callback, called from the main thread
+ virtual void completed() = 0;
+
+ virtual void setStatusMessage(const std::string& msg);
+ };
+
+ LLCondition* mSignal;
+ LLMutex* mMutex;
+
+ bool mInited;
+ bool mQuitting;
+ bool mDone;
+
+ LLPhysicsDecomp();
+ ~LLPhysicsDecomp();
+
+ void shutdown();
+
+ void submitRequest(Request* request);
+ static S32 llcdCallback(const char*, S32, S32);
+ void cancel();
+
+ void setMeshData(LLCDMeshData& mesh);
+ void doDecomposition();
+ void doDecompositionSingleHull();
+
+ virtual void run();
+
+ void completeCurrent();
+ void notifyCompleted();
+
+ std::map<std::string, S32> mStageID;
+
+ typedef std::queue<LLPointer<Request> > request_queue;
+ request_queue mRequestQ;
+
+ LLPointer<Request> mCurRequest;
+
+ std::queue<LLPointer<Request> > mCompletedQ;
+
+};
+
+class LLMeshRepoThread : public LLThread
+{
+public:
+
+ static S32 sActiveHeaderRequests;
+ static S32 sActiveLODRequests;
+ static U32 sMaxConcurrentRequests;
+
+ LLCurlRequest* mCurlRequest;
+ LLMutex* mMutex;
+ LLMutex* mHeaderMutex;
+ LLCondition* mSignal;
+
+ bool mWaiting;
+
+ //map of known mesh headers
+ typedef std::map<LLUUID, LLSD> mesh_header_map;
+ mesh_header_map mMeshHeader;
+
+ std::map<LLUUID, U32> mMeshHeaderSize;
+ std::map<LLUUID, U32> mMeshResourceCost;
+
+ class HeaderRequest
+ {
+ public:
+ const LLVolumeParams mMeshParams;
+
+ HeaderRequest(const LLVolumeParams& mesh_params)
+ : mMeshParams(mesh_params)
+ {
+ }
+
+ bool operator<(const HeaderRequest& rhs) const
+ {
+ return mMeshParams < rhs.mMeshParams;
+ }
+ };
+
+ class LODRequest
+ {
+ public:
+ LLVolumeParams mMeshParams;
+ S32 mLOD;
+ F32 mScore;
+
+ LODRequest(const LLVolumeParams& mesh_params, S32 lod)
+ : mMeshParams(mesh_params), mLOD(lod), mScore(0.f)
+ {
+ }
+ };
+
+ struct CompareScoreGreater
+ {
+ bool operator()(const LODRequest& lhs, const LODRequest& rhs)
+ {
+ return lhs.mScore > rhs.mScore; // greatest = first
+ }
+ };
+
+
+ class LoadedMesh
+ {
+ public:
+ LLPointer<LLVolume> mVolume;
+ LLVolumeParams mMeshParams;
+ S32 mLOD;
+
+ LoadedMesh(LLVolume* volume, const LLVolumeParams& mesh_params, S32 lod)
+ : mVolume(volume), mMeshParams(mesh_params), mLOD(lod)
+ {
+ }
+
+ };
+
+ //set of requested skin info
+ std::set<LLUUID> mSkinRequests;
+
+ //queue of completed skin info requests
+ std::queue<LLMeshSkinInfo> mSkinInfoQ;
+
+ //set of requested decompositions
+ std::set<LLUUID> mDecompositionRequests;
+
+ //set of requested physics shapes
+ std::set<LLUUID> mPhysicsShapeRequests;
+
+ //queue of completed Decomposition info requests
+ std::queue<LLModel::Decomposition*> mDecompositionQ;
+
+ //queue of requested headers
+ std::queue<HeaderRequest> mHeaderReqQ;
+
+ //queue of requested LODs
+ std::queue<LODRequest> mLODReqQ;
+
+ //queue of unavailable LODs (either asset doesn't exist or asset doesn't have desired LOD)
+ std::queue<LODRequest> mUnavailableQ;
+
+ //queue of successfully loaded meshes
+ std::queue<LoadedMesh> mLoadedQ;
+
+ //map of pending header requests and currently desired LODs
+ typedef std::map<LLVolumeParams, std::vector<S32> > pending_lod_map;
+ pending_lod_map mPendingLOD;
+
+ static std::string constructUrl(LLUUID mesh_id);
+
+ LLMeshRepoThread();
+ ~LLMeshRepoThread();
+
+ virtual void run();
+
+ void loadMeshLOD(const LLVolumeParams& mesh_params, S32 lod);
+ bool fetchMeshHeader(const LLVolumeParams& mesh_params);
+ bool fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod);
+ bool headerReceived(const LLVolumeParams& mesh_params, U8* data, S32 data_size);
+ bool lodReceived(const LLVolumeParams& mesh_params, S32 lod, U8* data, S32 data_size);
+ bool skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 data_size);
+ bool decompositionReceived(const LLUUID& mesh_id, U8* data, S32 data_size);
+ bool physicsShapeReceived(const LLUUID& mesh_id, U8* data, S32 data_size);
+ LLSD& getMeshHeader(const LLUUID& mesh_id);
+
+ void notifyLoadedMeshes();
+ S32 getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lod);
+ U32 getResourceCost(const LLUUID& mesh_params);
+
+ void loadMeshSkinInfo(const LLUUID& mesh_id);
+ void loadMeshDecomposition(const LLUUID& mesh_id);
+ void loadMeshPhysicsShape(const LLUUID& mesh_id);
+
+ //send request for skin info, returns true if header info exists
+ // (should hold onto mesh_id and try again later if header info does not exist)
+ bool fetchMeshSkinInfo(const LLUUID& mesh_id);
+
+ //send request for decomposition, returns true if header info exists
+ // (should hold onto mesh_id and try again later if header info does not exist)
+ bool fetchMeshDecomposition(const LLUUID& mesh_id);
+
+ //send request for PhysicsShape, returns true if header info exists
+ // (should hold onto mesh_id and try again later if header info does not exist)
+ bool fetchMeshPhysicsShape(const LLUUID& mesh_id);
+
+
+};
+
+class LLMeshUploadThread : public LLThread
+{
+public:
+ class DecompRequest : public LLPhysicsDecomp::Request
+ {
+ public:
+ LLPointer<LLModel> mModel;
+ LLPointer<LLModel> mBaseModel;
+
+ LLMeshUploadThread* mThread;
+
+ DecompRequest(LLModel* mdl, LLModel* base_model, LLMeshUploadThread* thread);
+
+ S32 statusCallback(const char* status, S32 p1, S32 p2) { return 1; }
+ void completed();
+ };
+
+ LLPointer<DecompRequest> mFinalDecomp;
+ bool mPhysicsComplete;
+
+ typedef std::map<LLPointer<LLModel>, std::vector<LLVector3> > hull_map;
+ hull_map mHullMap;
+
+ typedef std::vector<LLModelInstance> instance_list;
+ instance_list mInstanceList;
+
+ typedef std::map<LLPointer<LLModel>, instance_list> instance_map;
+ instance_map mInstance;
+
+ LLMutex* mMutex;
+ LLCurlRequest* mCurlRequest;
+ S32 mPendingConfirmations;
+ S32 mPendingUploads;
+ S32 mPendingCost;
+ LLVector3 mOrigin;
+ bool mFinished;
+ bool mUploadTextures;
+ bool mUploadSkin;
+ bool mUploadJoints;
+ BOOL mDiscarded ;
+
+ LLHost mHost;
+ std::string mUploadObjectAssetCapability;
+ std::string mNewInventoryCapability;
+ std::string mWholeModelUploadCapability;
+
+ std::queue<LLMeshUploadData> mUploadQ;
+ std::queue<LLMeshUploadData> mConfirmedQ;
+ std::queue<LLModelInstance> mInstanceQ;
+
+ std::queue<LLTextureUploadData> mTextureQ;
+ std::queue<LLTextureUploadData> mConfirmedTextureQ;
+
+ std::map<LLViewerFetchedTexture*, LLTextureUploadData> mTextureMap;
+
+ LLMeshUploadThread(instance_list& data, LLVector3& scale, bool upload_textures,
+ bool upload_skin, bool upload_joints);
+ ~LLMeshUploadThread();
+
+ void uploadTexture(LLTextureUploadData& data);
+ void doUploadTexture(LLTextureUploadData& data);
+ void sendCostRequest(LLTextureUploadData& data);
+ void priceResult(LLTextureUploadData& data, const LLSD& content);
+ void onTextureUploaded(LLTextureUploadData& data);
+
+ void uploadModel(LLMeshUploadData& data);
+ void sendCostRequest(LLMeshUploadData& data);
+ void doUploadModel(LLMeshUploadData& data);
+ void onModelUploaded(LLMeshUploadData& data);
+ void createObjects(LLMeshUploadData& data);
+ LLSD createObject(LLModelInstance& instance);
+ void priceResult(LLMeshUploadData& data, const LLSD& content);
+
+ bool finished() { return mFinished; }
+ virtual void run();
+ void preStart();
+ void discard() ;
+ BOOL isDiscarded();
+
+ void doWholeModelUpload();
+ void doIterativeUpload();
+
+ void wholeModelToLLSD(LLSD& dest, bool include_textures);
+
+ void decomposeMeshMatrix(LLMatrix4& transformation,
+ LLVector3& result_pos,
+ LLQuaternion& result_rot,
+ LLVector3& result_scale);
+};
+
+class LLMeshRepository
+{
+public:
+
+ //metrics
+ static U32 sBytesReceived;
+ static U32 sHTTPRequestCount;
+ static U32 sHTTPRetryCount;
+ static U32 sCacheBytesRead;
+ static U32 sCacheBytesWritten;
+ static U32 sPeakKbps;
+
+ static F32 getStreamingCost(LLSD& header, F32 radius, S32* bytes = NULL, S32* visible_bytes = NULL, S32 detail = -1);
+
+ LLMeshRepository();
+
+ void init();
+ void shutdown();
+ S32 update() ;
+
+ //mesh management functions
+ S32 loadMesh(LLVOVolume* volume, const LLVolumeParams& mesh_params, S32 detail = 0, S32 last_lod = -1);
+
+ void notifyLoadedMeshes();
+ void notifyMeshLoaded(const LLVolumeParams& mesh_params, LLVolume* volume);
+ void notifyMeshUnavailable(const LLVolumeParams& mesh_params, S32 lod);
+ void notifySkinInfoReceived(LLMeshSkinInfo& info);
+ void notifyDecompositionReceived(LLModel::Decomposition* info);
+
+ S32 getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lod);
+ static S32 getActualMeshLOD(LLSD& header, S32 lod);
+ U32 calcResourceCost(LLSD& header);
+ U32 getResourceCost(const LLUUID& mesh_params);
+ const LLMeshSkinInfo* getSkinInfo(const LLUUID& mesh_id);
+ LLModel::Decomposition* getDecomposition(const LLUUID& mesh_id);
+ void fetchPhysicsShape(const LLUUID& mesh_id);
+ bool hasPhysicsShape(const LLUUID& mesh_id);
+
+ void buildHull(const LLVolumeParams& params, S32 detail);
+ void buildPhysicsMesh(LLModel::Decomposition& decomp);
+
+ LLSD& getMeshHeader(const LLUUID& mesh_id);
+
+ void uploadModel(std::vector<LLModelInstance>& data, LLVector3& scale, bool upload_textures,
+ bool upload_skin, bool upload_joints);
+
+ S32 getMeshSize(const LLUUID& mesh_id, S32 lod);
+
+ typedef std::map<LLVolumeParams, std::set<LLUUID> > mesh_load_map;
+ mesh_load_map mLoadingMeshes[4];
+
+ typedef std::map<LLUUID, LLMeshSkinInfo> skin_map;
+ skin_map mSkinMap;
+
+ typedef std::map<LLUUID, LLModel::Decomposition*> decomposition_map;
+ decomposition_map mDecompositionMap;
+
+ LLMutex* mMeshMutex;
+
+ std::vector<LLMeshRepoThread::LODRequest> mPendingRequests;
+
+ //list of mesh ids awaiting skin info
+ std::set<LLUUID> mLoadingSkins;
+
+ //list of mesh ids that need to send skin info fetch requests
+ std::queue<LLUUID> mPendingSkinRequests;
+
+ //list of mesh ids awaiting decompositions
+ std::set<LLUUID> mLoadingDecompositions;
+
+ //list of mesh ids that need to send decomposition fetch requests
+ std::queue<LLUUID> mPendingDecompositionRequests;
+
+ //list of mesh ids awaiting physics shapes
+ std::set<LLUUID> mLoadingPhysicsShapes;
+
+ //list of mesh ids that need to send physics shape fetch requests
+ std::queue<LLUUID> mPendingPhysicsShapeRequests;
+
+ U32 mMeshThreadCount;
+
+ void cacheOutgoingMesh(LLMeshUploadData& data, LLSD& header);
+
+ LLMeshRepoThread* mThread;
+ std::vector<LLMeshUploadThread*> mUploads;
+ std::vector<LLMeshUploadThread*> mUploadWaitList;
+
+ LLPhysicsDecomp* mDecompThread;
+
+ class inventory_data
+ {
+ public:
+ LLSD mPostData;
+ LLSD mResponse;
+
+ inventory_data(const LLSD& data, const LLSD& content)
+ : mPostData(data), mResponse(content)
+ {
+ }
+ };
+
+ std::queue<inventory_data> mInventoryQ;
+
+ std::queue<LLSD> mUploadErrorQ;
+
+ void uploadError(LLSD& args);
+ void updateInventory(inventory_data data);
+
+ std::string mGetMeshCapability;
+
+};
+
+extern LLMeshRepository gMeshRepo;
+
+#endif
+
diff --git a/indra/newview/llmetricperformancetester.cpp b/indra/newview/llmetricperformancetester.cpp
deleted file mode 100644
index 903c97378e..0000000000
--- a/indra/newview/llmetricperformancetester.cpp
+++ /dev/null
@@ -1,252 +0,0 @@
-/**
- * @file llmetricperformancetester.cpp
- * @brief LLMetricPerformanceTester 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 "indra_constants.h"
-#include "llerror.h"
-#include "llmath.h"
-#include "llfontgl.h"
-#include "llsdserialize.h"
-#include "llstat.h"
-#include "lltreeiterators.h"
-#include "llmetricperformancetester.h"
-
-LLMetricPerformanceTester::name_tester_map_t LLMetricPerformanceTester::sTesterMap ;
-
-//static
-void LLMetricPerformanceTester::initClass()
-{
-}
-//static
-void LLMetricPerformanceTester::cleanClass()
-{
- for(name_tester_map_t::iterator iter = sTesterMap.begin() ; iter != sTesterMap.end() ; ++iter)
- {
- delete iter->second ;
- }
- sTesterMap.clear() ;
-}
-
-//static
-void LLMetricPerformanceTester::addTester(LLMetricPerformanceTester* tester)
-{
- if(!tester)
- {
- llerrs << "invalid tester!" << llendl ;
- return ;
- }
-
- std::string name = tester->getName() ;
- if(getTester(name))
- {
- llerrs << "Tester name is used by some other tester: " << name << llendl ;
- return ;
- }
-
- sTesterMap.insert(std::make_pair(name, tester));
-
- return ;
-}
-
-//static
-LLMetricPerformanceTester* LLMetricPerformanceTester::getTester(std::string label)
-{
- name_tester_map_t::iterator found_it = sTesterMap.find(label) ;
- if(found_it != sTesterMap.end())
- {
- return found_it->second ;
- }
-
- return NULL ;
-}
-
-LLMetricPerformanceTester::LLMetricPerformanceTester(std::string name, BOOL use_default_performance_analysis)
- : mName(name),
- mBaseSessionp(NULL),
- mCurrentSessionp(NULL),
- mCount(0),
- mUseDefaultPerformanceAnalysis(use_default_performance_analysis)
-{
- if(mName == std::string())
- {
- llerrs << "invalid name." << llendl ;
- }
-
- LLMetricPerformanceTester::addTester(this) ;
-}
-
-/*virtual*/
-LLMetricPerformanceTester::~LLMetricPerformanceTester()
-{
- if(mBaseSessionp)
- {
- delete mBaseSessionp ;
- mBaseSessionp = NULL ;
- }
- if(mCurrentSessionp)
- {
- delete mCurrentSessionp ;
- mCurrentSessionp = NULL ;
- }
-}
-
-void LLMetricPerformanceTester::incLabel()
-{
- mCurLabel = llformat("%s-%d", mName.c_str(), mCount++) ;
-}
-void LLMetricPerformanceTester::preOutputTestResults(LLSD* sd)
-{
- incLabel() ;
- (*sd)[mCurLabel]["Name"] = mName ;
-}
-void LLMetricPerformanceTester::postOutputTestResults(LLSD* sd)
-{
- LLMutexLock lock(LLFastTimer::sLogLock);
- LLFastTimer::sLogQueue.push((*sd));
-}
-
-void LLMetricPerformanceTester::outputTestResults()
-{
- LLSD sd ;
- preOutputTestResults(&sd) ;
-
- outputTestRecord(&sd) ;
-
- postOutputTestResults(&sd) ;
-}
-
-void LLMetricPerformanceTester::addMetricString(std::string str)
-{
- mMetricStrings.push_back(str) ;
-}
-
-const std::string& LLMetricPerformanceTester::getMetricString(U32 index) const
-{
- return mMetricStrings[index] ;
-}
-
-void LLMetricPerformanceTester::prePerformanceAnalysis()
-{
- mCount = 0 ;
- incLabel() ;
-}
-
-//
-//default analyzing the performance
-//
-/*virtual*/
-void LLMetricPerformanceTester::analyzePerformance(std::ofstream* os, LLSD* base, LLSD* current)
-{
- if(mUseDefaultPerformanceAnalysis)//use default performance analysis
- {
- prePerformanceAnalysis() ;
-
- BOOL in_base = (*base).has(mCurLabel) ;
- BOOL in_current = (*current).has(mCurLabel) ;
-
- while(in_base || in_current)
- {
- LLSD::String label = mCurLabel ;
-
- if(in_base && in_current)
- {
- *os << llformat("%s\n", label.c_str()) ;
-
- for(U32 index = 0 ; index < mMetricStrings.size() ; index++)
- {
- switch((*current)[label][ mMetricStrings[index] ].type())
- {
- case LLSD::TypeInteger:
- compareTestResults(os, mMetricStrings[index],
- (S32)((*base)[label][ mMetricStrings[index] ].asInteger()), (S32)((*current)[label][ mMetricStrings[index] ].asInteger())) ;
- break ;
- case LLSD::TypeReal:
- compareTestResults(os, mMetricStrings[index],
- (F32)((*base)[label][ mMetricStrings[index] ].asReal()), (F32)((*current)[label][ mMetricStrings[index] ].asReal())) ;
- break;
- default:
- llerrs << "unsupported metric " << mMetricStrings[index] << " LLSD type: " << (S32)(*current)[label][ mMetricStrings[index] ].type() << llendl ;
- }
- }
- }
-
- incLabel() ;
- in_base = (*base).has(mCurLabel) ;
- in_current = (*current).has(mCurLabel) ;
- }
- }//end of default
- else
- {
- //load the base session
- prePerformanceAnalysis() ;
- mBaseSessionp = loadTestSession(base) ;
-
- //load the current session
- prePerformanceAnalysis() ;
- mCurrentSessionp = loadTestSession(current) ;
-
- if(!mBaseSessionp || !mCurrentSessionp)
- {
- llerrs << "memory error during loading test sessions." << llendl ;
- }
-
- //compare
- compareTestSessions(os) ;
-
- //release memory
- if(mBaseSessionp)
- {
- delete mBaseSessionp ;
- mBaseSessionp = NULL ;
- }
- if(mCurrentSessionp)
- {
- delete mCurrentSessionp ;
- mCurrentSessionp = NULL ;
- }
- }
-}
-
-//virtual
-void LLMetricPerformanceTester::compareTestResults(std::ofstream* os, std::string metric_string, S32 v_base, S32 v_current)
-{
- *os << llformat(" ,%s, %d, %d, %d, %.4f\n", metric_string.c_str(), v_base, v_current,
- v_current - v_base, (v_base != 0) ? 100.f * v_current / v_base : 0) ;
-}
-
-//virtual
-void LLMetricPerformanceTester::compareTestResults(std::ofstream* os, std::string metric_string, F32 v_base, F32 v_current)
-{
- *os << llformat(" ,%s, %.4f, %.4f, %.4f, %.4f\n", metric_string.c_str(), v_base, v_current,
- v_current - v_base, (fabs(v_base) > 0.0001f) ? 100.f * v_current / v_base : 0.f ) ;
-}
-
-//virtual
-LLMetricPerformanceTester::LLTestSession::~LLTestSession()
-{
-}
-
diff --git a/indra/newview/llmetricperformancetester.h b/indra/newview/llmetricperformancetester.h
deleted file mode 100644
index 6f5dc03564..0000000000
--- a/indra/newview/llmetricperformancetester.h
+++ /dev/null
@@ -1,153 +0,0 @@
-/**
- * @file LLMetricPerformanceTester.h
- * @brief LLMetricPerformanceTester class definition
- *
- * $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_METRICPERFORMANCETESTER_H
-#define LL_METRICPERFORMANCETESTER_H
-
-class LLMetricPerformanceTester
-{
-public:
- //
- //name passed to the constructor is a unique string for each tester.
- //an error is reported if the name is already used by some other tester.
- //
- LLMetricPerformanceTester(std::string name, BOOL use_default_performance_analysis) ;
- virtual ~LLMetricPerformanceTester();
-
- //
- //return the name of the tester
- //
- std::string getName() const { return mName ;}
- //
- //return the number of the test metrics in this tester
- //
- S32 getNumOfMetricStrings() const { return mMetricStrings.size() ;}
- //
- //return the metric string at the index
- //
- const std::string& getMetricString(U32 index) const ;
-
- //
- //this function to compare the test results.
- //by default, it compares the test results against the baseline one by one, item by item,
- //in the increasing order of the LLSD label counter, starting from the first one.
- //you can define your own way to analyze performance by passing FALSE to "use_default_performance_analysis",
- //and implement two abstract virtual functions below: loadTestSession(...) and compareTestSessions(...).
- //
- void analyzePerformance(std::ofstream* os, LLSD* base, LLSD* current) ;
-
-protected:
- //
- //insert metric strings used in the tester.
- //
- void addMetricString(std::string str) ;
-
- //
- //increase LLSD label by 1
- //
- void incLabel() ;
-
- //
- //the function to write a set of test results to the log LLSD.
- //
- void outputTestResults() ;
-
- //
- //compare the test results.
- //you can write your own to overwrite the default one.
- //
- virtual void compareTestResults(std::ofstream* os, std::string metric_string, S32 v_base, S32 v_current) ;
- virtual void compareTestResults(std::ofstream* os, std::string metric_string, F32 v_base, F32 v_current) ;
-
- //
- //for performance analysis use
- //it defines an interface for the two abstract virtual functions loadTestSession(...) and compareTestSessions(...).
- //please make your own test session class derived from it.
- //
- class LLTestSession
- {
- public:
- virtual ~LLTestSession() ;
- };
-
- //
- //load a test session for log LLSD
- //you need to implement it only when you define your own way to analyze performance.
- //otherwise leave it empty.
- //
- virtual LLMetricPerformanceTester::LLTestSession* loadTestSession(LLSD* log) = 0 ;
- //
- //compare the base session and the target session
- //you need to implement it only when you define your own way to analyze performance.
- //otherwise leave it empty.
- //
- virtual void compareTestSessions(std::ofstream* os) = 0 ;
- //
- //the function to write a set of test results to the log LLSD.
- //you have to write you own version of this function.
- //
- virtual void outputTestRecord(LLSD* sd) = 0 ;
-
-private:
- void preOutputTestResults(LLSD* sd) ;
- void postOutputTestResults(LLSD* sd) ;
- void prePerformanceAnalysis() ;
-
-protected:
- //
- //the unique name string of the tester
- //
- std::string mName ;
- //
- //the current label counter for the log LLSD
- //
- std::string mCurLabel ;
- S32 mCount ;
-
- BOOL mUseDefaultPerformanceAnalysis ;
- LLTestSession* mBaseSessionp ;
- LLTestSession* mCurrentSessionp ;
-
- //metrics strings
- std::vector< std::string > mMetricStrings ;
-
-//static members
-private:
- static void addTester(LLMetricPerformanceTester* tester) ;
-
-public:
- typedef std::map< std::string, LLMetricPerformanceTester* > name_tester_map_t;
- static name_tester_map_t sTesterMap ;
-
- static LLMetricPerformanceTester* getTester(std::string label) ;
- static BOOL hasMetricPerformanceTesters() {return !sTesterMap.empty() ;}
-
- static void initClass() ;
- static void cleanClass() ;
-};
-
-#endif
-
diff --git a/indra/newview/llmoveview.cpp b/indra/newview/llmoveview.cpp
index 6658e1d7e8..142ee40cc8 100644
--- a/indra/newview/llmoveview.cpp
+++ b/indra/newview/llmoveview.cpp
@@ -94,6 +94,7 @@ BOOL LLFloaterMove::postBuild()
{
setIsChrome(TRUE);
setTitleVisible(TRUE); // restore title visibility after chrome applying
+ updateTransparency(TT_ACTIVE); // force using active floater transparency (STORM-730)
LLDockableFloater::postBuild();
@@ -448,17 +449,20 @@ void LLFloaterMove::updatePosition()
LLBottomTray* tray = LLBottomTray::getInstance();
if (!tray) return;
- LLButton* movement_btn = tray->getChild<LLButton>(BOTTOM_TRAY_BUTTON_NAME);
+ LLButton* movement_btn = tray->findChild<LLButton>(BOTTOM_TRAY_BUTTON_NAME);
- //align centers of a button and a floater
- S32 x = movement_btn->calcScreenRect().getCenterX() - getRect().getWidth()/2;
-
- S32 y = 0;
- if (!mModeActionsPanel->getVisible())
+ if (movement_btn)
{
- y = mModeActionsPanel->getRect().getHeight();
+ //align centers of a button and a floater
+ S32 x = movement_btn->calcScreenRect().getCenterX() - getRect().getWidth()/2;
+
+ S32 y = 0;
+ if (!mModeActionsPanel->getVisible())
+ {
+ y = mModeActionsPanel->getRect().getHeight();
+ }
+ setOrigin(x, y);
}
- setOrigin(x, y);
}
//static
@@ -552,7 +556,7 @@ LLPanelStandStopFlying::LLPanelStandStopFlying() :
}
// static
-inline LLPanelStandStopFlying* LLPanelStandStopFlying::getInstance()
+LLPanelStandStopFlying* LLPanelStandStopFlying::getInstance()
{
static LLPanelStandStopFlying* panel = getStandStopFlyingPanel();
return panel;
@@ -735,10 +739,18 @@ void LLPanelStandStopFlying::updatePosition()
LLBottomTray* tray = LLBottomTray::getInstance();
if (!tray || mAttached) return;
- LLButton* movement_btn = tray->getChild<LLButton>(BOTTOM_TRAY_BUTTON_NAME);
+ LLButton* movement_btn = tray->findChild<LLButton>(BOTTOM_TRAY_BUTTON_NAME);
- // Align centers of the button and the panel.
- S32 x = movement_btn->calcScreenRect().getCenterX() - getRect().getWidth()/2;
+ S32 x = 0;
+ if (movement_btn)
+ {
+ // Align centers of the button and the panel.
+ x = movement_btn->calcScreenRect().getCenterX() - getRect().getWidth()/2;
+ }
+ else
+ {
+ x = tray->calcScreenRect().getCenterX() - getRect().getWidth()/2;
+ }
setOrigin(x, 0);
}
diff --git a/indra/newview/llmutelist.cpp b/indra/newview/llmutelist.cpp
index af8fdb17cf..a7059eb519 100644
--- a/indra/newview/llmutelist.cpp
+++ b/indra/newview/llmutelist.cpp
@@ -373,17 +373,19 @@ BOOL LLMuteList::remove(const LLMute& mute, U32 flags)
// Must be after erase.
setLoaded(); // why is this here? -MG
}
-
- // Clean up any legacy mutes
- string_set_t::iterator legacy_it = mLegacyMutes.find(mute.mName);
- if (legacy_it != mLegacyMutes.end())
+ else
{
- // Database representation of legacy mute is UUID null.
- LLMute mute(LLUUID::null, *legacy_it, LLMute::BY_NAME);
- updateRemove(mute);
- mLegacyMutes.erase(legacy_it);
- // Must be after erase.
- setLoaded(); // why is this here? -MG
+ // Clean up any legacy mutes
+ string_set_t::iterator legacy_it = mLegacyMutes.find(mute.mName);
+ if (legacy_it != mLegacyMutes.end())
+ {
+ // Database representation of legacy mute is UUID null.
+ LLMute mute(LLUUID::null, *legacy_it, LLMute::BY_NAME);
+ updateRemove(mute);
+ mLegacyMutes.erase(legacy_it);
+ // Must be after erase.
+ setLoaded(); // why is this here? -MG
+ }
}
return found;
@@ -607,7 +609,8 @@ BOOL LLMuteList::isMuted(const LLUUID& id, const std::string& name, U32 flags) c
}
// empty names can't be legacy-muted
- if (name.empty()) return FALSE;
+ bool avatar = mute_object && mute_object->isAvatar();
+ if (name.empty() || avatar) return FALSE;
// Look in legacy pile
string_set_t::const_iterator legacy_it = mLegacyMutes.find(name);
diff --git a/indra/newview/llnamelistctrl.cpp b/indra/newview/llnamelistctrl.cpp
index 38100aa6c5..afceb58ccf 100644
--- a/indra/newview/llnamelistctrl.cpp
+++ b/indra/newview/llnamelistctrl.cpp
@@ -143,6 +143,30 @@ void LLNameListCtrl::mouseOverHighlightNthItem( S32 target_index )
S32 cur_index = getHighlightedItemInx();
if (cur_index != target_index)
{
+ bool is_mouse_over_name_cell = false;
+
+ S32 mouse_x, mouse_y;
+ LLUI::getMousePositionLocal(this, &mouse_x, &mouse_y);
+
+ S32 column_index = getColumnIndexFromOffset(mouse_x);
+ LLScrollListItem* hit_item = hitItem(mouse_x, mouse_y);
+ if (hit_item && column_index == mNameColumnIndex)
+ {
+ // Get the name cell which is currently under the mouse pointer.
+ LLScrollListCell* hit_cell = hit_item->getColumn(column_index);
+ if (hit_cell)
+ {
+ is_mouse_over_name_cell = getCellRect(cur_index, column_index).pointInRect(mouse_x, mouse_y);
+ }
+ }
+
+ // If the tool tip is visible and the mouse is over the currently highlighted item's name cell,
+ // we should not reset the highlighted item index i.e. set mHighlightedItem = -1
+ // and should not increase the width of the text inside the cell because it may
+ // overlap the tool tip icon.
+ if (LLToolTipMgr::getInstance()->toolTipVisible() && is_mouse_over_name_cell)
+ return;
+
if(0 <= cur_index && cur_index < (S32)getItemList().size())
{
LLScrollListItem* item = getItemList()[cur_index];
diff --git a/indra/newview/llnamelistctrl.h b/indra/newview/llnamelistctrl.h
index 6805630ef1..d64fdbe6a5 100644
--- a/indra/newview/llnamelistctrl.h
+++ b/indra/newview/llnamelistctrl.h
@@ -1,25 +1,25 @@
-/**
+/**
* @file llnamelistctrl.h
* @brief A list of names, automatically refreshing from the name cache.
*
* $LicenseInfo:firstyear=2003&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$
*/
@@ -58,7 +58,7 @@ public:
NameItem()
: name("name"),
target("target", INDIVIDUAL)
- {}
+ {}
};
struct NameColumn : public LLInitParam::Choice<NameColumn>
@@ -83,7 +83,7 @@ protected:
LLNameListCtrl(const Params&);
friend class LLUICtrlFactory;
public:
- // Add a user to the list by name. It will be added, the name
+ // Add a user to the list by name. It will be added, the name
// requested from the cache, and updated as necessary.
void addNameItem(const LLUUID& agent_id, EAddPosition pos = ADD_BOTTOM,
BOOL enabled = TRUE, const std::string& suffix = LLStringUtil::null);
@@ -92,7 +92,7 @@ public:
/*virtual*/ LLScrollListItem* addElement(const LLSD& element, EAddPosition pos = ADD_BOTTOM, void* userdata = NULL);
LLScrollListItem* addNameItemRow(const NameItem& value, EAddPosition pos = ADD_BOTTOM, const std::string& suffix = LLStringUtil::null);
- // Add a user to the list by name. It will be added, the name
+ // Add a user to the list by name. It will be added, the name
// requested from the cache, and updated as necessary.
void addGroupNameItem(const LLUUID& group_id, EAddPosition pos = ADD_BOTTOM,
BOOL enabled = TRUE);
@@ -126,7 +126,7 @@ private:
/**
* LLNameListCtrl item
- *
+ *
* We don't use LLScrollListItem to be able to override getUUID(), which is needed
* because the name list item value is not simply an UUID but a map (uuid, is_group).
*/
diff --git a/indra/newview/llnavigationbar.cpp b/indra/newview/llnavigationbar.cpp
index 58849393b4..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"
@@ -276,9 +277,6 @@ LLNavigationBar::LLNavigationBar()
// set a listener function for LoginComplete event
LLAppViewer::instance()->setOnLoginCompletedCallback(boost::bind(&LLNavigationBar::handleLoginComplete, this));
-
- // Necessary for focus movement among child controls
- setFocusRoot(TRUE);
}
LLNavigationBar::~LLNavigationBar()
@@ -327,6 +325,8 @@ BOOL LLNavigationBar::postBuild()
LLTeleportHistory::getInstance()->setHistoryChangedCallback(
boost::bind(&LLNavigationBar::onTeleportHistoryChanged, this));
+ LLHints::registerHintTarget("nav_bar", LLView::getHandle());
+
return TRUE;
}
@@ -639,18 +639,19 @@ void LLNavigationBar::onRegionNameResponse(
U64 region_handle, const std::string& url, const LLUUID& snapshot_id, bool teleport)
{
// Invalid location?
- if (!region_handle)
+ if (region_handle)
+ {
+ // Teleport to the location.
+ LLVector3d region_pos = from_region_handle(region_handle);
+ LLVector3d global_pos = region_pos + (LLVector3d) local_coords;
+
+ llinfos << "Teleporting to: " << LLSLURL(region_name, global_pos).getSLURLString() << llendl;
+ gAgent.teleportViaLocation(global_pos);
+ }
+ else if (gSavedSettings.getBOOL("SearchFromAddressBar"))
{
invokeSearch(typed_location);
- return;
}
-
- // Teleport to the location.
- LLVector3d region_pos = from_region_handle(region_handle);
- LLVector3d global_pos = region_pos + (LLVector3d) local_coords;
-
- llinfos << "Teleporting to: " << LLSLURL(region_name, global_pos).getSLURLString() << llendl;
- gAgent.teleportViaLocation(global_pos);
}
void LLNavigationBar::showTeleportHistoryMenu(LLUICtrl* btn_ctrl)
diff --git a/indra/newview/llnearbychat.cpp b/indra/newview/llnearbychat.cpp
index 180695e40b..03ebc344f1 100644
--- a/indra/newview/llnearbychat.cpp
+++ b/indra/newview/llnearbychat.cpp
@@ -250,9 +250,13 @@ void LLNearbyChat::getAllowedRect(LLRect& rect)
void LLNearbyChat::updateChatHistoryStyle()
{
mChatHistory->clear();
+
+ LLSD do_not_log;
+ do_not_log["do_not_log"] = true;
for(std::vector<LLChat>::iterator it = mMessageArchive.begin();it!=mMessageArchive.end();++it)
{
- addMessage(*it,false);
+ // Update the messages without re-writing them to a log file.
+ addMessage(*it,false, do_not_log);
}
}
@@ -365,3 +369,16 @@ BOOL LLNearbyChat::handleMouseDown(S32 x, S32 y, MASK mask)
mChatHistory->setFocus(TRUE);
return LLDockableFloater::handleMouseDown(x, y, mask);
}
+
+void LLNearbyChat::draw()
+{
+ // *HACK: Update transparency type depending on whether our children have focus.
+ // This is needed because this floater is chrome and thus cannot accept focus, so
+ // the transparency type setting code from LLFloater::setFocus() isn't reached.
+ if (getTransparencyType() != TT_DEFAULT)
+ {
+ setTransparencyType(hasFocus() ? TT_ACTIVE : TT_INACTIVE);
+ }
+
+ LLDockableFloater::draw();
+}
diff --git a/indra/newview/llnearbychat.h b/indra/newview/llnearbychat.h
index 1e62910385..2ea79797f8 100644
--- a/indra/newview/llnearbychat.h
+++ b/indra/newview/llnearbychat.h
@@ -48,6 +48,7 @@ public:
bool onNearbyChatCheckContextMenuItem(const LLSD& userdata);
virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask);
+ virtual void draw();
// focus overrides
/*virtual*/ void onFocusLost();
diff --git a/indra/newview/llnearbychatbar.cpp b/indra/newview/llnearbychatbar.cpp
index 932ad75f29..d3fd959152 100644
--- a/indra/newview/llnearbychatbar.cpp
+++ b/indra/newview/llnearbychatbar.cpp
@@ -47,6 +47,7 @@
#include "llwindow.h"
#include "llviewerwindow.h"
#include "llrootview.h"
+#include "llviewerchat.h"
S32 LLNearbyChatBar::sLastSpecialChatChannel = 0;
@@ -94,15 +95,19 @@ public:
LLGestureComboList::Params::Params()
: combo_button("combo_button"),
- combo_list("combo_list")
+ combo_list("combo_list"),
+ get_more("get_more", true),
+ view_all("view_all", true)
{
}
LLGestureComboList::LLGestureComboList(const LLGestureComboList::Params& p)
-: LLUICtrl(p)
- , mLabel(p.label)
- , mViewAllItemIndex(0)
- , mGetMoreItemIndex(0)
+: LLUICtrl(p),
+ mLabel(p.label),
+ mViewAllItemIndex(-1),
+ mGetMoreItemIndex(-1),
+ mShowViewAll(p.view_all),
+ mShowGetMore(p.get_more)
{
LLBottomtrayButton::Params button_params = p.combo_button;
button_params.follows.flags(FOLLOWS_LEFT|FOLLOWS_BOTTOM|FOLLOWS_RIGHT);
@@ -153,6 +158,16 @@ BOOL LLGestureComboList::handleKeyHere(KEY key, MASK mask)
return handled;
}
+void LLGestureComboList::draw()
+{
+ LLUICtrl::draw();
+
+ if(mButton->getToggleState())
+ {
+ showList();
+ }
+}
+
void LLGestureComboList::showList()
{
LLRect rect = mList->getRect();
@@ -176,6 +191,7 @@ void LLGestureComboList::showList()
// Show the list and push the button down
mButton->setToggleState(TRUE);
mList->setVisible(TRUE);
+ sendChildToFront(mList);
LLUI::addPopup(mList);
}
@@ -286,12 +302,16 @@ void LLGestureComboList::refreshGestures()
sortByName();
// store indices for Get More and View All items (idx is the index followed by the last added Gesture)
- mGetMoreItemIndex = idx;
- mViewAllItemIndex = idx + 1;
-
- // add Get More and View All items at the bottom
- mList->addSimpleElement(LLTrans::getString("GetMoreGestures"), ADD_BOTTOM, LLSD(mGetMoreItemIndex));
- mList->addSimpleElement(LLTrans::getString("ViewAllGestures"), ADD_BOTTOM, LLSD(mViewAllItemIndex));
+ if (mShowGetMore)
+ {
+ mGetMoreItemIndex = idx;
+ mList->addSimpleElement(LLTrans::getString("GetMoreGestures"), ADD_BOTTOM, LLSD(mGetMoreItemIndex));
+ }
+ if (mShowViewAll)
+ {
+ mViewAllItemIndex = idx + 1;
+ mList->addSimpleElement(LLTrans::getString("ViewAllGestures"), ADD_BOTTOM, LLSD(mViewAllItemIndex));
+ }
// Insert label after sorting, at top, with separator below it
mList->addSeparator(ADD_TOP);
@@ -414,13 +434,26 @@ BOOL LLNearbyChatBar::postBuild()
mChatBox->setPassDelete(TRUE);
mChatBox->setReplaceNewlinesWithSpaces(FALSE);
mChatBox->setEnableLineHistory(TRUE);
+ mChatBox->setFont(LLViewerChat::getChatFont());
mOutputMonitor = getChild<LLOutputMonitorCtrl>("chat_zone_indicator");
mOutputMonitor->setVisible(FALSE);
+ // Register for font change notifications
+ LLViewerChat::setFontChangedCallback(boost::bind(&LLNearbyChatBar::onChatFontChange, this, _1));
+
return TRUE;
}
+void LLNearbyChatBar::onChatFontChange(LLFontGL* fontp)
+{
+ // Update things with the new font whohoo
+ if (mChatBox)
+ {
+ mChatBox->setFont(fontp);
+ }
+}
+
//static
LLNearbyChatBar* LLNearbyChatBar::getInstance()
{
diff --git a/indra/newview/llnearbychatbar.h b/indra/newview/llnearbychatbar.h
index cc905736fd..efddec942f 100644
--- a/indra/newview/llnearbychatbar.h
+++ b/indra/newview/llnearbychatbar.h
@@ -46,6 +46,8 @@ public:
{
Optional<LLBottomtrayButton::Params> combo_button;
Optional<LLScrollListCtrl::Params> combo_list;
+ Optional<bool> get_more,
+ view_all;
Params();
};
@@ -56,6 +58,8 @@ protected:
LLGestureComboList(const Params&);
std::vector<LLMultiGesture*> mGestures;
std::string mLabel;
+ bool mShowViewAll;
+ bool mShowGetMore;
LLSD::Integer mViewAllItemIndex;
LLSD::Integer mGetMoreItemIndex;
@@ -68,6 +72,8 @@ public:
virtual void hideList();
virtual BOOL handleKeyHere(KEY key, MASK mask);
+ virtual void draw();
+
S32 getCurrentIndex() const;
void onItemSelected(const LLSD& data);
void sortByName(bool ascending = true);
@@ -121,6 +127,7 @@ protected:
void sendChat( EChatType type );
void onChatBoxCommit();
+ void onChatFontChange(LLFontGL* fontp);
static LLWString stripChannelNumber(const LLWString &mesg, S32* channel);
EChatType processChatTypeTriggers(EChatType type, std::string &str);
diff --git a/indra/newview/llnearbychathandler.cpp b/indra/newview/llnearbychathandler.cpp
index 47d32e57fb..b56fb65a4c 100644
--- a/indra/newview/llnearbychathandler.cpp
+++ b/indra/newview/llnearbychathandler.cpp
@@ -64,6 +64,18 @@ public:
LLNearbyChatScreenChannel(const LLUUID& id):LLScreenChannelBase(id)
{
mStopProcessing = false;
+
+ LLControlVariable* ctrl = gSavedSettings.getControl("NearbyToastLifeTime").get();
+ if (ctrl)
+ {
+ ctrl->getSignal()->connect(boost::bind(&LLNearbyChatScreenChannel::updateToastsLifetime, this));
+ }
+
+ ctrl = gSavedSettings.getControl("NearbyToastFadingTime").get();
+ if (ctrl)
+ {
+ ctrl->getSignal()->connect(boost::bind(&LLNearbyChatScreenChannel::updateToastFadingTime, this));
+ }
}
void addNotification (LLSD& notification);
@@ -111,11 +123,24 @@ protected:
toast->setVisible(FALSE);
toast->stopTimer();
toast->setIsHidden(true);
+
+ // Nearby chat toasts that are hidden, not destroyed. They are collected to the toast pool, so that
+ // they can be used next time, this is done for performance. But if the toast lifetime was changed
+ // (from preferences floater (STORY-36)) while it was shown (at this moment toast isn't in the pool yet)
+ // changes don't take affect.
+ // So toast's lifetime should be updated each time it's added to the pool. Otherwise viewer would have
+ // to be restarted so that changes take effect.
+ toast->setLifetime(gSavedSettings.getS32("NearbyToastLifeTime"));
+ toast->setFadingTime(gSavedSettings.getS32("NearbyToastFadingTime"));
m_toast_pool.push_back(toast->getHandle());
}
void createOverflowToast(S32 bottom, F32 timer);
+ void updateToastsLifetime();
+
+ void updateToastFadingTime();
+
create_toast_panel_callback_t m_create_toast_panel_callback_t;
bool createPoolToast();
@@ -205,6 +230,27 @@ void LLNearbyChatScreenChannel::onToastFade(LLToast* toast)
arrangeToasts();
}
+void LLNearbyChatScreenChannel::updateToastsLifetime()
+{
+ S32 seconds = gSavedSettings.getS32("NearbyToastLifeTime");
+ toast_list_t::iterator it;
+
+ for(it = m_toast_pool.begin(); it != m_toast_pool.end(); ++it)
+ {
+ (*it).get()->setLifetime(seconds);
+ }
+}
+
+void LLNearbyChatScreenChannel::updateToastFadingTime()
+{
+ S32 seconds = gSavedSettings.getS32("NearbyToastFadingTime");
+ toast_list_t::iterator it;
+
+ for(it = m_toast_pool.begin(); it != m_toast_pool.end(); ++it)
+ {
+ (*it).get()->setFadingTime(seconds);
+ }
+}
bool LLNearbyChatScreenChannel::createPoolToast()
{
@@ -250,7 +296,7 @@ void LLNearbyChatScreenChannel::addNotification(LLSD& notification)
{
panel->addMessage(notification);
toast->reshapeToPanel();
- toast->resetTimer();
+ toast->startTimer();
arrangeToasts();
return;
@@ -295,7 +341,7 @@ void LLNearbyChatScreenChannel::addNotification(LLSD& notification)
panel->init(notification);
toast->reshapeToPanel();
- toast->resetTimer();
+ toast->startTimer();
m_active_toasts.push_back(toast->getHandle());
@@ -325,9 +371,9 @@ void LLNearbyChatScreenChannel::arrangeToasts()
int sort_toasts_predicate(LLHandle<LLToast> first, LLHandle<LLToast> second)
{
- F32 v1 = first.get()->getTimer()->getEventTimer().getElapsedTimeF32();
- F32 v2 = second.get()->getTimer()->getEventTimer().getElapsedTimeF32();
- return v1 < v2;
+ F32 v1 = first.get()->getTimeLeftToLive();
+ F32 v2 = second.get()->getTimeLeftToLive();
+ return v1 > v2;
}
void LLNearbyChatScreenChannel::showToastsBottom()
@@ -336,7 +382,10 @@ void LLNearbyChatScreenChannel::showToastsBottom()
return;
LLRect toast_rect;
- S32 bottom = getRect().mBottom;
+ updateBottom();
+ S32 channel_bottom = getRect().mBottom;
+
+ S32 bottom = channel_bottom;
S32 margin = gSavedSettings.getS32("ToastGap");
//sort active toasts
@@ -468,9 +517,22 @@ void LLNearbyChatHandler::processChat(const LLChat& chat_msg, const LLSD &args)
}
nearby_chat->addMessage(chat_msg, true, args);
+
+ if(chat_msg.mSourceType == CHAT_SOURCE_AGENT
+ && chat_msg.mFromID.notNull()
+ && chat_msg.mFromID != gAgentID)
+ {
+ LLFirstUse::otherAvatarChatFirst();
+
+ // Add sender to the recent people list.
+ LLRecentPeople::instance().add(chat_msg.mFromID);
+
+ }
+
if( nearby_chat->getVisible()
|| ( chat_msg.mSourceType == CHAT_SOURCE_AGENT
- && gSavedSettings.getBOOL("UseChatBubbles") ) )
+ && gSavedSettings.getBOOL("UseChatBubbles") )
+ || !mChannel->getShowToasts() ) // to prevent toasts in Busy mode
return;//no need in toast if chat is visible or if bubble chat is enabled
// Handle irc styled messages for toast panel
@@ -500,6 +562,7 @@ void LLNearbyChatHandler::processChat(const LLChat& chat_msg, const LLSD &args)
}
*/
+ // Add a nearby chat toast.
LLUUID id;
id.generate();
@@ -525,15 +588,13 @@ void LLNearbyChatHandler::processChat(const LLChat& chat_msg, const LLSD &args)
notification["text_color"] = r_color_name;
notification["color_alpha"] = r_color_alpha;
notification["font_size"] = (S32)LLViewerChat::getChatFontSize() ;
+
+ // Pass sender info so that it can be rendered properly (STORM-1021).
+ notification["sender_slurl"] = LLViewerChat::getSenderSLURL(chat_msg, args);
+
channel->addNotification(notification);
}
-
- if(chat_msg.mSourceType == CHAT_SOURCE_AGENT
- && chat_msg.mFromID.notNull()
- && chat_msg.mFromID != gAgentID)
- {
- LLFirstUse::otherAvatarChatFirst();
- }
+
}
void LLNearbyChatHandler::onDeleteToast(LLToast* toast)
diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp
index f084002385..5fe5c9b1e8 100644
--- a/indra/newview/llnetmap.cpp
+++ b/indra/newview/llnetmap.cpp
@@ -47,6 +47,7 @@
#include "llagentcamera.h"
#include "llappviewer.h" // for gDisconnected
#include "llcallingcard.h" // LLAvatarTracker
+#include "llfloaterworldmap.h"
#include "lltracker.h"
#include "llsurface.h"
#include "llviewercamera.h"
@@ -91,13 +92,27 @@ LLNetMap::LLNetMap (const Params & p)
mObjectImagep(),
mClosestAgentToCursor(),
mClosestAgentAtLastRightClick(),
- mToolTipMsg()
+ mToolTipMsg(),
+ mPopupMenu(NULL)
{
mDotRadius = llmax(DOT_SCALE * mPixelsPerMeter, MIN_DOT_RADIUS);
+ setScale(gSavedSettings.getF32("MiniMapScale"));
}
LLNetMap::~LLNetMap()
{
+ gSavedSettings.setF32("MiniMapScale", mScale);
+}
+
+BOOL LLNetMap::postBuild()
+{
+ LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+
+ registrar.add("Minimap.Zoom", boost::bind(&LLNetMap::handleZoom, this, _2));
+ registrar.add("Minimap.Tracker", boost::bind(&LLNetMap::handleStopTracking, this, _2));
+
+ mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_mini_map.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+ return TRUE;
}
void LLNetMap::setScale( F32 scale )
@@ -315,8 +330,8 @@ void LLNetMap::draw()
//localMouse(&local_mouse_x, &local_mouse_y);
LLUI::getMousePositionLocal(this, &local_mouse_x, &local_mouse_y);
mClosestAgentToCursor.setNull();
- F32 closest_dist = F32_MAX;
- F32 min_pick_dist = mDotRadius * MIN_PICK_SCALE;
+ F32 closest_dist_squared = F32_MAX; // value will be overridden in the loop
+ F32 min_pick_dist_squared = (mDotRadius * MIN_PICK_SCALE) * (mDotRadius * MIN_PICK_SCALE);
// Draw avatars
for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
@@ -352,21 +367,54 @@ void LLNetMap::draw()
pos_map = globalPosToView(pos_global);
+ LLUUID uuid(NULL);
BOOL show_as_friend = FALSE;
if( i < regionp->mMapAvatarIDs.count())
{
- show_as_friend = (LLAvatarTracker::instance().getBuddyInfo(regionp->mMapAvatarIDs.get(i)) != NULL);
+ uuid = regionp->mMapAvatarIDs.get(i);
+ show_as_friend = (LLAvatarTracker::instance().getBuddyInfo(uuid) != NULL);
}
+
+ LLColor4 color = show_as_friend ? map_avatar_friend_color : map_avatar_color;
LLWorldMapView::drawAvatar(
pos_map.mV[VX], pos_map.mV[VY],
- show_as_friend ? map_avatar_friend_color : map_avatar_color,
+ color,
pos_map.mV[VZ], mDotRadius);
- F32 dist_to_cursor = dist_vec(LLVector2(pos_map.mV[VX], pos_map.mV[VY]),
+ if(uuid.notNull())
+ {
+ bool selected = false;
+ uuid_vec_t::iterator sel_iter = gmSelected.begin();
+ for (; sel_iter != gmSelected.end(); sel_iter++)
+ {
+ if(*sel_iter == uuid)
+ {
+ selected = true;
+ break;
+ }
+ }
+ if(selected)
+ {
+ if( (pos_map.mV[VX] < 0) ||
+ (pos_map.mV[VY] < 0) ||
+ (pos_map.mV[VX] >= getRect().getWidth()) ||
+ (pos_map.mV[VY] >= getRect().getHeight()) )
+ {
+ S32 x = llround( pos_map.mV[VX] );
+ S32 y = llround( pos_map.mV[VY] );
+ LLWorldMapView::drawTrackingCircle( getRect(), x, y, color, 1, 10);
+ } else
+ {
+ LLWorldMapView::drawTrackingDot(pos_map.mV[VX],pos_map.mV[VY],color,0.f);
+ }
+ }
+ }
+
+ F32 dist_to_cursor_squared = dist_vec_squared(LLVector2(pos_map.mV[VX], pos_map.mV[VY]),
LLVector2(local_mouse_x,local_mouse_y));
- if(dist_to_cursor < min_pick_dist && dist_to_cursor < closest_dist)
+ if(dist_to_cursor_squared < min_pick_dist_squared && dist_to_cursor_squared < closest_dist_squared)
{
- closest_dist = dist_to_cursor;
+ closest_dist_squared = dist_to_cursor_squared;
mClosestAgentToCursor = regionp->mMapAvatarIDs.get(i);
}
}
@@ -403,9 +451,9 @@ void LLNetMap::draw()
dot_width,
dot_width);
- F32 dist_to_cursor = dist_vec(LLVector2(pos_map.mV[VX], pos_map.mV[VY]),
+ F32 dist_to_cursor_squared = dist_vec_squared(LLVector2(pos_map.mV[VX], pos_map.mV[VY]),
LLVector2(local_mouse_x,local_mouse_y));
- if(dist_to_cursor < min_pick_dist && dist_to_cursor < closest_dist)
+ if(dist_to_cursor_squared < min_pick_dist_squared && dist_to_cursor_squared < closest_dist_squared)
{
mClosestAgentToCursor = gAgent.getID();
}
@@ -598,7 +646,6 @@ BOOL LLNetMap::handleToolTip( S32 x, S32 y, MASK mask )
args["[REGION]"] = region_name;
std::string msg = mToolTipMsg;
LLStringUtil::format(msg, args);
-
LLToolTipMgr::instance().show(LLToolTip::Params()
.message(msg)
.sticky_rect(sticky_rect));
@@ -791,6 +838,9 @@ BOOL LLNetMap::handleMouseDown( S32 x, S32 y, MASK mask )
BOOL LLNetMap::handleMouseUp( S32 x, S32 y, MASK mask )
{
+ if(abs(mMouseDown.mX-x)<3 && abs(mMouseDown.mY-y)<3)
+ handleClick(x,y,mask);
+
if (hasMouseCapture())
{
if (mPanning)
@@ -819,6 +869,60 @@ BOOL LLNetMap::handleMouseUp( S32 x, S32 y, MASK mask )
return FALSE;
}
+BOOL LLNetMap::handleRightMouseDown(S32 x, S32 y, MASK mask)
+{
+ if (mPopupMenu)
+ {
+ mPopupMenu->buildDrawLabels();
+ mPopupMenu->updateParent(LLMenuGL::sMenuContainer);
+ mPopupMenu->setItemEnabled("Stop Tracking", LLTracker::isTracking(0));
+ LLMenuGL::showPopup(this, mPopupMenu, x, y);
+ }
+ return TRUE;
+}
+
+BOOL LLNetMap::handleClick(S32 x, S32 y, MASK mask)
+{
+ // TODO: allow clicking an avatar on minimap to select avatar in the nearby avatar list
+ // if(mClosestAgentToCursor.notNull())
+ // mNearbyList->selectUser(mClosestAgentToCursor);
+ // Needs a registered observer i guess to accomplish this without using
+ // globals to tell the mNearbyList in llpeoplepanel to select the user
+ return TRUE;
+}
+
+BOOL LLNetMap::handleDoubleClick(S32 x, S32 y, MASK mask)
+{
+ LLVector3d pos_global = viewPosToGlobal(x, y);
+
+ bool double_click_teleport = gSavedSettings.getBOOL("DoubleClickTeleport");
+ bool double_click_show_world_map = gSavedSettings.getBOOL("DoubleClickShowWorldMap");
+
+ if (double_click_teleport || double_click_show_world_map)
+ {
+ // If we're not tracking a beacon already, double-click will set one
+ if (!LLTracker::isTracking(NULL))
+ {
+ LLFloaterWorldMap* world_map = LLFloaterWorldMap::getInstance();
+ if (world_map)
+ {
+ world_map->trackLocation(pos_global);
+ }
+ }
+ }
+
+ if (double_click_teleport)
+ {
+ // If DoubleClickTeleport is on, double clicking the minimap will teleport there
+ gAgent.teleportViaLocationLookAt(pos_global);
+ }
+ else if (double_click_show_world_map)
+ {
+ LLFloaterReg::showInstance("world_map");
+ }
+ return TRUE;
+}
+
// static
bool LLNetMap::outsideSlop( S32 x, S32 y, S32 start_x, S32 start_y, S32 slop )
{
@@ -869,3 +973,38 @@ BOOL LLNetMap::handleHover( S32 x, S32 y, MASK mask )
return TRUE;
}
+
+void LLNetMap::handleZoom(const LLSD& userdata)
+{
+ std::string level = userdata.asString();
+
+ F32 scale = 0.0f;
+ if (level == std::string("default"))
+ {
+ LLControlVariable *pvar = gSavedSettings.getControl("MiniMapScale");
+ if(pvar)
+ {
+ pvar->resetToDefault();
+ scale = gSavedSettings.getF32("MiniMapScale");
+ }
+ }
+ else if (level == std::string("close"))
+ scale = LLNetMap::MAP_SCALE_MAX;
+ else if (level == std::string("medium"))
+ scale = LLNetMap::MAP_SCALE_MID;
+ else if (level == std::string("far"))
+ scale = LLNetMap::MAP_SCALE_MIN;
+ if (scale != 0.0f)
+ {
+ setScale(scale);
+ }
+}
+
+void LLNetMap::handleStopTracking (const LLSD& userdata)
+{
+ if (mPopupMenu)
+ {
+ mPopupMenu->setItemEnabled ("Stop Tracking", false);
+ LLTracker::stopTracking ((void*)LLTracker::isTracking(NULL));
+ }
+}
diff --git a/indra/newview/llnetmap.h b/indra/newview/llnetmap.h
index 650bce0da4..20fcee0814 100644
--- a/indra/newview/llnetmap.h
+++ b/indra/newview/llnetmap.h
@@ -38,6 +38,8 @@ class LLColor4U;
class LLCoordGL;
class LLImageRaw;
class LLViewerTexture;
+class LLFloaterMap;
+class LLMenuGL;
class LLNetMap : public LLUICtrl
{
@@ -55,6 +57,7 @@ public:
protected:
LLNetMap (const Params & p);
friend class LLUICtrlFactory;
+ friend class LLFloaterMap;
public:
virtual ~LLNetMap();
@@ -70,7 +73,12 @@ public:
/*virtual*/ BOOL handleHover( S32 x, S32 y, MASK mask );
/*virtual*/ BOOL handleToolTip( S32 x, S32 y, MASK mask);
/*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
-
+
+ /*virtual*/ BOOL postBuild();
+ /*virtual*/ BOOL handleRightMouseDown( S32 x, S32 y, MASK mask );
+ /*virtual*/ BOOL handleClick(S32 x, S32 y, MASK mask);
+ /*virtual*/ BOOL handleDoubleClick( S32 x, S32 y, MASK mask );
+
void setScale( F32 scale );
void setToolTipMsg(const std::string& msg) { mToolTipMsg = msg; }
void renderScaledPointGlobal( const LLVector3d& pos, const LLColor4U &color, F32 radius );
@@ -118,6 +126,16 @@ private:
LLUUID mClosestAgentAtLastRightClick;
std::string mToolTipMsg;
+
+public:
+ void setSelected(uuid_vec_t uuids) { gmSelected=uuids; };
+
+private:
+ void handleZoom(const LLSD& userdata);
+ void handleStopTracking (const LLSD& userdata);
+
+ LLMenuGL* mPopupMenu;
+ uuid_vec_t gmSelected;
};
diff --git a/indra/newview/llnotificationhandlerutil.cpp b/indra/newview/llnotificationhandlerutil.cpp
index 70d588db52..de90023f3b 100644
--- a/indra/newview/llnotificationhandlerutil.cpp
+++ b/indra/newview/llnotificationhandlerutil.cpp
@@ -27,13 +27,17 @@
#include "llviewerprecompiledheaders.h" // must be first include
-#include "llnotificationhandler.h"
+#include "llavatarnamecache.h"
+
+#include "llfloaterreg.h"
#include "llnotifications.h"
-#include "llimview.h"
+#include "llurlaction.h"
+
#include "llagent.h"
-#include "llfloaterreg.h"
-#include "llnearbychat.h"
#include "llimfloater.h"
+#include "llimview.h"
+#include "llnearbychat.h"
+#include "llnotificationhandler.h"
using namespace LLNotificationsUI;
@@ -275,7 +279,11 @@ void LLHandlerUtil::logToIM(const EInstantMessage& session_type,
{
from = SYSTEM_FROM;
}
- LLIMModel::instance().logToFile(session_name, from, from_id, message);
+
+ // Build a new format username or firstname_lastname for legacy names
+ // to use it for a history log filename.
+ std::string user_name = LLCacheName::buildUsername(session_name);
+ LLIMModel::instance().logToFile(user_name, from, from_id, message);
}
else
{
diff --git a/indra/newview/llnotificationscripthandler.cpp b/indra/newview/llnotificationscripthandler.cpp
index 45590c3cdb..bbb4d03768 100644
--- a/indra/newview/llnotificationscripthandler.cpp
+++ b/indra/newview/llnotificationscripthandler.cpp
@@ -88,7 +88,7 @@ bool LLScriptHandler::processNotification(const LLSD& notify)
initChannel();
}
- if(notify["sigtype"].asString() == "add" || notify["sigtype"].asString() == "change")
+ if(notify["sigtype"].asString() == "add")
{
if (LLHandlerUtil::canLogToIM(notification))
{
diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp
index db9d386b6b..6435126fc0 100644
--- a/indra/newview/lloutfitslist.cpp
+++ b/indra/newview/lloutfitslist.cpp
@@ -38,9 +38,11 @@
#include "llinventoryfunctions.h"
#include "llinventorymodel.h"
#include "lllistcontextmenu.h"
+#include "llmenubutton.h"
#include "llnotificationsutil.h"
#include "lloutfitobserver.h"
#include "llsidetray.h"
+#include "lltoggleablemenu.h"
#include "lltransutil.h"
#include "llviewermenu.h"
#include "llvoavatar.h"
@@ -113,7 +115,7 @@ public:
registrar.add("Gear.Wear", boost::bind(&LLOutfitListGearMenu::onWear, this));
registrar.add("Gear.TakeOff", boost::bind(&LLOutfitListGearMenu::onTakeOff, this));
registrar.add("Gear.Rename", boost::bind(&LLOutfitListGearMenu::onRename, this));
- registrar.add("Gear.Delete", boost::bind(&LLOutfitListGearMenu::onDelete, this));
+ registrar.add("Gear.Delete", boost::bind(&LLOutfitsList::removeSelected, mOutfitList));
registrar.add("Gear.Create", boost::bind(&LLOutfitListGearMenu::onCreate, this, _2));
registrar.add("Gear.WearAdd", boost::bind(&LLOutfitListGearMenu::onAdd, this));
@@ -121,23 +123,11 @@ public:
enable_registrar.add("Gear.OnEnable", boost::bind(&LLOutfitListGearMenu::onEnable, this, _2));
enable_registrar.add("Gear.OnVisible", boost::bind(&LLOutfitListGearMenu::onVisible, this, _2));
- mMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>(
+ mMenu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>(
"menu_outfit_gear.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
llassert(mMenu);
}
- void show(LLView* spawning_view)
- {
- if (!mMenu) return;
-
- updateItemsVisibility();
- mMenu->buildDrawLabels();
- mMenu->updateParent(LLMenuGL::sMenuContainer);
- S32 menu_x = 0;
- S32 menu_y = spawning_view->getRect().getHeight() + mMenu->getRect().getHeight();
- LLMenuGL::showPopup(spawning_view, mMenu, menu_x, menu_y);
- }
-
void updateItemsVisibility()
{
if (!mMenu) return;
@@ -148,6 +138,8 @@ public:
mMenu->arrangeAndClear(); // update menu height
}
+ LLToggleableMenu* getMenu() { return mMenu; }
+
private:
const LLUUID& getSelectedOutfitID()
{
@@ -205,15 +197,6 @@ private:
}
}
- void onDelete()
- {
- const LLUUID& selected_outfit_id = getSelectedOutfitID();
- if (selected_outfit_id.notNull())
- {
- remove_category(&gInventory, selected_outfit_id);
- }
- }
-
void onCreate(const LLSD& data)
{
LLWearableType::EType type = LLWearableType::typeNameToType(data.asString());
@@ -260,14 +243,20 @@ private:
return true;
}
- LLOutfitsList* mOutfitList;
- LLMenuGL* mMenu;
+ LLOutfitsList* mOutfitList;
+ LLToggleableMenu* mMenu;
};
//////////////////////////////////////////////////////////////////////////
class LLOutfitContextMenu : public LLListContextMenu
{
+public:
+
+ LLOutfitContextMenu(LLOutfitsList* outfit_list)
+ : LLListContextMenu(),
+ mOutfitList(outfit_list)
+ {}
protected:
/* virtual */ LLContextMenu* createMenu()
{
@@ -283,7 +272,7 @@ protected:
boost::bind(&LLAppearanceMgr::takeOffOutfit, &LLAppearanceMgr::instance(), selected_id));
registrar.add("Outfit.Edit", boost::bind(editOutfit));
registrar.add("Outfit.Rename", boost::bind(renameOutfit, selected_id));
- registrar.add("Outfit.Delete", boost::bind(deleteOutfit, selected_id));
+ registrar.add("Outfit.Delete", boost::bind(&LLOutfitsList::removeSelected, mOutfitList));
enable_registrar.add("Outfit.OnEnable", boost::bind(&LLOutfitContextMenu::onEnable, this, _2));
enable_registrar.add("Outfit.OnVisible", boost::bind(&LLOutfitContextMenu::onVisible, this, _2));
@@ -346,10 +335,8 @@ protected:
LLAppearanceMgr::instance().renameOutfit(outfit_cat_id);
}
- static void deleteOutfit(const LLUUID& outfit_cat_id)
- {
- remove_category(&gInventory, outfit_cat_id);
- }
+private:
+ LLOutfitsList* mOutfitList;
};
//////////////////////////////////////////////////////////////////////////
@@ -366,7 +353,7 @@ LLOutfitsList::LLOutfitsList()
mCategoriesObserver = new LLInventoryCategoriesObserver();
mGearMenu = new LLOutfitListGearMenu(this);
- mOutfitMenu = new LLOutfitContextMenu();
+ mOutfitMenu = new LLOutfitContextMenu(this);
}
LLOutfitsList::~LLOutfitsList()
@@ -386,6 +373,11 @@ BOOL LLOutfitsList::postBuild()
mAccordion = getChild<LLAccordionCtrl>("outfits_accordion");
mAccordion->setComparator(&OUTFIT_TAB_NAME_COMPARATOR);
+ LLMenuButton* menu_gear_btn = getChild<LLMenuButton>("options_gear_btn");
+
+ menu_gear_btn->setMouseDownCallback(boost::bind(&LLOutfitListGearMenu::updateItemsVisibility, mGearMenu));
+ menu_gear_btn->setMenu(mGearMenu->getMenu());
+
return TRUE;
}
@@ -638,6 +630,14 @@ void LLOutfitsList::performAction(std::string action)
void LLOutfitsList::removeSelected()
{
+ LLNotificationsUtil::add("DeleteOutfits", LLSD(), LLSD(), boost::bind(&LLOutfitsList::onOutfitsRemovalConfirmation, this, _1, _2));
+}
+
+void LLOutfitsList::onOutfitsRemovalConfirmation(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (option != 0) return; // canceled
+
if (mSelectedOutfitUUID.notNull())
{
remove_category(&gInventory, mSelectedOutfitUUID);
@@ -727,13 +727,6 @@ bool LLOutfitsList::isActionEnabled(const LLSD& userdata)
return false;
}
-// virtual
-void LLOutfitsList::showGearMenu(LLView* spawning_view)
-{
- if (!mGearMenu) return;
- mGearMenu->show(spawning_view);
-}
-
void LLOutfitsList::getSelectedItemsUUIDs(uuid_vec_t& selected_uuids) const
{
// Collect selected items from all selected lists.
diff --git a/indra/newview/lloutfitslist.h b/indra/newview/lloutfitslist.h
index f73ae5bef2..a0598737f1 100644
--- a/indra/newview/lloutfitslist.h
+++ b/indra/newview/lloutfitslist.h
@@ -94,8 +94,6 @@ public:
/*virtual*/ bool isActionEnabled(const LLSD& userdata);
- /*virtual*/ void showGearMenu(LLView* spawning_view);
-
const LLUUID& getSelectedOutfitUUID() const { return mSelectedOutfitUUID; }
/*virtual*/ void getSelectedItemsUUIDs(uuid_vec_t& selected_uuids) const;
@@ -112,6 +110,8 @@ public:
private:
+ void onOutfitsRemovalConfirmation(const LLSD& notification, const LLSD& response);
+
/**
* Wrapper for LLCommonUtils::computeDifference. @see LLCommonUtils::computeDifference
*/
diff --git a/indra/newview/lloutputmonitorctrl.h b/indra/newview/lloutputmonitorctrl.h
index 026803584d..2d23753d46 100644
--- a/indra/newview/lloutputmonitorctrl.h
+++ b/indra/newview/lloutputmonitorctrl.h
@@ -31,6 +31,7 @@
#include "llview.h"
#include "llmutelist.h"
#include "llspeakingindicatormanager.h"
+#include "lluiimage.h"
class LLTextBox;
class LLUICtrlFactory;
diff --git a/indra/newview/llpanelappearancetab.h b/indra/newview/llpanelappearancetab.h
index 81366c5db4..2ed6b00497 100644
--- a/indra/newview/llpanelappearancetab.h
+++ b/indra/newview/llpanelappearancetab.h
@@ -39,8 +39,6 @@ public:
virtual bool isActionEnabled(const LLSD& userdata) = 0;
- virtual void showGearMenu(LLView* spawning_view) = 0;
-
virtual void getSelectedItemsUUIDs(uuid_vec_t& selected_uuids) const {}
static const std::string& getFilterSubString() { return sFilterSubString; }
diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp
index 57180f63b5..d58a1cb663 100644
--- a/indra/newview/llpanelavatar.cpp
+++ b/indra/newview/llpanelavatar.cpp
@@ -34,7 +34,9 @@
#include "llcombobox.h"
#include "lldateutil.h" // ageFromDate()
#include "llimview.h"
+#include "llmenubutton.h"
#include "llnotificationsutil.h"
+#include "llslurl.h"
#include "lltexteditor.h"
#include "lltexturectrl.h"
#include "lltoggleablemenu.h"
@@ -340,10 +342,11 @@ LLPanelAvatarNotes::~LLPanelAvatarNotes()
if(getAvatarId().notNull())
{
LLAvatarTracker::instance().removeParticularFriendObserver(getAvatarId(), this);
- if(LLVoiceClient::instanceExists())
- {
- LLVoiceClient::getInstance()->removeObserver((LLVoiceClientStatusObserver*)this);
- }
+ }
+
+ if(LLVoiceClient::instanceExists())
+ {
+ LLVoiceClient::getInstance()->removeObserver((LLVoiceClientStatusObserver*)this);
}
}
@@ -475,11 +478,11 @@ LLPanelAvatarProfile::LLPanelAvatarProfile()
BOOL LLPanelAvatarProfile::postBuild()
{
+ childSetCommitCallback("see_profile_btn",(boost::bind(&LLPanelAvatarProfile::onSeeProfileBtnClick,this)),NULL);
childSetCommitCallback("add_friend",(boost::bind(&LLPanelAvatarProfile::onAddFriendButtonClick,this)),NULL);
childSetCommitCallback("im",(boost::bind(&LLPanelAvatarProfile::onIMButtonClick,this)),NULL);
childSetCommitCallback("call",(boost::bind(&LLPanelAvatarProfile::onCallButtonClick,this)),NULL);
childSetCommitCallback("teleport",(boost::bind(&LLPanelAvatarProfile::onTeleportButtonClick,this)),NULL);
- childSetCommitCallback("overflow_btn", boost::bind(&LLPanelAvatarProfile::onOverflowButtonClicked, this), NULL);
childSetCommitCallback("share",(boost::bind(&LLPanelAvatarProfile::onShareButtonClick,this)),NULL);
childSetCommitCallback("show_on_map_btn", (boost::bind(
&LLPanelAvatarProfile::onMapButtonClick, this)), NULL);
@@ -500,7 +503,8 @@ BOOL LLPanelAvatarProfile::postBuild()
enable.add("Profile.EnableBlock", boost::bind(&LLPanelAvatarProfile::enableBlock, this));
enable.add("Profile.EnableUnblock", boost::bind(&LLPanelAvatarProfile::enableUnblock, this));
- mProfileMenu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_profile_overflow.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+ LLToggleableMenu* profile_menu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_profile_overflow.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+ getChild<LLMenuButton>("overflow_btn")->setMenu(profile_menu, LLMenuButton::MP_TOP_RIGHT);
LLVoiceClient::getInstance()->addObserver((LLVoiceClientStatusObserver*)this);
@@ -622,6 +626,40 @@ void LLPanelAvatarProfile::processGroupProperties(const LLAvatarGroups* avatar_g
getChild<LLUICtrl>("sl_groups")->setValue(groups);
}
+static void got_full_name_callback( LLHandle<LLPanel> profile_panel_handle, const std::string& full_name )
+{
+ if (profile_panel_handle.isDead() ) return;
+
+ LLPanelAvatarProfile* profile_panel = dynamic_cast<LLPanelAvatarProfile*>(profile_panel_handle.get());
+ if ( ! profile_panel ) return;
+
+ LLStringUtil::format_map_t args;
+
+ std::string name;
+ if (LLAvatarNameCache::useDisplayNames())
+ {
+ name = LLCacheName::buildUsername(full_name);
+ }
+ else
+ {
+ name = full_name;
+ }
+
+ args["[NAME]"] = name;
+
+ std::string linden_name = profile_panel->getString("name_text_args", args);
+ profile_panel->getChild<LLUICtrl>("name_descr_text")->setValue(linden_name);
+}
+
+void LLPanelAvatarProfile::onNameCache(const LLUUID& agent_id, const LLAvatarName& av_name)
+{
+ LLStringUtil::format_map_t args;
+ args["[DISPLAY_NAME]"] = av_name.mDisplayName;
+
+ std::string display_name = getString("display_name_text_args", args);
+ getChild<LLUICtrl>("display_name_descr_text")->setValue(display_name);
+}
+
void LLPanelAvatarProfile::fillCommonData(const LLAvatarData* avatar_data)
{
//remove avatar id from cache to get fresh info
@@ -633,6 +671,25 @@ void LLPanelAvatarProfile::fillCommonData(const LLAvatarData* avatar_data)
LLStringUtil::format(birth_date, LLSD().with("datetime", (S32) avatar_data->born_on.secondsSinceEpoch()));
args["[REG_DATE]"] = birth_date;
}
+
+ // ask (asynchronously) for the avatar name
+ LLHandle<LLPanel> profile_panel_handle = getHandle();
+ std::string full_name;
+ if (gCacheName->getFullName(avatar_data->agent_id, full_name))
+ {
+ // name in cache, call callback directly
+ got_full_name_callback( profile_panel_handle, full_name );
+ }
+ else
+ {
+ // not in cache, lookup name
+ gCacheName->get(avatar_data->agent_id, false, boost::bind( got_full_name_callback, profile_panel_handle, _2 ));
+ }
+
+ // get display name
+ LLAvatarNameCache::get(avatar_data->avatar_id,
+ boost::bind(&LLPanelAvatarProfile::onNameCache, this, _1, _2));
+
args["[AGE]"] = LLDateUtil::ageFromDate( avatar_data->born_on, LLDate::now());
std::string register_date = getString("RegisterDateFormat", args);
getChild<LLUICtrl>("register_date")->setValue(register_date );
@@ -732,6 +789,11 @@ void LLPanelAvatarProfile::onAddFriendButtonClick()
LLAvatarActions::requestFriendshipDialog(getAvatarId());
}
+void LLPanelAvatarProfile::onSeeProfileBtnClick()
+{
+ LLAvatarActions::showProfile(getAvatarId());
+}
+
void LLPanelAvatarProfile::onIMButtonClick()
{
LLAvatarActions::startIM(getAvatarId());
@@ -752,32 +814,16 @@ void LLPanelAvatarProfile::onShareButtonClick()
//*TODO not implemented
}
-void LLPanelAvatarProfile::onOverflowButtonClicked()
-{
- if (!mProfileMenu->toggleVisibility())
- return;
-
- LLView* btn = getChild<LLView>("overflow_btn");
-
- if (mProfileMenu->getButtonRect().isEmpty())
- {
- mProfileMenu->setButtonRect(btn);
- }
- mProfileMenu->updateParent(LLMenuGL::sMenuContainer);
-
- LLRect rect = btn->getRect();
- LLMenuGL::showPopup(this, mProfileMenu, rect.mRight, rect.mTop);
-}
-
LLPanelAvatarProfile::~LLPanelAvatarProfile()
{
if(getAvatarId().notNull())
{
LLAvatarTracker::instance().removeParticularFriendObserver(getAvatarId(), this);
- if(LLVoiceClient::instanceExists())
- {
- LLVoiceClient::getInstance()->removeObserver((LLVoiceClientStatusObserver*)this);
- }
+ }
+
+ if(LLVoiceClient::instanceExists())
+ {
+ LLVoiceClient::getInstance()->removeObserver((LLVoiceClientStatusObserver*)this);
}
}
diff --git a/indra/newview/llpanelavatar.h b/indra/newview/llpanelavatar.h
index 11c7716322..e95441cd58 100644
--- a/indra/newview/llpanelavatar.h
+++ b/indra/newview/llpanelavatar.h
@@ -31,10 +31,10 @@
#include "llavatarpropertiesprocessor.h"
#include "llcallingcard.h"
#include "llvoiceclient.h"
+#include "llavatarnamecache.h"
class LLComboBox;
class LLLineEditor;
-class LLToggleableMenu;
enum EOnlineStatus
{
@@ -201,20 +201,18 @@ protected:
bool enableUnblock();
bool enableGod();
-
+ void onSeeProfileBtnClick();
void onAddFriendButtonClick();
void onIMButtonClick();
void onCallButtonClick();
void onTeleportButtonClick();
void onShareButtonClick();
- void onOverflowButtonClicked();
private:
+ void onNameCache(const LLUUID& agent_id, const LLAvatarName& av_name);
typedef std::map< std::string,LLUUID> group_map_t;
group_map_t mGroups;
-
- LLToggleableMenu* mProfileMenu;
};
/**
diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp
index 90ed8b9e58..b73d97e4c4 100644
--- a/indra/newview/llpaneleditwearable.cpp
+++ b/indra/newview/llpaneleditwearable.cpp
@@ -51,7 +51,7 @@
#include "llcolorswatch.h"
#include "lltexturectrl.h"
#include "lltextureentry.h"
-#include "llviewercontrol.h" // gSavedSettings
+#include "llviewercontrol.h" // gSavedSettings
#include "llviewertexturelist.h"
#include "llagentcamera.h"
#include "llmorphview.h"
@@ -65,36 +65,43 @@ static LLRegisterPanelClassWrapper<LLPanelEditWearable> t_edit_wearable("panel_e
// subparts of the UI for focus, camera position, etc.
enum ESubpart {
- SUBPART_SHAPE_HEAD = 1, // avoid 0
- SUBPART_SHAPE_EYES,
- SUBPART_SHAPE_EARS,
- SUBPART_SHAPE_NOSE,
- SUBPART_SHAPE_MOUTH,
- SUBPART_SHAPE_CHIN,
- SUBPART_SHAPE_TORSO,
- SUBPART_SHAPE_LEGS,
- SUBPART_SHAPE_WHOLE,
- SUBPART_SHAPE_DETAIL,
- SUBPART_SKIN_COLOR,
- SUBPART_SKIN_FACEDETAIL,
- SUBPART_SKIN_MAKEUP,
- SUBPART_SKIN_BODYDETAIL,
- SUBPART_HAIR_COLOR,
- SUBPART_HAIR_STYLE,
- SUBPART_HAIR_EYEBROWS,
- SUBPART_HAIR_FACIAL,
- SUBPART_EYES,
- SUBPART_SHIRT,
- SUBPART_PANTS,
- SUBPART_SHOES,
- SUBPART_SOCKS,
- SUBPART_JACKET,
- SUBPART_GLOVES,
- SUBPART_UNDERSHIRT,
- SUBPART_UNDERPANTS,
- SUBPART_SKIRT,
- SUBPART_ALPHA,
- SUBPART_TATTOO
+ SUBPART_SHAPE_HEAD = 1, // avoid 0
+ SUBPART_SHAPE_EYES,
+ SUBPART_SHAPE_EARS,
+ SUBPART_SHAPE_NOSE,
+ SUBPART_SHAPE_MOUTH,
+ SUBPART_SHAPE_CHIN,
+ SUBPART_SHAPE_TORSO,
+ SUBPART_SHAPE_LEGS,
+ SUBPART_SHAPE_WHOLE,
+ SUBPART_SHAPE_DETAIL,
+ SUBPART_SKIN_COLOR,
+ SUBPART_SKIN_FACEDETAIL,
+ SUBPART_SKIN_MAKEUP,
+ SUBPART_SKIN_BODYDETAIL,
+ SUBPART_HAIR_COLOR,
+ SUBPART_HAIR_STYLE,
+ SUBPART_HAIR_EYEBROWS,
+ SUBPART_HAIR_FACIAL,
+ SUBPART_EYES,
+ SUBPART_SHIRT,
+ SUBPART_PANTS,
+ SUBPART_SHOES,
+ SUBPART_SOCKS,
+ SUBPART_JACKET,
+ SUBPART_GLOVES,
+ SUBPART_UNDERSHIRT,
+ SUBPART_UNDERPANTS,
+ SUBPART_SKIRT,
+ SUBPART_ALPHA,
+ SUBPART_TATTOO,
+ SUBPART_PHYSICS_BREASTS_UPDOWN,
+ SUBPART_PHYSICS_BREASTS_INOUT,
+ SUBPART_PHYSICS_BREASTS_LEFTRIGHT,
+ SUBPART_PHYSICS_BELLY_UPDOWN,
+ SUBPART_PHYSICS_BUTT_UPDOWN,
+ SUBPART_PHYSICS_BUTT_LEFTRIGHT,
+ SUBPART_PHYSICS_ADVANCED,
};
using namespace LLVOAvatarDefines;
@@ -105,102 +112,102 @@ typedef std::vector<ESubpart> subpart_vec_t;
class LLEditWearableDictionary : public LLSingleton<LLEditWearableDictionary>
{
- //--------------------------------------------------------------------
- // Constructors and Destructors
- //--------------------------------------------------------------------
+ //--------------------------------------------------------------------
+ // Constructors and Destructors
+ //--------------------------------------------------------------------
public:
- LLEditWearableDictionary();
- virtual ~LLEditWearableDictionary();
-
- //--------------------------------------------------------------------
- // Wearable Types
- //--------------------------------------------------------------------
+ LLEditWearableDictionary();
+ virtual ~LLEditWearableDictionary();
+
+ //--------------------------------------------------------------------
+ // Wearable Types
+ //--------------------------------------------------------------------
public:
- struct WearableEntry : public LLDictionaryEntry
- {
- WearableEntry(LLWearableType::EType type,
- const std::string &title,
- const std::string &desc_title,
- U8 num_color_swatches, // number of 'color_swatches'
- U8 num_texture_pickers, // number of 'texture_pickers'
- U8 num_subparts, ... ); // number of subparts followed by a list of ETextureIndex and ESubparts
-
-
- const LLWearableType::EType mWearableType;
- const std::string mTitle;
- const std::string mDescTitle;
- subpart_vec_t mSubparts;
- texture_vec_t mColorSwatchCtrls;
- texture_vec_t mTextureCtrls;
- };
-
- struct Wearables : public LLDictionary<LLWearableType::EType, WearableEntry>
- {
- Wearables();
- } mWearables;
-
- const WearableEntry* getWearable(LLWearableType::EType type) const { return mWearables.lookup(type); }
-
- //--------------------------------------------------------------------
- // Subparts
- //--------------------------------------------------------------------
+ struct WearableEntry : public LLDictionaryEntry
+ {
+ WearableEntry(LLWearableType::EType type,
+ const std::string &title,
+ const std::string &desc_title,
+ U8 num_color_swatches, // number of 'color_swatches'
+ U8 num_texture_pickers, // number of 'texture_pickers'
+ U8 num_subparts, ... ); // number of subparts followed by a list of ETextureIndex and ESubparts
+
+
+ const LLWearableType::EType mWearableType;
+ const std::string mTitle;
+ const std::string mDescTitle;
+ subpart_vec_t mSubparts;
+ texture_vec_t mColorSwatchCtrls;
+ texture_vec_t mTextureCtrls;
+ };
+
+ struct Wearables : public LLDictionary<LLWearableType::EType, WearableEntry>
+ {
+ Wearables();
+ } mWearables;
+
+ const WearableEntry* getWearable(LLWearableType::EType type) const { return mWearables.lookup(type); }
+
+ //--------------------------------------------------------------------
+ // Subparts
+ //--------------------------------------------------------------------
public:
- struct SubpartEntry : public LLDictionaryEntry
- {
- SubpartEntry(ESubpart part,
- const std::string &joint,
- const std::string &edit_group,
- const std::string &param_list,
- const std::string &accordion_tab,
- const LLVector3d &target_offset,
- const LLVector3d &camera_offset,
- const ESex &sex);
-
- ESubpart mSubpart;
- std::string mTargetJoint;
- std::string mEditGroup;
- std::string mParamList;
- std::string mAccordionTab;
- LLVector3d mTargetOffset;
- LLVector3d mCameraOffset;
- ESex mSex;
- };
-
- struct Subparts : public LLDictionary<ESubpart, SubpartEntry>
- {
- Subparts();
- } mSubparts;
-
- const SubpartEntry* getSubpart(ESubpart subpart) const { return mSubparts.lookup(subpart); }
-
- //--------------------------------------------------------------------
- // Picker Control Entries
- //--------------------------------------------------------------------
+ struct SubpartEntry : public LLDictionaryEntry
+ {
+ SubpartEntry(ESubpart part,
+ const std::string &joint,
+ const std::string &edit_group,
+ const std::string &param_list,
+ const std::string &accordion_tab,
+ const LLVector3d &target_offset,
+ const LLVector3d &camera_offset,
+ const ESex &sex);
+
+ ESubpart mSubpart;
+ std::string mTargetJoint;
+ std::string mEditGroup;
+ std::string mParamList;
+ std::string mAccordionTab;
+ LLVector3d mTargetOffset;
+ LLVector3d mCameraOffset;
+ ESex mSex;
+ };
+
+ struct Subparts : public LLDictionary<ESubpart, SubpartEntry>
+ {
+ Subparts();
+ } mSubparts;
+
+ const SubpartEntry* getSubpart(ESubpart subpart) const { return mSubparts.lookup(subpart); }
+
+ //--------------------------------------------------------------------
+ // Picker Control Entries
+ //--------------------------------------------------------------------
public:
- struct PickerControlEntry : public LLDictionaryEntry
- {
- PickerControlEntry(ETextureIndex tex_index,
- const std::string name,
- const LLUUID default_image_id = LLUUID::null,
- const bool allow_no_texture = false);
- ETextureIndex mTextureIndex;
- const std::string mControlName;
- const LLUUID mDefaultImageId;
- const bool mAllowNoTexture;
- };
-
- struct ColorSwatchCtrls : public LLDictionary<ETextureIndex, PickerControlEntry>
- {
- ColorSwatchCtrls();
- } mColorSwatchCtrls;
-
- struct TextureCtrls : public LLDictionary<ETextureIndex, PickerControlEntry>
- {
- TextureCtrls();
- } mTextureCtrls;
-
- const PickerControlEntry* getTexturePicker(ETextureIndex index) const { return mTextureCtrls.lookup(index); }
- const PickerControlEntry* getColorSwatch(ETextureIndex index) const { return mColorSwatchCtrls.lookup(index); }
+ struct PickerControlEntry : public LLDictionaryEntry
+ {
+ PickerControlEntry(ETextureIndex tex_index,
+ const std::string name,
+ const LLUUID default_image_id = LLUUID::null,
+ const bool allow_no_texture = false);
+ ETextureIndex mTextureIndex;
+ const std::string mControlName;
+ const LLUUID mDefaultImageId;
+ const bool mAllowNoTexture;
+ };
+
+ struct ColorSwatchCtrls : public LLDictionary<ETextureIndex, PickerControlEntry>
+ {
+ ColorSwatchCtrls();
+ } mColorSwatchCtrls;
+
+ struct TextureCtrls : public LLDictionary<ETextureIndex, PickerControlEntry>
+ {
+ TextureCtrls();
+ } mTextureCtrls;
+
+ const PickerControlEntry* getTexturePicker(ETextureIndex index) const { return mTextureCtrls.lookup(index); }
+ const PickerControlEntry* getColorSwatch(ETextureIndex index) const { return mColorSwatchCtrls.lookup(index); }
};
LLEditWearableDictionary::LLEditWearableDictionary()
@@ -215,166 +222,174 @@ LLEditWearableDictionary::~LLEditWearableDictionary()
LLEditWearableDictionary::Wearables::Wearables()
{
- // note the subpart that is listed first is treated as "default", regardless of what order is in enum.
- // Please match the order presented in XUI. -Nyx
- // this will affect what camera angle is shown when first editing a wearable
- addEntry(LLWearableType::WT_SHAPE, new WearableEntry(LLWearableType::WT_SHAPE,"edit_shape_title","shape_desc_text",0,0,9, SUBPART_SHAPE_WHOLE, SUBPART_SHAPE_HEAD, SUBPART_SHAPE_EYES, SUBPART_SHAPE_EARS, SUBPART_SHAPE_NOSE, SUBPART_SHAPE_MOUTH, SUBPART_SHAPE_CHIN, SUBPART_SHAPE_TORSO, SUBPART_SHAPE_LEGS ));
- addEntry(LLWearableType::WT_SKIN, new WearableEntry(LLWearableType::WT_SKIN,"edit_skin_title","skin_desc_text",0,3,4, TEX_HEAD_BODYPAINT, TEX_UPPER_BODYPAINT, TEX_LOWER_BODYPAINT, SUBPART_SKIN_COLOR, SUBPART_SKIN_FACEDETAIL, SUBPART_SKIN_MAKEUP, SUBPART_SKIN_BODYDETAIL));
- addEntry(LLWearableType::WT_HAIR, new WearableEntry(LLWearableType::WT_HAIR,"edit_hair_title","hair_desc_text",0,1,4, TEX_HAIR, SUBPART_HAIR_COLOR, SUBPART_HAIR_STYLE, SUBPART_HAIR_EYEBROWS, SUBPART_HAIR_FACIAL));
- addEntry(LLWearableType::WT_EYES, new WearableEntry(LLWearableType::WT_EYES,"edit_eyes_title","eyes_desc_text",0,1,1, TEX_EYES_IRIS, SUBPART_EYES));
- addEntry(LLWearableType::WT_SHIRT, new WearableEntry(LLWearableType::WT_SHIRT,"edit_shirt_title","shirt_desc_text",1,1,1, TEX_UPPER_SHIRT, TEX_UPPER_SHIRT, SUBPART_SHIRT));
- addEntry(LLWearableType::WT_PANTS, new WearableEntry(LLWearableType::WT_PANTS,"edit_pants_title","pants_desc_text",1,1,1, TEX_LOWER_PANTS, TEX_LOWER_PANTS, SUBPART_PANTS));
- addEntry(LLWearableType::WT_SHOES, new WearableEntry(LLWearableType::WT_SHOES,"edit_shoes_title","shoes_desc_text",1,1,1, TEX_LOWER_SHOES, TEX_LOWER_SHOES, SUBPART_SHOES));
- addEntry(LLWearableType::WT_SOCKS, new WearableEntry(LLWearableType::WT_SOCKS,"edit_socks_title","socks_desc_text",1,1,1, TEX_LOWER_SOCKS, TEX_LOWER_SOCKS, SUBPART_SOCKS));
- addEntry(LLWearableType::WT_JACKET, new WearableEntry(LLWearableType::WT_JACKET,"edit_jacket_title","jacket_desc_text",1,2,1, TEX_UPPER_JACKET, TEX_UPPER_JACKET, TEX_LOWER_JACKET, SUBPART_JACKET));
- addEntry(LLWearableType::WT_GLOVES, new WearableEntry(LLWearableType::WT_GLOVES,"edit_gloves_title","gloves_desc_text",1,1,1, TEX_UPPER_GLOVES, TEX_UPPER_GLOVES, SUBPART_GLOVES));
- addEntry(LLWearableType::WT_UNDERSHIRT, new WearableEntry(LLWearableType::WT_UNDERSHIRT,"edit_undershirt_title","undershirt_desc_text",1,1,1, TEX_UPPER_UNDERSHIRT, TEX_UPPER_UNDERSHIRT, SUBPART_UNDERSHIRT));
- addEntry(LLWearableType::WT_UNDERPANTS, new WearableEntry(LLWearableType::WT_UNDERPANTS,"edit_underpants_title","underpants_desc_text",1,1,1, TEX_LOWER_UNDERPANTS, TEX_LOWER_UNDERPANTS, SUBPART_UNDERPANTS));
- addEntry(LLWearableType::WT_SKIRT, new WearableEntry(LLWearableType::WT_SKIRT,"edit_skirt_title","skirt_desc_text",1,1,1, TEX_SKIRT, TEX_SKIRT, SUBPART_SKIRT));
- addEntry(LLWearableType::WT_ALPHA, new WearableEntry(LLWearableType::WT_ALPHA,"edit_alpha_title","alpha_desc_text",0,5,1, TEX_LOWER_ALPHA, TEX_UPPER_ALPHA, TEX_HEAD_ALPHA, TEX_EYES_ALPHA, TEX_HAIR_ALPHA, SUBPART_ALPHA));
- addEntry(LLWearableType::WT_TATTOO, new WearableEntry(LLWearableType::WT_TATTOO,"edit_tattoo_title","tattoo_desc_text",1,3,1, TEX_HEAD_TATTOO, TEX_LOWER_TATTOO, TEX_UPPER_TATTOO, TEX_HEAD_TATTOO, SUBPART_TATTOO));
+ // note the subpart that is listed first is treated as "default", regardless of what order is in enum.
+ // Please match the order presented in XUI. -Nyx
+ // this will affect what camera angle is shown when first editing a wearable
+ addEntry(LLWearableType::WT_SHAPE, new WearableEntry(LLWearableType::WT_SHAPE,"edit_shape_title","shape_desc_text",0,0,9, SUBPART_SHAPE_WHOLE, SUBPART_SHAPE_HEAD, SUBPART_SHAPE_EYES, SUBPART_SHAPE_EARS, SUBPART_SHAPE_NOSE, SUBPART_SHAPE_MOUTH, SUBPART_SHAPE_CHIN, SUBPART_SHAPE_TORSO, SUBPART_SHAPE_LEGS));
+ addEntry(LLWearableType::WT_SKIN, new WearableEntry(LLWearableType::WT_SKIN,"edit_skin_title","skin_desc_text",0,3,4, TEX_HEAD_BODYPAINT, TEX_UPPER_BODYPAINT, TEX_LOWER_BODYPAINT, SUBPART_SKIN_COLOR, SUBPART_SKIN_FACEDETAIL, SUBPART_SKIN_MAKEUP, SUBPART_SKIN_BODYDETAIL));
+ addEntry(LLWearableType::WT_HAIR, new WearableEntry(LLWearableType::WT_HAIR,"edit_hair_title","hair_desc_text",0,1,4, TEX_HAIR, SUBPART_HAIR_COLOR, SUBPART_HAIR_STYLE, SUBPART_HAIR_EYEBROWS, SUBPART_HAIR_FACIAL));
+ addEntry(LLWearableType::WT_EYES, new WearableEntry(LLWearableType::WT_EYES,"edit_eyes_title","eyes_desc_text",0,1,1, TEX_EYES_IRIS, SUBPART_EYES));
+ addEntry(LLWearableType::WT_SHIRT, new WearableEntry(LLWearableType::WT_SHIRT,"edit_shirt_title","shirt_desc_text",1,1,1, TEX_UPPER_SHIRT, TEX_UPPER_SHIRT, SUBPART_SHIRT));
+ addEntry(LLWearableType::WT_PANTS, new WearableEntry(LLWearableType::WT_PANTS,"edit_pants_title","pants_desc_text",1,1,1, TEX_LOWER_PANTS, TEX_LOWER_PANTS, SUBPART_PANTS));
+ addEntry(LLWearableType::WT_SHOES, new WearableEntry(LLWearableType::WT_SHOES,"edit_shoes_title","shoes_desc_text",1,1,1, TEX_LOWER_SHOES, TEX_LOWER_SHOES, SUBPART_SHOES));
+ addEntry(LLWearableType::WT_SOCKS, new WearableEntry(LLWearableType::WT_SOCKS,"edit_socks_title","socks_desc_text",1,1,1, TEX_LOWER_SOCKS, TEX_LOWER_SOCKS, SUBPART_SOCKS));
+ addEntry(LLWearableType::WT_JACKET, new WearableEntry(LLWearableType::WT_JACKET,"edit_jacket_title","jacket_desc_text",1,2,1, TEX_UPPER_JACKET, TEX_UPPER_JACKET, TEX_LOWER_JACKET, SUBPART_JACKET));
+ addEntry(LLWearableType::WT_GLOVES, new WearableEntry(LLWearableType::WT_GLOVES,"edit_gloves_title","gloves_desc_text",1,1,1, TEX_UPPER_GLOVES, TEX_UPPER_GLOVES, SUBPART_GLOVES));
+ addEntry(LLWearableType::WT_UNDERSHIRT, new WearableEntry(LLWearableType::WT_UNDERSHIRT,"edit_undershirt_title","undershirt_desc_text",1,1,1, TEX_UPPER_UNDERSHIRT, TEX_UPPER_UNDERSHIRT, SUBPART_UNDERSHIRT));
+ addEntry(LLWearableType::WT_UNDERPANTS, new WearableEntry(LLWearableType::WT_UNDERPANTS,"edit_underpants_title","underpants_desc_text",1,1,1, TEX_LOWER_UNDERPANTS, TEX_LOWER_UNDERPANTS, SUBPART_UNDERPANTS));
+ addEntry(LLWearableType::WT_SKIRT, new WearableEntry(LLWearableType::WT_SKIRT,"edit_skirt_title","skirt_desc_text",1,1,1, TEX_SKIRT, TEX_SKIRT, SUBPART_SKIRT));
+ addEntry(LLWearableType::WT_ALPHA, new WearableEntry(LLWearableType::WT_ALPHA,"edit_alpha_title","alpha_desc_text",0,5,1, TEX_LOWER_ALPHA, TEX_UPPER_ALPHA, TEX_HEAD_ALPHA, TEX_EYES_ALPHA, TEX_HAIR_ALPHA, SUBPART_ALPHA));
+ addEntry(LLWearableType::WT_TATTOO, new WearableEntry(LLWearableType::WT_TATTOO,"edit_tattoo_title","tattoo_desc_text",1,3,1, TEX_HEAD_TATTOO, TEX_LOWER_TATTOO, TEX_UPPER_TATTOO, TEX_HEAD_TATTOO, SUBPART_TATTOO));
+ addEntry(LLWearableType::WT_PHYSICS, new WearableEntry(LLWearableType::WT_PHYSICS,"edit_physics_title","physics_desc_text",0,0,7, SUBPART_PHYSICS_BREASTS_UPDOWN, SUBPART_PHYSICS_BREASTS_INOUT, SUBPART_PHYSICS_BREASTS_LEFTRIGHT, SUBPART_PHYSICS_BELLY_UPDOWN, SUBPART_PHYSICS_BUTT_UPDOWN, SUBPART_PHYSICS_BUTT_LEFTRIGHT, SUBPART_PHYSICS_ADVANCED));
}
LLEditWearableDictionary::WearableEntry::WearableEntry(LLWearableType::EType type,
- const std::string &title,
- const std::string &desc_title,
- U8 num_color_swatches,
- U8 num_texture_pickers,
- U8 num_subparts, ... ) :
- LLDictionaryEntry(title),
- mWearableType(type),
- mTitle(title),
- mDescTitle(desc_title)
-{
- va_list argp;
- va_start(argp, num_subparts);
-
- for (U8 i = 0; i < num_color_swatches; ++i)
- {
- ETextureIndex index = (ETextureIndex)va_arg(argp,int);
- mColorSwatchCtrls.push_back(index);
- }
-
- for (U8 i = 0; i < num_texture_pickers; ++i)
- {
- ETextureIndex index = (ETextureIndex)va_arg(argp,int);
- mTextureCtrls.push_back(index);
- }
-
- for (U8 i = 0; i < num_subparts; ++i)
- {
- ESubpart part = (ESubpart)va_arg(argp,int);
- mSubparts.push_back(part);
- }
+ const std::string &title,
+ const std::string &desc_title,
+ U8 num_color_swatches,
+ U8 num_texture_pickers,
+ U8 num_subparts, ... ) :
+ LLDictionaryEntry(title),
+ mWearableType(type),
+ mTitle(title),
+ mDescTitle(desc_title)
+{
+ va_list argp;
+ va_start(argp, num_subparts);
+
+ for (U8 i = 0; i < num_color_swatches; ++i)
+ {
+ ETextureIndex index = (ETextureIndex)va_arg(argp,int);
+ mColorSwatchCtrls.push_back(index);
+ }
+
+ for (U8 i = 0; i < num_texture_pickers; ++i)
+ {
+ ETextureIndex index = (ETextureIndex)va_arg(argp,int);
+ mTextureCtrls.push_back(index);
+ }
+
+ for (U8 i = 0; i < num_subparts; ++i)
+ {
+ ESubpart part = (ESubpart)va_arg(argp,int);
+ mSubparts.push_back(part);
+ }
}
LLEditWearableDictionary::Subparts::Subparts()
{
- addEntry(SUBPART_SHAPE_WHOLE, new SubpartEntry(SUBPART_SHAPE_WHOLE, "mPelvis", "shape_body","shape_body_param_list", "shape_body_tab", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f),SEX_BOTH));
- addEntry(SUBPART_SHAPE_HEAD, new SubpartEntry(SUBPART_SHAPE_HEAD, "mHead", "shape_head", "shape_head_param_list", "shape_head_tab", LLVector3d(0.f, 0.f, 0.05f), LLVector3d(-0.5f, 0.05f, 0.07f),SEX_BOTH));
- addEntry(SUBPART_SHAPE_EYES, new SubpartEntry(SUBPART_SHAPE_EYES, "mHead", "shape_eyes", "shape_eyes_param_list", "shape_eyes_tab", LLVector3d(0.f, 0.f, 0.05f), LLVector3d(-0.5f, 0.05f, 0.07f),SEX_BOTH));
- addEntry(SUBPART_SHAPE_EARS, new SubpartEntry(SUBPART_SHAPE_EARS, "mHead", "shape_ears", "shape_ears_param_list", "shape_ears_tab", LLVector3d(0.f, 0.f, 0.05f), LLVector3d(-0.5f, 0.05f, 0.07f),SEX_BOTH));
- addEntry(SUBPART_SHAPE_NOSE, new SubpartEntry(SUBPART_SHAPE_NOSE, "mHead", "shape_nose", "shape_nose_param_list", "shape_nose_tab", LLVector3d(0.f, 0.f, 0.05f), LLVector3d(-0.5f, 0.05f, 0.07f),SEX_BOTH));
- addEntry(SUBPART_SHAPE_MOUTH, new SubpartEntry(SUBPART_SHAPE_MOUTH, "mHead", "shape_mouth", "shape_mouth_param_list", "shape_mouth_tab", LLVector3d(0.f, 0.f, 0.05f), LLVector3d(-0.5f, 0.05f, 0.07f),SEX_BOTH));
- addEntry(SUBPART_SHAPE_CHIN, new SubpartEntry(SUBPART_SHAPE_CHIN, "mHead", "shape_chin", "shape_chin_param_list", "shape_chin_tab", LLVector3d(0.f, 0.f, 0.05f), LLVector3d(-0.5f, 0.05f, 0.07f),SEX_BOTH));
- addEntry(SUBPART_SHAPE_TORSO, new SubpartEntry(SUBPART_SHAPE_TORSO, "mTorso", "shape_torso", "shape_torso_param_list", "shape_torso_tab", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(-1.f, 0.15f, 0.3f),SEX_BOTH));
- addEntry(SUBPART_SHAPE_LEGS, new SubpartEntry(SUBPART_SHAPE_LEGS, "mPelvis", "shape_legs", "shape_legs_param_list", "shape_legs_tab", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f),SEX_BOTH));
-
- addEntry(SUBPART_SKIN_COLOR, new SubpartEntry(SUBPART_SKIN_COLOR, "mHead", "skin_color", "skin_color_param_list", "skin_color_tab", LLVector3d(0.f, 0.f, 0.05f), LLVector3d(-0.5f, 0.05f, 0.07f),SEX_BOTH));
- addEntry(SUBPART_SKIN_FACEDETAIL, new SubpartEntry(SUBPART_SKIN_FACEDETAIL, "mHead", "skin_facedetail", "skin_face_param_list", "skin_face_tab", LLVector3d(0.f, 0.f, 0.05f), LLVector3d(-0.5f, 0.05f, 0.07f),SEX_BOTH));
- addEntry(SUBPART_SKIN_MAKEUP, new SubpartEntry(SUBPART_SKIN_MAKEUP, "mHead", "skin_makeup", "skin_makeup_param_list", "skin_makeup_tab", LLVector3d(0.f, 0.f, 0.05f), LLVector3d(-0.5f, 0.05f, 0.07f),SEX_BOTH));
- addEntry(SUBPART_SKIN_BODYDETAIL, new SubpartEntry(SUBPART_SKIN_BODYDETAIL, "mPelvis", "skin_bodydetail", "skin_body_param_list", "skin_body_tab", LLVector3d(0.f, 0.f, -0.2f), LLVector3d(-2.5f, 0.5f, 0.5f),SEX_BOTH));
-
- addEntry(SUBPART_HAIR_COLOR, new SubpartEntry(SUBPART_HAIR_COLOR, "mHead", "hair_color", "hair_color_param_list", "hair_color_tab", LLVector3d(0.f, 0.f, 0.10f), LLVector3d(-0.4f, 0.05f, 0.10f),SEX_BOTH));
- addEntry(SUBPART_HAIR_STYLE, new SubpartEntry(SUBPART_HAIR_STYLE, "mHead", "hair_style", "hair_style_param_list", "hair_style_tab", LLVector3d(0.f, 0.f, 0.10f), LLVector3d(-0.4f, 0.05f, 0.10f),SEX_BOTH));
- addEntry(SUBPART_HAIR_EYEBROWS, new SubpartEntry(SUBPART_HAIR_EYEBROWS, "mHead", "hair_eyebrows", "hair_eyebrows_param_list", "hair_eyebrows_tab", LLVector3d(0.f, 0.f, 0.05f), LLVector3d(-0.5f, 0.05f, 0.07f),SEX_BOTH));
- addEntry(SUBPART_HAIR_FACIAL, new SubpartEntry(SUBPART_HAIR_FACIAL, "mHead", "hair_facial", "hair_facial_param_list", "hair_facial_tab", LLVector3d(0.f, 0.f, 0.05f), LLVector3d(-0.5f, 0.05f, 0.07f),SEX_MALE));
-
- addEntry(SUBPART_EYES, new SubpartEntry(SUBPART_EYES, "mHead", "eyes", "eyes_main_param_list", "eyes_main_tab", LLVector3d(0.f, 0.f, 0.05f), LLVector3d(-0.5f, 0.05f, 0.07f),SEX_BOTH));
-
- addEntry(SUBPART_SHIRT, new SubpartEntry(SUBPART_SHIRT, "mTorso", "shirt", "shirt_main_param_list", "shirt_main_tab", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(-1.f, 0.15f, 0.3f),SEX_BOTH));
- addEntry(SUBPART_PANTS, new SubpartEntry(SUBPART_PANTS, "mPelvis", "pants", "pants_main_param_list", "pants_main_tab", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f),SEX_BOTH));
- addEntry(SUBPART_SHOES, new SubpartEntry(SUBPART_SHOES, "mPelvis", "shoes", "shoes_main_param_list", "shoes_main_tab", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f),SEX_BOTH));
- addEntry(SUBPART_SOCKS, new SubpartEntry(SUBPART_SOCKS, "mPelvis", "socks", "socks_main_param_list", "socks_main_tab", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f),SEX_BOTH));
- addEntry(SUBPART_JACKET, new SubpartEntry(SUBPART_JACKET, "mTorso", "jacket", "jacket_main_param_list", "jacket_main_tab", LLVector3d(0.f, 0.f, 0.f), LLVector3d(-2.f, 0.1f, 0.3f),SEX_BOTH));
- addEntry(SUBPART_SKIRT, new SubpartEntry(SUBPART_SKIRT, "mPelvis", "skirt", "skirt_main_param_list", "skirt_main_tab", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f),SEX_BOTH));
- addEntry(SUBPART_GLOVES, new SubpartEntry(SUBPART_GLOVES, "mTorso", "gloves", "gloves_main_param_list", "gloves_main_tab", LLVector3d(0.f, 0.f, 0.f), LLVector3d(-1.f, 0.15f, 0.f),SEX_BOTH));
- addEntry(SUBPART_UNDERSHIRT, new SubpartEntry(SUBPART_UNDERSHIRT, "mTorso", "undershirt", "undershirt_main_param_list", "undershirt_main_tab", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(-1.f, 0.15f, 0.3f),SEX_BOTH));
- addEntry(SUBPART_UNDERPANTS, new SubpartEntry(SUBPART_UNDERPANTS, "mPelvis", "underpants", "underpants_main_param_list", "underpants_main_tab", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f),SEX_BOTH));
- addEntry(SUBPART_ALPHA, new SubpartEntry(SUBPART_ALPHA, "mPelvis", "alpha", "alpha_main_param_list", "alpha_main_tab", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f),SEX_BOTH));
- addEntry(SUBPART_TATTOO, new SubpartEntry(SUBPART_TATTOO, "mPelvis", "tattoo", "tattoo_main_param_list", "tattoo_main_tab", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f),SEX_BOTH));
+ addEntry(SUBPART_SHAPE_WHOLE, new SubpartEntry(SUBPART_SHAPE_WHOLE, "mPelvis", "shape_body","shape_body_param_list", "shape_body_tab", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f),SEX_BOTH));
+ addEntry(SUBPART_SHAPE_HEAD, new SubpartEntry(SUBPART_SHAPE_HEAD, "mHead", "shape_head", "shape_head_param_list", "shape_head_tab", LLVector3d(0.f, 0.f, 0.05f), LLVector3d(-0.5f, 0.05f, 0.07f),SEX_BOTH));
+ addEntry(SUBPART_SHAPE_EYES, new SubpartEntry(SUBPART_SHAPE_EYES, "mHead", "shape_eyes", "shape_eyes_param_list", "shape_eyes_tab", LLVector3d(0.f, 0.f, 0.05f), LLVector3d(-0.5f, 0.05f, 0.07f),SEX_BOTH));
+ addEntry(SUBPART_SHAPE_EARS, new SubpartEntry(SUBPART_SHAPE_EARS, "mHead", "shape_ears", "shape_ears_param_list", "shape_ears_tab", LLVector3d(0.f, 0.f, 0.05f), LLVector3d(-0.5f, 0.05f, 0.07f),SEX_BOTH));
+ addEntry(SUBPART_SHAPE_NOSE, new SubpartEntry(SUBPART_SHAPE_NOSE, "mHead", "shape_nose", "shape_nose_param_list", "shape_nose_tab", LLVector3d(0.f, 0.f, 0.05f), LLVector3d(-0.5f, 0.05f, 0.07f),SEX_BOTH));
+ addEntry(SUBPART_SHAPE_MOUTH, new SubpartEntry(SUBPART_SHAPE_MOUTH, "mHead", "shape_mouth", "shape_mouth_param_list", "shape_mouth_tab", LLVector3d(0.f, 0.f, 0.05f), LLVector3d(-0.5f, 0.05f, 0.07f),SEX_BOTH));
+ addEntry(SUBPART_SHAPE_CHIN, new SubpartEntry(SUBPART_SHAPE_CHIN, "mHead", "shape_chin", "shape_chin_param_list", "shape_chin_tab", LLVector3d(0.f, 0.f, 0.05f), LLVector3d(-0.5f, 0.05f, 0.07f),SEX_BOTH));
+ addEntry(SUBPART_SHAPE_TORSO, new SubpartEntry(SUBPART_SHAPE_TORSO, "mTorso", "shape_torso", "shape_torso_param_list", "shape_torso_tab", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(-1.f, 0.15f, 0.3f),SEX_BOTH));
+ addEntry(SUBPART_SHAPE_LEGS, new SubpartEntry(SUBPART_SHAPE_LEGS, "mPelvis", "shape_legs", "shape_legs_param_list", "shape_legs_tab", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f),SEX_BOTH));
+
+ addEntry(SUBPART_SKIN_COLOR, new SubpartEntry(SUBPART_SKIN_COLOR, "mHead", "skin_color", "skin_color_param_list", "skin_color_tab", LLVector3d(0.f, 0.f, 0.05f), LLVector3d(-0.5f, 0.05f, 0.07f),SEX_BOTH));
+ addEntry(SUBPART_SKIN_FACEDETAIL, new SubpartEntry(SUBPART_SKIN_FACEDETAIL, "mHead", "skin_facedetail", "skin_face_param_list", "skin_face_tab", LLVector3d(0.f, 0.f, 0.05f), LLVector3d(-0.5f, 0.05f, 0.07f),SEX_BOTH));
+ addEntry(SUBPART_SKIN_MAKEUP, new SubpartEntry(SUBPART_SKIN_MAKEUP, "mHead", "skin_makeup", "skin_makeup_param_list", "skin_makeup_tab", LLVector3d(0.f, 0.f, 0.05f), LLVector3d(-0.5f, 0.05f, 0.07f),SEX_BOTH));
+ addEntry(SUBPART_SKIN_BODYDETAIL, new SubpartEntry(SUBPART_SKIN_BODYDETAIL, "mPelvis", "skin_bodydetail", "skin_body_param_list", "skin_body_tab", LLVector3d(0.f, 0.f, -0.2f), LLVector3d(-2.5f, 0.5f, 0.5f),SEX_BOTH));
+
+ addEntry(SUBPART_HAIR_COLOR, new SubpartEntry(SUBPART_HAIR_COLOR, "mHead", "hair_color", "hair_color_param_list", "hair_color_tab", LLVector3d(0.f, 0.f, 0.10f), LLVector3d(-0.4f, 0.05f, 0.10f),SEX_BOTH));
+ addEntry(SUBPART_HAIR_STYLE, new SubpartEntry(SUBPART_HAIR_STYLE, "mHead", "hair_style", "hair_style_param_list", "hair_style_tab", LLVector3d(0.f, 0.f, 0.10f), LLVector3d(-0.4f, 0.05f, 0.10f),SEX_BOTH));
+ addEntry(SUBPART_HAIR_EYEBROWS, new SubpartEntry(SUBPART_HAIR_EYEBROWS, "mHead", "hair_eyebrows", "hair_eyebrows_param_list", "hair_eyebrows_tab", LLVector3d(0.f, 0.f, 0.05f), LLVector3d(-0.5f, 0.05f, 0.07f),SEX_BOTH));
+ addEntry(SUBPART_HAIR_FACIAL, new SubpartEntry(SUBPART_HAIR_FACIAL, "mHead", "hair_facial", "hair_facial_param_list", "hair_facial_tab", LLVector3d(0.f, 0.f, 0.05f), LLVector3d(-0.5f, 0.05f, 0.07f),SEX_MALE));
+
+ addEntry(SUBPART_EYES, new SubpartEntry(SUBPART_EYES, "mHead", "eyes", "eyes_main_param_list", "eyes_main_tab", LLVector3d(0.f, 0.f, 0.05f), LLVector3d(-0.5f, 0.05f, 0.07f),SEX_BOTH));
+
+ addEntry(SUBPART_SHIRT, new SubpartEntry(SUBPART_SHIRT, "mTorso", "shirt", "shirt_main_param_list", "shirt_main_tab", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(-1.f, 0.15f, 0.3f),SEX_BOTH));
+ addEntry(SUBPART_PANTS, new SubpartEntry(SUBPART_PANTS, "mPelvis", "pants", "pants_main_param_list", "pants_main_tab", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f),SEX_BOTH));
+ addEntry(SUBPART_SHOES, new SubpartEntry(SUBPART_SHOES, "mPelvis", "shoes", "shoes_main_param_list", "shoes_main_tab", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f),SEX_BOTH));
+ addEntry(SUBPART_SOCKS, new SubpartEntry(SUBPART_SOCKS, "mPelvis", "socks", "socks_main_param_list", "socks_main_tab", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f),SEX_BOTH));
+ addEntry(SUBPART_JACKET, new SubpartEntry(SUBPART_JACKET, "mTorso", "jacket", "jacket_main_param_list", "jacket_main_tab", LLVector3d(0.f, 0.f, 0.f), LLVector3d(-2.f, 0.1f, 0.3f),SEX_BOTH));
+ addEntry(SUBPART_SKIRT, new SubpartEntry(SUBPART_SKIRT, "mPelvis", "skirt", "skirt_main_param_list", "skirt_main_tab", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f),SEX_BOTH));
+ addEntry(SUBPART_GLOVES, new SubpartEntry(SUBPART_GLOVES, "mTorso", "gloves", "gloves_main_param_list", "gloves_main_tab", LLVector3d(0.f, 0.f, 0.f), LLVector3d(-1.f, 0.15f, 0.f),SEX_BOTH));
+ addEntry(SUBPART_UNDERSHIRT, new SubpartEntry(SUBPART_UNDERSHIRT, "mTorso", "undershirt", "undershirt_main_param_list", "undershirt_main_tab", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(-1.f, 0.15f, 0.3f),SEX_BOTH));
+ addEntry(SUBPART_UNDERPANTS, new SubpartEntry(SUBPART_UNDERPANTS, "mPelvis", "underpants", "underpants_main_param_list", "underpants_main_tab", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f),SEX_BOTH));
+ addEntry(SUBPART_ALPHA, new SubpartEntry(SUBPART_ALPHA, "mPelvis", "alpha", "alpha_main_param_list", "alpha_main_tab", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f),SEX_BOTH));
+ addEntry(SUBPART_TATTOO, new SubpartEntry(SUBPART_TATTOO, "mPelvis", "tattoo", "tattoo_main_param_list", "tattoo_main_tab", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f),SEX_BOTH));
+ addEntry(SUBPART_PHYSICS_BREASTS_UPDOWN, new SubpartEntry(SUBPART_PHYSICS_BREASTS_UPDOWN, "mTorso", "physics_breasts_updown", "physics_breasts_updown_param_list", "physics_breasts_updown_tab", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(0.f, 0.f, 0.f),SEX_FEMALE));
+ addEntry(SUBPART_PHYSICS_BREASTS_INOUT, new SubpartEntry(SUBPART_PHYSICS_BREASTS_INOUT, "mTorso", "physics_breasts_inout", "physics_breasts_inout_param_list", "physics_breasts_inout_tab", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(0.f, 0.f, 0.f),SEX_FEMALE));
+ addEntry(SUBPART_PHYSICS_BREASTS_LEFTRIGHT, new SubpartEntry(SUBPART_PHYSICS_BREASTS_LEFTRIGHT, "mTorso", "physics_breasts_leftright", "physics_breasts_leftright_param_list", "physics_breasts_leftright_tab", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(0.f, 0.f, 0.f),SEX_FEMALE));
+ addEntry(SUBPART_PHYSICS_BELLY_UPDOWN, new SubpartEntry(SUBPART_PHYSICS_BELLY_UPDOWN, "mTorso", "physics_belly_updown", "physics_belly_updown_param_list", "physics_belly_updown_tab", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(0.f, 0.f, 0.f),SEX_BOTH));
+ addEntry(SUBPART_PHYSICS_BUTT_UPDOWN, new SubpartEntry(SUBPART_PHYSICS_BUTT_UPDOWN, "mTorso", "physics_butt_updown", "physics_butt_updown_param_list", "physics_butt_updown_tab", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(0.f, 0.f, 0.f),SEX_BOTH));
+ addEntry(SUBPART_PHYSICS_BUTT_LEFTRIGHT, new SubpartEntry(SUBPART_PHYSICS_BUTT_LEFTRIGHT, "mTorso", "physics_butt_leftright", "physics_butt_leftright_param_list", "physics_butt_leftright_tab", LLVector3d(0.f, 0.f, 0.f), LLVector3d(0.f, 0.f, 0.f),SEX_BOTH));
+ addEntry(SUBPART_PHYSICS_ADVANCED, new SubpartEntry(SUBPART_PHYSICS_ADVANCED, "mTorso", "physics_advanced", "physics_advanced_param_list", "physics_advanced_tab", LLVector3d(0.f, 0.f, 0.f), LLVector3d(0.f, 0.f, 0.f),SEX_BOTH));
}
LLEditWearableDictionary::SubpartEntry::SubpartEntry(ESubpart part,
- const std::string &joint,
- const std::string &edit_group,
- const std::string &param_list,
- const std::string &accordion_tab,
- const LLVector3d &target_offset,
- const LLVector3d &camera_offset,
- const ESex &sex) :
- LLDictionaryEntry(edit_group),
- mSubpart(part),
- mTargetJoint(joint),
- mEditGroup(edit_group),
- mParamList(param_list),
- mAccordionTab(accordion_tab),
- mTargetOffset(target_offset),
- mCameraOffset(camera_offset),
- mSex(sex)
+ const std::string &joint,
+ const std::string &edit_group,
+ const std::string &param_list,
+ const std::string &accordion_tab,
+ const LLVector3d &target_offset,
+ const LLVector3d &camera_offset,
+ const ESex &sex) :
+ LLDictionaryEntry(edit_group),
+ mSubpart(part),
+ mTargetJoint(joint),
+ mEditGroup(edit_group),
+ mParamList(param_list),
+ mAccordionTab(accordion_tab),
+ mTargetOffset(target_offset),
+ mCameraOffset(camera_offset),
+ mSex(sex)
{
}
LLEditWearableDictionary::ColorSwatchCtrls::ColorSwatchCtrls()
{
- addEntry ( TEX_UPPER_SHIRT, new PickerControlEntry (TEX_UPPER_SHIRT, "Color/Tint" ));
- addEntry ( TEX_LOWER_PANTS, new PickerControlEntry (TEX_LOWER_PANTS, "Color/Tint" ));
- addEntry ( TEX_LOWER_SHOES, new PickerControlEntry (TEX_LOWER_SHOES, "Color/Tint" ));
- addEntry ( TEX_LOWER_SOCKS, new PickerControlEntry (TEX_LOWER_SOCKS, "Color/Tint" ));
- addEntry ( TEX_UPPER_JACKET, new PickerControlEntry (TEX_UPPER_JACKET, "Color/Tint" ));
- addEntry ( TEX_SKIRT, new PickerControlEntry (TEX_SKIRT, "Color/Tint" ));
- addEntry ( TEX_UPPER_GLOVES, new PickerControlEntry (TEX_UPPER_GLOVES, "Color/Tint" ));
- addEntry ( TEX_UPPER_UNDERSHIRT, new PickerControlEntry (TEX_UPPER_UNDERSHIRT, "Color/Tint" ));
- addEntry ( TEX_LOWER_UNDERPANTS, new PickerControlEntry (TEX_LOWER_UNDERPANTS, "Color/Tint" ));
- addEntry ( TEX_HEAD_TATTOO, new PickerControlEntry(TEX_HEAD_TATTOO, "Color/Tint" ));
+ addEntry ( TEX_UPPER_SHIRT, new PickerControlEntry (TEX_UPPER_SHIRT, "Color/Tint" ));
+ addEntry ( TEX_LOWER_PANTS, new PickerControlEntry (TEX_LOWER_PANTS, "Color/Tint" ));
+ addEntry ( TEX_LOWER_SHOES, new PickerControlEntry (TEX_LOWER_SHOES, "Color/Tint" ));
+ addEntry ( TEX_LOWER_SOCKS, new PickerControlEntry (TEX_LOWER_SOCKS, "Color/Tint" ));
+ addEntry ( TEX_UPPER_JACKET, new PickerControlEntry (TEX_UPPER_JACKET, "Color/Tint" ));
+ addEntry ( TEX_SKIRT, new PickerControlEntry (TEX_SKIRT, "Color/Tint" ));
+ addEntry ( TEX_UPPER_GLOVES, new PickerControlEntry (TEX_UPPER_GLOVES, "Color/Tint" ));
+ addEntry ( TEX_UPPER_UNDERSHIRT, new PickerControlEntry (TEX_UPPER_UNDERSHIRT, "Color/Tint" ));
+ addEntry ( TEX_LOWER_UNDERPANTS, new PickerControlEntry (TEX_LOWER_UNDERPANTS, "Color/Tint" ));
+ addEntry ( TEX_HEAD_TATTOO, new PickerControlEntry(TEX_HEAD_TATTOO, "Color/Tint" ));
}
LLEditWearableDictionary::TextureCtrls::TextureCtrls()
{
- addEntry ( TEX_HEAD_BODYPAINT, new PickerControlEntry (TEX_HEAD_BODYPAINT, "Head Tattoos", LLUUID::null, TRUE ));
- addEntry ( TEX_UPPER_BODYPAINT, new PickerControlEntry (TEX_UPPER_BODYPAINT, "Upper Tattoos", LLUUID::null, TRUE ));
- addEntry ( TEX_LOWER_BODYPAINT, new PickerControlEntry (TEX_LOWER_BODYPAINT, "Lower Tattoos", LLUUID::null, TRUE ));
- addEntry ( TEX_HAIR, new PickerControlEntry (TEX_HAIR, "Texture", LLUUID( gSavedSettings.getString( "UIImgDefaultHairUUID" ) ), FALSE ));
- addEntry ( TEX_EYES_IRIS, new PickerControlEntry (TEX_EYES_IRIS, "Iris", LLUUID( gSavedSettings.getString( "UIImgDefaultEyesUUID" ) ), FALSE ));
- addEntry ( TEX_UPPER_SHIRT, new PickerControlEntry (TEX_UPPER_SHIRT, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultShirtUUID" ) ), FALSE ));
- addEntry ( TEX_LOWER_PANTS, new PickerControlEntry (TEX_LOWER_PANTS, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultPantsUUID" ) ), FALSE ));
- addEntry ( TEX_LOWER_SHOES, new PickerControlEntry (TEX_LOWER_SHOES, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultShoesUUID" ) ), FALSE ));
- addEntry ( TEX_LOWER_SOCKS, new PickerControlEntry (TEX_LOWER_SOCKS, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultSocksUUID" ) ), FALSE ));
- addEntry ( TEX_UPPER_JACKET, new PickerControlEntry (TEX_UPPER_JACKET, "Upper Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultJacketUUID" ) ), FALSE ));
- addEntry ( TEX_LOWER_JACKET, new PickerControlEntry (TEX_LOWER_JACKET, "Lower Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultJacketUUID" ) ), FALSE ));
- addEntry ( TEX_SKIRT, new PickerControlEntry (TEX_SKIRT, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultSkirtUUID" ) ), FALSE ));
- addEntry ( TEX_UPPER_GLOVES, new PickerControlEntry (TEX_UPPER_GLOVES, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultGlovesUUID" ) ), FALSE ));
- addEntry ( TEX_UPPER_UNDERSHIRT, new PickerControlEntry (TEX_UPPER_UNDERSHIRT, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultUnderwearUUID" ) ), FALSE ));
- addEntry ( TEX_LOWER_UNDERPANTS, new PickerControlEntry (TEX_LOWER_UNDERPANTS, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultUnderwearUUID" ) ), FALSE ));
- addEntry ( TEX_LOWER_ALPHA, new PickerControlEntry (TEX_LOWER_ALPHA, "Lower Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE ));
- addEntry ( TEX_UPPER_ALPHA, new PickerControlEntry (TEX_UPPER_ALPHA, "Upper Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE ));
- addEntry ( TEX_HEAD_ALPHA, new PickerControlEntry (TEX_HEAD_ALPHA, "Head Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE ));
- addEntry ( TEX_EYES_ALPHA, new PickerControlEntry (TEX_EYES_ALPHA, "Eye Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE ));
- addEntry ( TEX_HAIR_ALPHA, new PickerControlEntry (TEX_HAIR_ALPHA, "Hair Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE ));
- addEntry ( TEX_LOWER_TATTOO, new PickerControlEntry (TEX_LOWER_TATTOO, "Lower Tattoo", LLUUID::null, TRUE ));
- addEntry ( TEX_UPPER_TATTOO, new PickerControlEntry (TEX_UPPER_TATTOO, "Upper Tattoo", LLUUID::null, TRUE ));
- addEntry ( TEX_HEAD_TATTOO, new PickerControlEntry (TEX_HEAD_TATTOO, "Head Tattoo", LLUUID::null, TRUE ));
+ addEntry ( TEX_HEAD_BODYPAINT, new PickerControlEntry (TEX_HEAD_BODYPAINT, "Head Tattoos", LLUUID::null, TRUE ));
+ addEntry ( TEX_UPPER_BODYPAINT, new PickerControlEntry (TEX_UPPER_BODYPAINT, "Upper Tattoos", LLUUID::null, TRUE ));
+ addEntry ( TEX_LOWER_BODYPAINT, new PickerControlEntry (TEX_LOWER_BODYPAINT, "Lower Tattoos", LLUUID::null, TRUE ));
+ addEntry ( TEX_HAIR, new PickerControlEntry (TEX_HAIR, "Texture", LLUUID( gSavedSettings.getString( "UIImgDefaultHairUUID" ) ), FALSE ));
+ addEntry ( TEX_EYES_IRIS, new PickerControlEntry (TEX_EYES_IRIS, "Iris", LLUUID( gSavedSettings.getString( "UIImgDefaultEyesUUID" ) ), FALSE ));
+ addEntry ( TEX_UPPER_SHIRT, new PickerControlEntry (TEX_UPPER_SHIRT, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultShirtUUID" ) ), FALSE ));
+ addEntry ( TEX_LOWER_PANTS, new PickerControlEntry (TEX_LOWER_PANTS, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultPantsUUID" ) ), FALSE ));
+ addEntry ( TEX_LOWER_SHOES, new PickerControlEntry (TEX_LOWER_SHOES, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultShoesUUID" ) ), FALSE ));
+ addEntry ( TEX_LOWER_SOCKS, new PickerControlEntry (TEX_LOWER_SOCKS, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultSocksUUID" ) ), FALSE ));
+ addEntry ( TEX_UPPER_JACKET, new PickerControlEntry (TEX_UPPER_JACKET, "Upper Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultJacketUUID" ) ), FALSE ));
+ addEntry ( TEX_LOWER_JACKET, new PickerControlEntry (TEX_LOWER_JACKET, "Lower Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultJacketUUID" ) ), FALSE ));
+ addEntry ( TEX_SKIRT, new PickerControlEntry (TEX_SKIRT, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultSkirtUUID" ) ), FALSE ));
+ addEntry ( TEX_UPPER_GLOVES, new PickerControlEntry (TEX_UPPER_GLOVES, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultGlovesUUID" ) ), FALSE ));
+ addEntry ( TEX_UPPER_UNDERSHIRT, new PickerControlEntry (TEX_UPPER_UNDERSHIRT, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultUnderwearUUID" ) ), FALSE ));
+ addEntry ( TEX_LOWER_UNDERPANTS, new PickerControlEntry (TEX_LOWER_UNDERPANTS, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultUnderwearUUID" ) ), FALSE ));
+ addEntry ( TEX_LOWER_ALPHA, new PickerControlEntry (TEX_LOWER_ALPHA, "Lower Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE ));
+ addEntry ( TEX_UPPER_ALPHA, new PickerControlEntry (TEX_UPPER_ALPHA, "Upper Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE ));
+ addEntry ( TEX_HEAD_ALPHA, new PickerControlEntry (TEX_HEAD_ALPHA, "Head Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE ));
+ addEntry ( TEX_EYES_ALPHA, new PickerControlEntry (TEX_EYES_ALPHA, "Eye Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE ));
+ addEntry ( TEX_HAIR_ALPHA, new PickerControlEntry (TEX_HAIR_ALPHA, "Hair Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE ));
+ addEntry ( TEX_LOWER_TATTOO, new PickerControlEntry (TEX_LOWER_TATTOO, "Lower Tattoo", LLUUID::null, TRUE ));
+ addEntry ( TEX_UPPER_TATTOO, new PickerControlEntry (TEX_UPPER_TATTOO, "Upper Tattoo", LLUUID::null, TRUE ));
+ addEntry ( TEX_HEAD_TATTOO, new PickerControlEntry (TEX_HEAD_TATTOO, "Head Tattoo", LLUUID::null, TRUE ));
}
LLEditWearableDictionary::PickerControlEntry::PickerControlEntry(ETextureIndex tex_index,
- const std::string name,
- const LLUUID default_image_id,
- const bool allow_no_texture) :
- LLDictionaryEntry(name),
- mTextureIndex(tex_index),
- mControlName(name),
- mDefaultImageId(default_image_id),
- mAllowNoTexture(allow_no_texture)
+ const std::string name,
+ const LLUUID default_image_id,
+ const bool allow_no_texture) :
+ LLDictionaryEntry(name),
+ mTextureIndex(tex_index),
+ mControlName(name),
+ mDefaultImageId(default_image_id),
+ mAllowNoTexture(allow_no_texture)
{
}
@@ -384,13 +399,13 @@ LLEditWearableDictionary::PickerControlEntry::PickerControlEntry(ETextureIndex t
class LLLabledBackButton : public LLButton
{
public:
- struct Params : public LLInitParam::Block<Params, LLButton::Params>
- {
- Params() {}
- };
+ struct Params : public LLInitParam::Block<Params, LLButton::Params>
+ {
+ Params() {}
+ };
protected:
- friend class LLUICtrlFactory;
- LLLabledBackButton(const Params&);
+ friend class LLUICtrlFactory;
+ LLLabledBackButton(const Params&);
};
static LLDefaultChildRegistry::Register<LLLabledBackButton> labeled_back_btn("labeled_back_button");
@@ -398,9 +413,9 @@ static LLDefaultChildRegistry::Register<LLLabledBackButton> labeled_back_btn("la
LLLabledBackButton::LLLabledBackButton(const Params& params)
: LLButton(params)
{
- // override hack in LLButton's constructor to use paddings have been set in xml
- setLeftHPad(params.pad_left);
- setRightHPad(params.pad_right);
+ // override hack in LLButton's constructor to use paddings have been set in xml
+ setLeftHPad(params.pad_left);
+ setRightHPad(params.pad_right);
}
// Helper functions.
@@ -421,13 +436,13 @@ typedef boost::function<void(LLPanel* panel, const LLEditWearableDictionary::Pic
typedef struct PickerControlEntryNamePredicate
{
- PickerControlEntryNamePredicate(const std::string name) : mName (name) {};
- bool operator()(const LLEditWearableDictionary::PickerControlEntry* entry) const
- {
- return (entry && entry->mName == mName);
- }
+ PickerControlEntryNamePredicate(const std::string name) : mName (name) {};
+ bool operator()(const LLEditWearableDictionary::PickerControlEntry* entry) const
+ {
+ return (entry && entry->mName == mName);
+ }
private:
- const std::string mName;
+ const std::string mName;
} PickerControlEntryNamePredicate;
// A full specialization of get_pickers_indexes for LLColorSwatchCtrl
@@ -435,12 +450,12 @@ template <>
const texture_vec_t&
get_pickers_indexes<LLColorSwatchCtrl> (const LLEditWearableDictionary::WearableEntry *wearable_entry)
{
- if (!wearable_entry)
- {
- llwarns << "could not get LLColorSwatchCtrl indexes for null wearable entry." << llendl;
- return null_texture_vec;
- }
- return wearable_entry->mColorSwatchCtrls;
+ if (!wearable_entry)
+ {
+ llwarns << "could not get LLColorSwatchCtrl indexes for null wearable entry." << llendl;
+ return null_texture_vec;
+ }
+ return wearable_entry->mColorSwatchCtrls;
}
// A full specialization of get_pickers_indexes for LLTextureCtrl
@@ -448,12 +463,12 @@ template <>
const texture_vec_t&
get_pickers_indexes<LLTextureCtrl> (const LLEditWearableDictionary::WearableEntry *wearable_entry)
{
- if (!wearable_entry)
- {
- llwarns << "could not get LLTextureCtrl indexes for null wearable entry." << llendl;
- return null_texture_vec;
- }
- return wearable_entry->mTextureCtrls;
+ if (!wearable_entry)
+ {
+ llwarns << "could not get LLTextureCtrl indexes for null wearable entry." << llendl;
+ return null_texture_vec;
+ }
+ return wearable_entry->mTextureCtrls;
}
// A full specialization of get_picker_entry for LLColorSwatchCtrl
@@ -461,7 +476,7 @@ template <>
const LLEditWearableDictionary::PickerControlEntry*
get_picker_entry<LLColorSwatchCtrl> (const ETextureIndex index)
{
- return LLEditWearableDictionary::getInstance()->getColorSwatch(index);
+ return LLEditWearableDictionary::getInstance()->getColorSwatch(index);
}
// A full specialization of get_picker_entry for LLTextureCtrl
@@ -469,161 +484,162 @@ template <>
const LLEditWearableDictionary::PickerControlEntry*
get_picker_entry<LLTextureCtrl> (const ETextureIndex index)
{
- return LLEditWearableDictionary::getInstance()->getTexturePicker(index);
+ return LLEditWearableDictionary::getInstance()->getTexturePicker(index);
}
template <typename CtrlType, class Predicate>
const LLEditWearableDictionary::PickerControlEntry*
find_picker_ctrl_entry_if(LLWearableType::EType type, const Predicate pred)
{
- const LLEditWearableDictionary::WearableEntry *wearable_entry
- = LLEditWearableDictionary::getInstance()->getWearable(type);
- if (!wearable_entry)
- {
- llwarns << "could not get wearable dictionary entry for wearable of type: " << type << llendl;
- return NULL;
- }
- const texture_vec_t& indexes = get_pickers_indexes<CtrlType>(wearable_entry);
- for (texture_vec_t::const_iterator
- iter = indexes.begin(),
- iter_end = indexes.end();
- iter != iter_end; ++iter)
- {
- const ETextureIndex te = *iter;
- const LLEditWearableDictionary::PickerControlEntry* entry
- = get_picker_entry<CtrlType>(te);
- if (!entry)
- {
- llwarns << "could not get picker dictionary entry (" << te << ") for wearable of type: " << type << llendl;
- continue;
- }
- if (pred(entry))
- {
- return entry;
- }
- }
- return NULL;
+ const LLEditWearableDictionary::WearableEntry *wearable_entry
+ = LLEditWearableDictionary::getInstance()->getWearable(type);
+ if (!wearable_entry)
+ {
+ llwarns << "could not get wearable dictionary entry for wearable of type: " << type << llendl;
+ return NULL;
+ }
+ const texture_vec_t& indexes = get_pickers_indexes<CtrlType>(wearable_entry);
+ for (texture_vec_t::const_iterator
+ iter = indexes.begin(),
+ iter_end = indexes.end();
+ iter != iter_end; ++iter)
+ {
+ const ETextureIndex te = *iter;
+ const LLEditWearableDictionary::PickerControlEntry* entry
+ = get_picker_entry<CtrlType>(te);
+ if (!entry)
+ {
+ llwarns << "could not get picker dictionary entry (" << te << ") for wearable of type: " << type << llendl;
+ continue;
+ }
+ if (pred(entry))
+ {
+ return entry;
+ }
+ }
+ return NULL;
}
template <typename CtrlType>
void
for_each_picker_ctrl_entry(LLPanel* panel, LLWearableType::EType type, function_t fun)
{
- if (!panel)
- {
- llwarns << "the panel wasn't passed for wearable of type: " << type << llendl;
- return;
- }
- const LLEditWearableDictionary::WearableEntry *wearable_entry
- = LLEditWearableDictionary::getInstance()->getWearable(type);
- if (!wearable_entry)
- {
- llwarns << "could not get wearable dictionary entry for wearable of type: " << type << llendl;
- return;
- }
- const texture_vec_t& indexes = get_pickers_indexes<CtrlType>(wearable_entry);
- for (texture_vec_t::const_iterator
- iter = indexes.begin(),
- iter_end = indexes.end();
- iter != iter_end; ++iter)
- {
- const ETextureIndex te = *iter;
- const LLEditWearableDictionary::PickerControlEntry* entry
- = get_picker_entry<CtrlType>(te);
- if (!entry)
- {
- llwarns << "could not get picker dictionary entry (" << te << ") for wearable of type: " << type << llendl;
- continue;
- }
- fun (panel, entry);
- }
+ if (!panel)
+ {
+ llwarns << "the panel wasn't passed for wearable of type: " << type << llendl;
+ return;
+ }
+ const LLEditWearableDictionary::WearableEntry *wearable_entry
+ = LLEditWearableDictionary::getInstance()->getWearable(type);
+ if (!wearable_entry)
+ {
+ llwarns << "could not get wearable dictionary entry for wearable of type: " << type << llendl;
+ return;
+ }
+ const texture_vec_t& indexes = get_pickers_indexes<CtrlType>(wearable_entry);
+ for (texture_vec_t::const_iterator
+ iter = indexes.begin(),
+ iter_end = indexes.end();
+ iter != iter_end; ++iter)
+ {
+ const ETextureIndex te = *iter;
+ const LLEditWearableDictionary::PickerControlEntry* entry
+ = get_picker_entry<CtrlType>(te);
+ if (!entry)
+ {
+ llwarns << "could not get picker dictionary entry (" << te << ") for wearable of type: " << type << llendl;
+ continue;
+ }
+ fun (panel, entry);
+ }
}
// The helper functions for pickers management
static void init_color_swatch_ctrl(LLPanelEditWearable* self, LLPanel* panel, const LLEditWearableDictionary::PickerControlEntry* entry)
{
- LLColorSwatchCtrl* color_swatch_ctrl = panel->getChild<LLColorSwatchCtrl>(entry->mControlName);
- if (color_swatch_ctrl)
- {
- // Can't get the color from the wearable here, since the wearable may not be set when this is called.
- color_swatch_ctrl->setOriginal(LLColor4::white);
- }
+ LLColorSwatchCtrl* color_swatch_ctrl = panel->getChild<LLColorSwatchCtrl>(entry->mControlName);
+ if (color_swatch_ctrl)
+ {
+ // Can't get the color from the wearable here, since the wearable may not be set when this is called.
+ color_swatch_ctrl->setOriginal(LLColor4::white);
+ }
}
static void init_texture_ctrl(LLPanelEditWearable* self, LLPanel* panel, const LLEditWearableDictionary::PickerControlEntry* entry)
{
- LLTextureCtrl* texture_ctrl = panel->getChild<LLTextureCtrl>(entry->mControlName);
- if (texture_ctrl)
- {
- texture_ctrl->setDefaultImageAssetID(entry->mDefaultImageId);
- texture_ctrl->setAllowNoTexture(entry->mAllowNoTexture);
- // Don't allow (no copy) or (notransfer) textures to be selected.
- texture_ctrl->setImmediateFilterPermMask(PERM_NONE);
- texture_ctrl->setNonImmediateFilterPermMask(PERM_NONE);
- }
+ LLTextureCtrl* texture_ctrl = panel->getChild<LLTextureCtrl>(entry->mControlName);
+ if (texture_ctrl)
+ {
+ texture_ctrl->setDefaultImageAssetID(entry->mDefaultImageId);
+ texture_ctrl->setAllowNoTexture(entry->mAllowNoTexture);
+ // Don't allow (no copy) or (notransfer) textures to be selected.
+ texture_ctrl->setImmediateFilterPermMask(PERM_NONE);
+ texture_ctrl->setNonImmediateFilterPermMask(PERM_NONE);
+ }
}
static void update_color_swatch_ctrl(LLPanelEditWearable* self, LLPanel* panel, const LLEditWearableDictionary::PickerControlEntry* entry)
{
- LLColorSwatchCtrl* color_swatch_ctrl = panel->getChild<LLColorSwatchCtrl>(entry->mControlName);
- if (color_swatch_ctrl)
- {
- color_swatch_ctrl->set(self->getWearable()->getClothesColor(entry->mTextureIndex));
- }
+ LLColorSwatchCtrl* color_swatch_ctrl = panel->getChild<LLColorSwatchCtrl>(entry->mControlName);
+ if (color_swatch_ctrl)
+ {
+ color_swatch_ctrl->set(self->getWearable()->getClothesColor(entry->mTextureIndex));
+ color_swatch_ctrl->closeFloaterColorPicker();
+ }
}
static void update_texture_ctrl(LLPanelEditWearable* self, LLPanel* panel, const LLEditWearableDictionary::PickerControlEntry* entry)
{
- LLTextureCtrl* texture_ctrl = panel->getChild<LLTextureCtrl>(entry->mControlName);
- if (texture_ctrl)
- {
- LLUUID new_id;
- LLLocalTextureObject *lto = self->getWearable()->getLocalTextureObject(entry->mTextureIndex);
- if( lto && (lto->getID() != IMG_DEFAULT_AVATAR) )
- {
- new_id = lto->getID();
- }
- else
- {
- new_id = LLUUID::null;
- }
- LLUUID old_id = texture_ctrl->getImageAssetID();
- if (old_id != new_id)
- {
- // texture has changed, close the floater to avoid DEV-22461
- texture_ctrl->closeDependentFloater();
- }
- texture_ctrl->setImageAssetID(new_id);
- }
+ LLTextureCtrl* texture_ctrl = panel->getChild<LLTextureCtrl>(entry->mControlName);
+ if (texture_ctrl)
+ {
+ LLUUID new_id;
+ LLLocalTextureObject *lto = self->getWearable()->getLocalTextureObject(entry->mTextureIndex);
+ if( lto && (lto->getID() != IMG_DEFAULT_AVATAR) )
+ {
+ new_id = lto->getID();
+ }
+ else
+ {
+ new_id = LLUUID::null;
+ }
+ LLUUID old_id = texture_ctrl->getImageAssetID();
+ if (old_id != new_id)
+ {
+ // texture has changed, close the floater to avoid DEV-22461
+ texture_ctrl->closeDependentFloater();
+ }
+ texture_ctrl->setImageAssetID(new_id);
+ }
}
static void set_enabled_color_swatch_ctrl(bool enabled, LLPanel* panel, const LLEditWearableDictionary::PickerControlEntry* entry)
{
- LLColorSwatchCtrl* color_swatch_ctrl = panel->getChild<LLColorSwatchCtrl>(entry->mControlName);
- if (color_swatch_ctrl)
- {
- color_swatch_ctrl->setEnabled(enabled);
- }
+ LLColorSwatchCtrl* color_swatch_ctrl = panel->getChild<LLColorSwatchCtrl>(entry->mControlName);
+ if (color_swatch_ctrl)
+ {
+ color_swatch_ctrl->setEnabled(enabled);
+ }
}
static void set_enabled_texture_ctrl(bool enabled, LLPanel* panel, const LLEditWearableDictionary::PickerControlEntry* entry)
{
- LLTextureCtrl* texture_ctrl = panel->getChild<LLTextureCtrl>(entry->mControlName);
- if (texture_ctrl)
- {
- texture_ctrl->setEnabled(enabled);
- }
+ LLTextureCtrl* texture_ctrl = panel->getChild<LLTextureCtrl>(entry->mControlName);
+ if (texture_ctrl)
+ {
+ texture_ctrl->setEnabled(enabled);
+ }
}
// LLPanelEditWearable
LLPanelEditWearable::LLPanelEditWearable()
- : LLPanel()
- , mWearablePtr(NULL)
- , mWearableItem(NULL)
+ : LLPanel()
+ , mWearablePtr(NULL)
+ , mWearableItem(NULL)
{
- mCommitCallbackRegistrar.add("ColorSwatch.Commit", boost::bind(&LLPanelEditWearable::onColorSwatchCommit, this, _1));
- mCommitCallbackRegistrar.add("TexturePicker.Commit", boost::bind(&LLPanelEditWearable::onTexturePickerCommit, this, _1));
+ mCommitCallbackRegistrar.add("ColorSwatch.Commit", boost::bind(&LLPanelEditWearable::onColorSwatchCommit, this, _1));
+ mCommitCallbackRegistrar.add("TexturePicker.Commit", boost::bind(&LLPanelEditWearable::onTexturePickerCommit, this, _1));
}
//virtual
@@ -634,917 +650,952 @@ LLPanelEditWearable::~LLPanelEditWearable()
bool LLPanelEditWearable::changeHeightUnits(const LLSD& new_value)
{
- updateMetricLayout( new_value.asBoolean() );
- updateTypeSpecificControls(LLWearableType::WT_SHAPE);
- return true;
+ updateMetricLayout( new_value.asBoolean() );
+ updateTypeSpecificControls(LLWearableType::WT_SHAPE);
+ return true;
}
void LLPanelEditWearable::updateMetricLayout(BOOL new_value)
{
- LLUIString current_metric, replacment_metric;
- current_metric = new_value ? mMeters : mFeet;
- replacment_metric = new_value ? mFeet : mMeters;
- mHeigthValue.setArg( "[METRIC1]", current_metric.getString() );
- mReplacementMetricUrl.setArg( "[URL_METRIC2]", std::string("[secondlife:///app/metricsystem ") + replacment_metric.getString() + std::string("]"));
+ LLUIString current_metric, replacment_metric;
+ current_metric = new_value ? mMeters : mFeet;
+ replacment_metric = new_value ? mFeet : mMeters;
+ mHeigthValue.setArg( "[METRIC1]", current_metric.getString() );
+ mReplacementMetricUrl.setArg( "[URL_METRIC2]", std::string("[secondlife:///app/metricsystem ") + replacment_metric.getString() + std::string("]"));
}
void LLPanelEditWearable::updateAvatarHeightLabel()
{
- mTxtAvatarHeight->setText(LLStringUtil::null);
- LLStyle::Params param;
- param.color = mAvatarHeigthLabelColor;
- mTxtAvatarHeight->appendText(mHeigth, false, param);
- param.color = mAvatarHeigthValueLabelColor;
- mTxtAvatarHeight->appendText(mHeigthValue, false, param);
- param.color = mAvatarHeigthLabelColor; // using mAvatarHeigthLabelColor for '/' separator
- mTxtAvatarHeight->appendText(" / ", false, param);
- mTxtAvatarHeight->appendText(this->mReplacementMetricUrl, false, param);
+ mTxtAvatarHeight->setText(LLStringUtil::null);
+ LLStyle::Params param;
+ param.color = mAvatarHeigthLabelColor;
+ mTxtAvatarHeight->appendText(mHeigth, false, param);
+ param.color = mAvatarHeigthValueLabelColor;
+ mTxtAvatarHeight->appendText(mHeigthValue, false, param);
+ param.color = mAvatarHeigthLabelColor; // using mAvatarHeigthLabelColor for '/' separator
+ mTxtAvatarHeight->appendText(" / ", false, param);
+ mTxtAvatarHeight->appendText(this->mReplacementMetricUrl, false, param);
}
void LLPanelEditWearable::onWearablePanelVisibilityChange(const LLSD &in_visible_chain, LLAccordionCtrl* accordion_ctrl)
{
- if (in_visible_chain.asBoolean() && accordion_ctrl != NULL)
- {
- accordion_ctrl->expandDefaultTab();
- }
+ if (in_visible_chain.asBoolean() && accordion_ctrl != NULL)
+ {
+ accordion_ctrl->expandDefaultTab();
+ }
}
void LLPanelEditWearable::setWearablePanelVisibilityChangeCallback(LLPanel* bodypart_panel)
{
- if (bodypart_panel != NULL)
- {
- LLAccordionCtrl* accordion_ctrl = bodypart_panel->getChild<LLAccordionCtrl>("wearable_accordion");
-
- if (accordion_ctrl != NULL)
- {
- bodypart_panel->setVisibleCallback(
- boost::bind(&LLPanelEditWearable::onWearablePanelVisibilityChange, this, _2, accordion_ctrl));
- }
- else
- {
- llwarns << "accordion_ctrl is NULL" << llendl;
- }
- }
- else
- {
- llwarns << "bodypart_panel is NULL" << llendl;
- }
+ if (bodypart_panel != NULL)
+ {
+ LLAccordionCtrl* accordion_ctrl = bodypart_panel->getChild<LLAccordionCtrl>("wearable_accordion");
+
+ if (accordion_ctrl != NULL)
+ {
+ bodypart_panel->setVisibleCallback(
+ boost::bind(&LLPanelEditWearable::onWearablePanelVisibilityChange, this, _2, accordion_ctrl));
+ }
+ else
+ {
+ llwarns << "accordion_ctrl is NULL" << llendl;
+ }
+ }
+ else
+ {
+ llwarns << "bodypart_panel is NULL" << llendl;
+ }
}
// virtual
BOOL LLPanelEditWearable::postBuild()
{
- // buttons
- mBtnRevert = getChild<LLButton>("revert_button");
- mBtnRevert->setClickedCallback(boost::bind(&LLPanelEditWearable::onRevertButtonClicked, this));
-
- mBtnBack = getChild<LLButton>("back_btn");
- mBackBtnLabel = mBtnBack->getLabelUnselected();
- mBtnBack->setLabel(LLStringUtil::null);
- // handled at appearance panel level?
- //mBtnBack->setClickedCallback(boost::bind(&LLPanelEditWearable::onBackButtonClicked, this));
-
- mNameEditor = getChild<LLLineEditor>("description");
-
- mPanelTitle = getChild<LLTextBox>("edit_wearable_title");
- mDescTitle = getChild<LLTextBox>("description_text");
-
- getChild<LLRadioGroup>("sex_radio")->setCommitCallback(boost::bind(&LLPanelEditWearable::onCommitSexChange, this));
- getChild<LLButton>("save_as_button")->setCommitCallback(boost::bind(&LLPanelEditWearable::onSaveAsButtonClicked, this));
-
- // The following panels will be shown/hidden based on what wearable we're editing
- // body parts
- mPanelShape = getChild<LLPanel>("edit_shape_panel");
- mPanelSkin = getChild<LLPanel>("edit_skin_panel");
- mPanelEyes = getChild<LLPanel>("edit_eyes_panel");
- mPanelHair = getChild<LLPanel>("edit_hair_panel");
-
- // Setting the visibility callback is applied only to the bodyparts panel
- // because currently they are the only ones whose 'wearable_accordion' has
- // multiple accordion tabs (see EXT-8164 for details).
- setWearablePanelVisibilityChangeCallback(mPanelShape);
- setWearablePanelVisibilityChangeCallback(mPanelSkin);
- setWearablePanelVisibilityChangeCallback(mPanelEyes);
- setWearablePanelVisibilityChangeCallback(mPanelHair);
-
- //clothes
- mPanelShirt = getChild<LLPanel>("edit_shirt_panel");
- mPanelPants = getChild<LLPanel>("edit_pants_panel");
- mPanelShoes = getChild<LLPanel>("edit_shoes_panel");
- mPanelSocks = getChild<LLPanel>("edit_socks_panel");
- mPanelJacket = getChild<LLPanel>("edit_jacket_panel");
- mPanelGloves = getChild<LLPanel>("edit_gloves_panel");
- mPanelUndershirt = getChild<LLPanel>("edit_undershirt_panel");
- mPanelUnderpants = getChild<LLPanel>("edit_underpants_panel");
- mPanelSkirt = getChild<LLPanel>("edit_skirt_panel");
- mPanelAlpha = getChild<LLPanel>("edit_alpha_panel");
- mPanelTattoo = getChild<LLPanel>("edit_tattoo_panel");
-
- mTxtAvatarHeight = mPanelShape->getChild<LLTextBox>("avatar_height");
-
- mWearablePtr = NULL;
-
- configureAlphaCheckbox(LLVOAvatarDefines::TEX_LOWER_ALPHA, "lower alpha texture invisible");
- configureAlphaCheckbox(LLVOAvatarDefines::TEX_UPPER_ALPHA, "upper alpha texture invisible");
- configureAlphaCheckbox(LLVOAvatarDefines::TEX_HEAD_ALPHA, "head alpha texture invisible");
- configureAlphaCheckbox(LLVOAvatarDefines::TEX_EYES_ALPHA, "eye alpha texture invisible");
- configureAlphaCheckbox(LLVOAvatarDefines::TEX_HAIR_ALPHA, "hair alpha texture invisible");
-
- // configure tab expanded callbacks
- for (U32 type_index = 0; type_index < (U32)LLWearableType::WT_COUNT; ++type_index)
- {
- LLWearableType::EType type = (LLWearableType::EType) type_index;
- const LLEditWearableDictionary::WearableEntry *wearable_entry = LLEditWearableDictionary::getInstance()->getWearable(type);
- if (!wearable_entry)
- {
- llwarns << "could not get wearable dictionary entry for wearable of type: " << type << llendl;
- continue;
- }
- U8 num_subparts = wearable_entry->mSubparts.size();
-
- for (U8 index = 0; index < num_subparts; ++index)
- {
- // dive into data structures to get the panel we need
- ESubpart subpart_e = wearable_entry->mSubparts[index];
- const LLEditWearableDictionary::SubpartEntry *subpart_entry = LLEditWearableDictionary::getInstance()->getSubpart(subpart_e);
-
- if (!subpart_entry)
- {
- llwarns << "could not get wearable subpart dictionary entry for subpart: " << subpart_e << llendl;
- continue;
- }
-
- const std::string accordion_tab = subpart_entry->mAccordionTab;
-
- LLAccordionCtrlTab *tab = getChild<LLAccordionCtrlTab>(accordion_tab);
-
- if (!tab)
- {
- llwarns << "could not get llaccordionctrltab from UI with name: " << accordion_tab << llendl;
- continue;
- }
-
- // initialize callback to ensure camera view changes appropriately.
- tab->setDropDownStateChangedCallback(boost::bind(&LLPanelEditWearable::onTabExpandedCollapsed,this,_2,index));
- }
-
- // initialize texture and color picker controls
- for_each_picker_ctrl_entry <LLColorSwatchCtrl> (getPanel(type), type, boost::bind(init_color_swatch_ctrl, this, _1, _2));
- for_each_picker_ctrl_entry <LLTextureCtrl> (getPanel(type), type, boost::bind(init_texture_ctrl, this, _1, _2));
- }
-
- // init all strings
- mMeters = mPanelShape->getString("meters");
- mFeet = mPanelShape->getString("feet");
- mHeigth = mPanelShape->getString("height") + " ";
- mHeigthValue = "[HEIGHT] [METRIC1]";
- mReplacementMetricUrl = "[URL_METRIC2]";
-
- std::string color = mPanelShape->getString("heigth_label_color");
- mAvatarHeigthLabelColor = LLUIColorTable::instance().getColor(color, LLColor4::green);
- color = mPanelShape->getString("heigth_value_label_color");
- mAvatarHeigthValueLabelColor = LLUIColorTable::instance().getColor(color, LLColor4::green);
- gSavedSettings.getControl("HeightUnits")->getSignal()->connect(boost::bind(&LLPanelEditWearable::changeHeightUnits, this, _2));
- updateMetricLayout(gSavedSettings.getBOOL("HeightUnits"));
-
- return TRUE;
+ // buttons
+ mBtnRevert = getChild<LLButton>("revert_button");
+ mBtnRevert->setClickedCallback(boost::bind(&LLPanelEditWearable::onRevertButtonClicked, this));
+
+ mBtnBack = getChild<LLButton>("back_btn");
+ mBackBtnLabel = mBtnBack->getLabelUnselected();
+ mBtnBack->setLabel(LLStringUtil::null);
+ // handled at appearance panel level?
+ //mBtnBack->setClickedCallback(boost::bind(&LLPanelEditWearable::onBackButtonClicked, this));
+
+ mNameEditor = getChild<LLLineEditor>("description");
+
+ mPanelTitle = getChild<LLTextBox>("edit_wearable_title");
+ mDescTitle = getChild<LLTextBox>("description_text");
+
+ getChild<LLRadioGroup>("sex_radio")->setCommitCallback(boost::bind(&LLPanelEditWearable::onCommitSexChange, this));
+ getChild<LLButton>("save_as_button")->setCommitCallback(boost::bind(&LLPanelEditWearable::onSaveAsButtonClicked, this));
+
+ // The following panels will be shown/hidden based on what wearable we're editing
+ // body parts
+ mPanelShape = getChild<LLPanel>("edit_shape_panel");
+ mPanelSkin = getChild<LLPanel>("edit_skin_panel");
+ mPanelEyes = getChild<LLPanel>("edit_eyes_panel");
+ mPanelHair = getChild<LLPanel>("edit_hair_panel");
+
+ // Setting the visibility callback is applied only to the bodyparts panel
+ // because currently they are the only ones whose 'wearable_accordion' has
+ // multiple accordion tabs (see EXT-8164 for details).
+ setWearablePanelVisibilityChangeCallback(mPanelShape);
+ setWearablePanelVisibilityChangeCallback(mPanelSkin);
+ setWearablePanelVisibilityChangeCallback(mPanelEyes);
+ setWearablePanelVisibilityChangeCallback(mPanelHair);
+
+ //clothes
+ mPanelShirt = getChild<LLPanel>("edit_shirt_panel");
+ mPanelPants = getChild<LLPanel>("edit_pants_panel");
+ mPanelShoes = getChild<LLPanel>("edit_shoes_panel");
+ mPanelSocks = getChild<LLPanel>("edit_socks_panel");
+ mPanelJacket = getChild<LLPanel>("edit_jacket_panel");
+ mPanelGloves = getChild<LLPanel>("edit_gloves_panel");
+ mPanelUndershirt = getChild<LLPanel>("edit_undershirt_panel");
+ mPanelUnderpants = getChild<LLPanel>("edit_underpants_panel");
+ mPanelSkirt = getChild<LLPanel>("edit_skirt_panel");
+ mPanelAlpha = getChild<LLPanel>("edit_alpha_panel");
+ mPanelTattoo = getChild<LLPanel>("edit_tattoo_panel");
+ mPanelPhysics = getChild<LLPanel>("edit_physics_panel");
+
+ mTxtAvatarHeight = mPanelShape->getChild<LLTextBox>("avatar_height");
+
+ mWearablePtr = NULL;
+
+ configureAlphaCheckbox(LLVOAvatarDefines::TEX_LOWER_ALPHA, "lower alpha texture invisible");
+ configureAlphaCheckbox(LLVOAvatarDefines::TEX_UPPER_ALPHA, "upper alpha texture invisible");
+ configureAlphaCheckbox(LLVOAvatarDefines::TEX_HEAD_ALPHA, "head alpha texture invisible");
+ configureAlphaCheckbox(LLVOAvatarDefines::TEX_EYES_ALPHA, "eye alpha texture invisible");
+ configureAlphaCheckbox(LLVOAvatarDefines::TEX_HAIR_ALPHA, "hair alpha texture invisible");
+
+ // configure tab expanded callbacks
+ for (U32 type_index = 0; type_index < (U32)LLWearableType::WT_COUNT; ++type_index)
+ {
+ LLWearableType::EType type = (LLWearableType::EType) type_index;
+ const LLEditWearableDictionary::WearableEntry *wearable_entry = LLEditWearableDictionary::getInstance()->getWearable(type);
+ if (!wearable_entry)
+ {
+ llwarns << "could not get wearable dictionary entry for wearable of type: " << type << llendl;
+ continue;
+ }
+ U8 num_subparts = wearable_entry->mSubparts.size();
+
+ for (U8 index = 0; index < num_subparts; ++index)
+ {
+ // dive into data structures to get the panel we need
+ ESubpart subpart_e = wearable_entry->mSubparts[index];
+ const LLEditWearableDictionary::SubpartEntry *subpart_entry = LLEditWearableDictionary::getInstance()->getSubpart(subpart_e);
+
+ if (!subpart_entry)
+ {
+ llwarns << "could not get wearable subpart dictionary entry for subpart: " << subpart_e << llendl;
+ continue;
+ }
+
+ const std::string accordion_tab = subpart_entry->mAccordionTab;
+
+ LLAccordionCtrlTab *tab = getChild<LLAccordionCtrlTab>(accordion_tab);
+
+ if (!tab)
+ {
+ llwarns << "could not get llaccordionctrltab from UI with name: " << accordion_tab << llendl;
+ continue;
+ }
+
+ // initialize callback to ensure camera view changes appropriately.
+ tab->setDropDownStateChangedCallback(boost::bind(&LLPanelEditWearable::onTabExpandedCollapsed,this,_2,index));
+ }
+
+ // initialize texture and color picker controls
+ for_each_picker_ctrl_entry <LLColorSwatchCtrl> (getPanel(type), type, boost::bind(init_color_swatch_ctrl, this, _1, _2));
+ for_each_picker_ctrl_entry <LLTextureCtrl> (getPanel(type), type, boost::bind(init_texture_ctrl, this, _1, _2));
+ }
+
+ // init all strings
+ mMeters = mPanelShape->getString("meters");
+ mFeet = mPanelShape->getString("feet");
+ mHeigth = mPanelShape->getString("height") + " ";
+ mHeigthValue = "[HEIGHT] [METRIC1]";
+ mReplacementMetricUrl = "[URL_METRIC2]";
+
+ std::string color = mPanelShape->getString("heigth_label_color");
+ mAvatarHeigthLabelColor = LLUIColorTable::instance().getColor(color, LLColor4::green);
+ color = mPanelShape->getString("heigth_value_label_color");
+ mAvatarHeigthValueLabelColor = LLUIColorTable::instance().getColor(color, LLColor4::green);
+ gSavedSettings.getControl("HeightUnits")->getSignal()->connect(boost::bind(&LLPanelEditWearable::changeHeightUnits, this, _2));
+ updateMetricLayout(gSavedSettings.getBOOL("HeightUnits"));
+
+ return TRUE;
}
// virtual
// LLUICtrl
BOOL LLPanelEditWearable::isDirty() const
{
- BOOL isDirty = FALSE;
- if (mWearablePtr)
- {
- if (mWearablePtr->isDirty() ||
- mWearableItem->getName().compare(mNameEditor->getText()) != 0)
- {
- isDirty = TRUE;
- }
- }
- return isDirty;
+ BOOL isDirty = FALSE;
+ if (mWearablePtr)
+ {
+ if (mWearablePtr->isDirty() ||
+ mWearableItem->getName().compare(mNameEditor->getText()) != 0)
+ {
+ isDirty = TRUE;
+ }
+ }
+ return isDirty;
}
//virtual
void LLPanelEditWearable::draw()
{
- updateVerbs();
- if (getWearable() && getWearable()->getType() == LLWearableType::WT_SHAPE)
- {
- //updating avatar height
- updateTypeSpecificControls(LLWearableType::WT_SHAPE);
- }
+ updateVerbs();
+ if (getWearable() && getWearable()->getType() == LLWearableType::WT_SHAPE)
+ {
+ //updating avatar height
+ updateTypeSpecificControls(LLWearableType::WT_SHAPE);
+ }
- LLPanel::draw();
+ LLPanel::draw();
}
void LLPanelEditWearable::setVisible(BOOL visible)
{
- if (!visible)
- {
- showWearable(mWearablePtr, FALSE);
- }
- LLPanel::setVisible(visible);
+ if (!visible)
+ {
+ showWearable(mWearablePtr, FALSE);
+ }
+ LLPanel::setVisible(visible);
}
-void LLPanelEditWearable::setWearable(LLWearable *wearable)
+void LLPanelEditWearable::setWearable(LLWearable *wearable, BOOL disable_camera_switch)
{
- showWearable(mWearablePtr, FALSE);
- mWearablePtr = wearable;
- showWearable(mWearablePtr, TRUE);
+ showWearable(mWearablePtr, FALSE, disable_camera_switch);
+ mWearablePtr = wearable;
+ showWearable(mWearablePtr, TRUE, disable_camera_switch);
}
//static
void LLPanelEditWearable::onRevertButtonClicked(void* userdata)
{
- LLPanelEditWearable *panel = (LLPanelEditWearable*) userdata;
- panel->revertChanges();
+ LLPanelEditWearable *panel = (LLPanelEditWearable*) userdata;
+ panel->revertChanges();
}
void LLPanelEditWearable::onSaveAsButtonClicked()
{
- LLSD args;
- args["DESC"] = mNameEditor->getText();
+ LLSD args;
+ args["DESC"] = mNameEditor->getText();
- LLNotificationsUtil::add("SaveWearableAs", args, LLSD(), boost::bind(&LLPanelEditWearable::saveAsCallback, this, _1, _2));
+ LLNotificationsUtil::add("SaveWearableAs", args, LLSD(), boost::bind(&LLPanelEditWearable::saveAsCallback, this, _1, _2));
}
void LLPanelEditWearable::saveAsCallback(const LLSD& notification, const LLSD& response)
{
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
- if (0 == option)
- {
- std::string wearable_name = response["message"].asString();
- LLStringUtil::trim(wearable_name);
- if( !wearable_name.empty() )
- {
- mNameEditor->setText(wearable_name);
- saveChanges(true);
- }
- }
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (0 == option)
+ {
+ std::string wearable_name = response["message"].asString();
+ LLStringUtil::trim(wearable_name);
+ if( !wearable_name.empty() )
+ {
+ mNameEditor->setText(wearable_name);
+ saveChanges(true);
+ }
+ }
}
void LLPanelEditWearable::onCommitSexChange()
{
- if (!isAgentAvatarValid()) return;
+ if (!isAgentAvatarValid()) return;
- LLWearableType::EType type = mWearablePtr->getType();
- U32 index = gAgentWearables.getWearableIndex(mWearablePtr);
+ LLWearableType::EType type = mWearablePtr->getType();
+ U32 index = gAgentWearables.getWearableIndex(mWearablePtr);
- if( !gAgentWearables.isWearableModifiable(type, index))
- {
- return;
- }
+ if( !gAgentWearables.isWearableModifiable(type, index))
+ {
+ return;
+ }
- LLViewerVisualParam* param = static_cast<LLViewerVisualParam*>(gAgentAvatarp->getVisualParam( "male" ));
- if( !param )
- {
- return;
- }
+ LLViewerVisualParam* param = static_cast<LLViewerVisualParam*>(gAgentAvatarp->getVisualParam( "male" ));
+ if( !param )
+ {
+ return;
+ }
- bool is_new_sex_male = (gSavedSettings.getU32("AvatarSex") ? SEX_MALE : SEX_FEMALE) == SEX_MALE;
- LLWearable* wearable = gAgentWearables.getWearable(type, index);
- if (wearable)
- {
- wearable->setVisualParamWeight(param->getID(), is_new_sex_male, FALSE);
- }
- param->setWeight( is_new_sex_male, FALSE );
+ bool is_new_sex_male = (gSavedSettings.getU32("AvatarSex") ? SEX_MALE : SEX_FEMALE) == SEX_MALE;
+ LLWearable* wearable = gAgentWearables.getWearable(type, index);
+ if (wearable)
+ {
+ wearable->setVisualParamWeight(param->getID(), is_new_sex_male, FALSE);
+ }
+ param->setWeight( is_new_sex_male, FALSE );
- gAgentAvatarp->updateSexDependentLayerSets( FALSE );
+ gAgentAvatarp->updateSexDependentLayerSets( FALSE );
- gAgentAvatarp->updateVisualParams();
+ gAgentAvatarp->updateVisualParams();
- updateScrollingPanelUI();
+ updateScrollingPanelUI();
}
void LLPanelEditWearable::onTexturePickerCommit(const LLUICtrl* ctrl)
{
- const LLTextureCtrl* texture_ctrl = dynamic_cast<const LLTextureCtrl*>(ctrl);
- if (!texture_ctrl)
- {
- llwarns << "got commit signal from not LLTextureCtrl." << llendl;
- return;
- }
-
- if (getWearable())
- {
- LLWearableType::EType type = getWearable()->getType();
- const PickerControlEntryNamePredicate name_pred(texture_ctrl->getName());
- const LLEditWearableDictionary::PickerControlEntry* entry
- = find_picker_ctrl_entry_if<LLTextureCtrl, PickerControlEntryNamePredicate>(type, name_pred);
- if (entry)
- {
- // Set the new version
- LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture(texture_ctrl->getImageAssetID());
- if( image->getID() == IMG_DEFAULT )
- {
- image = LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT_AVATAR);
- }
- if (getWearable())
- {
- U32 index = gAgentWearables.getWearableIndex(getWearable());
- gAgentAvatarp->setLocalTexture(entry->mTextureIndex, image, FALSE, index);
- LLVisualParamHint::requestHintUpdates();
- gAgentAvatarp->wearableUpdated(type, FALSE);
- }
- }
- else
- {
- llwarns << "could not get texture picker dictionary entry for wearable of type: " << type << llendl;
- }
- }
+ const LLTextureCtrl* texture_ctrl = dynamic_cast<const LLTextureCtrl*>(ctrl);
+ if (!texture_ctrl)
+ {
+ llwarns << "got commit signal from not LLTextureCtrl." << llendl;
+ return;
+ }
+
+ if (getWearable())
+ {
+ LLWearableType::EType type = getWearable()->getType();
+ const PickerControlEntryNamePredicate name_pred(texture_ctrl->getName());
+ const LLEditWearableDictionary::PickerControlEntry* entry
+ = find_picker_ctrl_entry_if<LLTextureCtrl, PickerControlEntryNamePredicate>(type, name_pred);
+ if (entry)
+ {
+ // Set the new version
+ LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture(texture_ctrl->getImageAssetID());
+ if( image->getID() == IMG_DEFAULT )
+ {
+ image = LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT_AVATAR);
+ }
+ if (getWearable())
+ {
+ U32 index = gAgentWearables.getWearableIndex(getWearable());
+ gAgentAvatarp->setLocalTexture(entry->mTextureIndex, image, FALSE, index);
+ LLVisualParamHint::requestHintUpdates();
+ gAgentAvatarp->wearableUpdated(type, FALSE);
+ }
+ }
+ else
+ {
+ llwarns << "could not get texture picker dictionary entry for wearable of type: " << type << llendl;
+ }
+ }
}
void LLPanelEditWearable::onColorSwatchCommit(const LLUICtrl* ctrl)
{
- if (getWearable())
- {
- LLWearableType::EType type = getWearable()->getType();
- const PickerControlEntryNamePredicate name_pred(ctrl->getName());
- const LLEditWearableDictionary::PickerControlEntry* entry
- = find_picker_ctrl_entry_if<LLColorSwatchCtrl, PickerControlEntryNamePredicate>(type, name_pred);
- if (entry)
- {
- const LLColor4& old_color = getWearable()->getClothesColor(entry->mTextureIndex);
- const LLColor4& new_color = LLColor4(ctrl->getValue());
- if( old_color != new_color )
- {
- getWearable()->setClothesColor(entry->mTextureIndex, new_color, TRUE);
- LLVisualParamHint::requestHintUpdates();
- gAgentAvatarp->wearableUpdated(getWearable()->getType(), FALSE);
- }
- }
- else
- {
- llwarns << "could not get color swatch dictionary entry for wearable of type: " << type << llendl;
- }
- }
+ if (getWearable())
+ {
+ LLWearableType::EType type = getWearable()->getType();
+ const PickerControlEntryNamePredicate name_pred(ctrl->getName());
+ const LLEditWearableDictionary::PickerControlEntry* entry
+ = find_picker_ctrl_entry_if<LLColorSwatchCtrl, PickerControlEntryNamePredicate>(type, name_pred);
+ if (entry)
+ {
+ const LLColor4& old_color = getWearable()->getClothesColor(entry->mTextureIndex);
+ const LLColor4& new_color = LLColor4(ctrl->getValue());
+ if( old_color != new_color )
+ {
+ getWearable()->setClothesColor(entry->mTextureIndex, new_color, TRUE);
+ LLVisualParamHint::requestHintUpdates();
+ gAgentAvatarp->wearableUpdated(getWearable()->getType(), FALSE);
+ }
+ }
+ else
+ {
+ llwarns << "could not get color swatch dictionary entry for wearable of type: " << type << llendl;
+ }
+ }
}
void LLPanelEditWearable::updatePanelPickerControls(LLWearableType::EType type)
{
- LLPanel* panel = getPanel(type);
- if (!panel)
- return;
-
- bool is_modifiable = false;
- bool is_copyable = false;
-
- if(mWearableItem)
- {
- const LLPermissions& perm = mWearableItem->getPermissions();
- is_modifiable = perm.allowModifyBy(gAgent.getID(), gAgent.getGroupID());
- is_copyable = perm.allowCopyBy(gAgent.getID(), gAgent.getGroupID());
- }
-
- if (is_modifiable)
- {
- // Update picker controls
- for_each_picker_ctrl_entry <LLColorSwatchCtrl> (panel, type, boost::bind(update_color_swatch_ctrl, this, _1, _2));
- for_each_picker_ctrl_entry <LLTextureCtrl> (panel, type, boost::bind(update_texture_ctrl, this, _1, _2));
- }
- else
- {
- // Disable controls
- for_each_picker_ctrl_entry <LLColorSwatchCtrl> (panel, type, boost::bind(set_enabled_color_swatch_ctrl, false, _1, _2));
- for_each_picker_ctrl_entry <LLTextureCtrl> (panel, type, boost::bind(set_enabled_texture_ctrl, false, _1, _2));
- }
+ LLPanel* panel = getPanel(type);
+ if (!panel)
+ return;
+
+ bool is_modifiable = false;
+ bool is_copyable = false;
+
+ if(mWearableItem)
+ {
+ const LLPermissions& perm = mWearableItem->getPermissions();
+ is_modifiable = perm.allowModifyBy(gAgent.getID(), gAgent.getGroupID());
+ is_copyable = perm.allowCopyBy(gAgent.getID(), gAgent.getGroupID());
+ }
+
+ if (is_modifiable)
+ {
+ // Update picker controls
+ for_each_picker_ctrl_entry <LLColorSwatchCtrl> (panel, type, boost::bind(update_color_swatch_ctrl, this, _1, _2));
+ for_each_picker_ctrl_entry <LLTextureCtrl> (panel, type, boost::bind(update_texture_ctrl, this, _1, _2));
+ }
+ else
+ {
+ // Disable controls
+ for_each_picker_ctrl_entry <LLColorSwatchCtrl> (panel, type, boost::bind(set_enabled_color_swatch_ctrl, false, _1, _2));
+ for_each_picker_ctrl_entry <LLTextureCtrl> (panel, type, boost::bind(set_enabled_texture_ctrl, false, _1, _2));
+ }
}
void LLPanelEditWearable::saveChanges(bool force_save_as)
{
- if (!mWearablePtr || !isDirty())
- {
- // do nothing if no unsaved changes
- return;
- }
-
- U32 index = gAgentWearables.getWearableIndex(mWearablePtr);
-
- std::string new_name = mNameEditor->getText();
- if (force_save_as)
- {
- // the name of the wearable has changed, re-save wearable with new name
- LLAppearanceMgr::instance().removeCOFItemLinks(mWearablePtr->getItemID(),false);
- gAgentWearables.saveWearableAs(mWearablePtr->getType(), index, new_name, FALSE);
- mNameEditor->setText(mWearableItem->getName());
- }
- else
- {
- gAgentWearables.saveWearable(mWearablePtr->getType(), index, TRUE, new_name);
- }
+ if (!mWearablePtr || !isDirty())
+ {
+ // do nothing if no unsaved changes
+ return;
+ }
+
+ U32 index = gAgentWearables.getWearableIndex(mWearablePtr);
+
+ std::string new_name = mNameEditor->getText();
+ if (force_save_as)
+ {
+ // the name of the wearable has changed, re-save wearable with new name
+ LLAppearanceMgr::instance().removeCOFItemLinks(mWearablePtr->getItemID(),false);
+ gAgentWearables.saveWearableAs(mWearablePtr->getType(), index, new_name, FALSE);
+ mNameEditor->setText(mWearableItem->getName());
+ }
+ else
+ {
+ gAgentWearables.saveWearable(mWearablePtr->getType(), index, TRUE, new_name);
+ }
}
void LLPanelEditWearable::revertChanges()
{
- if (!mWearablePtr || !isDirty())
- {
- // no unsaved changes to revert
- return;
- }
-
- mWearablePtr->revertValues();
- mNameEditor->setText(mWearableItem->getName());
- updatePanelPickerControls(mWearablePtr->getType());
- updateTypeSpecificControls(mWearablePtr->getType());
- gAgentAvatarp->wearableUpdated(mWearablePtr->getType(), FALSE);
+ if (!mWearablePtr || !isDirty())
+ {
+ // no unsaved changes to revert
+ return;
+ }
+
+ mWearablePtr->revertValues();
+ mNameEditor->setText(mWearableItem->getName());
+ updatePanelPickerControls(mWearablePtr->getType());
+ updateTypeSpecificControls(mWearablePtr->getType());
+ gAgentAvatarp->wearableUpdated(mWearablePtr->getType(), FALSE);
}
-void LLPanelEditWearable::showWearable(LLWearable* wearable, BOOL show)
-{
- if (!wearable)
- {
- return;
- }
-
- mWearableItem = gInventory.getItem(mWearablePtr->getItemID());
- llassert(mWearableItem);
-
- LLWearableType::EType type = wearable->getType();
- LLPanel *targetPanel = NULL;
- std::string title;
- std::string description_title;
-
- const LLEditWearableDictionary::WearableEntry *wearable_entry = LLEditWearableDictionary::getInstance()->getWearable(type);
- if (!wearable_entry)
- {
- llwarns << "called LLPanelEditWearable::showWearable with an invalid wearable type! (" << type << ")" << llendl;
- return;
- }
-
- targetPanel = getPanel(type);
- title = getString(wearable_entry->mTitle);
- description_title = getString(wearable_entry->mDescTitle);
-
- // Update picker controls state
- for_each_picker_ctrl_entry <LLColorSwatchCtrl> (targetPanel, type, boost::bind(set_enabled_color_swatch_ctrl, show, _1, _2));
- for_each_picker_ctrl_entry <LLTextureCtrl> (targetPanel, type, boost::bind(set_enabled_texture_ctrl, show, _1, _2));
-
- targetPanel->setVisible(show);
- toggleTypeSpecificControls(type);
-
- if (show)
- {
- mPanelTitle->setText(title);
- mPanelTitle->setToolTip(title);
- mDescTitle->setText(description_title);
-
- // set name
- mNameEditor->setText(mWearableItem->getName());
-
- updatePanelPickerControls(type);
- updateTypeSpecificControls(type);
-
- // clear and rebuild visual param list
- U8 num_subparts = wearable_entry->mSubparts.size();
-
- for (U8 index = 0; index < num_subparts; ++index)
- {
- // dive into data structures to get the panel we need
- ESubpart subpart_e = wearable_entry->mSubparts[index];
- const LLEditWearableDictionary::SubpartEntry *subpart_entry = LLEditWearableDictionary::getInstance()->getSubpart(subpart_e);
-
- if (!subpart_entry)
- {
- llwarns << "could not get wearable subpart dictionary entry for subpart: " << subpart_e << llendl;
- continue;
- }
-
- const std::string scrolling_panel = subpart_entry->mParamList;
- const std::string accordion_tab = subpart_entry->mAccordionTab;
-
- LLScrollingPanelList *panel_list = getChild<LLScrollingPanelList>(scrolling_panel);
- LLAccordionCtrlTab *tab = getChild<LLAccordionCtrlTab>(accordion_tab);
-
- if (!panel_list)
- {
- llwarns << "could not get scrolling panel list: " << scrolling_panel << llendl;
- continue;
- }
-
- if (!tab)
+void LLPanelEditWearable::showWearable(LLWearable* wearable, BOOL show, BOOL disable_camera_switch)
+{
+ if (!wearable)
+ {
+ return;
+ }
+
+ mWearableItem = gInventory.getItem(mWearablePtr->getItemID());
+ llassert(mWearableItem);
+
+ LLWearableType::EType type = wearable->getType();
+ LLPanel *targetPanel = NULL;
+ std::string title;
+ std::string description_title;
+
+ const LLEditWearableDictionary::WearableEntry *wearable_entry = LLEditWearableDictionary::getInstance()->getWearable(type);
+ if (!wearable_entry)
+ {
+ llwarns << "called LLPanelEditWearable::showWearable with an invalid wearable type! (" << type << ")" << llendl;
+ return;
+ }
+
+ targetPanel = getPanel(type);
+ title = getString(wearable_entry->mTitle);
+ description_title = getString(wearable_entry->mDescTitle);
+
+ // Update picker controls state
+ for_each_picker_ctrl_entry <LLColorSwatchCtrl> (targetPanel, type, boost::bind(set_enabled_color_swatch_ctrl, show, _1, _2));
+ for_each_picker_ctrl_entry <LLTextureCtrl> (targetPanel, type, boost::bind(set_enabled_texture_ctrl, show, _1, _2));
+
+ targetPanel->setVisible(show);
+ toggleTypeSpecificControls(type);
+
+ if (show)
+ {
+ mPanelTitle->setText(title);
+ mPanelTitle->setToolTip(title);
+ mDescTitle->setText(description_title);
+
+ // set name
+ mNameEditor->setText(mWearableItem->getName());
+
+ updatePanelPickerControls(type);
+ updateTypeSpecificControls(type);
+
+ // clear and rebuild visual param list
+ U8 num_subparts = wearable_entry->mSubparts.size();
+
+ for (U8 index = 0; index < num_subparts; ++index)
+ {
+ // dive into data structures to get the panel we need
+ ESubpart subpart_e = wearable_entry->mSubparts[index];
+ const LLEditWearableDictionary::SubpartEntry *subpart_entry = LLEditWearableDictionary::getInstance()->getSubpart(subpart_e);
+
+ if (!subpart_entry)
+ {
+ llwarns << "could not get wearable subpart dictionary entry for subpart: " << subpart_e << llendl;
+ continue;
+ }
+
+ const std::string scrolling_panel = subpart_entry->mParamList;
+ const std::string accordion_tab = subpart_entry->mAccordionTab;
+
+ LLScrollingPanelList *panel_list = getChild<LLScrollingPanelList>(scrolling_panel);
+ LLAccordionCtrlTab *tab = getChild<LLAccordionCtrlTab>(accordion_tab);
+
+ if (!panel_list)
+ {
+ llwarns << "could not get scrolling panel list: " << scrolling_panel << llendl;
+ continue;
+ }
+
+ if (!tab)
+ {
+ llwarns << "could not get llaccordionctrltab from UI with name: " << accordion_tab << llendl;
+ continue;
+ }
+
+ // Don't show female subparts if you're not female, etc.
+ if (!(gAgentAvatarp->getSex() & subpart_entry->mSex))
{
- llwarns << "could not get llaccordionctrltab from UI with name: " << accordion_tab << llendl;
+ tab->setVisible(FALSE);
continue;
}
-
- // what edit group do we want to extract params for?
- const std::string edit_group = subpart_entry->mEditGroup;
-
- // storage for ordered list of visual params
- value_map_t sorted_params;
- getSortedParams(sorted_params, edit_group);
-
- LLJoint* jointp = gAgentAvatarp->getJoint( subpart_entry->mTargetJoint );
- if (!jointp)
+ else
{
- jointp = gAgentAvatarp->getJoint("mHead");
+ tab->setVisible(TRUE);
}
-
- buildParamList(panel_list, sorted_params, tab, jointp);
-
- updateScrollingPanelUI();
- }
- showDefaultSubpart();
-
- updateVerbs();
- }
+
+ // what edit group do we want to extract params for?
+ const std::string edit_group = subpart_entry->mEditGroup;
+
+ // storage for ordered list of visual params
+ value_map_t sorted_params;
+ getSortedParams(sorted_params, edit_group);
+
+ LLJoint* jointp = gAgentAvatarp->getJoint( subpart_entry->mTargetJoint );
+ if (!jointp)
+ {
+ jointp = gAgentAvatarp->getJoint("mHead");
+ }
+
+ buildParamList(panel_list, sorted_params, tab, jointp);
+
+ updateScrollingPanelUI();
+ }
+ if (!disable_camera_switch)
+ {
+ showDefaultSubpart();
+ }
+
+ updateVerbs();
+ }
}
void LLPanelEditWearable::showDefaultSubpart()
{
- changeCamera(0);
+ changeCamera(3);
}
void LLPanelEditWearable::onTabExpandedCollapsed(const LLSD& param, U8 index)
{
- bool expanded = param.asBoolean();
+ bool expanded = param.asBoolean();
- if (!mWearablePtr || !gAgentCamera.cameraCustomizeAvatar())
- {
- // we don't have a valid wearable we're editing, or we've left the wearable editor
- return;
- }
+ if (!mWearablePtr || !gAgentCamera.cameraCustomizeAvatar())
+ {
+ // we don't have a valid wearable we're editing, or we've left the wearable editor
+ return;
+ }
- if (expanded)
- {
- changeCamera(index);
- }
+ if (expanded)
+ {
+ changeCamera(index);
+ }
}
void LLPanelEditWearable::changeCamera(U8 subpart)
{
- const LLEditWearableDictionary::WearableEntry *wearable_entry = LLEditWearableDictionary::getInstance()->getWearable(mWearablePtr->getType());
- if (!wearable_entry)
- {
- llinfos << "could not get wearable dictionary entry for wearable type: " << mWearablePtr->getType() << llendl;
- return;
- }
-
- if (subpart >= wearable_entry->mSubparts.size())
- {
- llinfos << "accordion tab expanded for invalid subpart. Wearable type: " << mWearablePtr->getType() << " subpart num: " << subpart << llendl;
- return;
- }
-
- ESubpart subpart_e = wearable_entry->mSubparts[subpart];
- const LLEditWearableDictionary::SubpartEntry *subpart_entry = LLEditWearableDictionary::getInstance()->getSubpart(subpart_e);
-
- if (!subpart_entry)
+ // 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()))
{
- llwarns << "could not get wearable subpart dictionary entry for subpart: " << subpart_e << llendl;
return;
}
-
- // Update the camera
- gMorphView->setCameraTargetJoint( gAgentAvatarp->getJoint( subpart_entry->mTargetJoint ) );
- gMorphView->setCameraTargetOffset( subpart_entry->mTargetOffset );
- gMorphView->setCameraOffset( subpart_entry->mCameraOffset );
- if (gSavedSettings.getBOOL("AppearanceCameraMovement"))
- {
- gMorphView->updateCamera();
- }
+ const LLEditWearableDictionary::WearableEntry *wearable_entry = LLEditWearableDictionary::getInstance()->getWearable(mWearablePtr->getType());
+ if (!wearable_entry)
+ {
+ llinfos << "could not get wearable dictionary entry for wearable type: " << mWearablePtr->getType() << llendl;
+ return;
+ }
+
+ if (subpart >= wearable_entry->mSubparts.size())
+ {
+ llinfos << "accordion tab expanded for invalid subpart. Wearable type: " << mWearablePtr->getType() << " subpart num: " << subpart << llendl;
+ return;
+ }
+
+ ESubpart subpart_e = wearable_entry->mSubparts[subpart];
+ const LLEditWearableDictionary::SubpartEntry *subpart_entry = LLEditWearableDictionary::getInstance()->getSubpart(subpart_e);
+
+ if (!subpart_entry)
+ {
+ llwarns << "could not get wearable subpart dictionary entry for subpart: " << subpart_e << llendl;
+ return;
+ }
+
+ // Update the camera
+ gMorphView->setCameraTargetJoint( gAgentAvatarp->getJoint( subpart_entry->mTargetJoint ) );
+ gMorphView->setCameraTargetOffset( subpart_entry->mTargetOffset );
+ gMorphView->setCameraOffset( subpart_entry->mCameraOffset );
+ if (gSavedSettings.getBOOL("AppearanceCameraMovement"))
+ {
+ gMorphView->updateCamera();
+ }
}
void LLPanelEditWearable::updateScrollingPanelList()
{
- updateScrollingPanelUI();
+ updateScrollingPanelUI();
}
void LLPanelEditWearable::toggleTypeSpecificControls(LLWearableType::EType type)
{
- // Toggle controls specific to shape editing panel.
- {
- bool is_shape = (type == LLWearableType::WT_SHAPE);
- getChildView("sex_radio")->setVisible( is_shape);
- getChildView("female_icon")->setVisible( is_shape);
- getChildView("male_icon")->setVisible( is_shape);
- }
+ // Toggle controls specific to shape editing panel.
+ {
+ bool is_shape = (type == LLWearableType::WT_SHAPE);
+ getChildView("sex_radio")->setVisible( is_shape);
+ getChildView("female_icon")->setVisible( is_shape);
+ getChildView("male_icon")->setVisible( is_shape);
+ }
}
void LLPanelEditWearable::updateTypeSpecificControls(LLWearableType::EType type)
{
- const F32 ONE_METER = 1.0;
- const F32 ONE_FOOT = 0.3048 * ONE_METER; // in meters
- // Update controls specific to shape editing panel.
- if (type == LLWearableType::WT_SHAPE)
- {
- // Update avatar height
- F32 new_size = gAgentAvatarp->mBodySize.mV[VZ];
- if (gSavedSettings.getBOOL("HeightUnits") == FALSE)
- {
- // convert meters to feet
- new_size = new_size / ONE_FOOT;
- }
-
- std::string avatar_height_str = llformat("%.2f", new_size);
- mHeigthValue.setArg("[HEIGHT]", avatar_height_str);
- updateAvatarHeightLabel();
- }
-
- if (LLWearableType::WT_ALPHA == type)
- {
- updateAlphaCheckboxes();
-
- initPreviousAlphaTextures();
- }
+ const F32 ONE_METER = 1.0;
+ const F32 ONE_FOOT = 0.3048 * ONE_METER; // in meters
+ // Update controls specific to shape editing panel.
+ if (type == LLWearableType::WT_SHAPE)
+ {
+ // Update avatar height
+ F32 new_size = gAgentAvatarp->mBodySize.mV[VZ];
+ if (gSavedSettings.getBOOL("HeightUnits") == FALSE)
+ {
+ // convert meters to feet
+ new_size = new_size / ONE_FOOT;
+ }
+
+ std::string avatar_height_str = llformat("%.2f", new_size);
+ mHeigthValue.setArg("[HEIGHT]", avatar_height_str);
+ updateAvatarHeightLabel();
+ }
+
+ if (LLWearableType::WT_ALPHA == type)
+ {
+ updateAlphaCheckboxes();
+
+ initPreviousAlphaTextures();
+ }
}
void LLPanelEditWearable::updateScrollingPanelUI()
{
- // do nothing if we don't have a valid wearable we're editing
- if (mWearablePtr == NULL)
- {
- return;
- }
-
- LLWearableType::EType type = mWearablePtr->getType();
- LLPanel *panel = getPanel(type);
-
- if(panel && (mWearablePtr->getItemID().notNull()))
- {
- const LLEditWearableDictionary::WearableEntry *wearable_entry = LLEditWearableDictionary::getInstance()->getWearable(type);
- llassert(wearable_entry);
- if (!wearable_entry) return;
- U8 num_subparts = wearable_entry->mSubparts.size();
-
- LLScrollingPanelParam::sUpdateDelayFrames = 0;
- for (U8 index = 0; index < num_subparts; ++index)
- {
- // dive into data structures to get the panel we need
- ESubpart subpart_e = wearable_entry->mSubparts[index];
- const LLEditWearableDictionary::SubpartEntry *subpart_entry = LLEditWearableDictionary::getInstance()->getSubpart(subpart_e);
-
- const std::string scrolling_panel = subpart_entry->mParamList;
-
- LLScrollingPanelList *panel_list = getChild<LLScrollingPanelList>(scrolling_panel);
-
- if (!panel_list)
- {
- llwarns << "could not get scrolling panel list: " << scrolling_panel << llendl;
- continue;
- }
-
- panel_list->updatePanels(TRUE);
- }
- }
+ // do nothing if we don't have a valid wearable we're editing
+ if (mWearablePtr == NULL)
+ {
+ return;
+ }
+
+ LLWearableType::EType type = mWearablePtr->getType();
+ LLPanel *panel = getPanel(type);
+
+ if(panel && (mWearablePtr->getItemID().notNull()))
+ {
+ const LLEditWearableDictionary::WearableEntry *wearable_entry = LLEditWearableDictionary::getInstance()->getWearable(type);
+ llassert(wearable_entry);
+ if (!wearable_entry) return;
+ U8 num_subparts = wearable_entry->mSubparts.size();
+
+ LLScrollingPanelParam::sUpdateDelayFrames = 0;
+ for (U8 index = 0; index < num_subparts; ++index)
+ {
+ // dive into data structures to get the panel we need
+ ESubpart subpart_e = wearable_entry->mSubparts[index];
+ const LLEditWearableDictionary::SubpartEntry *subpart_entry = LLEditWearableDictionary::getInstance()->getSubpart(subpart_e);
+
+ const std::string scrolling_panel = subpart_entry->mParamList;
+
+ LLScrollingPanelList *panel_list = getChild<LLScrollingPanelList>(scrolling_panel);
+
+ if (!panel_list)
+ {
+ llwarns << "could not get scrolling panel list: " << scrolling_panel << llendl;
+ continue;
+ }
+
+ panel_list->updatePanels(TRUE);
+ }
+ }
}
LLPanel* LLPanelEditWearable::getPanel(LLWearableType::EType type)
{
- switch (type)
- {
- case LLWearableType::WT_SHAPE:
- return mPanelShape;
- break;
-
- case LLWearableType::WT_SKIN:
- return mPanelSkin;
- break;
-
- case LLWearableType::WT_HAIR:
- return mPanelHair;
- break;
-
- case LLWearableType::WT_EYES:
- return mPanelEyes;
- break;
-
- case LLWearableType::WT_SHIRT:
- return mPanelShirt;
- break;
-
- case LLWearableType::WT_PANTS:
- return mPanelPants;
- break;
-
- case LLWearableType::WT_SHOES:
- return mPanelShoes;
- break;
-
- case LLWearableType::WT_SOCKS:
- return mPanelSocks;
- break;
-
- case LLWearableType::WT_JACKET:
- return mPanelJacket;
- break;
-
- case LLWearableType::WT_GLOVES:
- return mPanelGloves;
- break;
-
- case LLWearableType::WT_UNDERSHIRT:
- return mPanelUndershirt;
- break;
-
- case LLWearableType::WT_UNDERPANTS:
- return mPanelUnderpants;
- break;
-
- case LLWearableType::WT_SKIRT:
- return mPanelSkirt;
- break;
-
- case LLWearableType::WT_ALPHA:
- return mPanelAlpha;
- break;
-
- case LLWearableType::WT_TATTOO:
- return mPanelTattoo;
- break;
- default:
- break;
- }
- return NULL;
+ switch (type)
+ {
+ case LLWearableType::WT_SHAPE:
+ return mPanelShape;
+ break;
+
+ case LLWearableType::WT_SKIN:
+ return mPanelSkin;
+ break;
+
+ case LLWearableType::WT_HAIR:
+ return mPanelHair;
+ break;
+
+ case LLWearableType::WT_EYES:
+ return mPanelEyes;
+ break;
+
+ case LLWearableType::WT_SHIRT:
+ return mPanelShirt;
+ break;
+
+ case LLWearableType::WT_PANTS:
+ return mPanelPants;
+ break;
+
+ case LLWearableType::WT_SHOES:
+ return mPanelShoes;
+ break;
+
+ case LLWearableType::WT_SOCKS:
+ return mPanelSocks;
+ break;
+
+ case LLWearableType::WT_JACKET:
+ return mPanelJacket;
+ break;
+
+ case LLWearableType::WT_GLOVES:
+ return mPanelGloves;
+ break;
+
+ case LLWearableType::WT_UNDERSHIRT:
+ return mPanelUndershirt;
+ break;
+
+ case LLWearableType::WT_UNDERPANTS:
+ return mPanelUnderpants;
+ break;
+
+ case LLWearableType::WT_SKIRT:
+ return mPanelSkirt;
+ break;
+
+ case LLWearableType::WT_ALPHA:
+ return mPanelAlpha;
+ break;
+
+ case LLWearableType::WT_TATTOO:
+ return mPanelTattoo;
+ break;
+
+ case LLWearableType::WT_PHYSICS:
+ return mPanelPhysics;
+ break;
+
+ default:
+ break;
+ }
+ return NULL;
}
void LLPanelEditWearable::getSortedParams(value_map_t &sorted_params, const std::string &edit_group)
{
- LLWearable::visual_param_vec_t param_list;
- ESex avatar_sex = gAgentAvatarp->getSex();
-
- mWearablePtr->getVisualParams(param_list);
-
- for (LLWearable::visual_param_vec_t::iterator iter = param_list.begin();
- iter != param_list.end();
- ++iter)
- {
- LLViewerVisualParam *param = (LLViewerVisualParam*) *iter;
-
- if (param->getID() == -1
- || !param->isTweakable()
- || param->getEditGroup() != edit_group
- || !(param->getSex() & avatar_sex))
- {
- continue;
- }
-
- value_map_t::value_type vt(-param->getDisplayOrder(), param);
- llassert( sorted_params.find(-param->getDisplayOrder()) == sorted_params.end() ); //check for duplicates
- sorted_params.insert(vt);
- }
+ LLWearable::visual_param_vec_t param_list;
+ ESex avatar_sex = gAgentAvatarp->getSex();
+
+ mWearablePtr->getVisualParams(param_list);
+
+ for (LLWearable::visual_param_vec_t::iterator iter = param_list.begin();
+ iter != param_list.end();
+ ++iter)
+ {
+ LLViewerVisualParam *param = (LLViewerVisualParam*) *iter;
+
+ if (param->getID() == -1
+ || !param->isTweakable()
+ || param->getEditGroup() != edit_group
+ || !(param->getSex() & avatar_sex))
+ {
+ continue;
+ }
+
+ value_map_t::value_type vt(-param->getDisplayOrder(), param);
+ llassert( sorted_params.find(-param->getDisplayOrder()) == sorted_params.end() ); //check for duplicates
+ sorted_params.insert(vt);
+ }
}
void LLPanelEditWearable::buildParamList(LLScrollingPanelList *panel_list, value_map_t &sorted_params, LLAccordionCtrlTab *tab, LLJoint* jointp)
{
- // sorted_params is sorted according to magnitude of effect from
- // least to greatest. Adding to the front of the child list
- // reverses that order.
- if( panel_list )
- {
- panel_list->clearPanels();
- value_map_t::iterator end = sorted_params.end();
- S32 height = 0;
- for(value_map_t::iterator it = sorted_params.begin(); it != end; ++it)
- {
- LLPanel::Params p;
- p.name("LLScrollingPanelParam");
- LLScrollingPanelParam* panel_param = new LLScrollingPanelParam( p, NULL, (*it).second, TRUE, this->getWearable(), jointp);
- height = panel_list->addPanel( panel_param );
- }
- }
+ // sorted_params is sorted according to magnitude of effect from
+ // least to greatest. Adding to the front of the child list
+ // reverses that order.
+ if( panel_list )
+ {
+ panel_list->clearPanels();
+ value_map_t::iterator end = sorted_params.end();
+ S32 height = 0;
+ for(value_map_t::iterator it = sorted_params.begin(); it != end; ++it)
+ {
+ LLPanel::Params p;
+ p.name("LLScrollingPanelParam");
+ LLWearable *wearable = this->getWearable();
+ LLScrollingPanelParamBase *panel_param = NULL;
+ if (wearable && wearable->getType() == LLWearableType::WT_PHYSICS) // Hack to show a different panel for physics. Should generalize this later.
+ {
+ panel_param = new LLScrollingPanelParamBase( p, NULL, (*it).second, TRUE, this->getWearable(), jointp);
+ }
+ else
+ {
+ panel_param = new LLScrollingPanelParam( p, NULL, (*it).second, TRUE, this->getWearable(), jointp);
+ }
+ height = panel_list->addPanel( panel_param );
+ }
+ }
}
void LLPanelEditWearable::updateVerbs()
{
- bool can_copy = false;
+ bool can_copy = false;
- if(mWearableItem)
- {
- can_copy = mWearableItem->getPermissions().allowCopyBy(gAgentID);
- }
+ if(mWearableItem)
+ {
+ can_copy = mWearableItem->getPermissions().allowCopyBy(gAgentID);
+ }
- BOOL is_dirty = isDirty();
+ BOOL is_dirty = isDirty();
- mBtnRevert->setEnabled(is_dirty);
- getChildView("save_as_button")->setEnabled(is_dirty && can_copy);
+ mBtnRevert->setEnabled(is_dirty);
+ getChildView("save_as_button")->setEnabled(is_dirty && can_copy);
- if(isAgentAvatarValid())
- {
- // Update viewer's radio buttons (of RadioGroup with control_name="AvatarSex") of Avatar's gender
- // with value from "AvatarSex" setting
- gSavedSettings.setU32("AvatarSex", (gAgentAvatarp->getSex() == SEX_MALE) );
- }
+ if(isAgentAvatarValid())
+ {
+ // Update viewer's radio buttons (of RadioGroup with control_name="AvatarSex") of Avatar's gender
+ // with value from "AvatarSex" setting
+ gSavedSettings.setU32("AvatarSex", (gAgentAvatarp->getSex() == SEX_MALE) );
+ }
- // update back button and title according to dirty state.
- static BOOL was_dirty = FALSE;
- if (was_dirty != is_dirty) // to avoid redundant changes because this method is called from draw
- {
- static S32 label_width = mBtnBack->getFont()->getWidth(mBackBtnLabel);
- const std::string& label = is_dirty ? mBackBtnLabel : LLStringUtil::null;
- const S32 delta_width = is_dirty ? label_width : -label_width;
+ // update back button and title according to dirty state.
+ static BOOL was_dirty = FALSE;
+ if (was_dirty != is_dirty) // to avoid redundant changes because this method is called from draw
+ {
+ static S32 label_width = mBtnBack->getFont()->getWidth(mBackBtnLabel);
+ const std::string& label = is_dirty ? mBackBtnLabel : LLStringUtil::null;
+ const S32 delta_width = is_dirty ? label_width : -label_width;
- mBtnBack->setLabel(label);
+ mBtnBack->setLabel(label);
- // update rect according to label width
- LLRect rect = mBtnBack->getRect();
- rect.mRight += delta_width;
- mBtnBack->setShape(rect);
+ // update rect according to label width
+ LLRect rect = mBtnBack->getRect();
+ rect.mRight += delta_width;
+ mBtnBack->setShape(rect);
- // update title rect according to back button width
- rect = mPanelTitle->getRect();
- rect.mLeft += delta_width;
- mPanelTitle->setShape(rect);
+ // update title rect according to back button width
+ rect = mPanelTitle->getRect();
+ rect.mLeft += delta_width;
+ mPanelTitle->setShape(rect);
- was_dirty = is_dirty;
- }
+ was_dirty = is_dirty;
+ }
}
void LLPanelEditWearable::configureAlphaCheckbox(LLVOAvatarDefines::ETextureIndex te, const std::string& name)
{
- LLCheckBoxCtrl* checkbox = mPanelAlpha->getChild<LLCheckBoxCtrl>(name);
- checkbox->setCommitCallback(boost::bind(&LLPanelEditWearable::onInvisibilityCommit, this, checkbox, te));
+ LLCheckBoxCtrl* checkbox = mPanelAlpha->getChild<LLCheckBoxCtrl>(name);
+ checkbox->setCommitCallback(boost::bind(&LLPanelEditWearable::onInvisibilityCommit, this, checkbox, te));
- mAlphaCheckbox2Index[name] = te;
+ mAlphaCheckbox2Index[name] = te;
}
void LLPanelEditWearable::onInvisibilityCommit(LLCheckBoxCtrl* checkbox_ctrl, LLVOAvatarDefines::ETextureIndex te)
{
- if (!checkbox_ctrl) return;
- if (!getWearable()) return;
-
- llinfos << "onInvisibilityCommit, self " << this << " checkbox_ctrl " << checkbox_ctrl << llendl;
-
- bool new_invis_state = checkbox_ctrl->get();
- if (new_invis_state)
- {
- LLLocalTextureObject *lto = getWearable()->getLocalTextureObject(te);
- mPreviousAlphaTexture[te] = lto->getID();
-
- LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture( IMG_INVISIBLE );
- U32 index = gAgentWearables.getWearableIndex(getWearable());
- gAgentAvatarp->setLocalTexture(te, image, FALSE, index);
- gAgentAvatarp->wearableUpdated(getWearable()->getType(), FALSE);
- }
- else
- {
- // Try to restore previous texture, if any.
- LLUUID prev_id = mPreviousAlphaTexture[te];
- if (prev_id.isNull() || (prev_id == IMG_INVISIBLE))
- {
- prev_id = LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) );
- }
- if (prev_id.isNull()) return;
-
- LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture(prev_id);
- if (!image) return;
-
- U32 index = gAgentWearables.getWearableIndex(getWearable());
- gAgentAvatarp->setLocalTexture(te, image, FALSE, index);
- gAgentAvatarp->wearableUpdated(getWearable()->getType(), FALSE);
- }
-
- updatePanelPickerControls(getWearable()->getType());
+ if (!checkbox_ctrl) return;
+ if (!getWearable()) return;
+
+ llinfos << "onInvisibilityCommit, self " << this << " checkbox_ctrl " << checkbox_ctrl << llendl;
+
+ bool new_invis_state = checkbox_ctrl->get();
+ if (new_invis_state)
+ {
+ LLLocalTextureObject *lto = getWearable()->getLocalTextureObject(te);
+ mPreviousAlphaTexture[te] = lto->getID();
+
+ LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture( IMG_INVISIBLE );
+ U32 index = gAgentWearables.getWearableIndex(getWearable());
+ gAgentAvatarp->setLocalTexture(te, image, FALSE, index);
+ gAgentAvatarp->wearableUpdated(getWearable()->getType(), FALSE);
+ }
+ else
+ {
+ // Try to restore previous texture, if any.
+ LLUUID prev_id = mPreviousAlphaTexture[te];
+ if (prev_id.isNull() || (prev_id == IMG_INVISIBLE))
+ {
+ prev_id = LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) );
+ }
+ if (prev_id.isNull()) return;
+
+ LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture(prev_id);
+ if (!image) return;
+
+ U32 index = gAgentWearables.getWearableIndex(getWearable());
+ gAgentAvatarp->setLocalTexture(te, image, FALSE, index);
+ gAgentAvatarp->wearableUpdated(getWearable()->getType(), FALSE);
+ }
+
+ updatePanelPickerControls(getWearable()->getType());
}
void LLPanelEditWearable::updateAlphaCheckboxes()
{
- for(string_texture_index_map_t::iterator iter = mAlphaCheckbox2Index.begin();
- iter != mAlphaCheckbox2Index.end(); ++iter )
- {
- LLVOAvatarDefines::ETextureIndex te = (LLVOAvatarDefines::ETextureIndex)iter->second;
- LLCheckBoxCtrl* ctrl = mPanelAlpha->getChild<LLCheckBoxCtrl>(iter->first);
- if (ctrl)
- {
- ctrl->set(!gAgentAvatarp->isTextureVisible(te, mWearablePtr));
- }
- }
+ for(string_texture_index_map_t::iterator iter = mAlphaCheckbox2Index.begin();
+ iter != mAlphaCheckbox2Index.end(); ++iter )
+ {
+ LLVOAvatarDefines::ETextureIndex te = (LLVOAvatarDefines::ETextureIndex)iter->second;
+ LLCheckBoxCtrl* ctrl = mPanelAlpha->getChild<LLCheckBoxCtrl>(iter->first);
+ if (ctrl)
+ {
+ ctrl->set(!gAgentAvatarp->isTextureVisible(te, mWearablePtr));
+ }
+ }
}
void LLPanelEditWearable::initPreviousAlphaTextures()
{
- initPreviousAlphaTextureEntry(TEX_LOWER_ALPHA);
- initPreviousAlphaTextureEntry(TEX_UPPER_ALPHA);
- initPreviousAlphaTextureEntry(TEX_HEAD_ALPHA);
- initPreviousAlphaTextureEntry(TEX_EYES_ALPHA);
- initPreviousAlphaTextureEntry(TEX_LOWER_ALPHA);
+ initPreviousAlphaTextureEntry(TEX_LOWER_ALPHA);
+ initPreviousAlphaTextureEntry(TEX_UPPER_ALPHA);
+ initPreviousAlphaTextureEntry(TEX_HEAD_ALPHA);
+ initPreviousAlphaTextureEntry(TEX_EYES_ALPHA);
+ initPreviousAlphaTextureEntry(TEX_LOWER_ALPHA);
}
void LLPanelEditWearable::initPreviousAlphaTextureEntry(LLVOAvatarDefines::ETextureIndex te)
{
- LLLocalTextureObject *lto = getWearable()->getLocalTextureObject(te);
- if (lto)
- {
- mPreviousAlphaTexture[te] = lto->getID();
- }
+ LLLocalTextureObject *lto = getWearable()->getLocalTextureObject(te);
+ if (lto)
+ {
+ mPreviousAlphaTexture[te] = lto->getID();
+ }
}
// handle secondlife:///app/metricsystem
class LLMetricSystemHandler : public LLCommandHandler
{
public:
- LLMetricSystemHandler() : LLCommandHandler("metricsystem", UNTRUSTED_THROTTLE) { }
-
- bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web)
- {
- // change height units TRUE for meters and FALSE for feet
- BOOL new_value = (gSavedSettings.getBOOL("HeightUnits") == FALSE) ? TRUE : FALSE;
- gSavedSettings.setBOOL("HeightUnits", new_value);
- return true;
- }
+ LLMetricSystemHandler() : LLCommandHandler("metricsystem", UNTRUSTED_THROTTLE) { }
+
+ bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web)
+ {
+ // change height units TRUE for meters and FALSE for feet
+ BOOL new_value = (gSavedSettings.getBOOL("HeightUnits") == FALSE) ? TRUE : FALSE;
+ gSavedSettings.setBOOL("HeightUnits", new_value);
+ return true;
+ }
};
LLMetricSystemHandler gMetricSystemHandler;
diff --git a/indra/newview/llpaneleditwearable.h b/indra/newview/llpaneleditwearable.h
index 43513d8ab3..692a7ce90f 100644
--- a/indra/newview/llpaneleditwearable.h
+++ b/indra/newview/llpaneleditwearable.h
@@ -55,8 +55,11 @@ public:
/*virtual*/ BOOL isDirty() const; // LLUICtrl
/*virtual*/ void draw();
+ // changes camera angle to default for selected subpart
+ void changeCamera(U8 subpart);
+
LLWearable* getWearable() { return mWearablePtr; }
- void setWearable(LLWearable *wearable);
+ void setWearable(LLWearable *wearable, BOOL disable_camera_switch = FALSE);
void saveChanges(bool force_save_as = false);
void revertChanges();
@@ -77,7 +80,7 @@ public:
private:
typedef std::map<F32, LLViewerVisualParam*> value_map_t;
- void showWearable(LLWearable* wearable, BOOL show);
+ void showWearable(LLWearable* wearable, BOOL show, BOOL disable_camera_switch = FALSE);
void updateScrollingPanelUI();
LLPanel* getPanel(LLWearableType::EType type);
void getSortedParams(value_map_t &sorted_params, const std::string &edit_group);
@@ -91,9 +94,6 @@ private:
void toggleTypeSpecificControls(LLWearableType::EType type);
void updateTypeSpecificControls(LLWearableType::EType type);
- // changes camera angle to default for selected subpart
- void changeCamera(U8 subpart);
-
//alpha mask checkboxes
void configureAlphaCheckbox(LLVOAvatarDefines::ETextureIndex te, const std::string& name);
void onInvisibilityCommit(LLCheckBoxCtrl* checkbox_ctrl, LLVOAvatarDefines::ETextureIndex te);
@@ -163,6 +163,7 @@ private:
LLPanel *mPanelSkirt;
LLPanel *mPanelAlpha;
LLPanel *mPanelTattoo;
+ LLPanel *mPanelPhysics;
typedef std::map<std::string, LLVOAvatarDefines::ETextureIndex> string_texture_index_map_t;
string_texture_index_map_t mAlphaCheckbox2Index;
diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp
index bce496cbad..07c7f35989 100644
--- a/indra/newview/llpanelface.cpp
+++ b/indra/newview/llpanelface.cpp
@@ -376,6 +376,11 @@ struct LLPanelFaceSetAlignedTEFunctor : public LLSelectedTEFunctor
return true;
}
+ if (facep->getViewerObject()->getVolume()->getNumVolumeFaces() <= te)
+ {
+ return true;
+ }
+
bool set_aligned = true;
if (facep == mCenterFace)
{
@@ -418,6 +423,12 @@ struct LLPanelFaceGetIsAlignedTEFunctor : public LLSelectedTEFunctor
{
return false;
}
+
+ if (facep->getViewerObject()->getVolume()->getNumVolumeFaces() <= te)
+ { //volume face does not exist, can't be aligned
+ return false;
+ }
+
if (facep == mCenterFace)
{
return true;
diff --git a/indra/newview/llpanelgroupgeneral.cpp b/indra/newview/llpanelgroupgeneral.cpp
index 80df420a4e..1576ccccdf 100644
--- a/indra/newview/llpanelgroupgeneral.cpp
+++ b/indra/newview/llpanelgroupgeneral.cpp
@@ -44,6 +44,7 @@
#include "llnotificationsutil.h"
#include "llscrolllistitem.h"
#include "llspinctrl.h"
+#include "llslurl.h"
#include "lltextbox.h"
#include "lltexteditor.h"
#include "lltexturectrl.h"
@@ -692,7 +693,8 @@ void LLPanelGroupGeneral::updateMembers()
LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
if (!mListVisibleMembers || !gdatap
- || !gdatap->isMemberDataComplete())
+ || !gdatap->isMemberDataComplete()
+ || gdatap->mMembers.empty())
{
return;
}
diff --git a/indra/newview/llpanelgroupnotices.cpp b/indra/newview/llpanelgroupnotices.cpp
index cdf6e51bf8..e64192c2ae 100644
--- a/indra/newview/llpanelgroupnotices.cpp
+++ b/indra/newview/llpanelgroupnotices.cpp
@@ -154,6 +154,7 @@ BOOL LLGroupDropTarget::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
case DAD_ANIMATION:
case DAD_GESTURE:
case DAD_CALLINGCARD:
+ case DAD_MESH:
{
LLViewerInventoryItem* inv_item = (LLViewerInventoryItem*)cargo_data;
if(gInventory.getItem(inv_item->getUUID())
diff --git a/indra/newview/llpanelgrouproles.cpp b/indra/newview/llpanelgrouproles.cpp
index 35f898bfa6..fbe331c7ab 100644
--- a/indra/newview/llpanelgrouproles.cpp
+++ b/indra/newview/llpanelgrouproles.cpp
@@ -42,6 +42,7 @@
#include "llscrolllistctrl.h"
#include "llscrolllistitem.h"
#include "llscrolllistcell.h"
+#include "llslurl.h"
#include "lltabcontainer.h"
#include "lltextbox.h"
#include "lltexteditor.h"
@@ -49,6 +50,7 @@
#include "llviewertexturelist.h"
#include "llviewerwindow.h"
#include "llfocusmgr.h"
+#include "llviewercontrol.h"
#include "roles_constants.h"
@@ -742,10 +744,12 @@ LLPanelGroupMembersSubTab::LLPanelGroupMembersSubTab()
mHasMatch(FALSE),
mNumOwnerAdditions(0)
{
+ mUdpateSessionID = LLUUID::null;
}
LLPanelGroupMembersSubTab::~LLPanelGroupMembersSubTab()
{
+ gSavedSettings.setString("GroupMembersSortOrder", mMembersList->getSortColumnName());
}
BOOL LLPanelGroupMembersSubTab::postBuildSubTab(LLView* root)
@@ -772,6 +776,17 @@ BOOL LLPanelGroupMembersSubTab::postBuildSubTab(LLView* root)
// Show the member's profile on double click.
mMembersList->setDoubleClickCallback(onMemberDoubleClick, this);
mMembersList->setContextMenu(LLScrollListCtrl::MENU_AVATAR);
+
+ LLSD row;
+ row["columns"][0]["column"] = "name";
+ row["columns"][1]["column"] = "donated";
+ row["columns"][2]["column"] = "online";
+ mMembersList->addElement(row);
+ std::string order_by = gSavedSettings.getString("GroupMembersSortOrder");
+ if(!order_by.empty())
+ {
+ mMembersList->sortByColumn(order_by, TRUE);
+ }
LLButton* button = parent->getChild<LLButton>("member_invite", recurse);
if ( button )
@@ -1529,6 +1544,10 @@ void LLPanelGroupMembersSubTab::update(LLGroupChange gc)
mMemberProgress = gdatap->mMembers.begin();
mPendingMemberUpdate = TRUE;
mHasMatch = FALSE;
+ // Generate unique ID for current updateMembers()- see onNameCache for details.
+ // Using unique UUID is perhaps an overkill but this way we are perfectly safe
+ // from coincidences.
+ mUdpateSessionID.generate();
}
else
{
@@ -1556,6 +1575,63 @@ void LLPanelGroupMembersSubTab::update(LLGroupChange gc)
}
}
+void LLPanelGroupMembersSubTab::addMemberToList(LLUUID id, LLGroupMemberData* data)
+{
+ if (!data) return;
+ LLUIString donated = getString("donation_area");
+ donated.setArg("[AREA]", llformat("%d", data->getContribution()));
+
+ LLSD row;
+ row["id"] = id;
+
+ row["columns"][0]["column"] = "name";
+ // value is filled in by name list control
+
+ row["columns"][1]["column"] = "donated";
+ row["columns"][1]["value"] = donated.getString();
+
+ row["columns"][2]["column"] = "online";
+ row["columns"][2]["value"] = data->getOnlineStatus();
+ row["columns"][2]["font"] = "SANSSERIF_SMALL";
+
+ mMembersList->addElement(row);
+
+ mHasMatch = TRUE;
+}
+
+void LLPanelGroupMembersSubTab::onNameCache(const LLUUID& update_id, const LLUUID& id)
+{
+ // Update ID is used to determine whether member whose id is passed
+ // into onNameCache() was passed after current or previous user-initiated update.
+ // This is needed to avoid probable duplication of members in list after changing filter
+ // or adding of members of another group if gets for their names were called on
+ // previous update. If this id is from get() called from older update,
+ // we do nothing.
+ if (mUdpateSessionID != update_id) return;
+
+ LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
+ if (!gdatap)
+ {
+ llwarns << "LLPanelGroupMembersSubTab::updateMembers() -- No group data!" << llendl;
+ return;
+ }
+
+ std::string fullname;
+ gCacheName->getFullName(id, fullname);
+
+ LLGroupMemberData* data;
+ // trying to avoid unnecessary hash lookups
+ if (matchesSearchFilter(fullname) && ((data = gdatap->mMembers[id]) != NULL))
+ {
+ addMemberToList(id, data);
+ if(!mMembersList->getEnabled())
+ {
+ mMembersList->setEnabled(TRUE);
+ }
+ }
+
+}
+
void LLPanelGroupMembersSubTab::updateMembers()
{
mPendingMemberUpdate = FALSE;
@@ -1580,12 +1656,13 @@ void LLPanelGroupMembersSubTab::updateMembers()
//cleanup list only for first iretation
if(mMemberProgress == gdatap->mMembers.begin())
+ {
mMembersList->deleteAllItems();
+ }
LLGroupMgrGroupData::member_list_t::iterator end = gdatap->mMembers.end();
- LLUIString donated = getString("donation_area");
-
+
S32 i = 0;
for( ; mMemberProgress != end && i<UPDATE_MEMBERS_PER_FRAME;
++mMemberProgress, ++i)
@@ -1593,38 +1670,19 @@ void LLPanelGroupMembersSubTab::updateMembers()
if (!mMemberProgress->second)
continue;
// Do filtering on name if it is already in the cache.
- bool add_member = true;
-
std::string fullname;
if (gCacheName->getFullName(mMemberProgress->first, fullname))
{
- if ( !matchesSearchFilter(fullname) )
+ if (matchesSearchFilter(fullname))
{
- add_member = false;
+ addMemberToList(mMemberProgress->first, mMemberProgress->second);
}
}
-
- if (add_member)
+ else
{
- donated.setArg("[AREA]", llformat("%d", mMemberProgress->second->getContribution()));
-
- LLSD row;
- row["id"] = (*mMemberProgress).first;
-
- row["columns"][0]["column"] = "name";
- // value is filled in by name list control
-
- row["columns"][1]["column"] = "donated";
- row["columns"][1]["value"] = donated.getString();
-
- row["columns"][2]["column"] = "online";
- row["columns"][2]["value"] = mMemberProgress->second->getOnlineStatus();
- row["columns"][2]["font"] = "SANSSERIF_SMALL";
-
- LLScrollListItem* member = mMembersList->addElement(row);
-
- LLUUID id = member->getUUID();
- mHasMatch = TRUE;
+ // If name is not cached, onNameCache() should be called when it is cached and add this member to list.
+ gCacheName->get(mMemberProgress->first, FALSE, boost::bind(&LLPanelGroupMembersSubTab::onNameCache,
+ this, mUdpateSessionID, _1));
}
}
@@ -1786,7 +1844,8 @@ bool LLPanelGroupRolesSubTab::apply(std::string& mesg)
{
lldebugs << "LLPanelGroupRolesSubTab::apply()" << llendl;
- saveRoleChanges();
+ saveRoleChanges(true);
+
LLGroupMgr::getInstance()->sendGroupRoleChanges(mGroupID);
notifyObservers();
@@ -1965,7 +2024,7 @@ void LLPanelGroupRolesSubTab::handleRoleSelect()
return;
}
- saveRoleChanges();
+ saveRoleChanges(false);
// Check if there is anything selected.
LLScrollListItem* item = mRolesList->getFirstSelected();
@@ -2328,7 +2387,7 @@ void LLPanelGroupRolesSubTab::handleDeleteRole()
notifyObservers();
}
-void LLPanelGroupRolesSubTab::saveRoleChanges()
+void LLPanelGroupRolesSubTab::saveRoleChanges(bool select_saved_role)
{
LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
@@ -2343,13 +2402,23 @@ void LLPanelGroupRolesSubTab::saveRoleChanges()
rd.mRoleDescription = mRoleDescription->getText();
rd.mRoleTitle = mRoleTitle->getText();
+ S32 role_members_count = 0;
+ if (mSelectedRole.isNull())
+ {
+ role_members_count = gdatap->mMemberCount;
+ }
+ else if(LLGroupRoleData* grd = get_ptr_in_map(gdatap->mRoles, mSelectedRole))
+ {
+ role_members_count = grd->getTotalMembersInRole();
+ }
+
gdatap->setRoleData(mSelectedRole,rd);
mRolesList->deleteSingleItem(mRolesList->getItemIndex(mSelectedRole));
- LLSD row = createRoleItem(mSelectedRole,rd.mRoleName,rd.mRoleTitle,0);
+ LLSD row = createRoleItem(mSelectedRole,rd.mRoleName,rd.mRoleTitle,role_members_count);
LLScrollListItem* item = mRolesList->addElement(row, ADD_BOTTOM, this);
- item->setSelected(TRUE);
+ item->setSelected(select_saved_role);
mHasRoleChange = FALSE;
}
diff --git a/indra/newview/llpanelgrouproles.h b/indra/newview/llpanelgrouproles.h
index 6a773f1ebb..a55e264150 100644
--- a/indra/newview/llpanelgrouproles.h
+++ b/indra/newview/llpanelgrouproles.h
@@ -187,6 +187,9 @@ public:
virtual void setGroupID(const LLUUID& id);
+ void addMemberToList(LLUUID id, LLGroupMemberData* data);
+ void onNameCache(const LLUUID& update_id, const LLUUID& id);
+
protected:
typedef std::map<LLUUID, LLRoleMemberChangeType> role_change_data_map_t;
typedef std::map<LLUUID, role_change_data_map_t*> member_role_changes_map_t;
@@ -207,6 +210,9 @@ protected:
BOOL mPendingMemberUpdate;
BOOL mHasMatch;
+ // This id is generated after each user initiated member list update(opening Roles or changing filter)
+ LLUUID mUdpateSessionID;
+
member_role_changes_map_t mMemberRoleChangeData;
U32 mNumOwnerAdditions;
@@ -251,7 +257,7 @@ public:
static void onDeleteRole(void*);
void handleDeleteRole();
- void saveRoleChanges();
+ void saveRoleChanges(bool select_saved_role);
virtual void setGroupID(const LLUUID& id);
protected:
diff --git a/indra/newview/llpanellandaudio.cpp b/indra/newview/llpanellandaudio.cpp
index 5a943bc61d..f9730d9b71 100644
--- a/indra/newview/llpanellandaudio.cpp
+++ b/indra/newview/llpanellandaudio.cpp
@@ -91,9 +91,6 @@ BOOL LLPanelLandAudio::postBuild()
mMusicURLEdit = getChild<LLLineEditor>("music_url");
childSetCommitCallback("music_url", onCommitAny, this);
- mMusicUrlCheck = getChild<LLCheckBoxCtrl>("hide_music_url");
- childSetCommitCallback("hide_music_url", onCommitAny, this);
-
return TRUE;
}
@@ -117,9 +114,6 @@ void LLPanelLandAudio::refresh()
mCheckSoundLocal->set( parcel->getSoundLocal() );
mCheckSoundLocal->setEnabled( can_change_media );
- mMusicUrlCheck->set( parcel->getObscureMusic() );
- mMusicUrlCheck->setEnabled( can_change_media );
-
bool allow_voice = parcel->getParcelFlagAllowVoice();
LLViewerRegion* region = LLViewerParcelMgr::getInstance()->getSelectionRegion();
@@ -148,13 +142,6 @@ void LLPanelLandAudio::refresh()
mCheckParcelEnableVoice->set(allow_voice);
mCheckParcelVoiceLocal->set(!parcel->getParcelFlagUseEstateVoiceChannel());
- // don't display urls if you're not able to change it
- // much requested change in forums so people can't 'steal' urls
- // NOTE: bug#2009 means this is still vunerable - however, bug
- // should be closed since this bug opens up major security issues elsewhere.
- bool obscure_music = ! can_change_media && parcel->getObscureMusic();
-
- mMusicURLEdit->setDrawAsterixes(obscure_music);
mMusicURLEdit->setText(parcel->getMusicURL());
mMusicURLEdit->setEnabled( can_change_media );
}
@@ -173,7 +160,6 @@ void LLPanelLandAudio::onCommitAny(LLUICtrl*, void *userdata)
// Extract data from UI
BOOL sound_local = self->mCheckSoundLocal->get();
std::string music_url = self->mMusicURLEdit->getText();
- U8 obscure_music = self->mMusicUrlCheck->get();
BOOL voice_enabled = self->mCheckParcelEnableVoice->get();
BOOL voice_estate_chan = !self->mCheckParcelVoiceLocal->get();
@@ -186,7 +172,6 @@ void LLPanelLandAudio::onCommitAny(LLUICtrl*, void *userdata)
parcel->setParcelFlag(PF_USE_ESTATE_VOICE_CHAN, voice_estate_chan);
parcel->setParcelFlag(PF_SOUND_LOCAL, sound_local);
parcel->setMusicURL(music_url);
- parcel->setObscureMusic(obscure_music);
// Send current parcel data upstream to server
LLViewerParcelMgr::getInstance()->sendParcelPropertiesUpdate( parcel );
diff --git a/indra/newview/llpanellandmarkinfo.cpp b/indra/newview/llpanellandmarkinfo.cpp
index 87acd83b23..c57746ec00 100644
--- a/indra/newview/llpanellandmarkinfo.cpp
+++ b/indra/newview/llpanellandmarkinfo.cpp
@@ -180,6 +180,9 @@ void LLPanelLandmarkInfo::setInfoType(EInfoType type)
populateFoldersList();
+ // Prevent the floater from losing focus (if the sidepanel is undocked).
+ setFocus(TRUE);
+
LLPanelPlaceInfo::setInfoType(type);
}
@@ -330,6 +333,9 @@ void LLPanelLandmarkInfo::toggleLandmarkEditMode(BOOL enabled)
// when it was enabled/disabled we set the text once again.
mNotesEditor->setText(mNotesEditor->getText());
}
+
+ // Prevent the floater from losing focus (if the sidepanel is undocked).
+ setFocus(TRUE);
}
const std::string& LLPanelLandmarkInfo::getLandmarkTitle() const
diff --git a/indra/newview/llpanellandmarks.cpp b/indra/newview/llpanellandmarks.cpp
index c4a484d368..80f6862169 100644
--- a/indra/newview/llpanellandmarks.cpp
+++ b/indra/newview/llpanellandmarks.cpp
@@ -47,9 +47,11 @@
#include "llinventorymodelbackgroundfetch.h"
#include "llinventorypanel.h"
#include "lllandmarkactions.h"
+#include "llmenubutton.h"
#include "llplacesinventorybridge.h"
#include "llplacesinventorypanel.h"
#include "llsidetray.h"
+#include "lltoggleablemenu.h"
#include "llviewermenu.h"
#include "llviewerregion.h"
@@ -69,6 +71,7 @@ static void collapse_all_folders(LLFolderView* root_folder);
static void expand_all_folders(LLFolderView* root_folder);
static bool has_expanded_folders(LLFolderView* root_folder);
static bool has_collapsed_folders(LLFolderView* root_folder);
+static void toggle_restore_menu(LLMenuGL* menu, BOOL visible, BOOL enabled);
/**
* Functor counting expanded and collapsed folders in folder view tree to know
@@ -191,6 +194,7 @@ LLLandmarksPanel::LLLandmarksPanel()
, mLibraryInventoryPanel(NULL)
, mCurrentSelectedList(NULL)
, mListCommands(NULL)
+ , mGearButton(NULL)
, mGearFolderMenu(NULL)
, mGearLandmarkMenu(NULL)
{
@@ -517,9 +521,6 @@ void LLLandmarksPanel::setParcelID(const LLUUID& parcel_id)
{
if (!parcel_id.isNull())
{
- //ext-4655, defensive. remove now incase this gets called twice without a remove
- LLRemoteParcelInfoProcessor::getInstance()->removeObserver(parcel_id, this);
-
LLRemoteParcelInfoProcessor::getInstance()->addObserver(parcel_id, this);
LLRemoteParcelInfoProcessor::getInstance()->sendParcelInfoRequest(parcel_id);
}
@@ -685,7 +686,9 @@ void LLLandmarksPanel::initListCommandsHandlers()
{
mListCommands = getChild<LLPanel>("bottom_panel");
- mListCommands->childSetAction(OPTIONS_BUTTON_NAME, boost::bind(&LLLandmarksPanel::onActionsButtonClick, this));
+ mGearButton = getChild<LLMenuButton>(OPTIONS_BUTTON_NAME);
+ mGearButton->setMouseDownCallback(boost::bind(&LLLandmarksPanel::onActionsButtonClick, this));
+
mListCommands->childSetAction(TRASH_BUTTON_NAME, boost::bind(&LLLandmarksPanel::onTrashButtonClick, this));
LLDragAndDropButton* trash_btn = mListCommands->getChild<LLDragAndDropButton>(TRASH_BUTTON_NAME);
@@ -702,10 +705,13 @@ void LLLandmarksPanel::initListCommandsHandlers()
mCommitCallbackRegistrar.add("Places.LandmarksGear.Folding.Action", boost::bind(&LLLandmarksPanel::onFoldingAction, this, _2));
mEnableCallbackRegistrar.add("Places.LandmarksGear.Check", boost::bind(&LLLandmarksPanel::isActionChecked, this, _2));
mEnableCallbackRegistrar.add("Places.LandmarksGear.Enable", boost::bind(&LLLandmarksPanel::isActionEnabled, this, _2));
- mGearLandmarkMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_places_gear_landmark.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
- mGearFolderMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_places_gear_folder.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+ mGearLandmarkMenu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_places_gear_landmark.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+ mGearFolderMenu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_places_gear_folder.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
mMenuAdd = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_place_add_button.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+ mGearLandmarkMenu->setVisibilityChangeCallback(boost::bind(&LLLandmarksPanel::onMenuVisibilityChange, this, _1, _2));
+ mGearFolderMenu->setVisibilityChangeCallback(boost::bind(&LLLandmarksPanel::onMenuVisibilityChange, this, _1, _2));
+
mListCommands->childSetAction(ADD_BUTTON_NAME, boost::bind(&LLLandmarksPanel::showActionMenu, this, mMenuAdd, ADD_BUTTON_NAME));
}
@@ -722,7 +728,7 @@ void LLLandmarksPanel::updateListCommands()
void LLLandmarksPanel::onActionsButtonClick()
{
- LLMenuGL* menu = mGearFolderMenu;
+ LLToggleableMenu* menu = mGearFolderMenu;
LLFolderViewItem* cur_item = NULL;
if(mCurrentSelectedList)
@@ -741,7 +747,7 @@ void LLLandmarksPanel::onActionsButtonClick()
}
}
- showActionMenu(menu,OPTIONS_BUTTON_NAME);
+ mGearButton->setMenu(menu);
}
void LLLandmarksPanel::showActionMenu(LLMenuGL* menu, std::string spawning_view_name)
@@ -750,7 +756,10 @@ void LLLandmarksPanel::showActionMenu(LLMenuGL* menu, std::string spawning_view_
{
menu->buildDrawLabels();
menu->updateParent(LLMenuGL::sMenuContainer);
- LLView* spawning_view = getChild<LLView> (spawning_view_name);
+ menu->arrangeAndClear();
+
+ LLView* spawning_view = getChild<LLView>(spawning_view_name);
+
S32 menu_x, menu_y;
//show menu in co-ordinates of panel
spawning_view->localPointToOtherView(0, spawning_view->getRect().getHeight(), &menu_x, &menu_y, this);
@@ -1074,6 +1083,60 @@ void LLLandmarksPanel::onCustomAction(const LLSD& userdata)
{
doActionOnCurSelectedLandmark(boost::bind(&LLLandmarksPanel::doCreatePick, this, _1));
}
+ else if ("restore" == command_name && mCurrentSelectedList)
+ {
+ mCurrentSelectedList->doToSelected(userdata);
+ }
+}
+
+void LLLandmarksPanel::onMenuVisibilityChange(LLUICtrl* ctrl, const LLSD& param)
+{
+ bool new_visibility = param["visibility"].asBoolean();
+
+ // We don't have to update items visibility if the menu is hiding.
+ if (!new_visibility) return;
+
+ BOOL are_any_items_in_trash = FALSE;
+ BOOL are_all_items_in_trash = TRUE;
+
+ LLFolderView* root_folder_view = mCurrentSelectedList ? mCurrentSelectedList->getRootFolder() : NULL;
+ if(root_folder_view)
+ {
+ const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
+
+ std::set<LLUUID> selected_uuids = root_folder_view->getSelectionList();
+
+ // Iterate through selected items to find out if any of these items are in Trash
+ // or all the items are in Trash category.
+ for (std::set<LLUUID>::const_iterator iter = selected_uuids.begin(); iter != selected_uuids.end(); ++iter)
+ {
+ LLFolderViewItem* item = root_folder_view->getItemByID(*iter);
+
+ // If no item is found it might be a folder id.
+ if (!item)
+ {
+ item = root_folder_view->getFolderByID(*iter);
+ }
+ if (!item) continue;
+
+ LLFolderViewEventListener* listenerp = item->getListener();
+ if(!listenerp) continue;
+
+ // Trash category itself should not be included because it can't be
+ // actually restored from trash.
+ are_all_items_in_trash &= listenerp->isItemInTrash() && *iter != trash_id;
+
+ // If there are any selected items in Trash including the Trash category itself
+ // we show "Restore Item" in context menu and hide other irrelevant items.
+ are_any_items_in_trash |= listenerp->isItemInTrash();
+ }
+ }
+
+ // Display "Restore Item" menu entry if at least one of the selected items
+ // is in Trash or the Trash category itself is among selected items.
+ // Hide other menu entries in this case.
+ // Enable this menu entry only if all selected items are in the Trash category.
+ toggle_restore_menu((LLMenuGL*)ctrl, are_any_items_in_trash, are_all_items_in_trash);
}
/*
@@ -1409,4 +1472,31 @@ static bool has_collapsed_folders(LLFolderView* root_folder)
return true;
}
+
+// Displays "Restore Item" context menu entry while hiding
+// all other entries or vice versa.
+// Sets "Restore Item" enabled state.
+void toggle_restore_menu(LLMenuGL *menu, BOOL visible, BOOL enabled)
+{
+ if (!menu) return;
+
+ const LLView::child_list_t *list = menu->getChildList();
+ for (LLView::child_list_t::const_iterator itor = list->begin();
+ itor != list->end();
+ ++itor)
+ {
+ LLView *menu_item = (*itor);
+ std::string name = menu_item->getName();
+
+ if ("restore_item" == name)
+ {
+ menu_item->setVisible(visible);
+ menu_item->setEnabled(enabled);
+ }
+ else
+ {
+ menu_item->setVisible(!visible);
+ }
+ }
+}
// EOF
diff --git a/indra/newview/llpanellandmarks.h b/indra/newview/llpanellandmarks.h
index 0d4402d8cb..b2f4e92473 100644
--- a/indra/newview/llpanellandmarks.h
+++ b/indra/newview/llpanellandmarks.h
@@ -39,7 +39,9 @@
class LLAccordionCtrlTab;
class LLFolderViewItem;
+class LLMenuButton;
class LLMenuGL;
+class LLToggleableMenu;
class LLInventoryPanel;
class LLPlacesInventoryPanel;
@@ -127,6 +129,14 @@ private:
void onCustomAction(const LLSD& command_name);
/**
+ * Updates context menu depending on the selected items location.
+ *
+ * For items in Trash category the menu includes the "Restore Item"
+ * context menu entry.
+ */
+ void onMenuVisibilityChange(LLUICtrl* ctrl, const LLSD& param);
+
+ /**
* Determines if an item can be modified via context/gear menu.
*
* It validates Places Landmarks rules first. And then LLFolderView permissions.
@@ -155,8 +165,9 @@ private:
LLPlacesInventoryPanel* mLandmarksInventoryPanel;
LLPlacesInventoryPanel* mMyInventoryPanel;
LLPlacesInventoryPanel* mLibraryInventoryPanel;
- LLMenuGL* mGearLandmarkMenu;
- LLMenuGL* mGearFolderMenu;
+ LLMenuButton* mGearButton;
+ LLToggleableMenu* mGearLandmarkMenu;
+ LLToggleableMenu* mGearFolderMenu;
LLMenuGL* mMenuAdd;
LLPlacesInventoryPanel* mCurrentSelectedList;
LLInventoryObserver* mInventoryObserver;
diff --git a/indra/newview/llpanellandmedia.cpp b/indra/newview/llpanellandmedia.cpp
index f17defda55..b3adfac8a2 100644
--- a/indra/newview/llpanellandmedia.cpp
+++ b/indra/newview/llpanellandmedia.cpp
@@ -68,8 +68,7 @@ LLPanelLandMedia::LLPanelLandMedia(LLParcelSelectionHandle& parcel)
mMediaSizeCtrlLabel(NULL),
mMediaTextureCtrl(NULL),
mMediaAutoScaleCheck(NULL),
- mMediaLoopCheck(NULL),
- mMediaUrlCheck(NULL)
+ mMediaLoopCheck(NULL)
{
}
@@ -94,9 +93,6 @@ BOOL LLPanelLandMedia::postBuild()
mMediaLoopCheck = getChild<LLCheckBoxCtrl>("media_loop");
childSetCommitCallback("media_loop", onCommitAny, this );
- mMediaUrlCheck = getChild<LLCheckBoxCtrl>("hide_media_url");
- childSetCommitCallback("hide_media_url", onCommitAny, this );
-
mMediaURLEdit = getChild<LLLineEditor>("media_url");
childSetCommitCallback("media_url", onCommitAny, this );
@@ -153,25 +149,6 @@ void LLPanelLandMedia::refresh()
mMediaTypeCombo->setEnabled( can_change_media );
getChild<LLUICtrl>("mime_type")->setValue(mime_type);
- mMediaUrlCheck->set( parcel->getObscureMedia() );
- mMediaUrlCheck->setEnabled( can_change_media );
-
- // don't display urls if you're not able to change it
- // much requested change in forums so people can't 'steal' urls
- // NOTE: bug#2009 means this is still vunerable - however, bug
- // should be closed since this bug opens up major security issues elsewhere.
- bool obscure_media = ! can_change_media && parcel->getObscureMedia();
-
- // Special code to disable asterixes for html type
- if(mime_type == "text/html")
- {
- obscure_media = false;
- mMediaUrlCheck->set( 0 );
- mMediaUrlCheck->setEnabled( false );
- }
-
- mMediaURLEdit->setDrawAsterixes( obscure_media );
-
mMediaAutoScaleCheck->set( parcel->getMediaAutoScale () );
mMediaAutoScaleCheck->setEnabled ( can_change_media );
@@ -301,7 +278,6 @@ void LLPanelLandMedia::onCommitAny(LLUICtrl*, void *userdata)
std::string mime_type = self->getChild<LLUICtrl>("mime_type")->getValue().asString();
U8 media_auto_scale = self->mMediaAutoScaleCheck->get();
U8 media_loop = self->mMediaLoopCheck->get();
- U8 obscure_media = self->mMediaUrlCheck->get();
S32 media_width = (S32)self->mMediaWidthCtrl->get();
S32 media_height = (S32)self->mMediaHeightCtrl->get();
LLUUID media_id = self->mMediaTextureCtrl->getImageAssetID();
@@ -321,7 +297,6 @@ void LLPanelLandMedia::onCommitAny(LLUICtrl*, void *userdata)
parcel->setMediaID(media_id);
parcel->setMediaAutoScale ( media_auto_scale );
parcel->setMediaLoop ( media_loop );
- parcel->setObscureMedia( obscure_media );
// Send current parcel data upstream to server
LLViewerParcelMgr::getInstance()->sendParcelPropertiesUpdate( parcel );
diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp
index 467aefc60f..d0810d0772 100644
--- a/indra/newview/llpanellogin.cpp
+++ b/indra/newview/llpanellogin.cpp
@@ -34,7 +34,9 @@
#include "llmd5.h"
#include "llsecondlifeurls.h"
#include "v4color.h"
+#include "llversionviewer.h"
+#include "llappviewer.h"
#include "llbutton.h"
#include "llcheckboxctrl.h"
#include "llcommandhandler.h" // for secondlife:///app/login/
@@ -73,7 +75,6 @@
#endif // LL_WINDOWS
#include "llsdserialize.h"
-#define USE_VIEWER_AUTH 0
const S32 BLACK_BORDER_HEIGHT = 160;
const S32 MAX_PASSWORD = 16;
@@ -81,6 +82,9 @@ const S32 MAX_PASSWORD = 16;
LLPanelLogin *LLPanelLogin::sInstance = NULL;
BOOL LLPanelLogin::sCapslockDidNotification = FALSE;
+// Helper for converting a user name into the canonical "Firstname Lastname" form.
+// For new accounts without a last name "Resident" is added as a last name.
+static std::string canonicalize_username(const std::string& name);
class LLLoginRefreshHandler : public LLCommandHandler
{
@@ -97,58 +101,6 @@ public:
}
};
-LLLoginRefreshHandler gLoginRefreshHandler;
-
-
-// helper class that trys to download a URL from a web site and calls a method
-// on parent class indicating if the web server is working or not
-class LLIamHereLogin : public LLHTTPClient::Responder
-{
- private:
- LLIamHereLogin( LLPanelLogin* parent ) :
- mParent( parent )
- {}
-
- LLPanelLogin* mParent;
-
- public:
- static boost::intrusive_ptr< LLIamHereLogin > build( LLPanelLogin* parent )
- {
- return boost::intrusive_ptr< LLIamHereLogin >( new LLIamHereLogin( parent ) );
- };
-
- virtual void setParent( LLPanelLogin* parentIn )
- {
- mParent = parentIn;
- };
-
- // We don't actually expect LLSD back, so need to override completedRaw
- virtual void completedRaw(U32 status, const std::string& reason,
- const LLChannelDescriptors& channels,
- const LLIOPipe::buffer_ptr_t& buffer)
- {
- completed(status, reason, LLSD()); // will call result() or error()
- }
-
- virtual void result( const LLSD& content )
- {
- if ( mParent )
- mParent->setSiteIsAlive( true );
- };
-
- virtual void error( U32 status, const std::string& reason )
- {
- if ( mParent )
- mParent->setSiteIsAlive( false );
- };
-};
-
-// this is global and not a class member to keep crud out of the header file
-namespace {
- boost::intrusive_ptr< LLIamHereLogin > gResponsePtr = 0;
-};
-
-
//---------------------------------------------------------------------------
// Public methods
//---------------------------------------------------------------------------
@@ -160,11 +112,8 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,
mLogoImage(),
mCallback(callback),
mCallbackData(cb_data),
- mHtmlAvailable( TRUE ),
mListener(new LLPanelLoginListener(this))
{
- setFocusRoot(TRUE);
-
setBackgroundVisible(FALSE);
setBackgroundOpaque(TRUE);
@@ -181,39 +130,24 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,
mPasswordModified = FALSE;
LLPanelLogin::sInstance = this;
- // add to front so we are the bottom-most child
- gViewerWindow->getRootView()->addChildInBack(this);
+ LLView* login_holder = gViewerWindow->getLoginPanelHolder();
+ if (login_holder)
+ {
+ login_holder->addChild(this);
+ }
// Logo
mLogoImage = LLUI::getUIImage("startup_logo");
buildFromFile( "panel_login.xml");
-#if USE_VIEWER_AUTH
- //leave room for the login menu bar
- setRect(LLRect(0, rect.getHeight()-18, rect.getWidth(), 0));
-#endif
- // Legacy login web page is hidden under the menu bar.
- // Adjust reg-in-client web browser widget to not be hidden.
- if (gSavedSettings.getBOOL("RegInClient"))
- {
- reshape(rect.getWidth(), rect.getHeight() - MENU_BAR_HEIGHT);
- }
- else
- {
- reshape(rect.getWidth(), rect.getHeight());
- }
+ reshape(rect.getWidth(), rect.getHeight());
-#if !USE_VIEWER_AUTH
getChild<LLLineEditor>("password_edit")->setKeystrokeCallback(onPassKey, this);
// change z sort of clickable text to be behind buttons
- //sendChildToBack(getChildView("channel_text"));
sendChildToBack(getChildView("forgot_password_text"));
- LLLineEditor* edit = getChild<LLLineEditor>("password_edit");
- if (edit) edit->setDrawAsterixes(TRUE);
-
if(LLStartUp::getStartSLURL().getType() != LLSLURL::LOCATION)
{
LLSLURL slurl(gSavedSettings.getString("LoginLocation"));
@@ -221,6 +155,10 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,
}
updateLocationCombo(false);
+ 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);
server_choice_combo->setFocusLostCallback(boost::bind(onServerComboLostFocus, _1));
@@ -230,7 +168,7 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,
getChild<LLPanel>("login")->setDefaultBtn("connect_btn");
- std::string channel = gSavedSettings.getString("VersionChannelName");
+ std::string channel = LLVersionInfo::getChannel();
std::string version = llformat("%s (%d)",
LLVersionInfo::getShortVersion().c_str(),
LLVersionInfo::getBuild());
@@ -247,26 +185,82 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,
LLTextBox* need_help_text = getChild<LLTextBox>("login_help");
need_help_text->setClickedCallback(onClickHelp, NULL);
-#endif
// get the web browser control
LLMediaCtrl* web_browser = getChild<LLMediaCtrl>("login_html");
web_browser->addObserver(this);
- // Clear the browser's cache to avoid any potential for the cache messing up the login screen.
- web_browser->clearCache();
-
reshapeBrowser();
- // kick off a request to grab the url manually
- gResponsePtr = LLIamHereLogin::build( this );
+ loadLoginPage();
+
+ // Show last logged in user favorites in "Start at" combo.
+ addUsersWithFavoritesToUsername();
+ getChild<LLComboBox>("username_combo")->setTextChangedCallback(boost::bind(&LLPanelLogin::addFavoritesToStartLocation, this));
- LLHTTPClient::head( LLGridManager::getInstance()->getLoginPage(), gResponsePtr );
-
updateLocationCombo(false);
}
+void LLPanelLogin::addUsersWithFavoritesToUsername()
+{
+ LLComboBox* combo = getChild<LLComboBox>("username_combo");
+ if (!combo) return;
+ std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "stored_favorites.xml");
+ LLSD fav_llsd;
+ llifstream file;
+ file.open(filename);
+ if (!file.is_open()) return;
+ LLSDSerialize::fromXML(fav_llsd, file);
+ for (LLSD::map_const_iterator iter = fav_llsd.beginMap();
+ iter != fav_llsd.endMap(); ++iter)
+ {
+ combo->add(iter->first);
+ }
+}
+
+void LLPanelLogin::addFavoritesToStartLocation()
+{
+ LLComboBox* combo = getChild<LLComboBox>("start_location_combo");
+ if (!combo) return;
+ int num_items = combo->getItemCount();
+ for (int i = num_items - 1; i > 2; i--)
+ {
+ combo->remove(i);
+ }
+ std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "stored_favorites.xml");
+ LLSD fav_llsd;
+ llifstream file;
+ file.open(filename);
+ if (!file.is_open()) return;
+ LLSDSerialize::fromXML(fav_llsd, file);
+ for (LLSD::map_const_iterator iter = fav_llsd.beginMap();
+ iter != fav_llsd.endMap(); ++iter)
+ {
+ std::string user_defined_name = getChild<LLComboBox>("username_combo")->getSimple();
+
+ // The account name in stored_favorites.xml has Resident last name even if user has
+ // a single word account name, so it can be compared case-insensitive with the
+ // user defined "firstname lastname".
+ S32 res = LLStringUtil::compareInsensitive(canonicalize_username(user_defined_name), iter->first);
+ if (res != 0) continue;
+
+ combo->addSeparator();
+ LLSD user_llsd = iter->second;
+ for (LLSD::array_const_iterator iter1 = user_llsd.beginArray();
+ iter1 != user_llsd.endArray(); ++iter1)
+ {
+ std::string label = (*iter1)["name"].asString();
+ std::string value = (*iter1)["slurl"].asString();
+ if(label != "" && value != "")
+ {
+ combo->add(label, value);
+ }
+ }
+ break;
+ }
+}
+
// force the size to be correct (XML doesn't seem to be sufficient to do this)
// (with some padding so the other login screen doesn't show through)
void LLPanelLogin::reshapeBrowser()
@@ -274,71 +268,18 @@ void LLPanelLogin::reshapeBrowser()
LLMediaCtrl* web_browser = getChild<LLMediaCtrl>("login_html");
LLRect rect = gViewerWindow->getWindowRectScaled();
LLRect html_rect;
-#if USE_VIEWER_AUTH
- html_rect.setCenterAndSize(
- rect.getCenterX() - 2, rect.getCenterY(),
- rect.getWidth() + 6, rect.getHeight());
-#else
html_rect.setCenterAndSize(
rect.getCenterX() - 2, rect.getCenterY() + 40,
rect.getWidth() + 6, rect.getHeight() - 78 );
-#endif
web_browser->setRect( html_rect );
web_browser->reshape( html_rect.getWidth(), html_rect.getHeight(), TRUE );
reshape( rect.getWidth(), rect.getHeight(), 1 );
}
-void LLPanelLogin::setSiteIsAlive( bool alive )
-{
- LLMediaCtrl* web_browser = getChild<LLMediaCtrl>("login_html");
- // if the contents of the site was retrieved
- if ( alive )
- {
- if ( web_browser )
- {
- loadLoginPage();
-
- // mark as available
- mHtmlAvailable = TRUE;
- }
- }
- else
- // the site is not available (missing page, server down, other badness)
- {
-#if !USE_VIEWER_AUTH
- if ( web_browser )
- {
- // hide browser control (revealing default one)
- web_browser->setVisible( FALSE );
-
- // mark as unavailable
- mHtmlAvailable = FALSE;
- }
-#else
-
- if ( web_browser )
- {
- web_browser->navigateToLocalPage( "loading-error" , "index.html" );
-
- // mark as available
- mHtmlAvailable = TRUE;
- }
-#endif
- }
-}
-
-
LLPanelLogin::~LLPanelLogin()
{
LLPanelLogin::sInstance = NULL;
- // tell the responder we're not here anymore
- if ( gResponsePtr )
- gResponsePtr->setParent( 0 );
-
- //// We know we're done with the image, so be rid of it.
- //gTextureList.deleteImage( mLogoImage );
-
// Controls having keyboard focus by default
// must reset it on destroy. (EXT-2748)
gFocusMgr.setDefaultKeyboardFocus(NULL);
@@ -361,24 +302,13 @@ void LLPanelLogin::draw()
S32 width = getRect().getWidth();
S32 height = getRect().getHeight();
- if ( mHtmlAvailable )
- {
-#if !USE_VIEWER_AUTH
- if (getChild<LLView>("login_widgets")->getVisible())
- {
- // draw a background box in black
- gl_rect_2d( 0, height - 264, width, 264, LLColor4::black );
- // draw the bottom part of the background image
- // just the blue background to the native client UI
- mLogoImage->draw(0, -264, width + 8, mLogoImage->getHeight());
- }
-#endif
- }
- else
+ if (getChild<LLView>("login_widgets")->getVisible())
{
- // the HTML login page is not available so default to the original screen
- S32 offscreen_part = height / 3;
- mLogoImage->draw(0, -offscreen_part, width, height+offscreen_part);
+ // draw a background box in black
+ gl_rect_2d( 0, height - 264, width, 264, LLColor4::black );
+ // draw the bottom part of the background image
+ // just the blue background to the native client UI
+ mLogoImage->draw(0, -264, width + 8, mLogoImage->getHeight());
};
}
glPopMatrix();
@@ -418,22 +348,17 @@ void LLPanelLogin::setFocus(BOOL b)
// static
void LLPanelLogin::giveFocus()
{
-#if USE_VIEWER_AUTH
- if (sInstance)
- {
- sInstance->setFocus(TRUE);
- }
-#else
if( sInstance )
{
// Grab focus and move cursor to first blank input field
- std::string username = sInstance->getChild<LLUICtrl>("username_edit")->getValue().asString();
+ std::string username = sInstance->getChild<LLUICtrl>("username_combo")->getValue().asString();
std::string pass = sInstance->getChild<LLUICtrl>("password_edit")->getValue().asString();
BOOL have_username = !username.empty();
BOOL have_pass = !pass.empty();
LLLineEditor* edit = NULL;
+ LLComboBox* combo = NULL;
if (have_username && !have_pass)
{
// User saved his name but not his password. Move
@@ -443,7 +368,7 @@ void LLPanelLogin::giveFocus()
else
{
// User doesn't have a name, so start there.
- edit = sInstance->getChild<LLLineEditor>("username_edit");
+ combo = sInstance->getChild<LLComboBox>("username_combo");
}
if (edit)
@@ -451,21 +376,26 @@ void LLPanelLogin::giveFocus()
edit->setFocus(TRUE);
edit->selectAll();
}
+ else if (combo)
+ {
+ combo->setFocus(TRUE);
+ }
}
-#endif
}
// static
void LLPanelLogin::showLoginWidgets()
{
+ // *NOTE: Mani - This may or may not be obselete code.
+ // It seems to be part of the defunct? reg-in-client project.
sInstance->getChildView("login_widgets")->setVisible( true);
LLMediaCtrl* web_browser = sInstance->getChild<LLMediaCtrl>("login_html");
sInstance->reshapeBrowser();
// *TODO: Append all the usual login parameters, like first_login=Y etc.
- std::string splash_screen_url = sInstance->getString("real_url");
+ std::string splash_screen_url = LLGridManager::getInstance()->getLoginPage();
web_browser->navigateTo( splash_screen_url, "text/html" );
- LLUICtrl* username_edit = sInstance->getChild<LLUICtrl>("username_edit");
- username_edit->setFocus(TRUE);
+ LLUICtrl* username_combo = sInstance->getChild<LLUICtrl>("username_combo");
+ username_combo->setFocus(TRUE);
}
// static
@@ -509,16 +439,17 @@ void LLPanelLogin::setFields(LLPointer<LLCredential> credential,
login_id += " ";
login_id += lastname;
}
- sInstance->getChild<LLUICtrl>("username_edit")->setValue(login_id);
+ sInstance->getChild<LLComboBox>("username_combo")->setLabel(login_id);
}
else if((std::string)identifier["type"] == "account")
{
- sInstance->getChild<LLUICtrl>("username_edit")->setValue((std::string)identifier["account_name"]);
+ sInstance->getChild<LLComboBox>("username_combo")->setLabel((std::string)identifier["account_name"]);
}
else
{
- sInstance->getChild<LLUICtrl>("username_edit")->setValue(std::string());
+ sInstance->getChild<LLComboBox>("username_combo")->setLabel(std::string());
}
+ sInstance->addFavoritesToStartLocation();
// if the password exists in the credential, set the password field with
// a filler to get some stars
LLSD authenticator = credential->getAuthenticator();
@@ -566,7 +497,7 @@ void LLPanelLogin::getFields(LLPointer<LLCredential>& credential,
authenticator = credential->getAuthenticator();
}
- std::string username = sInstance->getChild<LLUICtrl>("username_edit")->getValue().asString();
+ std::string username = sInstance->getChild<LLUICtrl>("username_combo")->getValue().asString();
LLStringUtil::trim(username);
std::string password = sInstance->getChild<LLUICtrl>("password_edit")->getValue().asString();
@@ -658,15 +589,15 @@ BOOL LLPanelLogin::areCredentialFieldsDirty()
}
else
{
- std::string username = sInstance->getChild<LLUICtrl>("username_edit")->getValue().asString();
+ std::string username = sInstance->getChild<LLUICtrl>("username_combo")->getValue().asString();
LLStringUtil::trim(username);
std::string password = sInstance->getChild<LLUICtrl>("password_edit")->getValue().asString();
- LLLineEditor* ctrl = sInstance->getChild<LLLineEditor>("username_edit");
- if(ctrl && ctrl->isDirty())
+ LLComboBox* combo = sInstance->getChild<LLComboBox>("username_combo");
+ if(combo && combo->isDirty())
{
return true;
}
- ctrl = sInstance->getChild<LLLineEditor>("password_edit");
+ LLLineEditor* ctrl = sInstance->getChild<LLLineEditor>("password_edit");
if(ctrl && ctrl->isDirty())
{
return true;
@@ -761,7 +692,7 @@ void LLPanelLogin::closePanel()
{
if (sInstance)
{
- gViewerWindow->getRootView()->removeChild( LLPanelLogin::sInstance );
+ LLPanelLogin::sInstance->getParent()->removeChild( LLPanelLogin::sInstance );
delete sInstance;
sInstance = NULL;
@@ -817,12 +748,20 @@ void LLPanelLogin::loadLoginPage()
LLVersionInfo::getShortVersion().c_str(),
LLVersionInfo::getBuild());
- char* curl_channel = curl_escape(gSavedSettings.getString("VersionChannelName").c_str(), 0);
+ char* curl_channel ;
char* curl_version = curl_escape(version.c_str(), 0);
+ if(strcmp(LLVersionInfo::getChannel().c_str(), LL_CHANNEL))
+ {
+ curl_channel = curl_escape(LLVersionInfo::getChannel().c_str(), 0);
+ }
+ else //if LL_CHANNEL, direct it to "Second Life Beta Viewer".
+ {
+ curl_channel = curl_escape("Second Life Beta Viewer", 0);
+ }
oStr << "&channel=" << curl_channel;
oStr << "&version=" << curl_version;
-
+
curl_free(curl_channel);
curl_free(curl_version);
@@ -830,86 +769,16 @@ void LLPanelLogin::loadLoginPage()
char* curl_grid = curl_escape(LLGridManager::getInstance()->getGridLabel().c_str(), 0);
oStr << "&grid=" << curl_grid;
curl_free(curl_grid);
- gViewerWindow->setMenuBackgroundColor(false, !LLGridManager::getInstance()->isInProductionGrid());
- gLoginMenuBarView->setBackgroundColor(gMenuBarView->getBackgroundColor());
-
-
-#if USE_VIEWER_AUTH
- LLURLSimString::sInstance.parse();
-
- std::string location;
- std::string region;
- std::string password;
- if (LLURLSimString::parse())
- {
- std::ostringstream oRegionStr;
- location = "specify";
- oRegionStr << LLURLSimString::sInstance.mSimName << "/" << LLURLSimString::sInstance.mX << "/"
- << LLURLSimString::sInstance.mY << "/"
- << LLURLSimString::sInstance.mZ;
- region = oRegionStr.str();
- }
- else
- {
- location = gSavedSettings.getString("LoginLocation");
- }
-
- std::string username;
-
- if(gSavedSettings.getLLSD("UserLoginInfo").size() == 3)
- {
- LLSD cmd_line_login = gSavedSettings.getLLSD("UserLoginInfo");
- username = cmd_line_login[0].asString() + " " + cmd_line_login[1];
- password = cmd_line_login[2].asString();
- }
-
-
- char* curl_region = curl_escape(region.c_str(), 0);
-
- oStr <<"username=" << username <<
- "&location=" << location << "&region=" << curl_region;
+ // add OS info
+ char * os_info = curl_escape(LLAppViewer::instance()->getOSInfo().getOSStringSimple().c_str(), 0);
+ oStr << "&os=" << os_info;
+ curl_free(os_info);
- curl_free(curl_region);
-
- if (!password.empty())
- {
- oStr << "&password=" << password;
- }
- else if (!(password = load_password_from_disk()).empty())
- {
- oStr << "&password=$1$" << password;
- }
- if (gAutoLogin)
- {
- oStr << "&auto_login=TRUE";
- }
- if (gSavedSettings.getBOOL("ShowStartLocation"))
- {
- oStr << "&show_start_location=TRUE";
- }
- if (gSavedSettings.getBOOL("RememberPassword"))
- {
- oStr << "&remember_password=TRUE";
- }
-#ifndef LL_RELEASE_FOR_DOWNLOAD
- oStr << "&show_grid=TRUE";
-#else
- if (gSavedSettings.getBOOL("ForceShowGrid"))
- oStr << "&show_grid=TRUE";
-#endif
-#endif
+ gViewerWindow->setMenuBackgroundColor(false, !LLGridManager::getInstance()->isInProductionGrid());
LLMediaCtrl* web_browser = sInstance->getChild<LLMediaCtrl>("login_html");
-
- // navigate to the "real" page
- if (gSavedSettings.getBOOL("RegInClient"))
- {
- web_browser->setFocus(TRUE);
- login_page = sInstance->getString("reg_in_client_url");
- web_browser->navigateTo(login_page, "text/html");
- }
- else
+ if (web_browser->getCurrentNavUrl() != oStr.str())
{
web_browser->navigateTo( oStr.str(), "text/html" );
}
@@ -943,10 +812,6 @@ void LLPanelLogin::onClickConnect(void *)
{
if (sInstance && sInstance->mCallback)
{
- // tell the responder we're not here anymore
- if ( gResponsePtr )
- gResponsePtr->setParent( 0 );
-
// JC - Make sure the fields all get committed.
sInstance->setFocus(FALSE);
@@ -973,7 +838,7 @@ void LLPanelLogin::onClickConnect(void *)
return;
}
updateStartSLURL();
- std::string username = sInstance->getChild<LLUICtrl>("username_edit")->getValue().asString();
+ std::string username = sInstance->getChild<LLUICtrl>("username_combo")->getValue().asString();
if(username.empty())
@@ -1014,24 +879,6 @@ void LLPanelLogin::onClickConnect(void *)
}
}
-/*
-// static
-bool LLPanelLogin::newAccountAlertCallback(const LLSD& notification, const LLSD& response)
-{
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
- if (0 == option)
- {
- llinfos << "Going to account creation URL" << llendl;
- LLWeb::loadURLExternal( LLNotifications::instance().getGlobalString("CREATE_ACCOUNT_URL"));
- }
- else
- {
- sInstance->setFocus(TRUE);
- }
- return false;
-}
-*/
-
// static
void LLPanelLogin::onClickNewAccount(void*)
{
@@ -1186,3 +1033,54 @@ void LLPanelLogin::updateLoginPanelLinks()
sInstance->getChildView("create_new_account_text")->setVisible( system_grid);
sInstance->getChildView("forgot_password_text")->setVisible( system_grid);
}
+
+void LLPanelLogin::onModeChange(const LLSD& original_value, const LLSD& new_value)
+{
+ if (original_value.asString() != new_value.asString())
+ {
+ LLNotificationsUtil::add("ModeChange", LLSD(), LLSD(), boost::bind(&LLPanelLogin::onModeChangeConfirm, this, original_value, new_value, _1, _2));
+ }
+}
+
+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:
+ gSavedSettings.getControl("SessionSettingsFile")->set(new_value);
+ LLAppViewer::instance()->forceQuit();
+ break;
+ case 1:
+ // revert to original value
+ getChild<LLUICtrl>("mode_combo")->setValue(original_value);
+ break;
+ default:
+ break;
+ }
+}
+
+std::string canonicalize_username(const std::string& name)
+{
+ std::string cname = name;
+ LLStringUtil::trim(cname);
+
+ // determine if the username is a first/last form or not.
+ size_t separator_index = cname.find_first_of(" ._");
+ std::string first = cname.substr(0, separator_index);
+ std::string last;
+ if (separator_index != cname.npos)
+ {
+ last = cname.substr(separator_index+1, cname.npos);
+ LLStringUtil::trim(last);
+ }
+ else
+ {
+ // ...on Linden grids, single username users as considered to have
+ // last name "Resident"
+ last = "Resident";
+ }
+
+ // Username in traditional "firstname lastname" form.
+ return first + ' ' + last;
+}
diff --git a/indra/newview/llpanellogin.h b/indra/newview/llpanellogin.h
index 83e76a308b..11273453ba 100644
--- a/indra/newview/llpanellogin.h
+++ b/indra/newview/llpanellogin.h
@@ -85,9 +85,10 @@ public:
private:
friend class LLPanelLoginListener;
void reshapeBrowser();
+ void addFavoritesToStartLocation();
+ void addUsersWithFavoritesToUsername();
static void onClickConnect(void*);
static void onClickNewAccount(void*);
-// static bool newAccountAlertCallback(const LLSD& notification, const LLSD& response);
static void onClickVersion(void*);
static void onClickForgotPassword(void*);
static void onClickHelp(void*);
@@ -96,6 +97,8 @@ private:
static void onServerComboLostFocus(LLFocusableElement*);
static void updateServerCombo();
static void updateStartSLURL();
+ 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();
@@ -110,7 +113,6 @@ private:
static LLPanelLogin* sInstance;
static BOOL sCapslockDidNotification;
- BOOL mHtmlAvailable;
};
std::string load_password_from_disk(void);
diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp
index 5b07e4863b..bc4998dd0c 100644
--- a/indra/newview/llpanelmaininventory.cpp
+++ b/indra/newview/llpanelmaininventory.cpp
@@ -39,12 +39,14 @@
#include "llinventorypanel.h"
#include "llfiltereditor.h"
#include "llfloaterreg.h"
+#include "llmenubutton.h"
#include "lloutfitobserver.h"
#include "llpreviewtexture.h"
#include "llresmgr.h"
#include "llscrollcontainer.h"
#include "llsdserialize.h"
#include "llspinctrl.h"
+#include "lltoggleablemenu.h"
#include "lltooldraganddrop.h"
#include "llviewermenu.h"
#include "llviewertexturelist.h"
@@ -79,7 +81,6 @@ public:
BOOL getCheckSinceLogoff();
static void onTimeAgo(LLUICtrl*, void *);
- static void onCheckSinceLogoff(LLUICtrl*, void *);
static void onCloseBtn(void* user_data);
static void selectAllTypes(void* user_data);
static void selectNoTypes(void* user_data);
@@ -116,18 +117,6 @@ LLPanelMainInventory::LLPanelMainInventory()
mCommitCallbackRegistrar.add("Inventory.SetSortBy", boost::bind(&LLPanelMainInventory::setSortBy, this, _2));
mCommitCallbackRegistrar.add("Inventory.Share", boost::bind(&LLAvatarActions::shareWithAvatars));
- // Controls
- // *TODO: Just use persistant settings for each of these
- U32 sort_order = gSavedSettings.getU32(LLInventoryPanel::DEFAULT_SORT_ORDER);
- BOOL sort_by_name = ! ( sort_order & LLInventoryFilter::SO_DATE );
- BOOL sort_folders_by_name = ( sort_order & LLInventoryFilter::SO_FOLDERS_BY_NAME );
- BOOL sort_system_folders_to_top = ( sort_order & LLInventoryFilter::SO_SYSTEM_FOLDERS_TO_TOP );
-
- gSavedSettings.declareBOOL("Inventory.SortByName", sort_by_name, "Declared in code", FALSE);
- gSavedSettings.declareBOOL("Inventory.SortByDate", !sort_by_name, "Declared in code", FALSE);
- gSavedSettings.declareBOOL("Inventory.FoldersAlwaysByName", sort_folders_by_name, "Declared in code", FALSE);
- gSavedSettings.declareBOOL("Inventory.SystemFoldersToTop", sort_system_folders_to_top, "Declared in code", FALSE);
-
mSavedFolderState = new LLSaveFolderState();
mSavedFolderState->setApply(FALSE);
}
@@ -150,6 +139,7 @@ BOOL LLPanelMainInventory::postBuild()
mActivePanel->getFilter()->markDefault();
mActivePanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState);
mActivePanel->setSelectCallback(boost::bind(&LLPanelMainInventory::onSelectionChange, this, mActivePanel, _1, _2));
+ mResortActivePanel = true;
}
LLInventoryPanel* recent_items_panel = getChild<LLInventoryPanel>("Recent Items");
if (recent_items_panel)
@@ -192,6 +182,8 @@ BOOL LLPanelMainInventory::postBuild()
mFilterEditor->setCommitCallback(boost::bind(&LLPanelMainInventory::onFilterEdit, this, _2));
}
+ mGearMenuButton = getChild<LLMenuButton>("options_gear_btn");
+
initListCommandsHandlers();
// *TODO:Get the cost info from the server
@@ -321,57 +313,41 @@ void LLPanelMainInventory::resetFilters()
void LLPanelMainInventory::setSortBy(const LLSD& userdata)
{
- std::string sort_field = userdata.asString();
- if (sort_field == "name")
+ U32 sort_order_mask = getActivePanel()->getSortOrder();
+ std::string sort_type = userdata.asString();
+ if (sort_type == "name")
{
- U32 order = getActivePanel()->getSortOrder();
- getActivePanel()->setSortOrder( order & ~LLInventoryFilter::SO_DATE );
-
- gSavedSettings.setBOOL("Inventory.SortByName", TRUE );
- gSavedSettings.setBOOL("Inventory.SortByDate", FALSE );
+ sort_order_mask &= ~LLInventoryFilter::SO_DATE;
}
- else if (sort_field == "date")
+ else if (sort_type == "date")
{
- U32 order = getActivePanel()->getSortOrder();
- getActivePanel()->setSortOrder( order | LLInventoryFilter::SO_DATE );
-
- gSavedSettings.setBOOL("Inventory.SortByName", FALSE );
- gSavedSettings.setBOOL("Inventory.SortByDate", TRUE );
+ sort_order_mask |= LLInventoryFilter::SO_DATE;
}
- else if (sort_field == "foldersalwaysbyname")
+ else if (sort_type == "foldersalwaysbyname")
{
- U32 order = getActivePanel()->getSortOrder();
- if ( order & LLInventoryFilter::SO_FOLDERS_BY_NAME )
+ if ( sort_order_mask & LLInventoryFilter::SO_FOLDERS_BY_NAME )
{
- order &= ~LLInventoryFilter::SO_FOLDERS_BY_NAME;
-
- gSavedSettings.setBOOL("Inventory.FoldersAlwaysByName", FALSE );
+ sort_order_mask &= ~LLInventoryFilter::SO_FOLDERS_BY_NAME;
}
else
{
- order |= LLInventoryFilter::SO_FOLDERS_BY_NAME;
-
- gSavedSettings.setBOOL("Inventory.FoldersAlwaysByName", TRUE );
+ sort_order_mask |= LLInventoryFilter::SO_FOLDERS_BY_NAME;
}
- getActivePanel()->setSortOrder( order );
}
- else if (sort_field == "systemfolderstotop")
+ else if (sort_type == "systemfolderstotop")
{
- U32 order = getActivePanel()->getSortOrder();
- if ( order & LLInventoryFilter::SO_SYSTEM_FOLDERS_TO_TOP )
+ if ( sort_order_mask & LLInventoryFilter::SO_SYSTEM_FOLDERS_TO_TOP )
{
- order &= ~LLInventoryFilter::SO_SYSTEM_FOLDERS_TO_TOP;
-
- gSavedSettings.setBOOL("Inventory.SystemFoldersToTop", FALSE );
+ sort_order_mask &= ~LLInventoryFilter::SO_SYSTEM_FOLDERS_TO_TOP;
}
else
{
- order |= LLInventoryFilter::SO_SYSTEM_FOLDERS_TO_TOP;
-
- gSavedSettings.setBOOL("Inventory.SystemFoldersToTop", TRUE );
+ sort_order_mask |= LLInventoryFilter::SO_SYSTEM_FOLDERS_TO_TOP;
}
- getActivePanel()->setSortOrder( order );
}
+
+ getActivePanel()->setSortOrder(sort_order_mask);
+ gSavedSettings.setU32("InventorySortOrder", sort_order_mask);
}
// static
@@ -492,9 +468,6 @@ void LLPanelMainInventory::onFilterSelected()
return;
}
- BOOL recent_active = ("Recent Items" == mActivePanel->getName());
- getChildView("add_btn_panel")->setVisible( !recent_active);
-
setFilterSubString(mFilterSubString);
LLInventoryFilter* filter = mActivePanel->getFilter();
LLFloaterInventoryFinder *finder = getFinder();
@@ -556,6 +529,17 @@ void LLPanelMainInventory::draw()
{
mFilterEditor->setText(mFilterSubString);
}
+ if (mActivePanel && mResortActivePanel)
+ {
+ // EXP-756: Force resorting of the list the first time we draw the list:
+ // In the case of date sorting, we don't have enough information at initialization time
+ // to correctly sort the folders. Later manual resort doesn't do anything as the order value is
+ // set correctly. The workaround is to reset the order to alphabetical (or anything) then to the correct order.
+ U32 order = mActivePanel->getSortOrder();
+ mActivePanel->setSortOrder(LLInventoryFilter::SO_NAME);
+ mActivePanel->setSortOrder(order);
+ mResortActivePanel = false;
+ }
LLPanel::draw();
updateItemcountText();
}
@@ -646,20 +630,6 @@ LLFloaterInventoryFinder::LLFloaterInventoryFinder(LLPanelMainInventory* invento
updateElementsFromFilter();
}
-
-void LLFloaterInventoryFinder::onCheckSinceLogoff(LLUICtrl *ctrl, void *user_data)
-{
- LLFloaterInventoryFinder *self = (LLFloaterInventoryFinder *)user_data;
- if (!self) return;
-
- bool since_logoff= self->getChild<LLUICtrl>("check_since_logoff")->getValue();
-
- if (!since_logoff &&
- !( self->mSpinSinceDays->get() || self->mSpinSinceHours->get() ) )
- {
- self->mSpinSinceHours->set(1.0f);
- }
-}
BOOL LLFloaterInventoryFinder::postBuild()
{
const LLRect& viewrect = mPanelMainInventory->getRect();
@@ -674,9 +644,6 @@ BOOL LLFloaterInventoryFinder::postBuild()
mSpinSinceDays = getChild<LLSpinCtrl>("spin_days_ago");
childSetCommitCallback("spin_days_ago", onTimeAgo, this);
- // mCheckSinceLogoff = getChild<LLSpinCtrl>("check_since_logoff");
- childSetCommitCallback("check_since_logoff", onCheckSinceLogoff, this);
-
childSetAction("Close", onCloseBtn, this);
updateElementsFromFilter();
@@ -687,12 +654,10 @@ void LLFloaterInventoryFinder::onTimeAgo(LLUICtrl *ctrl, void *user_data)
LLFloaterInventoryFinder *self = (LLFloaterInventoryFinder *)user_data;
if (!self) return;
- bool since_logoff=true;
if ( self->mSpinSinceDays->get() || self->mSpinSinceHours->get() )
{
- since_logoff = false;
+ self->getChild<LLUICtrl>("check_since_logoff")->setValue(false);
}
- self->getChild<LLUICtrl>("check_since_logoff")->setValue(since_logoff);
}
void LLFloaterInventoryFinder::changeFilter(LLInventoryFilter* filter)
@@ -721,6 +686,7 @@ void LLFloaterInventoryFinder::updateElementsFromFilter()
getChild<LLUICtrl>("check_clothing")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_WEARABLE));
getChild<LLUICtrl>("check_gesture")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_GESTURE));
getChild<LLUICtrl>("check_landmark")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_LANDMARK));
+ getChild<LLUICtrl>("check_mesh")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_MESH));
getChild<LLUICtrl>("check_notecard")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_NOTECARD));
getChild<LLUICtrl>("check_object")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_OBJECT));
getChild<LLUICtrl>("check_script")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_LSL));
@@ -772,6 +738,12 @@ void LLFloaterInventoryFinder::draw()
filtered_by_all_types = FALSE;
}
+ if (!getChild<LLUICtrl>("check_mesh")->getValue())
+ {
+ filter &= ~(0x1 << LLInventoryType::IT_MESH);
+ filtered_by_all_types = FALSE;
+ }
+
if (!getChild<LLUICtrl>("check_notecard")->getValue())
{
filter &= ~(0x1 << LLInventoryType::IT_NOTECARD);
@@ -868,6 +840,7 @@ void LLFloaterInventoryFinder::selectAllTypes(void* user_data)
self->getChild<LLUICtrl>("check_clothing")->setValue(TRUE);
self->getChild<LLUICtrl>("check_gesture")->setValue(TRUE);
self->getChild<LLUICtrl>("check_landmark")->setValue(TRUE);
+ self->getChild<LLUICtrl>("check_mesh")->setValue(TRUE);
self->getChild<LLUICtrl>("check_notecard")->setValue(TRUE);
self->getChild<LLUICtrl>("check_object")->setValue(TRUE);
self->getChild<LLUICtrl>("check_script")->setValue(TRUE);
@@ -887,6 +860,7 @@ void LLFloaterInventoryFinder::selectNoTypes(void* user_data)
self->getChild<LLUICtrl>("check_clothing")->setValue(FALSE);
self->getChild<LLUICtrl>("check_gesture")->setValue(FALSE);
self->getChild<LLUICtrl>("check_landmark")->setValue(FALSE);
+ self->getChild<LLUICtrl>("check_mesh")->setValue(FALSE);
self->getChild<LLUICtrl>("check_notecard")->setValue(FALSE);
self->getChild<LLUICtrl>("check_object")->setValue(FALSE);
self->getChild<LLUICtrl>("check_script")->setValue(FALSE);
@@ -900,7 +874,6 @@ void LLFloaterInventoryFinder::selectNoTypes(void* user_data)
void LLPanelMainInventory::initListCommandsHandlers()
{
- childSetAction("options_gear_btn", boost::bind(&LLPanelMainInventory::onGearButtonClick, this));
childSetAction("trash_btn", boost::bind(&LLPanelMainInventory::onTrashButtonClick, this));
childSetAction("add_btn", boost::bind(&LLPanelMainInventory::onAddButtonClick, this));
@@ -912,8 +885,10 @@ void LLPanelMainInventory::initListCommandsHandlers()
));
mCommitCallbackRegistrar.add("Inventory.GearDefault.Custom.Action", boost::bind(&LLPanelMainInventory::onCustomAction, this, _2));
+ mEnableCallbackRegistrar.add("Inventory.GearDefault.Check", boost::bind(&LLPanelMainInventory::isActionChecked, this, _2));
mEnableCallbackRegistrar.add("Inventory.GearDefault.Enable", boost::bind(&LLPanelMainInventory::isActionEnabled, this, _2));
- mMenuGearDefault = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_inventory_gear_default.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+ mMenuGearDefault = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_inventory_gear_default.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+ mGearMenuButton->setMenu(mMenuGearDefault);
mMenuAdd = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_inventory_add.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
// Update the trash button when selected item(s) get worn or taken off.
@@ -927,13 +902,13 @@ void LLPanelMainInventory::updateListCommands()
mTrashButton->setEnabled(trash_enabled);
}
-void LLPanelMainInventory::onGearButtonClick()
-{
- showActionMenu(mMenuGearDefault,"options_gear_btn");
-}
-
void LLPanelMainInventory::onAddButtonClick()
{
+// Gray out the "New Folder" option when the Recent tab is active as new folders will not be displayed
+// unless "Always show folders" is checked in the filter options.
+ bool recent_active = ("Recent Items" == mActivePanel->getName());
+ mMenuAdd->getChild<LLMenuItemGL>("New Folder")->setEnabled(!recent_active);
+
setUploadCostIfNeeded();
showActionMenu(mMenuAdd,"add_btn");
@@ -1001,6 +976,16 @@ void LLPanelMainInventory::onCustomAction(const LLSD& userdata)
const LLSD arg = "date";
setSortBy(arg);
}
+ if (command_name == "sort_folders_by_name")
+ {
+ const LLSD arg = "foldersalwaysbyname";
+ setSortBy(arg);
+ }
+ if (command_name == "sort_system_folders_to_top")
+ {
+ const LLSD arg = "systemfolderstotop";
+ setSortBy(arg);
+ }
if (command_name == "show_filters")
{
toggleFindOptions();
@@ -1174,6 +1159,33 @@ BOOL LLPanelMainInventory::isActionEnabled(const LLSD& userdata)
return TRUE;
}
+BOOL LLPanelMainInventory::isActionChecked(const LLSD& userdata)
+{
+ U32 sort_order_mask = getActivePanel()->getSortOrder();
+ const std::string command_name = userdata.asString();
+ if (command_name == "sort_by_name")
+ {
+ return ~sort_order_mask & LLInventoryFilter::SO_DATE;
+ }
+
+ if (command_name == "sort_by_recent")
+ {
+ return sort_order_mask & LLInventoryFilter::SO_DATE;
+ }
+
+ if (command_name == "sort_folders_by_name")
+ {
+ return sort_order_mask & LLInventoryFilter::SO_FOLDERS_BY_NAME;
+ }
+
+ if (command_name == "sort_system_folders_to_top")
+ {
+ return sort_order_mask & LLInventoryFilter::SO_SYSTEM_FOLDERS_TO_TOP;
+ }
+
+ return FALSE;
+}
+
bool LLPanelMainInventory::handleDragAndDropToTrash(BOOL drop, EDragAndDropType cargo_type, EAcceptance* accept)
{
*accept = ACCEPT_NO;
diff --git a/indra/newview/llpanelmaininventory.h b/indra/newview/llpanelmaininventory.h
index cf2cc14531..2b2ee1c0c9 100644
--- a/indra/newview/llpanelmaininventory.h
+++ b/indra/newview/llpanelmaininventory.h
@@ -40,7 +40,9 @@ class LLSaveFolderState;
class LLFilterEditor;
class LLTabContainer;
class LLFloaterInventoryFinder;
+class LLMenuButton;
class LLMenuGL;
+class LLToggleableMenu;
class LLFloater;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -119,6 +121,7 @@ private:
LLTabContainer* mFilterTabs;
LLHandle<LLFloater> mFinderHandle;
LLInventoryPanel* mActivePanel;
+ bool mResortActivePanel;
LLSaveFolderState* mSavedFolderState;
std::string mFilterText;
std::string mFilterSubString;
@@ -129,12 +132,12 @@ private:
protected:
void initListCommandsHandlers();
void updateListCommands();
- void onGearButtonClick();
void onAddButtonClick();
void showActionMenu(LLMenuGL* menu, std::string spawning_view_name);
void onTrashButtonClick();
void onClipboardAction(const LLSD& userdata);
BOOL isActionEnabled(const LLSD& command_name);
+ BOOL isActionChecked(const LLSD& userdata);
void onCustomAction(const LLSD& command_name);
bool handleDragAndDropToTrash(BOOL drop, EDragAndDropType cargo_type, EAcceptance* accept);
/**
@@ -143,8 +146,9 @@ protected:
void setUploadCostIfNeeded();
private:
LLDragAndDropButton* mTrashButton;
- LLMenuGL* mMenuGearDefault;
+ LLToggleableMenu* mMenuGearDefault;
LLMenuGL* mMenuAdd;
+ LLMenuButton* mGearMenuButton;
bool mNeedUploadCost;
// List Commands //
diff --git a/indra/newview/llpanelme.cpp b/indra/newview/llpanelme.cpp
index 5ea94e0611..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;
}
@@ -76,17 +74,19 @@ void LLPanelMe::onOpen(const LLSD& key)
{
LLPanelProfile::onOpen(key);
- // Force Edit My Profile if this is the first time when user is opening Me Panel (EXT-5068)
- bool opened = gSavedSettings.getBOOL("MePanelOpened");
- // In some cases Side Tray my call onOpen() twice, check getCollapsed() to be sure this
- // is the last time onOpen() is called
- if( !opened && !LLSideTray::getInstance()->getCollapsed() )
- {
- buildEditPanel();
- openPanel(mEditPanel, getAvatarId());
-
- gSavedSettings.setBOOL("MePanelOpened", true);
- }
+ // Removed this action as per SOCIAL-431 The first time a new resident opens the profile tab
+ // in the sidebar, they see the old profile editing panel
+ //
+ //// Force Edit My Profile if this is the first time when user is opening Me Panel (EXT-5068)
+ //bool opened = gSavedSettings.getBOOL("MePanelOpened");
+ //// In some cases Side Tray my call onOpen() twice, check getCollapsed() to be sure this
+ //// is the last time onOpen() is called
+ //if( !opened && !LLSideTray::getInstance()->getCollapsed() )
+ //{
+ // buildEditPanel();
+ // openPanel(mEditPanel, getAvatarId());
+ // gSavedSettings.setBOOL("MePanelOpened", true);
+ //}
}
bool LLPanelMe::notifyChildren(const LLSD& info)
@@ -133,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);
}
}
@@ -145,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/llpanelnearbymedia.cpp b/indra/newview/llpanelnearbymedia.cpp
index fcc67d6840..2bbd15ae11 100644
--- a/indra/newview/llpanelnearbymedia.cpp
+++ b/indra/newview/llpanelnearbymedia.cpp
@@ -356,7 +356,7 @@ void LLPanelNearByMedia::updateListItem(LLScrollListItem* item, LLViewerMediaImp
debug_str += llformat("%g/", (float)impl->getInterest());
// proximity distance is actually distance squared -- display it as straight distance.
- debug_str += llformat("%g/", fsqrtf(impl->getProximityDistance()));
+ debug_str += llformat("%g/", (F32) sqrt(impl->getProximityDistance()));
// s += llformat("%g/", (float)impl->getCPUUsage());
// s += llformat("%g/", (float)impl->getApproximateTextureInterest());
@@ -564,16 +564,14 @@ void LLPanelNearByMedia::refreshParcelItems()
if (NULL != mParcelMediaItem)
{
std::string name, url, tooltip;
- if (!LLViewerParcelMgr::getInstance()->getAgentParcel()->getObscureMedia())
+ getNameAndUrlHelper(LLViewerParcelMedia::getParcelMedia(), name, url, "");
+ if (name.empty() || name == url)
{
- getNameAndUrlHelper(LLViewerParcelMedia::getParcelMedia(), name, url, "");
- if (name.empty() || name == url)
- {
- tooltip = url;
- }
- else {
- tooltip = name + " : " + url;
- }
+ tooltip = url;
+ }
+ else
+ {
+ tooltip = name + " : " + url;
}
LLViewerMediaImpl *impl = LLViewerParcelMedia::getParcelMedia();
updateListItem(mParcelMediaItem,
@@ -611,10 +609,8 @@ void LLPanelNearByMedia::refreshParcelItems()
bool is_playing = LLViewerMedia::isParcelAudioPlaying();
std::string url;
- if (!LLViewerParcelMgr::getInstance()->getAgentParcel()->getObscureMusic())
- {
- url = LLViewerMedia::getParcelAudioURL();
- }
+ url = LLViewerMedia::getParcelAudioURL();
+
updateListItem(mParcelAudioItem,
mParcelAudioName,
url,
@@ -958,7 +954,7 @@ void LLPanelNearByMedia::onAdvancedButtonClick()
void LLPanelNearByMedia::onMoreLess()
{
- bool is_more = getChild<LLUICtrl>("more_btn")->getVisible();
+ bool is_more = getChild<LLButton>("more_btn")->getToggleState();
mNearbyMediaPanel->setVisible(is_more);
// enable resizing when expanded
@@ -969,8 +965,7 @@ void LLPanelNearByMedia::onMoreLess()
setShape(new_rect);
- getChild<LLUICtrl>("more_btn")->setVisible(!is_more);
- getChild<LLUICtrl>("less_btn")->setVisible(is_more);
+ getChild<LLUICtrl>("more_btn")->setVisible(true);
}
void LLPanelNearByMedia::updateControls()
diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp
index d756a1b931..64af6c2157 100644
--- a/indra/newview/llpanelobject.cpp
+++ b/indra/newview/llpanelobject.cpp
@@ -131,7 +131,8 @@ BOOL LLPanelObject::postBuild()
// Phantom checkbox
mCheckPhantom = getChild<LLCheckBoxCtrl>("Phantom Checkbox Ctrl");
childSetCommitCallback("Phantom Checkbox Ctrl",onCommitPhantom,this);
-
+
+
// Position
mLabelPosition = getChild<LLTextBox>("label position");
mCtrlPosX = getChild<LLSpinCtrl>("Pos X");
@@ -519,6 +520,7 @@ void LLPanelObject::getState( )
mCheckPhantom->set( mIsPhantom );
mCheckPhantom->setEnabled( roots_selected>0 && editable && !is_flexible );
+
#if 0 // 1.9.2
mCastShadows = root_objectp->flagCastShadows();
mCheckCastShadows->set( mCastShadows );
@@ -569,6 +571,7 @@ void LLPanelObject::getState( )
BOOL enabled = FALSE;
BOOL hole_enabled = FALSE;
F32 scale_x=1.f, scale_y=1.f;
+ BOOL isMesh = FALSE;
if( !objectp || !objectp->getVolume() || !editable || !single_volume)
{
@@ -599,10 +602,9 @@ void LLPanelObject::getState( )
// Only allowed to change these parameters for objects
// that you have permissions on AND are not attachments.
enabled = root_objectp->permModify();
-
- const LLVolumeParams &volume_params = objectp->getVolume()->getParams();
-
+
// Volume type
+ const LLVolumeParams &volume_params = objectp->getVolume()->getParams();
U8 path = volume_params.getPathParams().getCurveType();
U8 profile_and_hole = volume_params.getProfileParams().getCurveType();
U8 profile = profile_and_hole & LL_PCODE_PROFILE_MASK;
@@ -833,7 +835,7 @@ void LLPanelObject::getState( )
}
mSpinSkew->set( skew );
}
-
+
// Compute control visibility, label names, and twist range.
// Start with defaults.
BOOL cut_visible = TRUE;
@@ -1101,7 +1103,9 @@ void LLPanelObject::getState( )
if (selected_item == MI_SCULPT)
{
- LLUUID id;
+
+
+ LLUUID id;
LLSculptParams *sculpt_params = (LLSculptParams *)objectp->getParameterEntry(LLNetworkData::PARAMS_SCULPT);
@@ -1113,26 +1117,29 @@ void LLPanelObject::getState( )
mSculptTypeRevert = sculpt_params->getSculptType();
}
+ U8 sculpt_type = sculpt_params->getSculptType();
+ U8 sculpt_stitching = sculpt_type & LL_SCULPT_TYPE_MASK;
+ BOOL sculpt_invert = sculpt_type & LL_SCULPT_FLAG_INVERT;
+ BOOL sculpt_mirror = sculpt_type & LL_SCULPT_FLAG_MIRROR;
+ isMesh = (sculpt_stitching == LL_SCULPT_TYPE_MESH);
+
LLTextureCtrl* mTextureCtrl = getChild<LLTextureCtrl>("sculpt texture control");
if(mTextureCtrl)
{
mTextureCtrl->setTentative(FALSE);
- mTextureCtrl->setEnabled(editable);
+ mTextureCtrl->setEnabled(editable && !isMesh);
if (editable)
mTextureCtrl->setImageAssetID(sculpt_params->getSculptTexture());
else
mTextureCtrl->setImageAssetID(LLUUID::null);
}
- U8 sculpt_type = sculpt_params->getSculptType();
- U8 sculpt_stitching = sculpt_type & LL_SCULPT_TYPE_MASK;
- BOOL sculpt_invert = sculpt_type & LL_SCULPT_FLAG_INVERT;
- BOOL sculpt_mirror = sculpt_type & LL_SCULPT_FLAG_MIRROR;
+ mComboBaseType->setEnabled(!isMesh);
if (mCtrlSculptType)
{
mCtrlSculptType->setCurrentByIndex(sculpt_stitching);
- mCtrlSculptType->setEnabled(editable);
+ mCtrlSculptType->setEnabled(editable && !isMesh);
}
if (mCtrlSculptMirror)
@@ -1151,14 +1158,14 @@ void LLPanelObject::getState( )
{
mLabelSculptType->setEnabled(TRUE);
}
+
}
}
else
{
- mSculptTextureRevert = LLUUID::null;
+ mSculptTextureRevert = LLUUID::null;
}
-
//----------------------------------------------------------------------------
mObject = objectp;
@@ -1695,10 +1702,10 @@ void LLPanelObject::sendPosition(BOOL btn_down)
LLVector3 newpos(mCtrlPosX->get(), mCtrlPosY->get(), mCtrlPosZ->get());
LLViewerRegion* regionp = mObject->getRegion();
-
+
// Clamp the Z height
const F32 height = newpos.mV[VZ];
- const F32 min_height = LLWorld::getInstance()->getMinAllowedZ(mObject);
+ const F32 min_height = LLWorld::getInstance()->getMinAllowedZ(mObject, mObject->getPositionGlobal());
const F32 max_height = LLWorld::getInstance()->getRegionMaxHeight();
if (!mObject->isAttachment())
@@ -1786,6 +1793,17 @@ void LLPanelObject::sendSculpt()
if (mCtrlSculptType)
sculpt_type |= mCtrlSculptType->getCurrentIndex();
+ bool enabled = sculpt_type != LL_SCULPT_TYPE_MESH;
+
+ if (mCtrlSculptMirror)
+ {
+ mCtrlSculptMirror->setEnabled(enabled ? TRUE : FALSE);
+ }
+ if (mCtrlSculptInvert)
+ {
+ mCtrlSculptInvert->setEnabled(enabled ? TRUE : FALSE);
+ }
+
if ((mCtrlSculptMirror) && (mCtrlSculptMirror->get()))
sculpt_type |= LL_SCULPT_FLAG_MIRROR;
@@ -1808,6 +1826,26 @@ void LLPanelObject::refresh()
{
mRootObject = NULL;
}
+
+ bool enable_mesh = gSavedSettings.getBOOL("MeshEnabled") &&
+ gAgent.getRegion() &&
+ !gAgent.getRegion()->getCapability("GetMesh").empty();
+
+ F32 max_scale = get_default_max_prim_scale(LLPickInfo::isFlora(mObject));
+
+ getChild<LLSpinCtrl>("Scale X")->setMaxValue(max_scale);
+ getChild<LLSpinCtrl>("Scale Y")->setMaxValue(max_scale);
+ getChild<LLSpinCtrl>("Scale Z")->setMaxValue(max_scale);
+
+ BOOL found = mCtrlSculptType->itemExists("Mesh");
+ if (enable_mesh && !found)
+ {
+ mCtrlSculptType->add("Mesh");
+ }
+ else if (!enable_mesh && found)
+ {
+ mCtrlSculptType->remove("Mesh");
+ }
}
@@ -1894,6 +1932,7 @@ void LLPanelObject::clearCtrls()
mCheckTemporary ->setEnabled( FALSE );
mCheckPhantom ->set(FALSE);
mCheckPhantom ->setEnabled( FALSE );
+
#if 0 // 1.9.2
mCheckCastShadows->set(FALSE);
mCheckCastShadows->setEnabled( FALSE );
diff --git a/indra/newview/llpanelobject.h b/indra/newview/llpanelobject.h
index e07bf007ec..e2f2a4400d 100644
--- a/indra/newview/llpanelobject.h
+++ b/indra/newview/llpanelobject.h
@@ -62,14 +62,14 @@ public:
static void onCommitPosition( LLUICtrl* ctrl, void* userdata);
static void onCommitScale( LLUICtrl* ctrl, void* userdata);
static void onCommitRotation( LLUICtrl* ctrl, void* userdata);
- static void onCommitPhysics( LLUICtrl* ctrl, void* userdata);
static void onCommitTemporary( LLUICtrl* ctrl, void* userdata);
static void onCommitPhantom( LLUICtrl* ctrl, void* userdata);
static void onCommitCastShadows( LLUICtrl* ctrl, void* userdata);
+ static void onCommitPhysics( LLUICtrl* ctrl, void* userdata);
+ static void onCommitMaterial( LLUICtrl* ctrl, void* userdata);
static void onCommitParametric(LLUICtrl* ctrl, void* userdata);
- static void onCommitMaterial( LLUICtrl* ctrl, void* userdata);
void onCommitSculpt(const LLSD& data);
void onCancelSculpt(const LLSD& data);
@@ -87,6 +87,7 @@ protected:
void sendIsPhysical();
void sendIsTemporary();
void sendIsPhantom();
+
void sendCastShadows();
void sendSculpt();
diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp
index 211b9cf4b1..bfe6cab52f 100644
--- a/indra/newview/llpanelobjectinventory.cpp
+++ b/indra/newview/llpanelobjectinventory.cpp
@@ -766,22 +766,12 @@ BOOL LLTaskCategoryBridge::startDrag(EDragAndDropType* type, LLUUID* id) const
LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID());
if(object)
{
- const LLInventoryItem *inv = dynamic_cast<LLInventoryItem*>(object->getInventoryObject(mUUID));
- if (inv)
+ const LLInventoryObject* cat = object->getInventoryObject(mUUID);
+ if ( (cat) && (move_inv_category_world_to_agent(mUUID, LLUUID::null, FALSE)) )
{
- const LLPermissions& perm = inv->getPermissions();
- bool can_copy = gAgent.allowOperation(PERM_COPY, perm,
- GP_OBJECT_MANIPULATE);
- if((can_copy && perm.allowTransferTo(gAgent.getID()))
- || object->permYouOwner())
-// || gAgent.isGodlike())
-
- {
- *type = LLViewerAssetType::lookupDragAndDropType(inv->getType());
-
- *id = inv->getUUID();
- return TRUE;
- }
+ *type = LLViewerAssetType::lookupDragAndDropType(cat->getType());
+ *id = mUUID;
+ return TRUE;
}
}
}
@@ -812,6 +802,7 @@ BOOL LLTaskCategoryBridge::dragOrDrop(MASK mask, BOOL drop,
case DAD_ANIMATION:
case DAD_GESTURE:
case DAD_CALLINGCARD:
+ case DAD_MESH:
accept = LLToolDragAndDrop::isInventoryDropAcceptable(object, (LLViewerInventoryItem*)cargo_data);
if(accept && drop)
{
@@ -1237,6 +1228,116 @@ LLUIImagePtr LLTaskWearableBridge::getIcon() const
return LLInventoryIcon::getIcon(mAssetType, mInventoryType, mFlags, FALSE );
}
+///----------------------------------------------------------------------------
+/// Class LLTaskMeshBridge
+///----------------------------------------------------------------------------
+
+class LLTaskMeshBridge : public LLTaskInvFVBridge
+{
+public:
+ LLTaskMeshBridge(
+ LLPanelObjectInventory* panel,
+ const LLUUID& uuid,
+ const std::string& name);
+
+ virtual LLUIImagePtr getIcon() const;
+ virtual void openItem();
+ virtual void performAction(LLInventoryModel* model, std::string action);
+ virtual void buildContextMenu(LLMenuGL& menu, U32 flags);
+};
+
+LLTaskMeshBridge::LLTaskMeshBridge(
+ LLPanelObjectInventory* panel,
+ const LLUUID& uuid,
+ const std::string& name) :
+ LLTaskInvFVBridge(panel, uuid, name)
+{
+}
+
+LLUIImagePtr LLTaskMeshBridge::getIcon() const
+{
+ return LLInventoryIcon::getIcon(LLAssetType::AT_MESH, LLInventoryType::IT_MESH, 0, FALSE);
+}
+
+void LLTaskMeshBridge::openItem()
+{
+ // open mesh
+}
+
+
+// virtual
+void LLTaskMeshBridge::performAction(LLInventoryModel* model, std::string action)
+{
+ if (action == "mesh action")
+ {
+ LLInventoryItem* item = findItem();
+ if(item)
+ {
+ // do action
+ }
+ }
+ LLTaskInvFVBridge::performAction(model, action);
+}
+
+void LLTaskMeshBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
+{
+ LLInventoryItem* item = findItem();
+ if(!item) return;
+ std::vector<std::string> items;
+ std::vector<std::string> disabled_items;
+
+ if(item->getPermissions().getOwner() != gAgent.getID()
+ && item->getSaleInfo().isForSale())
+ {
+ items.push_back(std::string("Task Buy"));
+
+ std::string label= LLTrans::getString("Buy");
+ // Check the price of the item.
+ S32 price = getPrice();
+ if (-1 == price)
+ {
+ llwarns << "label_buy_task_bridged_item: Invalid price" << llendl;
+ }
+ else
+ {
+ std::ostringstream info;
+ info << LLTrans::getString("BuyforL$") << price;
+ label.assign(info.str());
+ }
+
+ const LLView::child_list_t *list = menu.getChildList();
+ LLView::child_list_t::const_iterator itor;
+ for (itor = list->begin(); itor != list->end(); ++itor)
+ {
+ std::string name = (*itor)->getName();
+ LLMenuItemCallGL* menu_itemp = dynamic_cast<LLMenuItemCallGL*>(*itor);
+ if (name == "Task Buy" && menu_itemp)
+ {
+ menu_itemp->setLabel(label);
+ }
+ }
+ }
+ else
+ {
+ items.push_back(std::string("Task Open"));
+ if (!isItemCopyable())
+ {
+ disabled_items.push_back(std::string("Task Open"));
+ }
+ }
+ items.push_back(std::string("Task Properties"));
+ if(isItemRenameable())
+ {
+ items.push_back(std::string("Task Rename"));
+ }
+ if(isItemRemovable())
+ {
+ items.push_back(std::string("Task Remove"));
+ }
+
+
+ hide_context_entries(menu, items, disabled_items);
+}
///----------------------------------------------------------------------------
/// LLTaskInvFVBridge impl
@@ -1317,6 +1418,11 @@ LLTaskInvFVBridge* LLTaskInvFVBridge::createObjectBridge(LLPanelObjectInventory*
object->getUUID(),
object->getName());
break;
+ case LLAssetType::AT_MESH:
+ new_bridge = new LLTaskMeshBridge(panel,
+ object->getUUID(),
+ object->getName());
+ break;
default:
llinfos << "Unhandled inventory type (llassetstorage.h): "
<< (S32)type << llendl;
diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp
index 408d4f29b7..62f582c343 100644
--- a/indra/newview/llpaneloutfitedit.cpp
+++ b/indra/newview/llpaneloutfitedit.cpp
@@ -56,11 +56,13 @@
#include "llinventorymodel.h"
#include "llinventorymodelbackgroundfetch.h"
#include "llloadingindicator.h"
+#include "llmenubutton.h"
#include "llpaneloutfitsinventory.h"
#include "lluiconstants.h"
#include "llsaveoutfitcombobtn.h"
#include "llscrolllistctrl.h"
#include "lltextbox.h"
+#include "lltoggleablemenu.h"
#include "lltrans.h"
#include "lluictrlfactory.h"
#include "llsdutil.h"
@@ -151,13 +153,13 @@ std::string LLShopURLDispatcher::resolveURL(LLAssetType::EType asset_type, ESex
class LLPanelOutfitEditGearMenu
{
public:
- static LLMenuGL* create()
+ static LLToggleableMenu* create()
{
LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
registrar.add("Wearable.Create", boost::bind(onCreate, _2));
- LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>(
+ LLToggleableMenu* menu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>(
"menu_cof_gear.xml", LLMenuGL::sMenuContainer, LLViewerMenuHolderGL::child_registry_t::instance());
llassert(menu);
if (menu)
@@ -184,14 +186,8 @@ private:
// Populate the menu with items like "New Skin", "New Pants", etc.
static void populateCreateWearableSubmenus(LLMenuGL* menu)
{
- LLView* menu_clothes = gMenuHolder->findChildView("COF.Gear.New_Clothes", FALSE);
- LLView* menu_bp = gMenuHolder->findChildView("COF.Geear.New_Body_Parts", FALSE);
-
- if (!menu_clothes || !menu_bp)
- {
- llassert(menu_clothes && menu_bp);
- return;
- }
+ LLView* menu_clothes = gMenuHolder->getChildView("COF.Gear.New_Clothes", FALSE);
+ LLView* menu_bp = gMenuHolder->getChildView("COF.Geear.New_Body_Parts", FALSE);
for (U8 i = LLWearableType::WT_SHAPE; i != (U8) LLWearableType::WT_COUNT; ++i)
{
@@ -218,7 +214,7 @@ private:
class LLAddWearablesGearMenu : public LLInitClass<LLAddWearablesGearMenu>
{
public:
- static LLMenuGL* create(LLWearableItemsList* flat_list, LLInventoryPanel* inventory_panel)
+ static LLToggleableMenu* create(LLWearableItemsList* flat_list, LLInventoryPanel* inventory_panel)
{
LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
@@ -233,7 +229,7 @@ public:
enable_registrar.add("AddWearable.Gear.Check", boost::bind(onCheck, flat_list_handle, inventory_panel_handle, _2));
enable_registrar.add("AddWearable.Gear.Visible", boost::bind(onVisible, inventory_panel_handle, _2));
- LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>(
+ LLToggleableMenu* menu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>(
"menu_add_wearable_gear.xml",
LLMenuGL::sMenuContainer, LLViewerMenuHolderGL::child_registry_t::instance());
@@ -404,7 +400,9 @@ LLPanelOutfitEdit::LLPanelOutfitEdit()
mFolderViewFilterCmbBox(NULL),
mListViewFilterCmbBox(NULL),
mWearableListManager(NULL),
- mPlusBtn(NULL)
+ mPlusBtn(NULL),
+ mWearablesGearMenuBtn(NULL),
+ mGearMenuBtn(NULL)
{
mSavedFolderState = new LLSaveFolderState();
mSavedFolderState->setApply(FALSE);
@@ -468,6 +466,7 @@ BOOL LLPanelOutfitEdit::postBuild()
mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("skirt"), new LLFindActualWearablesOfType(LLWearableType::WT_SKIRT)));
mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("alpha"), new LLFindActualWearablesOfType(LLWearableType::WT_ALPHA)));
mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("tattoo"), new LLFindActualWearablesOfType(LLWearableType::WT_TATTOO)));
+ mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("physics"), new LLFindActualWearablesOfType(LLWearableType::WT_PHYSICS)));
mCurrentOutfitName = getChild<LLTextBox>("curr_outfit_name");
mStatus = getChild<LLTextBox>("status");
@@ -480,13 +479,14 @@ BOOL LLPanelOutfitEdit::postBuild()
childSetCommitCallback("folder_view_btn", boost::bind(&LLPanelOutfitEdit::saveListSelection, this), NULL);
childSetCommitCallback("list_view_btn", boost::bind(&LLPanelOutfitEdit::showWearablesListView, this), NULL);
childSetCommitCallback("list_view_btn", boost::bind(&LLPanelOutfitEdit::saveListSelection, this), NULL);
- childSetCommitCallback("wearables_gear_menu_btn", boost::bind(&LLPanelOutfitEdit::onGearButtonClick, this, _1), NULL);
- childSetCommitCallback("gear_menu_btn", boost::bind(&LLPanelOutfitEdit::onGearButtonClick, this, _1), NULL);
childSetCommitCallback("shop_btn_1", boost::bind(&LLPanelOutfitEdit::onShopButtonClicked, this), NULL);
childSetCommitCallback("shop_btn_2", boost::bind(&LLPanelOutfitEdit::onShopButtonClicked, this), NULL);
setVisibleCallback(boost::bind(&LLPanelOutfitEdit::onVisibilityChange, this, _2));
+ mWearablesGearMenuBtn = getChild<LLMenuButton>("wearables_gear_menu_btn");
+ mGearMenuBtn = getChild<LLMenuButton>("gear_menu_btn");
+
mCOFWearables = findChild<LLCOFWearables>("cof_wearables_list");
mCOFWearables->setCommitCallback(boost::bind(&LLPanelOutfitEdit::filterWearablesBySelectedItem, this));
@@ -559,6 +559,13 @@ BOOL LLPanelOutfitEdit::postBuild()
mWearableItemsList->setComparator(mWearableListViewItemsComparator);
+ // Creating "Add Wearables" panel gear menu after initialization of mWearableItemsList and mInventoryItemsPanel.
+ mAddWearablesGearMenu = LLAddWearablesGearMenu::create(mWearableItemsList, mInventoryItemsPanel);
+ mWearablesGearMenuBtn->setMenu(mAddWearablesGearMenu);
+
+ mGearMenu = LLPanelOutfitEditGearMenu::create();
+ mGearMenuBtn->setMenu(mGearMenu);
+
mSaveComboBtn.reset(new LLSaveOutfitComboBtn(this));
return TRUE;
}
@@ -1258,37 +1265,6 @@ void LLPanelOutfitEdit::resetAccordionState()
}
}
-void LLPanelOutfitEdit::onGearButtonClick(LLUICtrl* clicked_button)
-{
- LLMenuGL* menu = NULL;
-
- if (mAddWearablesPanel->getVisible())
- {
- if (!mAddWearablesGearMenu)
- {
- mAddWearablesGearMenu = LLAddWearablesGearMenu::create(mWearableItemsList, mInventoryItemsPanel);
- }
-
- menu = mAddWearablesGearMenu;
- }
- else
- {
- if (!mGearMenu)
- {
- mGearMenu = LLPanelOutfitEditGearMenu::create();
- }
-
- menu = mGearMenu;
- }
-
- if (!menu) return;
-
- menu->arrangeAndClear(); // update menu height
- S32 menu_y = menu->getRect().getHeight() + clicked_button->getRect().getHeight();
- menu->buildDrawLabels();
- LLMenuGL::showPopup(clicked_button, menu, 0, menu_y);
-}
-
void LLPanelOutfitEdit::onAddMoreButtonClicked()
{
toggleAddWearablesPanel();
@@ -1348,19 +1324,19 @@ void LLPanelOutfitEdit::getCurrentItemUUID(LLUUID& selected_id)
void LLPanelOutfitEdit::getSelectedItemsUUID(uuid_vec_t& uuid_list)
{
+ void (uuid_vec_t::* tmp)(LLUUID const &) = &uuid_vec_t::push_back;
if (mInventoryItemsPanel->getVisible())
{
std::set<LLUUID> item_set = mInventoryItemsPanel->getRootFolder()->getSelectionList();
- std::for_each(item_set.begin(), item_set.end(), boost::bind( &uuid_vec_t::push_back, &uuid_list, _1));
+ std::for_each(item_set.begin(), item_set.end(), boost::bind( tmp, &uuid_list, _1));
}
else if (mWearablesListViewPanel->getVisible())
{
std::vector<LLSD> item_set;
mWearableItemsList->getSelectedValues(item_set);
- std::for_each(item_set.begin(), item_set.end(), boost::bind( &uuid_vec_t::push_back, &uuid_list, boost::bind(&LLSD::asUUID, _1 )));
-
+ std::for_each(item_set.begin(), item_set.end(), boost::bind( tmp, &uuid_list, boost::bind(&LLSD::asUUID, _1 )));
}
// return selected_id;
diff --git a/indra/newview/llpaneloutfitedit.h b/indra/newview/llpaneloutfitedit.h
index 2dca986e33..5d4b8d4644 100644
--- a/indra/newview/llpaneloutfitedit.h
+++ b/indra/newview/llpaneloutfitedit.h
@@ -54,6 +54,7 @@ class LLScrollListCtrl;
class LLToggleableMenu;
class LLFilterEditor;
class LLFilteredWearableListManager;
+class LLMenuButton;
class LLMenuGL;
class LLFindNonLinksByMask;
class LLFindWearablesOfType;
@@ -96,6 +97,7 @@ public:
LVIT_SKIRT,
LVIT_ALPHA,
LVIT_TATTOO,
+ LVIT_PHYSICS,
NUM_LIST_VIEW_ITEM_TYPES
} EListViewItemType;
@@ -186,8 +188,6 @@ public:
std::string& tooltip_msg);
private:
-
- void onGearButtonClick(LLUICtrl* clicked_button);
void onAddMoreButtonClicked();
void showFilteredWearablesListView(LLWearableType::EType type);
void onOutfitChanging(bool started);
@@ -234,12 +234,12 @@ private:
std::vector<LLFilterItem*> mListViewItemTypes;
LLCOFWearables* mCOFWearables;
- LLMenuGL* mGearMenu;
- LLMenuGL* mAddWearablesGearMenu;
+ LLToggleableMenu* mGearMenu;
+ LLToggleableMenu* mAddWearablesGearMenu;
bool mInitialized;
std::auto_ptr<LLSaveOutfitComboBtn> mSaveComboBtn;
-
-
+ LLMenuButton* mWearablesGearMenuBtn;
+ LLMenuButton* mGearMenuBtn;
};
diff --git a/indra/newview/llpaneloutfitsinventory.cpp b/indra/newview/llpaneloutfitsinventory.cpp
index d6d8a38ebe..a90f864ae2 100644
--- a/indra/newview/llpaneloutfitsinventory.cpp
+++ b/indra/newview/llpaneloutfitsinventory.cpp
@@ -232,9 +232,7 @@ void LLPanelOutfitsInventory::initListCommandsHandlers()
{
mListCommands = getChild<LLPanel>("bottom_panel");
mListCommands->childSetAction("wear_btn", boost::bind(&LLPanelOutfitsInventory::onWearButtonClick, this));
- mMyOutfitsPanel->childSetAction("options_gear_btn", boost::bind(&LLPanelOutfitsInventory::showGearMenu, this));
mMyOutfitsPanel->childSetAction("trash_btn", boost::bind(&LLPanelOutfitsInventory::onTrashButtonClick, this));
- mCurrentOutfitPanel->childSetAction("options_gear_btn", boost::bind(&LLPanelOutfitsInventory::showGearMenu, this));
}
void LLPanelOutfitsInventory::updateListCommands()
@@ -258,27 +256,9 @@ void LLPanelOutfitsInventory::updateListCommands()
}
}
-void LLPanelOutfitsInventory::showGearMenu()
-{
- if (!mActivePanel) return;
-
- LLView* spawning_view = getChild<LLView>("options_gear_btn");
- mActivePanel->showGearMenu(spawning_view);
-}
-
void LLPanelOutfitsInventory::onTrashButtonClick()
{
- LLNotificationsUtil::add("DeleteOutfits", LLSD(), LLSD(), boost::bind(&LLPanelOutfitsInventory::onOutfitsRemovalConfirmation, this, _1, _2));
-}
-
-void LLPanelOutfitsInventory::onOutfitsRemovalConfirmation(const LLSD& notification, const LLSD& response)
-{
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
- if (option != 0) return; // canceled
-
mMyOutfitsPanel->removeSelected();
- updateListCommands();
- updateVerbs();
}
bool LLPanelOutfitsInventory::isActionEnabled(const LLSD& userdata)
diff --git a/indra/newview/llpaneloutfitsinventory.h b/indra/newview/llpaneloutfitsinventory.h
index f1ca1dbfeb..a7917b457c 100644
--- a/indra/newview/llpaneloutfitsinventory.h
+++ b/indra/newview/llpaneloutfitsinventory.h
@@ -89,7 +89,6 @@ protected:
void onWearButtonClick();
void showGearMenu();
void onTrashButtonClick();
- void onOutfitsRemovalConfirmation(const LLSD& notification, const LLSD& response);
bool isActionEnabled(const LLSD& userdata);
void setWearablesLoading(bool val);
void onWearablesLoaded();
diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp
index 040b5319b9..e3a7b749ea 100644
--- a/indra/newview/llpanelpeople.cpp
+++ b/indra/newview/llpanelpeople.cpp
@@ -29,11 +29,13 @@
// libs
#include "llavatarname.h"
#include "llfloaterreg.h"
+#include "llmenubutton.h"
#include "llmenugl.h"
#include "llnotificationsutil.h"
#include "lleventtimer.h"
#include "llfiltereditor.h"
#include "lltabcontainer.h"
+#include "lltoggleablemenu.h"
#include "lluictrlfactory.h"
#include "llpanelpeople.h"
@@ -52,6 +54,7 @@
#include "llgroupactions.h"
#include "llgrouplist.h"
#include "llinventoryobserver.h"
+#include "llnetmap.h"
#include "llpanelpeoplemenus.h"
#include "llsidetray.h"
#include "llsidetraypanelcontainer.h"
@@ -155,9 +158,8 @@ protected:
const LLVector3d& me_pos = gAgent.getPositionGlobal();
const LLVector3d& item1_pos = mAvatarsPositions.find(item1->getAvatarId())->second;
const LLVector3d& item2_pos = mAvatarsPositions.find(item2->getAvatarId())->second;
- F32 dist1 = dist_vec(item1_pos, me_pos);
- F32 dist2 = dist_vec(item2_pos, me_pos);
- return dist1 < dist2;
+
+ return dist_vec_squared(item1_pos, me_pos) < dist_vec_squared(item2_pos, me_pos);
}
private:
id_to_pos_map_t mAvatarsPositions;
@@ -229,7 +231,7 @@ public:
virtual void setActive(bool) {}
protected:
- void updateList()
+ void update()
{
mCallback();
}
@@ -237,6 +239,30 @@ protected:
callback_t mCallback;
};
+/**
+ * Update buttons on changes in our friend relations (STORM-557).
+ */
+class LLButtonsUpdater : public LLPanelPeople::Updater, public LLFriendObserver
+{
+public:
+ LLButtonsUpdater(callback_t cb)
+ : LLPanelPeople::Updater(cb)
+ {
+ LLAvatarTracker::instance().addObserver(this);
+ }
+
+ ~LLButtonsUpdater()
+ {
+ LLAvatarTracker::instance().removeObserver(this);
+ }
+
+ /*virtual*/ void changed(U32 mask)
+ {
+ (void) mask;
+ update();
+ }
+};
+
class LLAvatarListUpdater : public LLPanelPeople::Updater, public LLEventTimer
{
public:
@@ -304,7 +330,7 @@ public:
if (mMask & (LLFriendObserver::ADD | LLFriendObserver::REMOVE | LLFriendObserver::ONLINE))
{
- updateList();
+ update();
}
// Stop updates.
@@ -357,6 +383,16 @@ private:
{
lldebugs << "Inventory changed: " << mask << llendl;
+ static bool synchronize_friends_folders = true;
+ if (synchronize_friends_folders)
+ {
+ // Checks whether "Friends" and "Friends/All" folders exist in "Calling Cards" folder,
+ // fetches their contents if needed and synchronizes it with buddies list.
+ // If the folders are not found they are created.
+ LLFriendCardsManager::instance().syncFriendCardsFolders();
+ synchronize_friends_folders = false;
+ }
+
// *NOTE: deleting of InventoryItem is performed via moving to Trash.
// That means LLInventoryObserver::STRUCTURE is present in MASK instead of LLInventoryObserver::REMOVE
if ((CALLINGCARD_ADDED & mask) == CALLINGCARD_ADDED)
@@ -419,7 +455,7 @@ public:
if (val)
{
// update immediately and start regular updates
- updateList();
+ update();
mEventTimer.start();
}
else
@@ -431,7 +467,7 @@ public:
/*virtual*/ BOOL tick()
{
- updateList();
+ update();
return FALSE;
}
private:
@@ -448,7 +484,7 @@ public:
LLRecentListUpdater(callback_t cb)
: LLAvatarListUpdater(cb, 0)
{
- LLRecentPeople::instance().setChangedCallback(boost::bind(&LLRecentListUpdater::updateList, this));
+ LLRecentPeople::instance().setChangedCallback(boost::bind(&LLRecentListUpdater::update, this));
}
};
@@ -464,16 +500,23 @@ LLPanelPeople::LLPanelPeople()
mAllFriendList(NULL),
mNearbyList(NULL),
mRecentList(NULL),
- mGroupList(NULL)
+ mGroupList(NULL),
+ mNearbyGearButton(NULL),
+ mFriendsGearButton(NULL),
+ mGroupsGearButton(NULL),
+ mRecentGearButton(NULL),
+ mMiniMap(NULL)
{
mFriendListUpdater = new LLFriendListUpdater(boost::bind(&LLPanelPeople::updateFriendList, this));
mNearbyListUpdater = new LLNearbyListUpdater(boost::bind(&LLPanelPeople::updateNearbyList, this));
mRecentListUpdater = new LLRecentListUpdater(boost::bind(&LLPanelPeople::updateRecentList, this));
+ mButtonsUpdater = new LLButtonsUpdater(boost::bind(&LLPanelPeople::updateButtons, this));
mCommitCallbackRegistrar.add("People.addFriend", boost::bind(&LLPanelPeople::onAddFriendButtonClicked, this));
}
LLPanelPeople::~LLPanelPeople()
{
+ delete mButtonsUpdater;
delete mNearbyListUpdater;
delete mFriendListUpdater;
delete mRecentListUpdater;
@@ -535,6 +578,9 @@ BOOL LLPanelPeople::postBuild()
mNearbyList->setNoItemsMsg(getString("no_one_near"));
mNearbyList->setNoFilteredItemsMsg(getString("no_one_filtered_near"));
mNearbyList->setShowIcons("NearbyListShowIcons");
+ mMiniMap = (LLNetMap*)getChildView("Net Map",true);
+ mMiniMap->setToolTipMsg(gSavedSettings.getBOOL("DoubleClickTeleport") ?
+ getString("AltMiniMapToolTipMsg") : getString("MiniMapToolTipMsg"));
mRecentList = getChild<LLPanel>(RECENT_TAB_NAME)->getChild<LLAvatarList>("avatar_list");
mRecentList->setNoItemsCommentText(getString("no_recent_people"));
@@ -600,11 +646,6 @@ BOOL LLPanelPeople::postBuild()
buttonSetAction("teleport_btn", boost::bind(&LLPanelPeople::onTeleportButtonClicked, this));
buttonSetAction("share_btn", boost::bind(&LLPanelPeople::onShareButtonClicked, this));
- getChild<LLPanel>(NEARBY_TAB_NAME)->childSetAction("nearby_view_sort_btn",boost::bind(&LLPanelPeople::onNearbyViewSortButtonClicked, this));
- getChild<LLPanel>(RECENT_TAB_NAME)->childSetAction("recent_viewsort_btn",boost::bind(&LLPanelPeople::onRecentViewSortButtonClicked, this));
- getChild<LLPanel>(FRIENDS_TAB_NAME)->childSetAction("friends_viewsort_btn",boost::bind(&LLPanelPeople::onFriendsViewSortButtonClicked, this));
- getChild<LLPanel>(GROUP_TAB_NAME)->childSetAction("groups_viewsort_btn",boost::bind(&LLPanelPeople::onGroupsViewSortButtonClicked, this));
-
// Must go after setting commit callback and initializing all pointers to children.
mTabContainer->selectTabByName(NEARBY_TAB_NAME);
@@ -624,24 +665,41 @@ BOOL LLPanelPeople::postBuild()
enable_registrar.add("People.Recent.ViewSort.CheckItem", boost::bind(&LLPanelPeople::onRecentViewSortMenuItemCheck, this, _2));
enable_registrar.add("People.Nearby.ViewSort.CheckItem", boost::bind(&LLPanelPeople::onNearbyViewSortMenuItemCheck, this, _2));
+ mNearbyGearButton = getChild<LLMenuButton>("nearby_view_sort_btn");
+ mFriendsGearButton = getChild<LLMenuButton>("friends_viewsort_btn");
+ mGroupsGearButton = getChild<LLMenuButton>("groups_viewsort_btn");
+ mRecentGearButton = getChild<LLMenuButton>("recent_viewsort_btn");
+
LLMenuGL* plus_menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_group_plus.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
mGroupPlusMenuHandle = plus_menu->getHandle();
- LLMenuGL* nearby_view_sort = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_people_nearby_view_sort.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+ LLToggleableMenu* nearby_view_sort = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_people_nearby_view_sort.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
if(nearby_view_sort)
+ {
mNearbyViewSortMenuHandle = nearby_view_sort->getHandle();
+ mNearbyGearButton->setMenu(nearby_view_sort);
+ }
- LLMenuGL* friend_view_sort = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_people_friends_view_sort.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+ LLToggleableMenu* friend_view_sort = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_people_friends_view_sort.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
if(friend_view_sort)
+ {
mFriendsViewSortMenuHandle = friend_view_sort->getHandle();
+ mFriendsGearButton->setMenu(friend_view_sort);
+ }
- LLMenuGL* group_view_sort = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_people_groups_view_sort.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+ LLToggleableMenu* group_view_sort = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_people_groups_view_sort.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
if(group_view_sort)
+ {
mGroupsViewSortMenuHandle = group_view_sort->getHandle();
+ mGroupsGearButton->setMenu(group_view_sort);
+ }
- LLMenuGL* recent_view_sort = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_people_recent_view_sort.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+ LLToggleableMenu* recent_view_sort = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_people_recent_view_sort.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
if(recent_view_sort)
+ {
mRecentViewSortMenuHandle = recent_view_sort->getHandle();
+ mRecentGearButton->setMenu(recent_view_sort);
+ }
LLVoiceClient::getInstance()->addObserver(this);
@@ -701,18 +759,23 @@ void LLPanelPeople::updateFriendList()
all_friendsp.clear();
online_friendsp.clear();
- LLFriendCardsManager::folderid_buddies_map_t listMap;
+ uuid_vec_t buddies_uuids;
+ LLAvatarTracker::buddy_map_t::const_iterator buddies_iter;
- // *NOTE: For now collectFriendsLists returns data only for Friends/All folder. EXT-694.
- LLFriendCardsManager::instance().collectFriendsLists(listMap);
- if (listMap.size() > 0)
+ // Fill the avatar list with friends UUIDs
+ for (buddies_iter = all_buddies.begin(); buddies_iter != all_buddies.end(); ++buddies_iter)
{
- lldebugs << "Friends Cards were found, count: " << listMap.begin()->second.size() << llendl;
- all_friendsp = listMap.begin()->second;
+ buddies_uuids.push_back(buddies_iter->first);
+ }
+
+ if (buddies_uuids.size() > 0)
+ {
+ lldebugs << "Friends added to the list: " << buddies_uuids.size() << llendl;
+ all_friendsp = buddies_uuids;
}
else
{
- lldebugs << "Friends Cards were not found" << llendl;
+ lldebugs << "No friends found" << llendl;
}
LLAvatarTracker::buddy_map_t::const_iterator buddy_it = all_buddies.begin();
@@ -911,7 +974,7 @@ void LLPanelPeople::showGroupMenu(LLMenuGL* menu)
// Calculate its coordinates.
// (assumes that groups panel is the current tab)
- LLPanel* bottom_panel = mTabContainer->getCurrentPanel()->getChild<LLPanel>("bottom_panel");
+ LLPanel* bottom_panel = mTabContainer->getCurrentPanel()->getChild<LLPanel>("bottom_panel");
LLPanel* parent_panel = mTabContainer->getCurrentPanel();
menu->arrangeAndClear();
S32 menu_height = menu->getRect().getHeight();
@@ -1044,6 +1107,12 @@ void LLPanelPeople::onAvatarListDoubleClicked(LLUICtrl* ctrl)
void LLPanelPeople::onAvatarListCommitted(LLAvatarList* list)
{
+ if (getActiveTabName() == NEARBY_TAB_NAME)
+ {
+ uuid_vec_t selected_uuids;
+ getCurrentItemIDs(selected_uuids);
+ mMiniMap->setSelected(selected_uuids);
+ } else
// Make sure only one of the friends lists (online/all) has selection.
if (getActiveTabName() == FRIENDS_TAB_NAME)
{
@@ -1346,44 +1415,9 @@ void LLPanelPeople::onMoreButtonClicked()
// *TODO: not implemented yet
}
-void LLPanelPeople::onFriendsViewSortButtonClicked()
-{
- LLMenuGL* menu = (LLMenuGL*)mFriendsViewSortMenuHandle.get();
- if (!menu)
- return;
- showGroupMenu(menu);
-}
-
-void LLPanelPeople::onGroupsViewSortButtonClicked()
-{
- LLMenuGL* menu = (LLMenuGL*)mGroupsViewSortMenuHandle.get();
- if (!menu)
- return;
- showGroupMenu(menu);
-}
-
-void LLPanelPeople::onRecentViewSortButtonClicked()
-{
- LLMenuGL* menu = (LLMenuGL*)mRecentViewSortMenuHandle.get();
- if (!menu)
- return;
- showGroupMenu(menu);
-}
-
-void LLPanelPeople::onNearbyViewSortButtonClicked()
-{
- LLMenuGL* menu = (LLMenuGL*)mNearbyViewSortMenuHandle.get();
- if (!menu)
- return;
- showGroupMenu(menu);
-}
-
void LLPanelPeople::onOpen(const LLSD& key)
{
std::string tab_name = key["people_panel_tab_name"];
- mFilterEditor -> clear();
- onFilterEdit("");
-
if (!tab_name.empty())
mTabContainer->selectTabByName(tab_name);
}
diff --git a/indra/newview/llpanelpeople.h b/indra/newview/llpanelpeople.h
index f5ff09b038..46c58cd139 100644
--- a/indra/newview/llpanelpeople.h
+++ b/indra/newview/llpanelpeople.h
@@ -36,6 +36,7 @@ class LLAvatarList;
class LLAvatarName;
class LLFilterEditor;
class LLGroupList;
+class LLMenuButton;
class LLTabContainer;
class LLPanelPeople
@@ -101,10 +102,6 @@ private:
void onShareButtonClicked();
void onMoreButtonClicked();
void onActivateButtonClicked();
- void onRecentViewSortButtonClicked();
- void onNearbyViewSortButtonClicked();
- void onFriendsViewSortButtonClicked();
- void onGroupsViewSortButtonClicked();
void onAvatarListDoubleClicked(LLUICtrl* ctrl);
void onAvatarListCommitted(LLAvatarList* list);
void onGroupPlusButtonClicked();
@@ -145,6 +142,7 @@ private:
LLAvatarList* mNearbyList;
LLAvatarList* mRecentList;
LLGroupList* mGroupList;
+ LLNetMap* mMiniMap;
LLHandle<LLView> mGroupPlusMenuHandle;
LLHandle<LLView> mNearbyViewSortMenuHandle;
@@ -155,6 +153,12 @@ private:
Updater* mFriendListUpdater;
Updater* mNearbyListUpdater;
Updater* mRecentListUpdater;
+ Updater* mButtonsUpdater;
+
+ LLMenuButton* mNearbyGearButton;
+ LLMenuButton* mFriendsGearButton;
+ LLMenuButton* mGroupsGearButton;
+ LLMenuButton* mRecentGearButton;
std::string mFilterSubString;
std::string mFilterSubStringOrig;
diff --git a/indra/newview/llpanelpick.cpp b/indra/newview/llpanelpick.cpp
index 271728220c..44cca21a76 100644
--- a/indra/newview/llpanelpick.cpp
+++ b/indra/newview/llpanelpick.cpp
@@ -204,9 +204,6 @@ void LLPanelPickInfo::sendParcelInfoRequest()
{
if (mParcelId != mRequestedId)
{
- //ext-4655, remove now incase this gets called twice without a remove
- LLRemoteParcelInfoProcessor::getInstance()->removeObserver(mRequestedId, this);
-
LLRemoteParcelInfoProcessor::getInstance()->addObserver(mParcelId, this);
LLRemoteParcelInfoProcessor::getInstance()->sendParcelInfoRequest(mParcelId);
diff --git a/indra/newview/llpanelpicks.cpp b/indra/newview/llpanelpicks.cpp
index ccef563544..ddce83c616 100644
--- a/indra/newview/llpanelpicks.cpp
+++ b/indra/newview/llpanelpicks.cpp
@@ -70,6 +70,118 @@ static const std::string CLASSIFIED_NAME("classified_name");
static LLRegisterPanelClassWrapper<LLPanelPicks> t_panel_picks("panel_picks");
+
+class LLPickHandler : public LLCommandHandler,
+ public LLAvatarPropertiesObserver
+{
+public:
+
+ std::set<LLUUID> mPickIds;
+
+ // requires trusted browser to trigger
+ LLPickHandler() : LLCommandHandler("pick", UNTRUSTED_THROTTLE) { }
+
+ bool handle(const LLSD& params, const LLSD& query_map,
+ LLMediaCtrl* web)
+ {
+ if (!LLUI::sSettingGroups["config"]->getBOOL("EnablePicks"))
+ {
+ LLNotificationsUtil::add("NoPicks", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit"));
+ return true;
+ }
+
+ // handle app/classified/create urls first
+ if (params.size() == 1 && params[0].asString() == "create")
+ {
+ createPick();
+ return true;
+ }
+
+ // then handle the general app/pick/{UUID}/{CMD} urls
+ if (params.size() < 2)
+ {
+ return false;
+ }
+
+ // get the ID for the pick_id
+ LLUUID pick_id;
+ if (!pick_id.set(params[0], FALSE))
+ {
+ return false;
+ }
+
+ // edit the pick in the side tray.
+ // need to ask the server for more info first though...
+ const std::string verb = params[1].asString();
+ if (verb == "edit")
+ {
+ mPickIds.insert(pick_id);
+ LLAvatarPropertiesProcessor::getInstance()->addObserver(LLUUID(), this);
+ LLAvatarPropertiesProcessor::getInstance()->sendPickInfoRequest(gAgent.getID(),pick_id);
+ return true;
+ }
+ else
+ {
+ llwarns << "unknown verb " << verb << llendl;
+ return false;
+ }
+ }
+
+ void createPick()
+ {
+ LLSD params;
+ params["id"] = gAgent.getID();
+ params["open_tab_name"] = "panel_picks";
+ params["show_tab_panel"] = "create_pick";
+ LLSideTray::getInstance()->showPanel("panel_me", params);
+ }
+
+ void editPick(LLPickData* pick_info)
+ {
+ LLSD params;
+ params["open_tab_name"] = "panel_picks";
+ params["show_tab_panel"] = "edit_pick";
+ params["pick_id"] = pick_info->pick_id;
+ params["avatar_id"] = pick_info->creator_id;
+ params["snapshot_id"] = pick_info->snapshot_id;
+ params["pick_name"] = pick_info->name;
+ params["pick_desc"] = pick_info->desc;
+
+ LLSideTray::getInstance()->showPanel("panel_me", params);
+ }
+
+ /*virtual*/ void processProperties(void* data, EAvatarProcessorType type)
+ {
+ if (APT_PICK_INFO != type)
+ {
+ return;
+ }
+
+ // is this the pick that we asked for?
+ LLPickData* pick_info = static_cast<LLPickData*>(data);
+ if (!pick_info || mPickIds.find(pick_info->pick_id) == mPickIds.end())
+ {
+ return;
+ }
+
+ // open the edit side tray for this pick
+ if (pick_info->creator_id == gAgent.getID())
+ {
+ editPick(pick_info);
+ }
+ else
+ {
+ llwarns << "Can't edit a pick you did not create" << llendl;
+ }
+
+ // remove our observer now that we're done
+ mPickIds.erase(pick_info->pick_id);
+ LLAvatarPropertiesProcessor::getInstance()->removeObserver(LLUUID(), this);
+ }
+};
+
+LLPickHandler gPickHandler;
+
class LLClassifiedHandler :
public LLCommandHandler,
public LLAvatarPropertiesObserver
@@ -80,8 +192,16 @@ public:
std::set<LLUUID> mClassifiedIds;
+ std::string mRequestVerb;
+
bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web)
{
+ if (!LLUI::sSettingGroups["config"]->getBOOL("EnableClassifieds"))
+ {
+ LLNotificationsUtil::add("NoClassifieds", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit"));
+ return true;
+ }
+
// handle app/classified/create urls first
if (params.size() == 1 && params[0].asString() == "create")
{
@@ -107,6 +227,15 @@ public:
const std::string verb = params[1].asString();
if (verb == "about")
{
+ mRequestVerb = verb;
+ mClassifiedIds.insert(classified_id);
+ LLAvatarPropertiesProcessor::getInstance()->addObserver(LLUUID(), this);
+ LLAvatarPropertiesProcessor::getInstance()->sendClassifiedInfoRequest(classified_id);
+ return true;
+ }
+ else if (verb == "edit")
+ {
+ mRequestVerb = verb;
mClassifiedIds.insert(classified_id);
LLAvatarPropertiesProcessor::getInstance()->addObserver(LLUUID(), this);
LLAvatarPropertiesProcessor::getInstance()->sendClassifiedInfoRequest(classified_id);
@@ -128,18 +257,39 @@ public:
void openClassified(LLAvatarClassifiedInfo* c_info)
{
- // open the classified info panel on the Me > Picks sidetray
- LLSD params;
- params["id"] = c_info->creator_id;
- params["open_tab_name"] = "panel_picks";
- params["show_tab_panel"] = "classified_details";
- params["classified_id"] = c_info->classified_id;
- params["classified_creator_id"] = c_info->creator_id;
- params["classified_snapshot_id"] = c_info->snapshot_id;
- params["classified_name"] = c_info->name;
- params["classified_desc"] = c_info->description;
- params["from_search"] = true;
- LLSideTray::getInstance()->showPanel("panel_profile_view", params);
+ if (mRequestVerb == "about")
+ {
+ // open the classified info panel on the Me > Picks sidetray
+ LLSD params;
+ params["id"] = c_info->creator_id;
+ params["open_tab_name"] = "panel_picks";
+ params["show_tab_panel"] = "classified_details";
+ params["classified_id"] = c_info->classified_id;
+ params["classified_creator_id"] = c_info->creator_id;
+ params["classified_snapshot_id"] = c_info->snapshot_id;
+ params["classified_name"] = c_info->name;
+ params["classified_desc"] = c_info->description;
+ params["from_search"] = true;
+ LLSideTray::getInstance()->showPanel("panel_profile_view", params);
+ }
+ else if (mRequestVerb == "edit")
+ {
+ if (c_info->creator_id == gAgent.getID())
+ {
+ llwarns << "edit in progress" << llendl;
+ // open the new classified panel on the Me > Picks sidetray
+ LLSD params;
+ params["id"] = gAgent.getID();
+ params["open_tab_name"] = "panel_picks";
+ params["show_tab_panel"] = "edit_classified";
+ params["classified_id"] = c_info->classified_id;
+ LLSideTray::getInstance()->showPanel("panel_me", params);
+ }
+ else
+ {
+ llwarns << "Can't edit a classified you did not create" << llendl;
+ }
+ }
}
/*virtual*/ void processProperties(void* data, EAvatarProcessorType type)
@@ -212,7 +362,8 @@ void LLPanelPicks::updateData()
mNoPicks = false;
mNoClassifieds = false;
- getChild<LLUICtrl>("picks_panel_text")->setValue(LLTrans::getString("PicksClassifiedsLoadingText"));
+ mNoItemsLabel->setValue(LLTrans::getString("PicksClassifiedsLoadingText"));
+ mNoItemsLabel->setVisible(TRUE);
mPicksList->clear();
LLAvatarPropertiesProcessor::getInstance()->sendAvatarPicksRequest(getAvatarId());
@@ -298,7 +449,10 @@ void LLPanelPicks::processProperties(void* data, EAvatarProcessorType type)
pick_value.insert(CLASSIFIED_ID, c_data.classified_id);
pick_value.insert(CLASSIFIED_NAME, c_data.name);
- mClassifiedsList->addItem(c_item, pick_value);
+ if (!findClassifiedById(c_data.classified_id))
+ {
+ mClassifiedsList->addItem(c_item, pick_value);
+ }
c_item->setDoubleClickCallback(boost::bind(&LLPanelPicks::onDoubleClickClassifiedItem, this, _1));
c_item->setRightMouseUpCallback(boost::bind(&LLPanelPicks::onRightMouseUpItem, this, _1, _2, _3, _4));
@@ -314,15 +468,17 @@ void LLPanelPicks::processProperties(void* data, EAvatarProcessorType type)
mNoClassifieds = !mClassifiedsList->size();
}
- if (mNoPicks && mNoClassifieds)
+ bool no_data = mNoPicks && mNoClassifieds;
+ mNoItemsLabel->setVisible(no_data);
+ if (no_data)
{
if(getAvatarId() == gAgentID)
{
- getChild<LLUICtrl>("picks_panel_text")->setValue(LLTrans::getString("NoPicksClassifiedsText"));
+ mNoItemsLabel->setValue(LLTrans::getString("NoPicksClassifiedsText"));
}
else
{
- getChild<LLUICtrl>("picks_panel_text")->setValue(LLTrans::getString("NoAvatarPicksClassifiedsText"));
+ mNoItemsLabel->setValue(LLTrans::getString("NoAvatarPicksClassifiedsText"));
}
}
}
@@ -359,6 +515,8 @@ BOOL LLPanelPicks::postBuild()
mPicksList->setNoItemsCommentText(getString("no_picks"));
mClassifiedsList->setNoItemsCommentText(getString("no_classifieds"));
+ mNoItemsLabel = getChild<LLUICtrl>("picks_panel_text");
+
childSetAction(XML_BTN_NEW, boost::bind(&LLPanelPicks::onClickPlusBtn, this));
childSetAction(XML_BTN_DELETE, boost::bind(&LLPanelPicks::onClickDelete, this));
childSetAction(XML_BTN_TELEPORT, boost::bind(&LLPanelPicks::onClickTeleport, this));
@@ -771,6 +929,13 @@ void LLPanelPicks::openClassifiedInfo(const LLSD &params)
getProfilePanel()->openPanel(mPanelClassifiedInfo, params);
}
+void LLPanelPicks::openClassifiedEdit(const LLSD& params)
+{
+ LLUUID classified_id = params["classified_id"].asUUID();;
+ llinfos << "opening classified " << classified_id << " for edit" << llendl;
+ editClassified(classified_id);
+}
+
void LLPanelPicks::showAccordion(const std::string& name, bool show)
{
LLAccordionCtrlTab* tab = getChild<LLAccordionCtrlTab>(name);
@@ -781,7 +946,7 @@ void LLPanelPicks::showAccordion(const std::string& name, bool show)
void LLPanelPicks::onPanelPickClose(LLPanel* panel)
{
- panel->setVisible(FALSE);
+ getProfilePanel()->closePanel(panel);
}
void LLPanelPicks::onPanelPickSave(LLPanel* panel)
@@ -940,6 +1105,12 @@ void LLPanelPicks::createPickEditPanel()
// getProfilePanel()->openPanel(mPanelPickInfo, params);
// }
+void LLPanelPicks::openPickEdit(const LLSD& params)
+{
+ createPickEditPanel();
+ getProfilePanel()->openPanel(mPanelPickEdit, params);
+}
+
void LLPanelPicks::onPanelPickEdit()
{
LLSD selected_value = mPicksList->getSelectedValue();
@@ -973,6 +1144,35 @@ void LLPanelPicks::onPanelClassifiedEdit()
{
return;
}
+ editClassified(c_item->getClassifiedId());
+}
+
+LLClassifiedItem *LLPanelPicks::findClassifiedById(const LLUUID& classified_id)
+{
+ // HACK - find item by classified id. Should be a better way.
+ std::vector<LLPanel*> items;
+ mClassifiedsList->getItems(items);
+ LLClassifiedItem* c_item = NULL;
+ for(std::vector<LLPanel*>::iterator it = items.begin(); it != items.end(); ++it)
+ {
+ LLClassifiedItem *test_item = dynamic_cast<LLClassifiedItem*>(*it);
+ if (test_item && test_item->getClassifiedId() == classified_id)
+ {
+ c_item = test_item;
+ break;
+ }
+ }
+ return c_item;
+}
+
+void LLPanelPicks::editClassified(const LLUUID& classified_id)
+{
+ LLClassifiedItem* c_item = findClassifiedById(classified_id);
+ if (!c_item)
+ {
+ llwarns << "item not found for classified_id " << classified_id << llendl;
+ return;
+ }
LLSD params;
params["classified_id"] = c_item->getClassifiedId();
diff --git a/indra/newview/llpanelpicks.h b/indra/newview/llpanelpicks.h
index 526ba48dcb..29db110523 100644
--- a/indra/newview/llpanelpicks.h
+++ b/indra/newview/llpanelpicks.h
@@ -76,6 +76,7 @@ public:
// returns the selected pick item
LLPickItem* getSelectedPickItem();
LLClassifiedItem* getSelectedClassifiedItem();
+ LLClassifiedItem* findClassifiedById(const LLUUID& classified_id);
//*NOTE top down approch when panel toggling is done only by
// parent panels failed to work (picks related code was in my profile panel)
@@ -106,8 +107,10 @@ private:
void onPanelPickSave(LLPanel* panel);
void onPanelClassifiedSave(LLPanelClassifiedEdit* panel);
void onPanelClassifiedClose(LLPanelClassifiedInfo* panel);
+ void openPickEdit(const LLSD& params);
void onPanelPickEdit();
void onPanelClassifiedEdit();
+ void editClassified(const LLUUID& classified_id);
void onClickMenuEdit();
bool onEnableMenuItem(const LLSD& user_data);
@@ -118,6 +121,7 @@ private:
void openPickInfo();
void openClassifiedInfo();
void openClassifiedInfo(const LLSD& params);
+ void openClassifiedEdit(const LLSD& params);
friend class LLPanelProfile;
void showAccordion(const std::string& name, bool show);
@@ -149,6 +153,7 @@ private:
LLPanelClassifiedInfo* mPanelClassifiedInfo;
LLPanelPickEdit* mPanelPickEdit;
LLToggleableMenu* mPlusMenu;
+ LLUICtrl* mNoItemsLabel;
// <classified_id, edit_panel>
typedef std::map<LLUUID, LLPanelClassifiedEdit*> panel_classified_edit_map_t;
diff --git a/indra/newview/llpanelplaceinfo.cpp b/indra/newview/llpanelplaceinfo.cpp
index 9cbb512e70..4ae0c0eb12 100644
--- a/indra/newview/llpanelplaceinfo.cpp
+++ b/indra/newview/llpanelplaceinfo.cpp
@@ -128,10 +128,6 @@ void LLPanelPlaceInfo::sendParcelInfoRequest()
{
if (mParcelID != mRequestedID)
{
- //ext-4655, defensive. remove now incase this gets called twice without a remove
- //as panel never closes its ok atm (but wrong :)
- LLRemoteParcelInfoProcessor::getInstance()->removeObserver(mRequestedID, this);
-
LLRemoteParcelInfoProcessor::getInstance()->addObserver(mParcelID, this);
LLRemoteParcelInfoProcessor::getInstance()->sendParcelInfoRequest(mParcelID);
diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp
index f0e60386b6..46262832dc 100644
--- a/indra/newview/llpanelplaces.cpp
+++ b/indra/newview/llpanelplaces.cpp
@@ -39,6 +39,7 @@
#include "llfiltereditor.h"
#include "llfirstuse.h"
#include "llfloaterreg.h"
+#include "llmenubutton.h"
#include "llnotificationsutil.h"
#include "lltabcontainer.h"
#include "lltexteditor.h"
@@ -90,11 +91,18 @@ public:
LLParcelHandler() : LLCommandHandler("parcel", UNTRUSTED_THROTTLE) { }
bool handle(const LLSD& params, const LLSD& query_map,
LLMediaCtrl* web)
- {
+ {
if (params.size() < 2)
{
return false;
}
+
+ if (!LLUI::sSettingGroups["config"]->getBOOL("EnablePlaceProfile"))
+ {
+ LLNotificationsUtil::add("NoPlaceInfo", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit"));
+ return true;
+ }
+
LLUUID parcel_id;
if (!parcel_id.set(params[0], FALSE))
{
@@ -282,8 +290,8 @@ BOOL LLPanelPlaces::postBuild()
mCloseBtn = getChild<LLButton>("close_btn");
mCloseBtn->setClickedCallback(boost::bind(&LLPanelPlaces::onBackButtonClicked, this));
- mOverflowBtn = getChild<LLButton>("overflow_btn");
- mOverflowBtn->setClickedCallback(boost::bind(&LLPanelPlaces::onOverflowButtonClicked, this));
+ mOverflowBtn = getChild<LLMenuButton>("overflow_btn");
+ mOverflowBtn->setMouseDownCallback(boost::bind(&LLPanelPlaces::onOverflowButtonClicked, this));
mPlaceInfoBtn = getChild<LLButton>("profile_btn");
mPlaceInfoBtn->setClickedCallback(boost::bind(&LLPanelPlaces::onProfileButtonClicked, this));
@@ -330,8 +338,7 @@ BOOL LLPanelPlaces::postBuild()
mPlaceProfileBackBtn = mPlaceProfile->getChild<LLButton>("back_btn");
mPlaceProfileBackBtn->setClickedCallback(boost::bind(&LLPanelPlaces::onBackButtonClicked, this));
- mLandmarkInfoBackBtn = mLandmarkInfo->getChild<LLButton>("back_btn");
- mLandmarkInfoBackBtn->setClickedCallback(boost::bind(&LLPanelPlaces::onBackButtonClicked, this));
+ mLandmarkInfo->getChild<LLButton>("back_btn")->setClickedCallback(boost::bind(&LLPanelPlaces::onBackButtonClicked, this));
LLLineEditor* title_editor = mLandmarkInfo->getChild<LLLineEditor>("title_editor");
title_editor->setKeystrokeCallback(boost::bind(&LLPanelPlaces::onEditButtonClicked, this), NULL);
@@ -347,8 +354,6 @@ BOOL LLPanelPlaces::postBuild()
void LLPanelPlaces::onOpen(const LLSD& key)
{
- LLFirstUse::notUsingDestinationGuide(false);
-
if (!mPlaceProfile || !mLandmarkInfo)
return;
@@ -384,12 +389,7 @@ void LLPanelPlaces::onOpen(const LLSD& key)
mLandmarkInfo->displayParcelInfo(LLUUID(), mPosGlobal);
- // Disabling "Save", "Close" and "Back" buttons to prevent closing "Create Landmark"
- // panel before created landmark is loaded.
- // These buttons will be enabled when created landmark is added to inventory.
mSaveBtn->setEnabled(FALSE);
- mCloseBtn->setEnabled(FALSE);
- mLandmarkInfoBackBtn->setEnabled(FALSE);
}
else if (mPlaceInfoType == LANDMARK_INFO_TYPE)
{
@@ -497,8 +497,6 @@ void LLPanelPlaces::setItem(LLInventoryItem* item)
mEditBtn->setEnabled(is_landmark_editable);
mSaveBtn->setEnabled(is_landmark_editable);
- mCloseBtn->setEnabled(TRUE);
- mLandmarkInfoBackBtn->setEnabled(TRUE);
if (is_landmark_editable)
{
@@ -762,6 +760,11 @@ void LLPanelPlaces::onOverflowButtonClicked()
// there is no landmark already pointing to that parcel in agent's inventory.
menu->getChild<LLMenuItemCallGL>("landmark")->setEnabled(is_agent_place_info_visible &&
!LLLandmarkActions::landmarkAlreadyExists());
+ // STORM-411
+ // Creating landmarks for remote locations is impossible.
+ // So hide menu item "Make a Landmark" in "Teleport History Profile" panel.
+ menu->setItemVisible("landmark", mPlaceInfoType != TELEPORT_HISTORY_INFO_TYPE);
+ menu->arrangeAndClear();
}
else if (mPlaceInfoType == LANDMARK_INFO_TYPE && mLandmarkMenu != NULL)
{
@@ -783,16 +786,7 @@ void LLPanelPlaces::onOverflowButtonClicked()
return;
}
- if (!menu->toggleVisibility())
- return;
-
- if (menu->getButtonRect().isEmpty())
- {
- menu->setButtonRect(mOverflowBtn);
- }
- menu->updateParent(LLMenuGL::sMenuContainer);
- LLRect rect = mOverflowBtn->getRect();
- LLMenuGL::showPopup(this, menu, rect.mRight, rect.mTop);
+ mOverflowBtn->setMenu(menu, LLMenuButton::MP_TOP_RIGHT);
}
void LLPanelPlaces::onProfileButtonClicked()
@@ -1137,13 +1131,6 @@ void LLPanelPlaces::updateVerbs()
{
mTeleportBtn->setEnabled(have_3d_pos);
}
-
- // Do not enable landmark info Back button when we are waiting
- // for newly created landmark to load.
- if (!is_create_landmark_visible)
- {
- mLandmarkInfoBackBtn->setEnabled(TRUE);
- }
}
else
{
diff --git a/indra/newview/llpanelplaces.h b/indra/newview/llpanelplaces.h
index c3b2ab806f..b335f88a48 100644
--- a/indra/newview/llpanelplaces.h
+++ b/indra/newview/llpanelplaces.h
@@ -47,6 +47,7 @@ class LLPlacesParcelObserver;
class LLRemoteParcelInfoObserver;
class LLTabContainer;
class LLToggleableMenu;
+class LLMenuButton;
typedef std::pair<LLUUID, std::string> folder_pair_t;
@@ -116,14 +117,13 @@ private:
LLToggleableMenu* mLandmarkMenu;
LLButton* mPlaceProfileBackBtn;
- LLButton* mLandmarkInfoBackBtn;
LLButton* mTeleportBtn;
LLButton* mShowOnMapBtn;
LLButton* mEditBtn;
LLButton* mSaveBtn;
LLButton* mCancelBtn;
LLButton* mCloseBtn;
- LLButton* mOverflowBtn;
+ LLMenuButton* mOverflowBtn;
LLButton* mPlaceInfoBtn;
LLPlacesInventoryObserver* mInventoryObserver;
diff --git a/indra/newview/llpanelprimmediacontrols.cpp b/indra/newview/llpanelprimmediacontrols.cpp
index b04971f980..933b40ec79 100644
--- a/indra/newview/llpanelprimmediacontrols.cpp
+++ b/indra/newview/llpanelprimmediacontrols.cpp
@@ -59,7 +59,9 @@
#include "llvovolume.h"
#include "llweb.h"
#include "llwindow.h"
+#include "llwindowshade.h"
#include "llfloatertools.h" // to enable hide if build tools are up
+#include "llvector4a.h"
// Functions pulled from pipeline.cpp
glh::matrix4f glh_get_current_modelview();
@@ -90,7 +92,9 @@ LLPanelPrimMediaControls::LLPanelPrimMediaControls() :
mTargetObjectNormal(LLVector3::zero),
mZoomObjectID(LLUUID::null),
mZoomObjectFace(0),
- mVolumeSliderVisible(0)
+ mVolumeSliderVisible(0),
+ mWindowShade(NULL),
+ mHideImmediately(false)
{
mCommitCallbackRegistrar.add("MediaCtrl.Close", boost::bind(&LLPanelPrimMediaControls::onClickClose, this));
mCommitCallbackRegistrar.add("MediaCtrl.Back", boost::bind(&LLPanelPrimMediaControls::onClickBack, this));
@@ -205,6 +209,11 @@ BOOL LLPanelPrimMediaControls::postBuild()
mMediaAddress->setFocusReceivedCallback(boost::bind(&LLPanelPrimMediaControls::onInputURL, _1, this ));
+ gAgent.setMouselookModeInCallback(boost::bind(&LLPanelPrimMediaControls::onMouselookModeIn, this));
+
+ LLWindowShade::Params window_shade_params;
+ window_shade_params.name = "window_shade";
+
mCurrentZoom = ZOOM_NONE;
// clicks on buttons do not remove keyboard focus from media
setIsChrome(TRUE);
@@ -519,7 +528,7 @@ void LLPanelPrimMediaControls::updateShape()
if(LLPluginClassMediaOwner::MEDIA_LOADING == media_plugin->getStatus())
{
mMediaProgressPanel->setVisible(true);
- mMediaProgressBar->setPercent(media_plugin->getProgressPercent());
+ mMediaProgressBar->setValue(media_plugin->getProgressPercent());
}
else
{
@@ -569,7 +578,9 @@ void LLPanelPrimMediaControls::updateShape()
{
const LLVolumeFace& vf = volume->getVolumeFace(mTargetObjectFace);
- const LLVector3* ext = vf.mExtents;
+ LLVector3 ext[2];
+ ext[0].set(vf.mExtents[0].getF32ptr());
+ ext[1].set(vf.mExtents[1].getF32ptr());
LLVector3 center = (ext[0]+ext[1])*0.5f;
LLVector3 size = (ext[1]-ext[0])*0.5f;
@@ -620,12 +631,12 @@ void LLPanelPrimMediaControls::updateShape()
// convert screenspace bbox to pixels (in screen coords)
LLRect window_rect = gViewerWindow->getWorldViewRectScaled();
LLCoordGL screen_min;
- screen_min.mX = llround((F32)window_rect.getWidth() * (min.mV[VX] + 1.f) * 0.5f);
- screen_min.mY = llround((F32)window_rect.getHeight() * (min.mV[VY] + 1.f) * 0.5f);
+ screen_min.mX = llround((F32)window_rect.mLeft + (F32)window_rect.getWidth() * (min.mV[VX] + 1.f) * 0.5f);
+ screen_min.mY = llround((F32)window_rect.mBottom + (F32)window_rect.getHeight() * (min.mV[VY] + 1.f) * 0.5f);
LLCoordGL screen_max;
- screen_max.mX = llround((F32)window_rect.getWidth() * (max.mV[VX] + 1.f) * 0.5f);
- screen_max.mY = llround((F32)window_rect.getHeight() * (max.mV[VY] + 1.f) * 0.5f);
+ screen_max.mX = llround((F32)window_rect.mLeft + (F32)window_rect.getWidth() * (max.mV[VX] + 1.f) * 0.5f);
+ screen_max.mY = llround((F32)window_rect.mBottom + (F32)window_rect.getHeight() * (max.mV[VY] + 1.f) * 0.5f);
// grow panel so that screenspace bounding box fits inside "media_region" element of panel
LLRect media_panel_rect;
@@ -698,27 +709,41 @@ void LLPanelPrimMediaControls::updateShape()
/*virtual*/
void LLPanelPrimMediaControls::draw()
{
+ LLViewerMediaImpl* impl = getTargetMediaImpl();
+ if (impl)
+ {
+ LLNotificationPtr notification = impl->getCurrentNotification();
+ if (notification != mActiveNotification)
+ {
+ mActiveNotification = notification;
+ if (notification)
+ {
+ showNotification(notification);
+ }
+ else
+ {
+ hideNotification();
+ }
+ }
+ }
+
F32 alpha = getDrawContext().mAlpha;
- if(mFadeTimer.getStarted())
+ if(mHideImmediately)
+ {
+ //hide this panel
+ clearFaceOnFade();
+
+ mHideImmediately = false;
+ }
+ else if(mFadeTimer.getStarted())
{
F32 time = mFadeTimer.getElapsedTimeF32();
alpha *= llmax(lerp(1.0, 0.0, time / mControlFadeTime), 0.0f);
if(time >= mControlFadeTime)
{
- if(mClearFaceOnFade)
- {
- // Hiding this object makes scroll events go missing after it fades out
- // (see DEV-41755 for a full description of the train wreck).
- // Only hide the controls when we're untargeting.
- setVisible(FALSE);
-
- mClearFaceOnFade = false;
- mVolumeSliderVisible = 0;
- mTargetImplID = LLUUID::null;
- mTargetObjectID = LLUUID::null;
- mTargetObjectFace = 0;
- }
+ //hide this panel
+ clearFaceOnFade();
}
}
@@ -1295,3 +1320,62 @@ bool LLPanelPrimMediaControls::shouldVolumeSliderBeVisible()
{
return mVolumeSliderVisible > 0;
}
+
+
+void LLPanelPrimMediaControls::clearFaceOnFade()
+{
+ if(mClearFaceOnFade)
+ {
+ // Hiding this object makes scroll events go missing after it fades out
+ // (see DEV-41755 for a full description of the train wreck).
+ // Only hide the controls when we're untargeting.
+ setVisible(FALSE);
+
+ mClearFaceOnFade = false;
+ mVolumeSliderVisible = 0;
+ mTargetImplID = LLUUID::null;
+ mTargetObjectID = LLUUID::null;
+ mTargetObjectFace = 0;
+ }
+}
+
+void LLPanelPrimMediaControls::onMouselookModeIn()
+{
+ LLViewerMediaFocus::getInstance()->clearHover();
+ mHideImmediately = true;
+}
+
+void LLPanelPrimMediaControls::showNotification(LLNotificationPtr notify)
+{
+ delete mWindowShade;
+ LLWindowShade::Params params;
+ params.rect = mMediaRegion->getLocalRect();
+ params.follows.flags = FOLLOWS_ALL;
+ params.notification = notify;
+
+ //HACK: don't hardcode this
+ if (notify->getIcon() == "Popup_Caution")
+ {
+ params.bg_image.name = "Yellow_Gradient";
+ params.text_color = LLColor4::black;
+ }
+ else
+ {
+ //HACK: make this a property of the notification itself, "cancellable"
+ params.can_close = false;
+ params.text_color.control = "LabelTextColor";
+ }
+
+ mWindowShade = LLUICtrlFactory::create<LLWindowShade>(params);
+
+ mMediaRegion->addChild(mWindowShade);
+ mWindowShade->show();
+}
+
+void LLPanelPrimMediaControls::hideNotification()
+{
+ if (mWindowShade)
+ {
+ mWindowShade->hide();
+ }
+}
diff --git a/indra/newview/llpanelprimmediacontrols.h b/indra/newview/llpanelprimmediacontrols.h
index 3ec24f0e24..66956181f2 100644
--- a/indra/newview/llpanelprimmediacontrols.h
+++ b/indra/newview/llpanelprimmediacontrols.h
@@ -29,6 +29,7 @@
#include "llpanel.h"
#include "llviewermedia.h"
+#include "llnotificationptr.h"
class LLButton;
class LLCoordWindow;
@@ -37,6 +38,7 @@ class LLLayoutStack;
class LLProgressBar;
class LLSliderCtrl;
class LLViewerMediaImpl;
+class LLWindowShade;
class LLPanelPrimMediaControls : public LLPanel
{
@@ -54,6 +56,10 @@ public:
void updateShape();
bool isMouseOver();
+ void showNotification(LLNotificationPtr notify);
+ void hideNotification();
+
+
enum EZoomLevel
{
ZOOM_NONE = 0,
@@ -131,7 +137,11 @@ private:
LLPluginClassMedia* getTargetMediaPlugin();
private:
-
+
+ void clearFaceOnFade();
+
+ void onMouselookModeIn();
+
LLView *mMediaRegion;
LLUICtrl *mBackCtrl;
LLUICtrl *mFwdCtrl;
@@ -162,6 +172,7 @@ private:
LLUICtrl *mRightBookend;
LLUIImage* mBackgroundImage;
LLUIImage* mVolumeSliderBackgroundImage;
+ LLWindowShade* mWindowShade;
F32 mSkipStep;
S32 mMinWidth;
S32 mMinHeight;
@@ -179,6 +190,7 @@ private:
bool mPauseFadeout;
bool mUpdateSlider;
bool mClearFaceOnFade;
+ bool mHideImmediately;
LLMatrix4 mLastCameraMat;
EZoomLevel mCurrentZoom;
@@ -204,6 +216,8 @@ private:
S32 mZoomObjectFace;
S32 mVolumeSliderVisible;
+
+ LLNotificationPtr mActiveNotification;
};
#endif // LL_PANELPRIMMEDIACONTROLS_H
diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp
index 4e63563979..fd5c3362bb 100644
--- a/indra/newview/llpanelprofile.cpp
+++ b/indra/newview/llpanelprofile.cpp
@@ -31,12 +31,54 @@
#include "llavataractions.h"
#include "llfloaterreg.h"
#include "llcommandhandler.h"
+#include "llnotificationsutil.h"
#include "llpanelpicks.h"
#include "lltabcontainer.h"
+#include "llviewercontrol.h"
+#include "llviewernetwork.h"
static const std::string PANEL_PICKS = "panel_picks";
static const std::string PANEL_PROFILE = "panel_profile";
+std::string getProfileURL(const std::string& agent_name)
+{
+ std::string url;
+
+ if (LLGridManager::getInstance()->isInProductionGrid())
+ {
+ url = gSavedSettings.getString("WebProfileURL");
+ }
+ else
+ {
+ url = gSavedSettings.getString("WebProfileNonProductionURL");
+ }
+ LLSD subs;
+ subs["AGENT_NAME"] = agent_name;
+ url = LLWeb::expandURLSubstitutions(url,subs);
+ LLStringUtil::toLower(url);
+ return url;
+}
+
+class LLProfileHandler : public LLCommandHandler
+{
+public:
+ // requires trusted browser to trigger
+ LLProfileHandler() : LLCommandHandler("profile", UNTRUSTED_THROTTLE) { }
+
+ bool handle(const LLSD& params, const LLSD& query_map,
+ LLMediaCtrl* web)
+ {
+ if (params.size() < 1) return false;
+ std::string agent_name = params[0];
+ llinfos << "Profile, agent_name " << agent_name << llendl;
+ std::string url = getProfileURL(agent_name);
+ LLWeb::loadWebURLInternal(url);
+
+ return true;
+ }
+};
+LLProfileHandler gProfileHandler;
+
class LLAgentHandler : public LLCommandHandler
{
public:
@@ -74,6 +116,12 @@ public:
if (verb == "pay")
{
+ if (!LLUI::sSettingGroups["config"]->getBOOL("EnableAvatarPay"))
+ {
+ LLNotificationsUtil::add("NoAvatarPay", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit"));
+ return true;
+ }
+
LLAvatarActions::pay(avatar_id);
return true;
}
@@ -114,11 +162,109 @@ public:
LLAgentHandler gAgentHandler;
+//-- LLPanelProfile::ChildStack begins ----------------------------------------
+LLPanelProfile::ChildStack::ChildStack()
+: mParent(NULL)
+{
+}
+
+void LLPanelProfile::ChildStack::setParent(LLPanel* parent)
+{
+ llassert_always(parent != NULL);
+ mParent = parent;
+}
+
+/// Save current parent's child views and remove them from the child list.
+bool LLPanelProfile::ChildStack::push()
+{
+ view_list_t vlist = *mParent->getChildList();
+
+ for (view_list_t::const_iterator it = vlist.begin(); it != vlist.end(); ++it)
+ {
+ LLView* viewp = *it;
+ mParent->removeChild(viewp);
+ }
+
+ mStack.push_back(vlist);
+ dump();
+ return true;
+}
+
+/// Restore saved children (adding them back to the child list).
+bool LLPanelProfile::ChildStack::pop()
+{
+ if (mStack.size() == 0)
+ {
+ llwarns << "Empty stack" << llendl;
+ llassert(mStack.size() == 0);
+ return false;
+ }
+
+ view_list_t& top = mStack.back();
+ for (view_list_t::const_iterator it = top.begin(); it != top.end(); ++it)
+ {
+ LLView* viewp = *it;
+ mParent->addChild(viewp);
+ }
+
+ mStack.pop_back();
+ dump();
+ return true;
+}
+
+/// Temporarily add all saved children back.
+void LLPanelProfile::ChildStack::preParentReshape()
+{
+ mSavedStack = mStack;
+ while(mStack.size() > 0)
+ {
+ pop();
+ }
+}
+
+/// Add the temporarily saved children back.
+void LLPanelProfile::ChildStack::postParentReshape()
+{
+ mStack = mSavedStack;
+ mSavedStack = stack_t();
+
+ for (stack_t::const_iterator stack_it = mStack.begin(); stack_it != mStack.end(); ++stack_it)
+ {
+ const view_list_t& vlist = (*stack_it);
+ for (view_list_t::const_iterator list_it = vlist.begin(); list_it != vlist.end(); ++list_it)
+ {
+ LLView* viewp = *list_it;
+ lldebugs << "removing " << viewp->getName() << llendl;
+ mParent->removeChild(viewp);
+ }
+ }
+}
+
+void LLPanelProfile::ChildStack::dump()
+{
+ unsigned lvl = 0;
+ lldebugs << "child stack dump:" << llendl;
+ for (stack_t::const_iterator stack_it = mStack.begin(); stack_it != mStack.end(); ++stack_it, ++lvl)
+ {
+ std::ostringstream dbg_line;
+ dbg_line << "lvl #" << lvl << ":";
+ const view_list_t& vlist = (*stack_it);
+ for (view_list_t::const_iterator list_it = vlist.begin(); list_it != vlist.end(); ++list_it)
+ {
+ dbg_line << " " << (*list_it)->getName();
+ }
+ lldebugs << dbg_line.str() << llendl;
+ }
+}
+
+//-- LLPanelProfile::ChildStack ends ------------------------------------------
+
LLPanelProfile::LLPanelProfile()
: LLPanel()
, mTabCtrl(NULL)
, mAvatarId(LLUUID::null)
{
+ mChildStack.setParent(this);
}
BOOL LLPanelProfile::postBuild()
@@ -136,6 +282,15 @@ BOOL LLPanelProfile::postBuild()
return TRUE;
}
+// virtual
+void LLPanelProfile::reshape(S32 width, S32 height, BOOL called_from_parent)
+{
+ // Temporarily add saved children back and reshape them.
+ mChildStack.preParentReshape();
+ LLPanel::reshape(width, height, called_from_parent);
+ mChildStack.postParentReshape();
+}
+
void LLPanelProfile::onOpen(const LLSD& key)
{
// open the desired panel
@@ -174,10 +329,39 @@ void LLPanelProfile::onOpen(const LLSD& key)
picks->openClassifiedInfo(params);
}
}
+ else if (panel == "edit_classified")
+ {
+ LLPanelPicks* picks = dynamic_cast<LLPanelPicks *>(getTabContainer()[PANEL_PICKS]);
+ if (picks)
+ {
+ LLSD params = key;
+ params.erase("show_tab_panel");
+ params.erase("open_tab_name");
+ picks->openClassifiedEdit(params);
+ }
+ }
+ else if (panel == "create_pick")
+ {
+ LLPanelPicks* picks = dynamic_cast<LLPanelPicks *>(getTabContainer()[PANEL_PICKS]);
+ if (picks)
+ {
+ picks->createNewPick();
+ }
+ }
+ else if (panel == "edit_pick")
+ {
+ LLPanelPicks* picks = dynamic_cast<LLPanelPicks *>(getTabContainer()[PANEL_PICKS]);
+ if (picks)
+ {
+ LLSD params = key;
+ params.erase("show_tab_panel");
+ params.erase("open_tab_name");
+ picks->openPickEdit(params);
+ }
+ }
}
}
-//*TODO redo panel toggling
void LLPanelProfile::togglePanel(LLPanel* panel, const LLSD& key)
{
// TRUE - we need to open/expand "panel"
@@ -204,19 +388,12 @@ void LLPanelProfile::onTabSelected(const LLSD& param)
}
}
-void LLPanelProfile::setAllChildrenVisible(BOOL visible)
-{
- const child_list_t* child_list = getChildList();
- child_list_const_iter_t child_it = child_list->begin();
- for (; child_it != child_list->end(); ++child_it)
- {
- LLView* viewp = *child_it;
- viewp->setVisible(visible);
- }
-}
-
void LLPanelProfile::openPanel(LLPanel* panel, const LLSD& params)
{
+ // Hide currently visible panel (STORM-690).
+ mChildStack.push();
+
+ // Add the panel or bring it to front.
if (panel->getParent() != this)
{
addChild(panel);
@@ -227,7 +404,7 @@ void LLPanelProfile::openPanel(LLPanel* panel, const LLSD& params)
}
panel->setVisible(TRUE);
-
+ panel->setFocus(TRUE); // prevent losing focus by the floater
panel->onOpen(params);
LLRect new_rect = getRect();
@@ -243,6 +420,20 @@ void LLPanelProfile::closePanel(LLPanel* panel)
if (panel->getParent() == this)
{
removeChild(panel);
+
+ // Make the underlying panel visible.
+ mChildStack.pop();
+
+ // Prevent losing focus by the floater
+ const child_list_t* child_list = getChildList();
+ if (child_list->size() > 0)
+ {
+ child_list->front()->setFocus(TRUE);
+ }
+ else
+ {
+ llwarns << "No underlying panel to focus." << llendl;
+ }
}
}
diff --git a/indra/newview/llpanelprofile.h b/indra/newview/llpanelprofile.h
index d2bcee8076..fca359f51e 100644
--- a/indra/newview/llpanelprofile.h
+++ b/indra/newview/llpanelprofile.h
@@ -32,6 +32,8 @@
class LLTabContainer;
+std::string getProfileURL(const std::string& agent_name);
+
/**
* Base class for Profile View and My Profile.
*/
@@ -41,7 +43,7 @@ class LLPanelProfile : public LLPanel
public:
/*virtual*/ BOOL postBuild();
-
+ /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
/*virtual*/ void onOpen(const LLSD& key);
virtual void togglePanel(LLPanel*, const LLSD& key = LLSD());
@@ -58,8 +60,6 @@ protected:
virtual void onTabSelected(const LLSD& param);
- virtual void setAllChildrenVisible(BOOL visible);
-
LLTabContainer* getTabCtrl() { return mTabCtrl; }
const LLUUID& getAvatarId() { return mAvatarId; }
@@ -72,8 +72,34 @@ protected:
private:
+ //-- ChildStack begins ----------------------------------------------------
+ class ChildStack
+ {
+ LOG_CLASS(LLPanelProfile::ChildStack);
+ public:
+ ChildStack();
+ void setParent(LLPanel* parent);
+
+ bool push();
+ bool pop();
+ void preParentReshape();
+ void postParentReshape();
+
+ private:
+ void dump();
+
+ typedef LLView::child_list_t view_list_t;
+ typedef std::list<view_list_t> stack_t;
+
+ stack_t mStack;
+ stack_t mSavedStack;
+ LLPanel* mParent;
+ };
+ //-- ChildStack ends ------------------------------------------------------
+
LLTabContainer* mTabCtrl;
profile_tabs_t mTabContainer;
+ ChildStack mChildStack;
LLUUID mAvatarId;
};
diff --git a/indra/newview/llpanelteleporthistory.cpp b/indra/newview/llpanelteleporthistory.cpp
index 9b8167b15a..9b35e78134 100644
--- a/indra/newview/llpanelteleporthistory.cpp
+++ b/indra/newview/llpanelteleporthistory.cpp
@@ -27,6 +27,7 @@
#include "llviewerprecompiledheaders.h"
#include "llfloaterreg.h"
+#include "llmenubutton.h"
#include "llfloaterworldmap.h"
#include "llpanelteleporthistory.h"
@@ -40,6 +41,7 @@
#include "llflatlistview.h"
#include "llnotificationsutil.h"
#include "lltextbox.h"
+#include "lltoggleablemenu.h"
#include "llviewermenu.h"
#include "lllandmarkactions.h"
#include "llclipboard.h"
@@ -179,9 +181,11 @@ void LLTeleportHistoryFlatItem::setRegionName(const std::string& name)
void LLTeleportHistoryFlatItem::updateTitle()
{
+ static LLUIColor sFgColor = LLUIColorTable::instance().getColor("MenuItemEnabledColor", LLColor4U(255, 255, 255));
+
LLTextUtil::textboxSetHighlightedVal(
mTitle,
- LLStyle::Params(),
+ LLStyle::Params().color(sFgColor),
mRegionName,
mHighlight);
}
@@ -375,7 +379,8 @@ LLTeleportHistoryPanel::LLTeleportHistoryPanel()
mHistoryAccordion(NULL),
mAccordionTabMenu(NULL),
mLastSelectedFlatlList(NULL),
- mLastSelectedItemIndex(-1)
+ mLastSelectedItemIndex(-1),
+ mMenuGearButton(NULL)
{
buildFromFile( "panel_teleport_history.xml");
}
@@ -439,8 +444,6 @@ BOOL LLTeleportHistoryPanel::postBuild()
}
}
- getChild<LLPanel>("bottom_panel")->childSetAction("gear_btn",boost::bind(&LLTeleportHistoryPanel::onGearButtonClicked, this));
-
LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
registrar.add("TeleportHistory.ExpandAllFolders", boost::bind(&LLTeleportHistoryPanel::onExpandAllFolders, this));
@@ -448,9 +451,14 @@ BOOL LLTeleportHistoryPanel::postBuild()
registrar.add("TeleportHistory.ClearTeleportHistory", boost::bind(&LLTeleportHistoryPanel::onClearTeleportHistory, this));
mEnableCallbackRegistrar.add("TeleportHistory.GearMenu.Enable", boost::bind(&LLTeleportHistoryPanel::isActionEnabled, this, _2));
- LLMenuGL* gear_menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_teleport_history_gear.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+ mMenuGearButton = getChild<LLMenuButton>("gear_btn");
+
+ LLToggleableMenu* gear_menu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_teleport_history_gear.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());;
if(gear_menu)
+ {
mGearMenuHandle = gear_menu->getHandle();
+ mMenuGearButton->setMenu(gear_menu);
+ }
return TRUE;
}
@@ -985,27 +993,6 @@ LLFlatListView* LLTeleportHistoryPanel::getFlatListViewFromTab(LLAccordionCtrlTa
return NULL;
}
-void LLTeleportHistoryPanel::onGearButtonClicked()
-{
- LLMenuGL* menu = (LLMenuGL*)mGearMenuHandle.get();
- if (!menu)
- return;
-
- // Shows the menu at the top of the button bar.
-
- // Calculate its coordinates.
- LLPanel* bottom_panel = getChild<LLPanel>("bottom_panel");
- menu->arrangeAndClear();
- S32 menu_height = menu->getRect().getHeight();
- S32 menu_x = -2; // *HACK: compensates HPAD in showPopup()
- S32 menu_y = bottom_panel->getRect().mTop + menu_height;
-
- // Actually show the menu.
- menu->buildDrawLabels();
- menu->updateParent(LLMenuGL::sMenuContainer);
- LLMenuGL::showPopup(this, menu, menu_x, menu_y);
-}
-
bool LLTeleportHistoryPanel::isActionEnabled(const LLSD& userdata) const
{
S32 tabs_cnt = mItemContainers.size();
diff --git a/indra/newview/llpanelteleporthistory.h b/indra/newview/llpanelteleporthistory.h
index b5a025b39b..3d29454d15 100644
--- a/indra/newview/llpanelteleporthistory.h
+++ b/indra/newview/llpanelteleporthistory.h
@@ -38,6 +38,7 @@ class LLTeleportHistoryStorage;
class LLAccordionCtrl;
class LLAccordionCtrlTab;
class LLFlatListView;
+class LLMenuButton;
class LLTeleportHistoryPanel : public LLPanelPlacesTab
{
@@ -94,7 +95,6 @@ private:
void showTeleportHistory();
void handleItemSelect(LLFlatListView* );
LLFlatListView* getFlatListViewFromTab(LLAccordionCtrlTab *);
- void onGearButtonClicked();
bool isActionEnabled(const LLSD& userdata) const;
void setAccordionCollapsedByUser(LLUICtrl* acc_tab, bool collapsed);
@@ -118,6 +118,7 @@ private:
ContextMenu mContextMenu;
LLContextMenu* mAccordionTabMenu;
LLHandle<LLView> mGearMenuHandle;
+ LLMenuButton* mMenuGearButton;
};
diff --git a/indra/newview/llpaneltopinfobar.cpp b/indra/newview/llpaneltopinfobar.cpp
index a9ca7314ce..30949f8f02 100644
--- a/indra/newview/llpaneltopinfobar.cpp
+++ b/indra/newview/llpaneltopinfobar.cpp
@@ -38,6 +38,7 @@
#include "llsidetray.h"
#include "llslurl.h"
#include "llstatusbar.h"
+#include "lltrans.h"
#include "llviewercontrol.h"
#include "llviewerinventory.h"
#include "llviewermenu.h"
@@ -102,6 +103,13 @@ void LLPanelTopInfoBar::initParcelIcons()
mParcelIcon[SCRIPTS_ICON] = getChild<LLIconCtrl>("scripts_icon");
mParcelIcon[DAMAGE_ICON] = getChild<LLIconCtrl>("damage_icon");
+ mParcelIcon[VOICE_ICON]->setToolTip(LLTrans::getString("LocationCtrlVoiceTooltip"));
+ mParcelIcon[FLY_ICON]->setToolTip(LLTrans::getString("LocationCtrlFlyTooltip"));
+ mParcelIcon[PUSH_ICON]->setToolTip(LLTrans::getString("LocationCtrlPushTooltip"));
+ mParcelIcon[BUILD_ICON]->setToolTip(LLTrans::getString("LocationCtrlBuildTooltip"));
+ mParcelIcon[SCRIPTS_ICON]->setToolTip(LLTrans::getString("LocationCtrlScriptsTooltip"));
+ mParcelIcon[DAMAGE_ICON]->setToolTip(LLTrans::getString("LocationCtrlDamageTooltip"));
+
mParcelIcon[VOICE_ICON]->setMouseDownCallback(boost::bind(&LLPanelTopInfoBar::onParcelIconClick, this, VOICE_ICON));
mParcelIcon[FLY_ICON]->setMouseDownCallback(boost::bind(&LLPanelTopInfoBar::onParcelIconClick, this, FLY_ICON));
mParcelIcon[PUSH_ICON]->setMouseDownCallback(boost::bind(&LLPanelTopInfoBar::onParcelIconClick, this, PUSH_ICON));
@@ -129,6 +137,7 @@ BOOL LLPanelTopInfoBar::postBuild()
{
mInfoBtn = getChild<LLButton>("place_info_btn");
mInfoBtn->setClickedCallback(boost::bind(&LLPanelTopInfoBar::onInfoButtonClicked, this));
+ mInfoBtn->setToolTip(LLTrans::getString("LocationCtrlInfoBtnTooltip"));
mParcelInfoText = getChild<LLTextBox>("parcel_info_text");
mDamageText = getChild<LLTextBox>("damage_text");
diff --git a/indra/newview/llpanelvoicedevicesettings.cpp b/indra/newview/llpanelvoicedevicesettings.cpp
index aef870d352..dc87bd0077 100644
--- a/indra/newview/llpanelvoicedevicesettings.cpp
+++ b/indra/newview/llpanelvoicedevicesettings.cpp
@@ -51,6 +51,7 @@ LLPanelVoiceDeviceSettings::LLPanelVoiceDeviceSettings()
mInputDevice = gSavedSettings.getString("VoiceInputAudioDevice");
mOutputDevice = gSavedSettings.getString("VoiceOutputAudioDevice");
mDevicesUpdated = FALSE;
+ mUseTuningMode = true;
// grab "live" mic volume level
mMicVolume = gSavedSettings.getF32("AudioLevelMic");
@@ -96,7 +97,7 @@ void LLPanelVoiceDeviceSettings::draw()
// let user know that volume indicator is not yet available
bool is_in_tuning_mode = LLVoiceClient::getInstance()->inTuningMode();
- getChildView("wait_text")->setVisible( !is_in_tuning_mode);
+ getChildView("wait_text")->setVisible( !is_in_tuning_mode && mUseTuningMode);
LLPanel::draw();
@@ -220,23 +221,7 @@ void LLPanelVoiceDeviceSettings::refresh()
iter != LLVoiceClient::getInstance()->getCaptureDevices().end();
iter++)
{
- // Lets try to localize some system device names. EXT-8375
- std::string device_name = *iter;
- LLStringUtil::toLower(device_name); //compare in low case
- if ("default system device" == device_name)
- {
- device_name = getString(device_name);
- }
- else if ("no device" == device_name)
- {
- device_name = getString(device_name);
- }
- else
- {
- // restore original value
- device_name = *iter;
- }
- mCtrlInputDevices->add(device_name, ADD_BOTTOM );
+ mCtrlInputDevices->add( *iter, ADD_BOTTOM );
}
if(!mCtrlInputDevices->setSimple(mInputDevice))
@@ -253,23 +238,7 @@ void LLPanelVoiceDeviceSettings::refresh()
for(iter= LLVoiceClient::getInstance()->getRenderDevices().begin();
iter != LLVoiceClient::getInstance()->getRenderDevices().end(); iter++)
{
- // Lets try to localize some system device names. EXT-8375
- std::string device_name = *iter;
- LLStringUtil::toLower(device_name); //compare in low case
- if ("default system device" == device_name)
- {
- device_name = getString(device_name);
- }
- else if ("no device" == device_name)
- {
- device_name = getString(device_name);
- }
- else
- {
- // restore original value
- device_name = *iter;
- }
- mCtrlOutputDevices->add(device_name, ADD_BOTTOM );
+ mCtrlOutputDevices->add( *iter, ADD_BOTTOM );
}
if(!mCtrlOutputDevices->setSimple(mOutputDevice))
@@ -292,14 +261,20 @@ void LLPanelVoiceDeviceSettings::initialize()
LLVoiceClient::getInstance()->refreshDeviceLists();
// put voice client in "tuning" mode
- LLVoiceClient::getInstance()->tuningStart();
- LLVoiceChannel::suspend();
+ if (mUseTuningMode)
+ {
+ LLVoiceClient::getInstance()->tuningStart();
+ LLVoiceChannel::suspend();
+ }
}
void LLPanelVoiceDeviceSettings::cleanup()
{
- LLVoiceClient::getInstance()->tuningStop();
- LLVoiceChannel::resume();
+ if (mUseTuningMode)
+ {
+ LLVoiceClient::getInstance()->tuningStop();
+ LLVoiceChannel::resume();
+ }
}
void LLPanelVoiceDeviceSettings::onCommitInputDevice()
@@ -316,6 +291,6 @@ void LLPanelVoiceDeviceSettings::onCommitOutputDevice()
if(LLVoiceClient::getInstance())
{
LLVoiceClient::getInstance()->setRenderDevice(
- getChild<LLComboBox>("voice_input_device")->getValue().asString());
+ getChild<LLComboBox>("voice_output_device")->getValue().asString());
}
}
diff --git a/indra/newview/llpanelvoicedevicesettings.h b/indra/newview/llpanelvoicedevicesettings.h
index 636b8b9948..d09476d469 100644
--- a/indra/newview/llpanelvoicedevicesettings.h
+++ b/indra/newview/llpanelvoicedevicesettings.h
@@ -45,6 +45,8 @@ public:
void cleanup();
/*virtual*/ void handleVisibilityChange ( BOOL new_visibility );
+
+ void setUseTuningMode(bool use) { mUseTuningMode = use; };
protected:
void onCommitInputDevice();
@@ -56,6 +58,7 @@ protected:
class LLComboBox *mCtrlInputDevices;
class LLComboBox *mCtrlOutputDevices;
BOOL mDevicesUpdated;
+ bool mUseTuningMode;
};
#endif // LL_LLPANELVOICEDEVICESETTINGS_H
diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp
index 065c4d0b92..c443814c89 100644
--- a/indra/newview/llpanelvolume.cpp
+++ b/indra/newview/llpanelvolume.cpp
@@ -71,6 +71,11 @@
#include "lldrawpool.h"
#include "lluictrlfactory.h"
+// For mesh physics
+#include "llagent.h"
+#include "llviewercontrol.h"
+#include "llmeshrepository.h"
+
// "Features" Tab
BOOL LLPanelVolume::postBuild()
@@ -129,6 +134,29 @@ BOOL LLPanelVolume::postBuild()
getChild<LLUICtrl>("Light Ambiance")->setValidateBeforeCommit( precommitValidate);
}
+ // PHYSICS Parameters
+ {
+ // PhysicsShapeType combobox
+ mComboPhysicsShapeType = getChild<LLComboBox>("Physics Shape Type Combo Ctrl");
+ mComboPhysicsShapeType->setCommitCallback(boost::bind(&LLPanelVolume::sendPhysicsShapeType, this, _1, mComboPhysicsShapeType));
+
+ // PhysicsGravity
+ mSpinPhysicsGravity = getChild<LLSpinCtrl>("Physics Gravity");
+ mSpinPhysicsGravity->setCommitCallback(boost::bind(&LLPanelVolume::sendPhysicsGravity, this, _1, mSpinPhysicsGravity));
+
+ // PhysicsFriction
+ mSpinPhysicsFriction = getChild<LLSpinCtrl>("Physics Friction");
+ mSpinPhysicsFriction->setCommitCallback(boost::bind(&LLPanelVolume::sendPhysicsFriction, this, _1, mSpinPhysicsFriction));
+
+ // PhysicsDensity
+ mSpinPhysicsDensity = getChild<LLSpinCtrl>("Physics Density");
+ mSpinPhysicsDensity->setCommitCallback(boost::bind(&LLPanelVolume::sendPhysicsDensity, this, _1, mSpinPhysicsDensity));
+
+ // PhysicsRestitution
+ mSpinPhysicsRestitution = getChild<LLSpinCtrl>("Physics Restitution");
+ mSpinPhysicsRestitution->setCommitCallback(boost::bind(&LLPanelVolume::sendPhysicsRestitution, this, _1, mSpinPhysicsRestitution));
+ }
+
// Start with everyone disabled
clearCtrls();
@@ -351,6 +379,54 @@ void LLPanelVolume::getState( )
getChildView("FlexForceZ")->setEnabled(false);
}
+ // Physics properties
+
+ mSpinPhysicsGravity->set(objectp->getPhysicsGravity());
+ mSpinPhysicsGravity->setEnabled(editable);
+
+ mSpinPhysicsFriction->set(objectp->getPhysicsFriction());
+ mSpinPhysicsFriction->setEnabled(editable);
+
+ mSpinPhysicsDensity->set(objectp->getPhysicsDensity());
+ mSpinPhysicsDensity->setEnabled(editable);
+
+ mSpinPhysicsRestitution->set(objectp->getPhysicsRestitution());
+ mSpinPhysicsRestitution->setEnabled(editable);
+
+ // update the physics shape combo to include allowed physics shapes
+ mComboPhysicsShapeType->removeall();
+ mComboPhysicsShapeType->add(getString("None"), LLSD(1));
+
+ BOOL isMesh = FALSE;
+ LLSculptParams *sculpt_params = (LLSculptParams *)objectp->getParameterEntry(LLNetworkData::PARAMS_SCULPT);
+ if (sculpt_params)
+ {
+ U8 sculpt_type = sculpt_params->getSculptType();
+ U8 sculpt_stitching = sculpt_type & LL_SCULPT_TYPE_MASK;
+ isMesh = (sculpt_stitching == LL_SCULPT_TYPE_MESH);
+ }
+
+ if(isMesh && objectp)
+ {
+ const LLVolumeParams &volume_params = objectp->getVolume()->getParams();
+ LLUUID mesh_id = volume_params.getSculptID();
+ if(gMeshRepo.hasPhysicsShape(mesh_id))
+ {
+ // if a mesh contains an uploaded or decomposed physics mesh,
+ // allow 'Prim'
+ mComboPhysicsShapeType->add(getString("Prim"), LLSD(0));
+ }
+ }
+ else
+ {
+ // simple prims always allow physics shape prim
+ mComboPhysicsShapeType->add(getString("Prim"), LLSD(0));
+ }
+
+ mComboPhysicsShapeType->add(getString("Convex Hull"), LLSD(2));
+ mComboPhysicsShapeType->setValue(LLSD(objectp->getPhysicsShapeType()));
+ mComboPhysicsShapeType->setEnabled(editable);
+
mObject = objectp;
mRootObject = root_objectp;
}
@@ -384,6 +460,17 @@ void LLPanelVolume::refresh()
getChildView("Light Ambiance")->setVisible( visible);
getChildView("light texture control")->setVisible( visible);
+ bool enable_mesh = gSavedSettings.getBOOL("MeshEnabled") &&
+ gAgent.getRegion() &&
+ !gAgent.getRegion()->getCapability("GetMesh").empty();
+
+ getChildView("label physicsshapetype")->setVisible(enable_mesh);
+ getChildView("Physics Shape Type Combo Ctrl")->setVisible(enable_mesh);
+ getChildView("Physics Gravity")->setVisible(enable_mesh);
+ getChildView("Physics Material Override")->setVisible(enable_mesh);
+ getChildView("Physics Friction")->setVisible(enable_mesh);
+ getChildView("Physics Density")->setVisible(enable_mesh);
+ getChildView("Physics Restitution")->setVisible(enable_mesh);
}
@@ -430,6 +517,11 @@ void LLPanelVolume::clearCtrls()
getChildView("FlexForceX")->setEnabled(false);
getChildView("FlexForceY")->setEnabled(false);
getChildView("FlexForceZ")->setEnabled(false);
+
+ mSpinPhysicsGravity->setEnabled(FALSE);
+ mSpinPhysicsFriction->setEnabled(FALSE);
+ mSpinPhysicsDensity->setEnabled(FALSE);
+ mSpinPhysicsRestitution->setEnabled(FALSE);
}
//
@@ -482,6 +574,48 @@ void LLPanelVolume::sendIsFlexible()
llinfos << "update flexible sent" << llendl;
}
+void LLPanelVolume::sendPhysicsShapeType(LLUICtrl* ctrl, void* userdata)
+{
+ U8 type = ctrl->getValue().asInteger();
+ LLSelectMgr::getInstance()->selectionSetPhysicsType(type);
+
+ refreshCost();
+}
+
+void LLPanelVolume::sendPhysicsGravity(LLUICtrl* ctrl, void* userdata)
+{
+ F32 val = ctrl->getValue().asReal();
+ LLSelectMgr::getInstance()->selectionSetGravity(val);
+}
+
+void LLPanelVolume::sendPhysicsFriction(LLUICtrl* ctrl, void* userdata)
+{
+ F32 val = ctrl->getValue().asReal();
+ LLSelectMgr::getInstance()->selectionSetFriction(val);
+}
+
+void LLPanelVolume::sendPhysicsRestitution(LLUICtrl* ctrl, void* userdata)
+{
+ F32 val = ctrl->getValue().asReal();
+ LLSelectMgr::getInstance()->selectionSetRestitution(val);
+}
+
+void LLPanelVolume::sendPhysicsDensity(LLUICtrl* ctrl, void* userdata)
+{
+ F32 val = ctrl->getValue().asReal();
+ LLSelectMgr::getInstance()->selectionSetDensity(val);
+}
+
+void LLPanelVolume::refreshCost()
+{
+ LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getFirstObject();
+
+ if (obj)
+ {
+ obj->getObjectCost();
+ }
+}
+
void LLPanelVolume::onLightCancelColor(const LLSD& data)
{
LLColorSwatchCtrl* LightColorSwatch = getChild<LLColorSwatchCtrl>("colorswatch");
diff --git a/indra/newview/llpanelvolume.h b/indra/newview/llpanelvolume.h
index 90a2abda25..776a2c1f4a 100644
--- a/indra/newview/llpanelvolume.h
+++ b/indra/newview/llpanelvolume.h
@@ -64,6 +64,8 @@ public:
static void onCommitIsFlexible( LLUICtrl* ctrl, void* userdata);
static void onCommitFlexible( LLUICtrl* ctrl, void* userdata);
+ static void onCommitPhysicsParam( LLUICtrl* ctrl, void* userdata);
+
void onLightCancelColor(const LLSD& data);
void onLightSelectColor(const LLSD& data);
@@ -73,8 +75,15 @@ public:
protected:
void getState();
+ void refreshCost();
protected:
+ void sendPhysicsShapeType(LLUICtrl* ctrl, void* userdata);
+ void sendPhysicsGravity(LLUICtrl* ctrl, void* userdata);
+ void sendPhysicsFriction(LLUICtrl* ctrl, void* userdata);
+ void sendPhysicsRestitution(LLUICtrl* ctrl, void* userdata);
+ void sendPhysicsDensity(LLUICtrl* ctrl, void* userdata);
+
/*
LLTextBox* mLabelSelectSingleMessage;
// Light
@@ -99,6 +108,12 @@ protected:
LLUUID mLightSavedTexture;
LLPointer<LLViewerObject> mObject;
LLPointer<LLViewerObject> mRootObject;
+
+ LLComboBox* mComboPhysicsShapeType;
+ LLSpinCtrl* mSpinPhysicsGravity;
+ LLSpinCtrl* mSpinPhysicsFriction;
+ LLSpinCtrl* mSpinPhysicsDensity;
+ LLSpinCtrl* mSpinPhysicsRestitution;
};
#endif
diff --git a/indra/newview/llpanelwearing.cpp b/indra/newview/llpanelwearing.cpp
index 860470cd73..911a9e5dda 100644
--- a/indra/newview/llpanelwearing.cpp
+++ b/indra/newview/llpanelwearing.cpp
@@ -28,10 +28,13 @@
#include "llpanelwearing.h"
+#include "lltoggleablemenu.h"
+
#include "llappearancemgr.h"
#include "llinventoryfunctions.h"
#include "llinventorymodel.h"
#include "llinventoryobserver.h"
+#include "llmenubutton.h"
#include "llsidetray.h"
#include "llviewermenu.h"
#include "llwearableitemslist.h"
@@ -58,21 +61,12 @@ public:
enable_registrar.add("Gear.OnEnable", boost::bind(&LLPanelWearing::isActionEnabled, mPanelWearing, _2));
- mMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>(
+ mMenu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>(
"menu_wearing_gear.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
llassert(mMenu);
}
- void show(LLView* spawning_view)
- {
- if (!mMenu) return;
-
- mMenu->buildDrawLabels();
- mMenu->updateParent(LLMenuGL::sMenuContainer);
- S32 menu_x = 0;
- S32 menu_y = spawning_view->getRect().getHeight() + mMenu->getRect().getHeight();
- LLMenuGL::showPopup(spawning_view, mMenu, menu_x, menu_y);
- }
+ LLToggleableMenu* getMenu() { return mMenu; }
private:
@@ -87,8 +81,8 @@ private:
}
}
- LLMenuGL* mMenu;
- LLPanelWearing* mPanelWearing;
+ LLToggleableMenu* mMenu;
+ LLPanelWearing* mPanelWearing;
};
//////////////////////////////////////////////////////////////////////////
@@ -189,6 +183,10 @@ BOOL LLPanelWearing::postBuild()
mCOFItemsList = getChild<LLWearableItemsList>("cof_items_list");
mCOFItemsList->setRightMouseDownCallback(boost::bind(&LLPanelWearing::onWearableItemsListRightClick, this, _1, _2, _3));
+ LLMenuButton* menu_gear_btn = getChild<LLMenuButton>("options_gear_btn");
+
+ menu_gear_btn->setMenu(mGearMenu->getMenu());
+
return TRUE;
}
@@ -253,13 +251,6 @@ bool LLPanelWearing::isActionEnabled(const LLSD& userdata)
return false;
}
-// virtual
-void LLPanelWearing::showGearMenu(LLView* spawning_view)
-{
- if (!mGearMenu) return;
- mGearMenu->show(spawning_view);
-}
-
boost::signals2::connection LLPanelWearing::setSelectionChangeCallback(commit_callback_t cb)
{
if (!mCOFItemsList) return boost::signals2::connection();
diff --git a/indra/newview/llpanelwearing.h b/indra/newview/llpanelwearing.h
index 1fa97735b1..157b2c4c5f 100644
--- a/indra/newview/llpanelwearing.h
+++ b/indra/newview/llpanelwearing.h
@@ -58,8 +58,6 @@ public:
/*virtual*/ bool isActionEnabled(const LLSD& userdata);
- /*virtual*/ void showGearMenu(LLView* spawning_view);
-
/*virtual*/ void getSelectedItemsUUIDs(uuid_vec_t& selected_uuids) const;
boost::signals2::connection setSelectionChangeCallback(commit_callback_t cb);
diff --git a/indra/newview/llparticipantlist.cpp b/indra/newview/llparticipantlist.cpp
index 01b3b5572e..54053cf89f 100644
--- a/indra/newview/llparticipantlist.cpp
+++ b/indra/newview/llparticipantlist.cpp
@@ -197,17 +197,20 @@ private:
uuid_set_t mAvalineCallers;
};
-LLParticipantList::LLParticipantList(LLSpeakerMgr* data_source, LLAvatarList* avatar_list, bool use_context_menu/* = true*/,
- bool exclude_agent /*= true*/, bool can_toggle_icons /*= true*/):
+LLParticipantList::LLParticipantList(LLSpeakerMgr* data_source,
+ LLAvatarList* avatar_list,
+ bool use_context_menu/* = true*/,
+ bool exclude_agent /*= true*/,
+ bool can_toggle_icons /*= true*/) :
mSpeakerMgr(data_source),
mAvatarList(avatar_list),
- mSortOrder(E_SORT_BY_NAME)
-, mParticipantListMenu(NULL)
-, mExcludeAgent(exclude_agent)
-, mValidateSpeakerCallback(NULL)
+ mParticipantListMenu(NULL),
+ mExcludeAgent(exclude_agent),
+ mValidateSpeakerCallback(NULL)
{
+
mAvalineUpdater = new LLAvalineUpdater(boost::bind(&LLParticipantList::onAvalineCallerFound, this, _1),
- boost::bind(&LLParticipantList::onAvalineCallerRemoved, this, _1));
+ boost::bind(&LLParticipantList::onAvalineCallerRemoved, this, _1));
mSpeakerAddListener = new SpeakerAddListener(*this);
mSpeakerRemoveListener = new SpeakerRemoveListener(*this);
@@ -393,15 +396,15 @@ void LLParticipantList::onAvatarListRefreshed(LLUICtrl* ctrl, const LLSD& param)
}
/*
-Seems this method is not necessary after onAvalineCallerRemoved was implemented;
+ Seems this method is not necessary after onAvalineCallerRemoved was implemented;
-It does nothing because list item is always created with correct class type for Avaline caller.
-For now Avaline Caller is removed from the LLSpeakerMgr List when it is removed from the Voice Client
-session.
-This happens in two cases: if Avaline Caller ends call itself or if Resident ends group call.
+ It does nothing because list item is always created with correct class type for Avaline caller.
+ For now Avaline Caller is removed from the LLSpeakerMgr List when it is removed from the Voice Client
+ session.
+ This happens in two cases: if Avaline Caller ends call itself or if Resident ends group call.
-Probably Avaline caller should be removed from the LLSpeakerMgr list ONLY if it ends call itself.
-Asked in EXT-4301.
+ Probably Avaline caller should be removed from the LLSpeakerMgr list ONLY if it ends call itself.
+ Asked in EXT-4301.
*/
void LLParticipantList::onAvalineCallerFound(const LLUUID& participant_id)
{
@@ -443,16 +446,19 @@ void LLParticipantList::onAvalineCallerRemoved(const LLUUID& participant_id)
void LLParticipantList::setSortOrder(EParticipantSortOrder order)
{
- if ( mSortOrder != order )
+ const U32 speaker_sort_order = gSavedSettings.getU32("SpeakerParticipantDefaultOrder");
+
+ if ( speaker_sort_order != order )
{
- mSortOrder = order;
+ gSavedSettings.setU32("SpeakerParticipantDefaultOrder", (U32)order);
sort();
}
}
-LLParticipantList::EParticipantSortOrder LLParticipantList::getSortOrder()
+const LLParticipantList::EParticipantSortOrder LLParticipantList::getSortOrder() const
{
- return mSortOrder;
+ const U32 speaker_sort_order = gSavedSettings.getU32("SpeakerParticipantDefaultOrder");
+ return EParticipantSortOrder(speaker_sort_order);
}
void LLParticipantList::setValidateSpeakerCallback(validate_speaker_callback_t cb)
@@ -551,28 +557,29 @@ void LLParticipantList::sort()
if ( !mAvatarList )
return;
- switch ( mSortOrder ) {
- case E_SORT_BY_NAME :
- // if mExcludeAgent == true , then no need to keep agent on top of the list
- if(mExcludeAgent)
- {
- mAvatarList->sortByName();
- }
- else
- {
- mAvatarList->setComparator(&AGENT_ON_TOP_NAME_COMPARATOR);
+ switch ( getSortOrder() )
+ {
+ case E_SORT_BY_NAME :
+ // if mExcludeAgent == true , then no need to keep agent on top of the list
+ if(mExcludeAgent)
+ {
+ mAvatarList->sortByName();
+ }
+ else
+ {
+ mAvatarList->setComparator(&AGENT_ON_TOP_NAME_COMPARATOR);
+ mAvatarList->sort();
+ }
+ break;
+ case E_SORT_BY_RECENT_SPEAKERS:
+ if (mSortByRecentSpeakers.isNull())
+ mSortByRecentSpeakers = new LLAvatarItemRecentSpeakerComparator(*this);
+ mAvatarList->setComparator(mSortByRecentSpeakers.get());
mAvatarList->sort();
- }
- break;
- case E_SORT_BY_RECENT_SPEAKERS:
- if (mSortByRecentSpeakers.isNull())
- mSortByRecentSpeakers = new LLAvatarItemRecentSpeakerComparator(*this);
- mAvatarList->setComparator(mSortByRecentSpeakers.get());
- mAvatarList->sort();
- break;
- default :
- llwarns << "Unrecognized sort order for " << mAvatarList->getName() << llendl;
- return;
+ break;
+ default :
+ llwarns << "Unrecognized sort order for " << mAvatarList->getName() << llendl;
+ return;
}
}
@@ -645,7 +652,7 @@ bool LLParticipantList::SpeakerClearListener::handleEvent(LLPointer<LLOldEvents:
//
bool LLParticipantList::SpeakerModeratorUpdateListener::handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata)
{
- return mParent.onModeratorUpdateEvent(event, userdata);
+ return mParent.onModeratorUpdateEvent(event, userdata);
}
bool LLParticipantList::SpeakerMuteListener::handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata)
@@ -867,7 +874,7 @@ void LLParticipantList::LLParticipantListMenu::confirmMuteAllCallback(const LLSD
const LLUUID& session_id = payload["session_id"];
LLIMSpeakerMgr * speaker_manager = dynamic_cast<LLIMSpeakerMgr*> (
- LLIMModel::getInstance()->getSpeakerManager(session_id));
+ LLIMModel::getInstance()->getSpeakerManager(session_id));
if (speaker_manager)
{
speaker_manager->moderateVoiceAllParticipants(false);
@@ -925,9 +932,9 @@ bool LLParticipantList::LLParticipantListMenu::enableContextMenuItem(const LLSD&
}
/*
-Processed menu items with such parameters:
- can_allow_text_chat
- can_moderate_voice
+ Processed menu items with such parameters:
+ can_allow_text_chat
+ can_moderate_voice
*/
bool LLParticipantList::LLParticipantListMenu::enableModerateContextMenuItem(const LLSD& userdata)
{
@@ -978,11 +985,11 @@ bool LLParticipantList::LLParticipantListMenu::checkContextMenuItem(const LLSD&
}
else if(item == "is_sorted_by_name")
{
- return E_SORT_BY_NAME == mParent.mSortOrder;
+ return E_SORT_BY_NAME == mParent.getSortOrder();
}
else if(item == "is_sorted_by_recent_speakers")
{
- return E_SORT_BY_RECENT_SPEAKERS == mParent.mSortOrder;
+ return E_SORT_BY_RECENT_SPEAKERS == mParent.getSortOrder();
}
return false;
diff --git a/indra/newview/llparticipantlist.h b/indra/newview/llparticipantlist.h
index 722a749d19..e0b3d42c25 100644
--- a/indra/newview/llparticipantlist.h
+++ b/indra/newview/llparticipantlist.h
@@ -24,6 +24,9 @@
* $/LicenseInfo$
*/
+#ifndef LL_PARTICIPANTLIST_H
+#define LL_PARTICIPANTLIST_H
+
#include "llviewerprecompiledheaders.h"
#include "llevent.h"
#include "llavatarlist.h" // for LLAvatarItemRecentSpeakerComparator
@@ -37,239 +40,247 @@ class LLAvalineUpdater;
class LLParticipantList
{
LOG_CLASS(LLParticipantList);
+public:
+
+ typedef boost::function<bool (const LLUUID& speaker_id)> validate_speaker_callback_t;
+
+ LLParticipantList(LLSpeakerMgr* data_source,
+ LLAvatarList* avatar_list,
+ bool use_context_menu = true,
+ bool exclude_agent = true,
+ bool can_toggle_icons = true);
+ ~LLParticipantList();
+ void setSpeakingIndicatorsVisible(BOOL visible);
+
+ enum EParticipantSortOrder
+ {
+ E_SORT_BY_NAME = 0,
+ E_SORT_BY_RECENT_SPEAKERS = 1,
+ };
+
+ /**
+ * Adds specified avatar ID to the existing list if it is not Agent's ID
+ *
+ * @param[in] avatar_id - Avatar UUID to be added into the list
+ */
+ void addAvatarIDExceptAgent(const LLUUID& avatar_id);
+
+ /**
+ * Set and sort Avatarlist by given order
+ */
+ void setSortOrder(EParticipantSortOrder order = E_SORT_BY_NAME);
+ const EParticipantSortOrder getSortOrder() const;
+
+ /**
+ * Refreshes the participant list if it's in sort by recent speaker order.
+ */
+ void updateRecentSpeakersOrder();
+
+ /**
+ * Set a callback to be called before adding a speaker. Invalid speakers will not be added.
+ *
+ * If the callback is unset all speakers are considered as valid.
+ *
+ * @see onAddItemEvent()
+ */
+ void setValidateSpeakerCallback(validate_speaker_callback_t cb);
+
+protected:
+ /**
+ * LLSpeakerMgr event handlers
+ */
+ bool onAddItemEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata);
+ bool onRemoveItemEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata);
+ bool onClearListEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata);
+ bool onModeratorUpdateEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata);
+ bool onSpeakerMuteEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata);
+
+ /**
+ * Sorts the Avatarlist by stored order
+ */
+ void sort();
+
+ /**
+ * List of listeners implementing LLOldEvents::LLSimpleListener.
+ * There is no way to handle all the events in one listener as LLSpeakerMgr registers
+ * listeners in such a way that one listener can handle only one type of event
+ **/
+ class BaseSpeakerListener : public LLOldEvents::LLSimpleListener
+ {
public:
+ BaseSpeakerListener(LLParticipantList& parent) : mParent(parent) {}
+ protected:
+ LLParticipantList& mParent;
+ };
- typedef boost::function<bool (const LLUUID& speaker_id)> validate_speaker_callback_t;
-
- LLParticipantList(LLSpeakerMgr* data_source, LLAvatarList* avatar_list, bool use_context_menu = true, bool exclude_agent = true, bool can_toggle_icons = true);
- ~LLParticipantList();
- void setSpeakingIndicatorsVisible(BOOL visible);
-
- typedef enum e_participant_sort_oder {
- E_SORT_BY_NAME = 0,
- E_SORT_BY_RECENT_SPEAKERS = 1,
- } EParticipantSortOrder;
+ class SpeakerAddListener : public BaseSpeakerListener
+ {
+ public:
+ SpeakerAddListener(LLParticipantList& parent) : BaseSpeakerListener(parent) {}
+ /*virtual*/ bool handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata);
+ };
- /**
- * Adds specified avatar ID to the existing list if it is not Agent's ID
- *
- * @param[in] avatar_id - Avatar UUID to be added into the list
- */
- void addAvatarIDExceptAgent(const LLUUID& avatar_id);
+ class SpeakerRemoveListener : public BaseSpeakerListener
+ {
+ public:
+ SpeakerRemoveListener(LLParticipantList& parent) : BaseSpeakerListener(parent) {}
+ /*virtual*/ bool handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata);
+ };
- /**
- * Set and sort Avatarlist by given order
- */
- void setSortOrder(EParticipantSortOrder order = E_SORT_BY_NAME);
- EParticipantSortOrder getSortOrder();
+ class SpeakerClearListener : public BaseSpeakerListener
+ {
+ public:
+ SpeakerClearListener(LLParticipantList& parent) : BaseSpeakerListener(parent) {}
+ /*virtual*/ bool handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata);
+ };
- /**
- * Refreshes the participant list if it's in sort by recent speaker order.
- */
- void updateRecentSpeakersOrder();
+ class SpeakerModeratorUpdateListener : public BaseSpeakerListener
+ {
+ public:
+ SpeakerModeratorUpdateListener(LLParticipantList& parent) : BaseSpeakerListener(parent) {}
+ /*virtual*/ bool handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata);
+ };
+
+ class SpeakerMuteListener : public BaseSpeakerListener
+ {
+ public:
+ SpeakerMuteListener(LLParticipantList& parent) : BaseSpeakerListener(parent) {}
- /**
- * Set a callback to be called before adding a speaker. Invalid speakers will not be added.
- *
- * If the callback is unset all speakers are considered as valid.
- *
- * @see onAddItemEvent()
- */
- void setValidateSpeakerCallback(validate_speaker_callback_t cb);
+ /*virtual*/ bool handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata);
+ };
+ /**
+ * Menu used in the participant list.
+ */
+ class LLParticipantListMenu : public LLListContextMenu
+ {
+ public:
+ LLParticipantListMenu(LLParticipantList& parent):mParent(parent){};
+ /*virtual*/ LLContextMenu* createMenu();
+ /*virtual*/ void show(LLView* spawning_view, const uuid_vec_t& uuids, S32 x, S32 y);
protected:
+ LLParticipantList& mParent;
+ private:
+ bool enableContextMenuItem(const LLSD& userdata);
+ bool enableModerateContextMenuItem(const LLSD& userdata);
+ bool checkContextMenuItem(const LLSD& userdata);
+
+ void sortParticipantList(const LLSD& userdata);
+ void toggleAllowTextChat(const LLSD& userdata);
+ void toggleMute(const LLSD& userdata, U32 flags);
+ void toggleMuteText(const LLSD& userdata);
+ void toggleMuteVoice(const LLSD& userdata);
+
/**
- * LLSpeakerMgr event handlers
+ * Return true if Agent is group moderator(and moderator of group call).
*/
- bool onAddItemEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata);
- bool onRemoveItemEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata);
- bool onClearListEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata);
- bool onModeratorUpdateEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata);
- bool onSpeakerMuteEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata);
+ bool isGroupModerator();
+ // Voice moderation support
/**
- * Sorts the Avatarlist by stored order
+ * Check whether specified by argument avatar is muted for group chat or not.
*/
- void sort();
-
- //List of listeners implementing LLOldEvents::LLSimpleListener.
- //There is no way to handle all the events in one listener as LLSpeakerMgr registers listeners in such a way
- //that one listener can handle only one type of event
- class BaseSpeakerListner : public LLOldEvents::LLSimpleListener
- {
- public:
- BaseSpeakerListner(LLParticipantList& parent) : mParent(parent) {}
- protected:
- LLParticipantList& mParent;
- };
-
- class SpeakerAddListener : public BaseSpeakerListner
- {
- public:
- SpeakerAddListener(LLParticipantList& parent) : BaseSpeakerListner(parent) {}
- /*virtual*/ bool handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata);
- };
-
- class SpeakerRemoveListener : public BaseSpeakerListner
- {
- public:
- SpeakerRemoveListener(LLParticipantList& parent) : BaseSpeakerListner(parent) {}
- /*virtual*/ bool handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata);
- };
-
- class SpeakerClearListener : public BaseSpeakerListner
- {
- public:
- SpeakerClearListener(LLParticipantList& parent) : BaseSpeakerListner(parent) {}
- /*virtual*/ bool handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata);
- };
-
- class SpeakerModeratorUpdateListener : public BaseSpeakerListner
- {
- public:
- SpeakerModeratorUpdateListener(LLParticipantList& parent) : BaseSpeakerListner(parent) {}
- /*virtual*/ bool handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata);
- };
-
- class SpeakerMuteListener : public BaseSpeakerListner
- {
- public:
- SpeakerMuteListener(LLParticipantList& parent) : BaseSpeakerListner(parent) {}
-
- /*virtual*/ bool handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata);
- };
+ bool isMuted(const LLUUID& avatar_id);
/**
- * Menu used in the participant list.
+ * Processes Voice moderation menu items.
+ *
+ * It calls either moderateVoiceParticipant() or moderateVoiceParticipant() depend on
+ * passed parameter.
+ *
+ * @param userdata can be "selected" or "others".
+ *
+ * @see moderateVoiceParticipant()
+ * @see moderateVoiceAllParticipants()
*/
- class LLParticipantListMenu : public LLListContextMenu
- {
- public:
- LLParticipantListMenu(LLParticipantList& parent):mParent(parent){};
- /*virtual*/ LLContextMenu* createMenu();
- /*virtual*/ void show(LLView* spawning_view, const uuid_vec_t& uuids, S32 x, S32 y);
- protected:
- LLParticipantList& mParent;
- private:
- bool enableContextMenuItem(const LLSD& userdata);
- bool enableModerateContextMenuItem(const LLSD& userdata);
- bool checkContextMenuItem(const LLSD& userdata);
-
- void sortParticipantList(const LLSD& userdata);
- void toggleAllowTextChat(const LLSD& userdata);
- void toggleMute(const LLSD& userdata, U32 flags);
- void toggleMuteText(const LLSD& userdata);
- void toggleMuteVoice(const LLSD& userdata);
-
- /**
- * Return true if Agent is group moderator(and moderator of group call).
- */
- bool isGroupModerator();
-
- // Voice moderation support
- /**
- * Check whether specified by argument avatar is muted for group chat or not.
- */
- bool isMuted(const LLUUID& avatar_id);
-
- /**
- * Processes Voice moderation menu items.
- *
- * It calls either moderateVoiceParticipant() or moderateVoiceParticipant() depend on
- * passed parameter.
- *
- * @param userdata can be "selected" or "others".
- *
- * @see moderateVoiceParticipant()
- * @see moderateVoiceAllParticipants()
- */
- void moderateVoice(const LLSD& userdata);
-
- /**
- * Mutes/Unmutes avatar for current group voice chat.
- *
- * It only marks avatar as muted for session and does not use local Agent's Block list.
- * It does not mute Agent itself.
- *
- * @param[in] avatar_id UUID of avatar to be processed
- * @param[in] unmute if true - specified avatar will be muted, otherwise - unmuted.
- *
- * @see moderateVoiceAllParticipants()
- */
- void moderateVoiceParticipant(const LLUUID& avatar_id, bool unmute);
-
- /**
- * Mutes/Unmutes all avatars for current group voice chat.
- *
- * It only marks avatars as muted for session and does not use local Agent's Block list.
- *
- * @param[in] unmute if true - avatars will be muted, otherwise - unmuted.
- *
- * @see moderateVoiceParticipant()
- */
- void moderateVoiceAllParticipants(bool unmute);
-
- static void confirmMuteAllCallback(const LLSD& notification, const LLSD& response);
- };
+ void moderateVoice(const LLSD& userdata);
/**
- * Comparator for comparing avatar items by last spoken time
+ * Mutes/Unmutes avatar for current group voice chat.
+ *
+ * It only marks avatar as muted for session and does not use local Agent's Block list.
+ * It does not mute Agent itself.
+ *
+ * @param[in] avatar_id UUID of avatar to be processed
+ * @param[in] unmute if true - specified avatar will be muted, otherwise - unmuted.
+ *
+ * @see moderateVoiceAllParticipants()
*/
- class LLAvatarItemRecentSpeakerComparator : public LLAvatarItemNameComparator, public LLRefCount
- {
- LOG_CLASS(LLAvatarItemRecentSpeakerComparator);
- public:
- LLAvatarItemRecentSpeakerComparator(LLParticipantList& parent):mParent(parent){};
- virtual ~LLAvatarItemRecentSpeakerComparator() {};
- protected:
- virtual bool doCompare(const LLAvatarListItem* avatar_item1, const LLAvatarListItem* avatar_item2) const;
- private:
- LLParticipantList& mParent;
- };
-
- private:
- void onAvatarListDoubleClicked(LLUICtrl* ctrl);
- void onAvatarListRefreshed(LLUICtrl* ctrl, const LLSD& param);
-
- void onAvalineCallerFound(const LLUUID& participant_id);
- void onAvalineCallerRemoved(const LLUUID& participant_id);
+ void moderateVoiceParticipant(const LLUUID& avatar_id, bool unmute);
/**
- * Adjusts passed participant to work properly.
+ * Mutes/Unmutes all avatars for current group voice chat.
*
- * Adds SpeakerMuteListener to process moderation actions.
- */
- void adjustParticipant(const LLUUID& speaker_id);
-
- LLSpeakerMgr* mSpeakerMgr;
- LLAvatarList* mAvatarList;
-
- std::set<LLUUID> mModeratorList;
- std::set<LLUUID> mModeratorToRemoveList;
-
- LLPointer<SpeakerAddListener> mSpeakerAddListener;
- LLPointer<SpeakerRemoveListener> mSpeakerRemoveListener;
- LLPointer<SpeakerClearListener> mSpeakerClearListener;
- LLPointer<SpeakerModeratorUpdateListener> mSpeakerModeratorListener;
- LLPointer<SpeakerMuteListener> mSpeakerMuteListener;
-
- LLParticipantListMenu* mParticipantListMenu;
-
- EParticipantSortOrder mSortOrder;
- /*
- * This field manages an adding a new avatar_id in the mAvatarList
- * If true, then agent_id wont be added into mAvatarList
- * Also by default this field is controlling a sort procedure, @c sort()
+ * It only marks avatars as muted for session and does not use local Agent's Block list.
+ *
+ * @param[in] unmute if true - avatars will be muted, otherwise - unmuted.
+ *
+ * @see moderateVoiceParticipant()
*/
- bool mExcludeAgent;
+ void moderateVoiceAllParticipants(bool unmute);
- // boost::connections
- boost::signals2::connection mAvatarListDoubleClickConnection;
- boost::signals2::connection mAvatarListRefreshConnection;
- boost::signals2::connection mAvatarListReturnConnection;
- boost::signals2::connection mAvatarListToggleIconsConnection;
+ static void confirmMuteAllCallback(const LLSD& notification, const LLSD& response);
+ };
- LLPointer<LLAvatarItemRecentSpeakerComparator> mSortByRecentSpeakers;
- validate_speaker_callback_t mValidateSpeakerCallback;
- LLAvalineUpdater* mAvalineUpdater;
+ /**
+ * Comparator for comparing avatar items by last spoken time
+ */
+ class LLAvatarItemRecentSpeakerComparator : public LLAvatarItemNameComparator, public LLRefCount
+ {
+ LOG_CLASS(LLAvatarItemRecentSpeakerComparator);
+ public:
+ LLAvatarItemRecentSpeakerComparator(LLParticipantList& parent):mParent(parent){};
+ virtual ~LLAvatarItemRecentSpeakerComparator() {};
+ protected:
+ virtual bool doCompare(const LLAvatarListItem* avatar_item1, const LLAvatarListItem* avatar_item2) const;
+ private:
+ LLParticipantList& mParent;
+ };
+
+private:
+ void onAvatarListDoubleClicked(LLUICtrl* ctrl);
+ void onAvatarListRefreshed(LLUICtrl* ctrl, const LLSD& param);
+
+ void onAvalineCallerFound(const LLUUID& participant_id);
+ void onAvalineCallerRemoved(const LLUUID& participant_id);
+
+ /**
+ * Adjusts passed participant to work properly.
+ *
+ * Adds SpeakerMuteListener to process moderation actions.
+ */
+ void adjustParticipant(const LLUUID& speaker_id);
+
+ LLSpeakerMgr* mSpeakerMgr;
+ LLAvatarList* mAvatarList;
+
+ std::set<LLUUID> mModeratorList;
+ std::set<LLUUID> mModeratorToRemoveList;
+
+ LLPointer<SpeakerAddListener> mSpeakerAddListener;
+ LLPointer<SpeakerRemoveListener> mSpeakerRemoveListener;
+ LLPointer<SpeakerClearListener> mSpeakerClearListener;
+ LLPointer<SpeakerModeratorUpdateListener> mSpeakerModeratorListener;
+ LLPointer<SpeakerMuteListener> mSpeakerMuteListener;
+
+ LLParticipantListMenu* mParticipantListMenu;
+
+ /**
+ * This field manages an adding a new avatar_id in the mAvatarList
+ * If true, then agent_id wont be added into mAvatarList
+ * Also by default this field is controlling a sort procedure, @c sort()
+ */
+ bool mExcludeAgent;
+
+ // boost::connections
+ boost::signals2::connection mAvatarListDoubleClickConnection;
+ boost::signals2::connection mAvatarListRefreshConnection;
+ boost::signals2::connection mAvatarListReturnConnection;
+ boost::signals2::connection mAvatarListToggleIconsConnection;
+
+ LLPointer<LLAvatarItemRecentSpeakerComparator> mSortByRecentSpeakers;
+ validate_speaker_callback_t mValidateSpeakerCallback;
+ LLAvalineUpdater* mAvalineUpdater;
};
+
+#endif // LL_PARTICIPANTLIST_H
diff --git a/indra/newview/llphysicsmotion.cpp b/indra/newview/llphysicsmotion.cpp
new file mode 100644
index 0000000000..e124916c48
--- /dev/null
+++ b/indra/newview/llphysicsmotion.cpp
@@ -0,0 +1,732 @@
+/**
+ * @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_AVATAR_PHYSICS_MOTION 0.f
+#define TIME_ITERATION_STEP 0.1f
+
+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();
+ F32 calculateAcceleration_local(F32 velocity_local);
+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_AVATAR_PHYSICS_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 world_to_model_scale = 100.0f;
+ 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 positionchange_world = (position_world-last_position_world) * world_to_model_scale;
+ const LLVector3 velocity_world = positionchange_world;
+ const F32 velocity_local = toLocal(velocity_world);
+ return velocity_local;
+}
+
+F32 LLPhysicsMotion::calculateAcceleration_local(const F32 velocity_local)
+{
+// 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;
+
+ // Don't update too frequently, to avoid precision errors from small time slices.
+ if (time_delta <= .01)
+ {
+ return FALSE;
+ }
+
+ // If less than 1FPS, we don't want to be spending time updating physics at all.
+ if (time_delta > 1.0)
+ {
+ 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 = FALSE; // Enable this to simulate bouncing on all parts.
+
+ F32 behavior_maxeffect = getParamValue("MaxEffect");
+ if (physics_test)
+ behavior_maxeffect = 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.
+ const F32 position_user_local = (mParamDriver->getWeight() - mParamDriver->getMinWeight()) / (mParamDriver->getMaxWeight() - mParamDriver->getMinWeight());
+
+ //
+ // End parameters and settings
+ ////////////////////////////////////////////////////////////////////////////////
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Calculate velocity and acceleration in parameter space.
+ //
+
+ //const F32 velocity_joint_local = calculateVelocity_local(time_iteration_step);
+ const F32 velocity_joint_local = calculateVelocity_local();
+ const F32 acceleration_joint_local = calculateAcceleration_local(velocity_joint_local);
+
+ //
+ // End velocity and acceleration
+ ////////////////////////////////////////////////////////////////////////////////
+
+ BOOL update_visuals = FALSE;
+
+ // Break up the physics into a bunch of iterations so that differing framerates will show
+ // roughly the same behavior.
+ for (F32 time_iteration = 0; time_iteration <= time_delta; time_iteration += TIME_ITERATION_STEP)
+ {
+ F32 time_iteration_step = TIME_ITERATION_STEP;
+ if (time_iteration + TIME_ITERATION_STEP > time_delta)
+ {
+ time_iteration_step = time_delta-time_iteration;
+ }
+
+ // mPositon_local should be in normalized 0,1 range already. Just making sure...
+ const F32 position_current_local = llclamp(mPosition_local,
+ 0.0f,
+ 1.0f);
+ // 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 update_visuals;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // 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 = (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_velocity = 100.0f; // magic number, used to be customizable.
+ F32 velocity_new_local = mVelocity_local + acceleration_new_local*time_iteration_step;
+ velocity_new_local = llclamp(velocity_new_local,
+ -max_velocity, max_velocity);
+
+ // 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_iteration_step;
+ 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;
+ 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.
+
+ // 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.0001f-lod_factor)*0.4f;
+ if (llabs(position_diff_local) > min_delta)
+ {
+ update_visuals = TRUE;
+ mPositionLastUpdate_local = position_new_local;
+ }
+ }
+
+ //
+ // End update visual params
+ ////////////////////////////////////////////////////////////////////////////////
+
+ mVelocity_local = velocity_new_local;
+ mAccelerationJoint_local = acceleration_joint_local;
+ mPosition_local = position_new_local;
+ }
+ mLastTime = time;
+ mPosition_world = joint->getWorldPosition();
+ mVelocityJoint_local = velocity_joint_local;
+
+
+ /*
+ // 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
new file mode 100644
index 0000000000..b246fa99bb
--- /dev/null
+++ b/indra/newview/llphysicsmotion.h
@@ -0,0 +1,118 @@
+/**
+ * @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/llphysicsshapebuilderutil.cpp b/indra/newview/llphysicsshapebuilderutil.cpp
new file mode 100644
index 0000000000..5bfe5c9941
--- /dev/null
+++ b/indra/newview/llphysicsshapebuilderutil.cpp
@@ -0,0 +1,210 @@
+/**
+ * @file llphysicsshapebuilder.cpp
+ * @brief Generic system to convert LL(Physics)VolumeParams to physics shapes
+ *
+ * $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 "llphysicsshapebuilderutil.h"
+
+/* static */
+void LLPhysicsShapeBuilderUtil::determinePhysicsShape( const LLPhysicsVolumeParams& volume_params, const LLVector3& scale, PhysicsShapeSpecification& specOut )
+{
+ const LLProfileParams& profile_params = volume_params.getProfileParams();
+ const LLPathParams& path_params = volume_params.getPathParams();
+
+ specOut.mScale = scale;
+
+ const F32 avgScale = ( scale[VX] + scale[VY] + scale[VZ] )/3.0f;
+
+ // count the scale elements that are small
+ S32 min_size_counts = 0;
+ for (S32 i = 0; i < 3; ++i)
+ {
+ if (scale[i] < SHAPE_BUILDER_CONVEXIFICATION_SIZE)
+ {
+ ++min_size_counts;
+ }
+ }
+
+ const bool profile_complete = ( profile_params.getBegin() <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT/avgScale ) &&
+ ( profile_params.getEnd() >= (1.0f - SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT/avgScale) );
+
+ const bool path_complete = ( path_params.getBegin() <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT/avgScale ) &&
+ ( path_params.getEnd() >= (1.0f - SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT/avgScale) );
+
+ const bool simple_params = ( volume_params.getHollow() <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_HOLLOW/avgScale )
+ && ( fabs(path_params.getShearX()) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_SHEAR/avgScale )
+ && ( fabs(path_params.getShearY()) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_SHEAR/avgScale )
+ && ( !volume_params.isMeshSculpt() && !volume_params.isSculpt() );
+
+ if (simple_params && profile_complete)
+ {
+ // Try to create an implicit shape or convexified
+ bool no_taper = ( fabs(path_params.getScaleX() - 1.0f) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_TAPER/avgScale )
+ && ( fabs(path_params.getScaleY() - 1.0f) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_TAPER/avgScale );
+
+ bool no_twist = ( fabs(path_params.getTwistBegin()) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_TWIST/avgScale )
+ && ( fabs(path_params.getTwistEnd()) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_TWIST/avgScale);
+
+ // Box
+ if(
+ ( profile_params.getCurveType() == LL_PCODE_PROFILE_SQUARE )
+ && ( path_params.getCurveType() == LL_PCODE_PATH_LINE )
+ && no_taper
+ && no_twist
+ )
+ {
+ specOut.mType = PhysicsShapeSpecification::BOX;
+ if ( path_complete )
+ {
+ return;
+ }
+ else
+ {
+ // Side lengths
+ specOut.mScale[VX] = llmax( scale[VX], SHAPE_BUILDER_MIN_GEOMETRY_SIZE );
+ specOut.mScale[VY] = llmax( scale[VY], SHAPE_BUILDER_MIN_GEOMETRY_SIZE );
+ specOut.mScale[VZ] = llmax( scale[VZ] * (path_params.getEnd() - path_params.getBegin()), SHAPE_BUILDER_MIN_GEOMETRY_SIZE );
+
+ specOut.mCenter.set( 0.f, 0.f, 0.5f * scale[VZ] * ( path_params.getEnd() + path_params.getBegin() - 1.0f ) );
+ return;
+ }
+ }
+
+ // Sphere
+ if( path_complete
+ && ( profile_params.getCurveType() == LL_PCODE_PROFILE_CIRCLE_HALF )
+ && ( path_params.getCurveType() == LL_PCODE_PATH_CIRCLE )
+ && ( fabs(volume_params.getTaper()) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_TAPER/avgScale )
+ && no_twist
+ )
+ {
+ if ( ( scale[VX] == scale[VZ] )
+ && ( scale[VY] == scale[VZ] ) )
+ {
+ // perfect sphere
+ specOut.mType = PhysicsShapeSpecification::SPHERE;
+ specOut.mScale = scale;
+ return;
+ }
+ else if (min_size_counts > 1)
+ {
+ // small or narrow sphere -- we can boxify
+ for (S32 i=0; i<3; ++i)
+ {
+ if (specOut.mScale[i] < SHAPE_BUILDER_CONVEXIFICATION_SIZE)
+ {
+ // reduce each small dimension size to split the approximation errors
+ specOut.mScale[i] *= 0.75f;
+ }
+ }
+ specOut.mType = PhysicsShapeSpecification::BOX;
+ return;
+ }
+ }
+
+ // Cylinder
+ if( (scale[VX] == scale[VY])
+ && ( profile_params.getCurveType() == LL_PCODE_PROFILE_CIRCLE )
+ && ( path_params.getCurveType() == LL_PCODE_PATH_LINE )
+ && ( volume_params.getBeginS() <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT/avgScale )
+ && ( volume_params.getEndS() >= (1.0f - SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT/avgScale) )
+ && no_taper
+ )
+ {
+ if (min_size_counts > 1)
+ {
+ // small or narrow sphere -- we can boxify
+ for (S32 i=0; i<3; ++i)
+ {
+ if (specOut.mScale[i] < SHAPE_BUILDER_CONVEXIFICATION_SIZE)
+ {
+ // reduce each small dimension size to split the approximation errors
+ specOut.mScale[i] *= 0.75f;
+ }
+ }
+
+ specOut.mType = PhysicsShapeSpecification::BOX;
+ }
+ else
+ {
+ specOut.mType = PhysicsShapeSpecification::CYLINDER;
+ F32 length = (volume_params.getPathParams().getEnd() - volume_params.getPathParams().getBegin()) * scale[VZ];
+
+ specOut.mScale[VY] = specOut.mScale[VX];
+ specOut.mScale[VZ] = length;
+ // The minus one below fixes the fact that begin and end range from 0 to 1 not -1 to 1.
+ specOut.mCenter.set( 0.f, 0.f, 0.5f * (volume_params.getPathParams().getBegin() + volume_params.getPathParams().getEnd() - 1.f) * scale[VZ] );
+ }
+
+ return;
+ }
+ }
+
+ if ( (min_size_counts == 3 )
+ // Possible dead code here--who wants to take it out?
+ || (path_complete
+ && profile_complete
+ && ( path_params.getCurveType() == LL_PCODE_PATH_LINE )
+ && (min_size_counts > 1 ) )
+ )
+ {
+ // it isn't simple but
+ // we might be able to convexify this shape if the path and profile are complete
+ // or the path is linear and both path and profile are complete --> we can boxify it
+ specOut.mType = PhysicsShapeSpecification::BOX;
+ specOut.mScale = scale;
+ return;
+ }
+
+ // Special case for big, very thin objects - bump the small dimensions up to the COLLISION_TOLERANCE
+ if (min_size_counts == 1 // One dimension is small
+ && avgScale > 3.f) // ... but others are fairly large
+ {
+ for (S32 i = 0; i < 3; ++i)
+ {
+ specOut.mScale[i] = llmax( specOut.mScale[i], COLLISION_TOLERANCE );
+ }
+ }
+
+ if ( volume_params.shouldForceConvex() )
+ {
+ specOut.mType = PhysicsShapeSpecification::USER_CONVEX;
+ }
+ // Make a simpler convex shape if we can.
+ else if (volume_params.isConvex() // is convex
+ || min_size_counts > 1 ) // two or more small dimensions
+ {
+ specOut.mType = PhysicsShapeSpecification::PRIM_CONVEX;
+ }
+ else if ( volume_params.isSculpt() ) // Is a sculpt of any kind (mesh or legacy)
+ {
+ specOut.mType = volume_params.isMeshSculpt() ? PhysicsShapeSpecification::USER_MESH : PhysicsShapeSpecification::SCULPT;
+ }
+ else // Resort to mesh
+ {
+ specOut.mType = PhysicsShapeSpecification::PRIM_MESH;
+ }
+}
diff --git a/indra/newview/llphysicsshapebuilderutil.h b/indra/newview/llphysicsshapebuilderutil.h
new file mode 100644
index 0000000000..7dedfb05e2
--- /dev/null
+++ b/indra/newview/llphysicsshapebuilderutil.h
@@ -0,0 +1,138 @@
+/**
+ * @file llphysicsshapebuilder.h
+ * @brief Generic system to convert LL(Physics)VolumeParams to physics shapes
+ *
+ * $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_PHYSICS_SHAPE_BUILDER_H
+#define LL_PHYSICS_SHAPE_BUILDER_H
+
+#include "indra_constants.h"
+#include "llvolume.h"
+
+#define USE_SHAPE_QUANTIZATION 0
+
+#define SHAPE_BUILDER_DEFAULT_VOLUME_DETAIL 1
+
+#define SHAPE_BUILDER_IMPLICIT_THRESHOLD_HOLLOW 0.10f
+#define SHAPE_BUILDER_IMPLICIT_THRESHOLD_HOLLOW_SPHERES 0.90f
+#define SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT 0.05f
+#define SHAPE_BUILDER_IMPLICIT_THRESHOLD_TAPER 0.05f
+#define SHAPE_BUILDER_IMPLICIT_THRESHOLD_TWIST 0.09f
+#define SHAPE_BUILDER_IMPLICIT_THRESHOLD_SHEAR 0.05f
+
+const F32 SHAPE_BUILDER_ENTRY_SNAP_SCALE_BIN_SIZE = 0.15f;
+const F32 SHAPE_BUILDER_ENTRY_SNAP_PARAMETER_BIN_SIZE = 0.010f;
+const F32 SHAPE_BUILDER_CONVEXIFICATION_SIZE = 2.f * COLLISION_TOLERANCE;
+const F32 SHAPE_BUILDER_MIN_GEOMETRY_SIZE = 0.5f * COLLISION_TOLERANCE;
+
+class LLPhysicsVolumeParams : public LLVolumeParams
+{
+public:
+
+ LLPhysicsVolumeParams( const LLVolumeParams& params, bool forceConvex ) :
+ LLVolumeParams( params ),
+ mForceConvex(forceConvex) {}
+
+ bool operator==(const LLPhysicsVolumeParams &params) const
+ {
+ return ( LLVolumeParams::operator==(params) && (mForceConvex == params.mForceConvex) );
+ }
+
+ bool operator!=(const LLPhysicsVolumeParams &params) const
+ {
+ return !operator==(params);
+ }
+
+ bool operator<(const LLPhysicsVolumeParams &params) const
+ {
+ if ( LLVolumeParams::operator!=(params) )
+ {
+ return LLVolumeParams::operator<(params);
+ }
+ return (params.mForceConvex == false) && (mForceConvex == true);
+ }
+
+ bool shouldForceConvex() const { return mForceConvex; }
+
+private:
+ bool mForceConvex;
+};
+
+
+class LLPhysicsShapeBuilderUtil
+{
+public:
+
+ class PhysicsShapeSpecification
+ {
+ public:
+ enum ShapeType
+ {
+ // Primitive types
+ BOX,
+ SPHERE,
+ CYLINDER,
+
+ USER_CONVEX, // User specified they wanted the convex hull of the volume
+
+ PRIM_CONVEX, // Either a volume that is inherently convex but not a primitive type, or a shape
+ // with dimensions such that will convexify it anyway.
+
+ SCULPT, // Special case for traditional sculpts--they are the convex hull of a single particular set of volume params
+
+ USER_MESH, // A user mesh. May or may not contain a convex decomposition.
+
+ PRIM_MESH, // A non-convex volume which we have to represent accurately
+
+ INVALID
+ };
+
+ PhysicsShapeSpecification() :
+ mType( INVALID ),
+ mScale( 0.f, 0.f, 0.f ),
+ mCenter( 0.f, 0.f, 0.f ) {}
+
+ bool isConvex() { return (mType != USER_MESH && mType != PRIM_MESH && mType != INVALID); }
+ bool isMesh() { return (mType == USER_MESH) || (mType == PRIM_MESH); }
+
+ ShapeType getType() { return mType; }
+ const LLVector3& getScale() { return mScale; }
+ const LLVector3& getCenter() { return mCenter; }
+
+ private:
+ friend class LLPhysicsShapeBuilderUtil;
+
+ ShapeType mType;
+
+ // Dimensions of an AABB around the shape
+ LLVector3 mScale;
+
+ // Offset of shape from origin of primitive's reference frame
+ LLVector3 mCenter;
+ };
+
+ static void determinePhysicsShape( const LLPhysicsVolumeParams& volume_params, const LLVector3& scale, PhysicsShapeSpecification& specOut );
+};
+
+#endif //LL_PHYSICS_SHAPE_BUILDER_H
diff --git a/indra/newview/llplacesinventorypanel.cpp b/indra/newview/llplacesinventorypanel.cpp
index 408270a1a0..29e262199e 100644
--- a/indra/newview/llplacesinventorypanel.cpp
+++ b/indra/newview/llplacesinventorypanel.cpp
@@ -205,24 +205,6 @@ BOOL LLPlacesFolderView::handleRightMouseDown(S32 x, S32 y, MASK mask)
return LLFolderView::handleRightMouseDown(x, y, mask);
}
-BOOL LLPlacesFolderView::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
- EDragAndDropType cargo_type,
- void* cargo_data,
- EAcceptance* accept,
- std::string& tooltip_msg)
-{
- // Don't accept anything except landmarks and folders to be dropped
- // in places folder view. See STORM-296.
- if (cargo_type != DAD_LANDMARK && cargo_type != DAD_CATEGORY)
- {
- *accept = ACCEPT_NO;
- return FALSE;
- }
-
- return LLFolderView::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data,
- accept, tooltip_msg);
-}
-
void LLPlacesFolderView::setupMenuHandle(LLInventoryType::EType asset_type, LLHandle<LLView> menu_handle)
{
mMenuHandlesByInventoryType[asset_type] = menu_handle;
diff --git a/indra/newview/llplacesinventorypanel.h b/indra/newview/llplacesinventorypanel.h
index a44776d18b..6641871a0b 100644
--- a/indra/newview/llplacesinventorypanel.h
+++ b/indra/newview/llplacesinventorypanel.h
@@ -70,12 +70,6 @@ public:
*/
/*virtual*/ BOOL handleRightMouseDown( S32 x, S32 y, MASK mask );
- /*virtual*/ BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
- EDragAndDropType cargo_type,
- void* cargo_data,
- EAcceptance* accept,
- std::string& tooltip_msg);
-
void setupMenuHandle(LLInventoryType::EType asset_type, LLHandle<LLView> menu_handle);
void setParentLandmarksPanel(LLLandmarksPanel* panel)
diff --git a/indra/newview/llpolymesh.cpp b/indra/newview/llpolymesh.cpp
index 363b0b8e9d..450f9b2be7 100644
--- a/indra/newview/llpolymesh.cpp
+++ b/indra/newview/llpolymesh.cpp
@@ -29,7 +29,8 @@
//-----------------------------------------------------------------------------
#include "llviewerprecompiledheaders.h"
-#include "llpolymesh.h"
+#include "llfasttimer.h"
+#include "llmemory.h"
#include "llviewercontrol.h"
#include "llxmltree.h"
@@ -39,12 +40,21 @@
#include "llvolume.h"
#include "llendianswizzle.h"
-#include "llfasttimer.h"
+#include "llpolymesh.h"
#define HEADER_ASCII "Linden Mesh 1.0"
#define HEADER_BINARY "Linden Binary Mesh 1.0"
-extern LLControlGroup gSavedSettings; // read only
+extern LLControlGroup gSavedSettings; // read only
+
+LLPolyMorphData *clone_morph_param_duplicate(const LLPolyMorphData *src_data,
+ const std::string &name);
+LLPolyMorphData *clone_morph_param_direction(const LLPolyMorphData *src_data,
+ const LLVector3 &direction,
+ const std::string &name);
+LLPolyMorphData *clone_morph_param_cleavage(const LLPolyMorphData *src_data,
+ F32 scale,
+ const std::string &name);
//-----------------------------------------------------------------------------
// Global table of loaded LLPolyMeshes
@@ -56,28 +66,28 @@ LLPolyMesh::LLPolyMeshSharedDataTable LLPolyMesh::sGlobalSharedMeshList;
//-----------------------------------------------------------------------------
LLPolyMeshSharedData::LLPolyMeshSharedData()
{
- mNumVertices = 0;
- mBaseCoords = NULL;
- mBaseNormals = NULL;
- mBaseBinormals = NULL;
- mTexCoords = NULL;
- mDetailTexCoords = NULL;
- mWeights = NULL;
- mHasWeights = FALSE;
- mHasDetailTexCoords = FALSE;
+ mNumVertices = 0;
+ mBaseCoords = NULL;
+ mBaseNormals = NULL;
+ mBaseBinormals = NULL;
+ mTexCoords = NULL;
+ mDetailTexCoords = NULL;
+ mWeights = NULL;
+ mHasWeights = FALSE;
+ mHasDetailTexCoords = FALSE;
- mNumFaces = 0;
- mFaces = NULL;
+ mNumFaces = 0;
+ mFaces = NULL;
- mNumJointNames = 0;
- mJointNames = NULL;
+ mNumJointNames = 0;
+ mJointNames = NULL;
- mTriangleIndices = NULL;
- mNumTriangleIndices = 0;
+ mTriangleIndices = NULL;
+ mNumTriangleIndices = 0;
- mReferenceData = NULL;
+ mReferenceData = NULL;
- mLastIndexOffset = -1;
+ mLastIndexOffset = -1;
}
//-----------------------------------------------------------------------------
@@ -85,9 +95,9 @@ LLPolyMeshSharedData::LLPolyMeshSharedData()
//-----------------------------------------------------------------------------
LLPolyMeshSharedData::~LLPolyMeshSharedData()
{
- freeMeshData();
- for_each(mMorphData.begin(), mMorphData.end(), DeletePointer());
- mMorphData.clear();
+ freeMeshData();
+ for_each(mMorphData.begin(), mMorphData.end(), DeletePointer());
+ mMorphData.clear();
}
//-----------------------------------------------------------------------------
@@ -95,19 +105,19 @@ LLPolyMeshSharedData::~LLPolyMeshSharedData()
//-----------------------------------------------------------------------------
void LLPolyMeshSharedData::setupLOD(LLPolyMeshSharedData* reference_data)
{
- mReferenceData = reference_data;
-
- if (reference_data)
- {
- mBaseCoords = reference_data->mBaseCoords;
- mBaseNormals = reference_data->mBaseNormals;
- mBaseBinormals = reference_data->mBaseBinormals;
- mTexCoords = reference_data->mTexCoords;
- mDetailTexCoords = reference_data->mDetailTexCoords;
- mWeights = reference_data->mWeights;
- mHasWeights = reference_data->mHasWeights;
- mHasDetailTexCoords = reference_data->mHasDetailTexCoords;
- }
+ mReferenceData = reference_data;
+
+ if (reference_data)
+ {
+ mBaseCoords = reference_data->mBaseCoords;
+ mBaseNormals = reference_data->mBaseNormals;
+ mBaseBinormals = reference_data->mBaseBinormals;
+ mTexCoords = reference_data->mTexCoords;
+ mDetailTexCoords = reference_data->mDetailTexCoords;
+ mWeights = reference_data->mWeights;
+ mHasWeights = reference_data->mHasWeights;
+ mHasDetailTexCoords = reference_data->mHasDetailTexCoords;
+ }
}
//-----------------------------------------------------------------------------
@@ -115,41 +125,41 @@ void LLPolyMeshSharedData::setupLOD(LLPolyMeshSharedData* reference_data)
//-----------------------------------------------------------------------------
void LLPolyMeshSharedData::freeMeshData()
{
- if (!mReferenceData)
- {
- mNumVertices = 0;
+ if (!mReferenceData)
+ {
+ mNumVertices = 0;
- delete [] mBaseCoords;
- mBaseCoords = NULL;
+ delete [] mBaseCoords;
+ mBaseCoords = NULL;
- delete [] mBaseNormals;
- mBaseNormals = NULL;
+ delete [] mBaseNormals;
+ mBaseNormals = NULL;
- delete [] mBaseBinormals;
- mBaseBinormals = NULL;
+ delete [] mBaseBinormals;
+ mBaseBinormals = NULL;
- delete [] mTexCoords;
- mTexCoords = NULL;
+ delete [] mTexCoords;
+ mTexCoords = NULL;
- delete [] mDetailTexCoords;
- mDetailTexCoords = NULL;
+ delete [] mDetailTexCoords;
+ mDetailTexCoords = NULL;
- delete [] mWeights;
- mWeights = NULL;
- }
+ delete [] mWeights;
+ mWeights = NULL;
+ }
- mNumFaces = 0;
- delete [] mFaces;
- mFaces = NULL;
+ mNumFaces = 0;
+ delete [] mFaces;
+ mFaces = NULL;
- mNumJointNames = 0;
- delete [] mJointNames;
- mJointNames = NULL;
+ mNumJointNames = 0;
+ delete [] mJointNames;
+ mJointNames = NULL;
- delete [] mTriangleIndices;
- mTriangleIndices = NULL;
+ delete [] mTriangleIndices;
+ mTriangleIndices = NULL;
-// mVertFaceMap.deleteAllData();
+// mVertFaceMap.deleteAllData();
}
// compate_int is used by the qsort function to sort the index array
@@ -160,26 +170,26 @@ int compare_int(const void *a, const void *b);
//-----------------------------------------------------------------------------
void LLPolyMeshSharedData::genIndices(S32 index_offset)
{
- if (index_offset == mLastIndexOffset)
- {
- return;
- }
-
- delete []mTriangleIndices;
- mTriangleIndices = new U32[mNumTriangleIndices];
-
- S32 cur_index = 0;
- for (S32 i = 0; i < mNumFaces; i++)
- {
- mTriangleIndices[cur_index] = mFaces[i][0] + index_offset;
- cur_index++;
- mTriangleIndices[cur_index] = mFaces[i][1] + index_offset;
- cur_index++;
- mTriangleIndices[cur_index] = mFaces[i][2] + index_offset;
- cur_index++;
- }
-
- mLastIndexOffset = index_offset;
+ if (index_offset == mLastIndexOffset)
+ {
+ return;
+ }
+
+ delete []mTriangleIndices;
+ mTriangleIndices = new U32[mNumTriangleIndices];
+
+ S32 cur_index = 0;
+ for (S32 i = 0; i < mNumFaces; i++)
+ {
+ mTriangleIndices[cur_index] = mFaces[i][0] + index_offset;
+ cur_index++;
+ mTriangleIndices[cur_index] = mFaces[i][1] + index_offset;
+ cur_index++;
+ mTriangleIndices[cur_index] = mFaces[i][2] + index_offset;
+ cur_index++;
+ }
+
+ mLastIndexOffset = index_offset;
}
//--------------------------------------------------------------------
@@ -187,30 +197,30 @@ void LLPolyMeshSharedData::genIndices(S32 index_offset)
//--------------------------------------------------------------------
U32 LLPolyMeshSharedData::getNumKB()
{
- U32 num_kb = sizeof(LLPolyMesh);
-
- if (!isLOD())
- {
- num_kb += mNumVertices *
- ( sizeof(LLVector3) + // coords
- sizeof(LLVector3) + // normals
- sizeof(LLVector2) ); // texCoords
- }
-
- if (mHasDetailTexCoords && !isLOD())
- {
- num_kb += mNumVertices * sizeof(LLVector2); // detailTexCoords
- }
-
- if (mHasWeights && !isLOD())
- {
- num_kb += mNumVertices * sizeof(float); // weights
- }
-
- num_kb += mNumFaces * sizeof(LLPolyFace); // faces
-
- num_kb /= 1024;
- return num_kb;
+ U32 num_kb = sizeof(LLPolyMesh);
+
+ if (!isLOD())
+ {
+ num_kb += mNumVertices *
+ ( sizeof(LLVector3) + // coords
+ sizeof(LLVector3) + // normals
+ sizeof(LLVector2) ); // texCoords
+ }
+
+ if (mHasDetailTexCoords && !isLOD())
+ {
+ num_kb += mNumVertices * sizeof(LLVector2); // detailTexCoords
+ }
+
+ if (mHasWeights && !isLOD())
+ {
+ num_kb += mNumVertices * sizeof(float); // weights
+ }
+
+ num_kb += mNumFaces * sizeof(LLPolyFace); // faces
+
+ num_kb /= 1024;
+ return num_kb;
}
//-----------------------------------------------------------------------------
@@ -218,19 +228,19 @@ U32 LLPolyMeshSharedData::getNumKB()
//-----------------------------------------------------------------------------
BOOL LLPolyMeshSharedData::allocateVertexData( U32 numVertices )
{
- U32 i;
- mBaseCoords = new LLVector3[ numVertices ];
- mBaseNormals = new LLVector3[ numVertices ];
- mBaseBinormals = new LLVector3[ numVertices ];
- mTexCoords = new LLVector2[ numVertices ];
- mDetailTexCoords = new LLVector2[ numVertices ];
- mWeights = new F32[ numVertices ];
- for (i = 0; i < numVertices; i++)
- {
- mWeights[i] = 0.f;
- }
- mNumVertices = numVertices;
- return TRUE;
+ U32 i;
+ mBaseCoords = new LLVector3[ numVertices ];
+ mBaseNormals = new LLVector3[ numVertices ];
+ mBaseBinormals = new LLVector3[ numVertices ];
+ mTexCoords = new LLVector2[ numVertices ];
+ mDetailTexCoords = new LLVector2[ numVertices ];
+ mWeights = new F32[ numVertices ];
+ for (i = 0; i < numVertices; i++)
+ {
+ mWeights[i] = 0.f;
+ }
+ mNumVertices = numVertices;
+ return TRUE;
}
//-----------------------------------------------------------------------------
@@ -238,10 +248,10 @@ BOOL LLPolyMeshSharedData::allocateVertexData( U32 numVertices )
//-----------------------------------------------------------------------------
BOOL LLPolyMeshSharedData::allocateFaceData( U32 numFaces )
{
- mFaces = new LLPolyFace[ numFaces ];
- mNumFaces = numFaces;
- mNumTriangleIndices = mNumFaces * 3;
- return TRUE;
+ mFaces = new LLPolyFace[ numFaces ];
+ mNumFaces = numFaces;
+ mNumTriangleIndices = mNumFaces * 3;
+ return TRUE;
}
//-----------------------------------------------------------------------------
@@ -249,9 +259,9 @@ BOOL LLPolyMeshSharedData::allocateFaceData( U32 numFaces )
//-----------------------------------------------------------------------------
BOOL LLPolyMeshSharedData::allocateJointNames( U32 numJointNames )
{
- mJointNames = new std::string[ numJointNames ];
- mNumJointNames = numJointNames;
- return TRUE;
+ mJointNames = new std::string[ numJointNames ];
+ mNumJointNames = numJointNames;
+ return TRUE;
}
//--------------------------------------------------------------------
@@ -259,393 +269,445 @@ BOOL LLPolyMeshSharedData::allocateJointNames( U32 numJointNames )
//--------------------------------------------------------------------
BOOL LLPolyMeshSharedData::loadMesh( const std::string& fileName )
{
- //-------------------------------------------------------------------------
- // Open the file
- //-------------------------------------------------------------------------
- if(fileName.empty())
- {
- llerrs << "Filename is Empty!" << llendl;
- return FALSE;
- }
- LLFILE* fp = LLFile::fopen(fileName, "rb"); /*Flawfinder: ignore*/
- if (!fp)
- {
- llerrs << "can't open: " << fileName << llendl;
- return FALSE;
- }
-
- //-------------------------------------------------------------------------
- // Read a chunk
- //-------------------------------------------------------------------------
- char header[128]; /*Flawfinder: ignore*/
- if (fread(header, sizeof(char), 128, fp) != 128)
- {
- llwarns << "Short read" << llendl;
- }
-
- //-------------------------------------------------------------------------
- // Check for proper binary header
- //-------------------------------------------------------------------------
- BOOL status = FALSE;
- if ( strncmp(header, HEADER_BINARY, strlen(HEADER_BINARY)) == 0 ) /*Flawfinder: ignore*/
- {
- lldebugs << "Loading " << fileName << llendl;
-
- //----------------------------------------------------------------
- // File Header (seek past it)
- //----------------------------------------------------------------
- fseek(fp, 24, SEEK_SET);
-
- //----------------------------------------------------------------
- // HasWeights
- //----------------------------------------------------------------
- U8 hasWeights;
- size_t numRead = fread(&hasWeights, sizeof(U8), 1, fp);
- if (numRead != 1)
- {
- llerrs << "can't read HasWeights flag from " << fileName << llendl;
- return FALSE;
- }
- if (!isLOD())
- {
- mHasWeights = (hasWeights==0) ? FALSE : TRUE;
- }
-
- //----------------------------------------------------------------
- // HasDetailTexCoords
- //----------------------------------------------------------------
- U8 hasDetailTexCoords;
- numRead = fread(&hasDetailTexCoords, sizeof(U8), 1, fp);
- if (numRead != 1)
- {
- llerrs << "can't read HasDetailTexCoords flag from " << fileName << llendl;
- return FALSE;
- }
-
- //----------------------------------------------------------------
- // Position
- //----------------------------------------------------------------
- LLVector3 position;
- numRead = fread(position.mV, sizeof(float), 3, fp);
- llendianswizzle(position.mV, sizeof(float), 3);
- if (numRead != 3)
- {
- llerrs << "can't read Position from " << fileName << llendl;
- return FALSE;
- }
- setPosition( position );
-
- //----------------------------------------------------------------
- // Rotation
- //----------------------------------------------------------------
- LLVector3 rotationAngles;
- numRead = fread(rotationAngles.mV, sizeof(float), 3, fp);
- llendianswizzle(rotationAngles.mV, sizeof(float), 3);
- if (numRead != 3)
- {
- llerrs << "can't read RotationAngles from " << fileName << llendl;
- return FALSE;
- }
-
- U8 rotationOrder;
- numRead = fread(&rotationOrder, sizeof(U8), 1, fp);
-
- if (numRead != 1)
- {
- llerrs << "can't read RotationOrder from " << fileName << llendl;
- return FALSE;
- }
-
- rotationOrder = 0;
-
- setRotation( mayaQ( rotationAngles.mV[0],
- rotationAngles.mV[1],
- rotationAngles.mV[2],
- (LLQuaternion::Order)rotationOrder ) );
-
- //----------------------------------------------------------------
- // Scale
- //----------------------------------------------------------------
- LLVector3 scale;
- numRead = fread(scale.mV, sizeof(float), 3, fp);
- llendianswizzle(scale.mV, sizeof(float), 3);
- if (numRead != 3)
- {
- llerrs << "can't read Scale from " << fileName << llendl;
- return FALSE;
- }
- setScale( scale );
-
- //-------------------------------------------------------------------------
- // Release any existing mesh geometry
- //-------------------------------------------------------------------------
- freeMeshData();
-
- U16 numVertices = 0;
-
- //----------------------------------------------------------------
- // NumVertices
- //----------------------------------------------------------------
- if (!isLOD())
- {
- numRead = fread(&numVertices, sizeof(U16), 1, fp);
- llendianswizzle(&numVertices, sizeof(U16), 1);
- if (numRead != 1)
- {
- llerrs << "can't read NumVertices from " << fileName << llendl;
- return FALSE;
- }
-
- allocateVertexData( numVertices );
-
- //----------------------------------------------------------------
- // Coords
- //----------------------------------------------------------------
- numRead = fread(mBaseCoords, 3*sizeof(float), numVertices, fp);
- llendianswizzle(mBaseCoords, sizeof(float), 3*numVertices);
- if (numRead != numVertices)
- {
- llerrs << "can't read Coordinates from " << fileName << llendl;
- return FALSE;
- }
-
- //----------------------------------------------------------------
- // Normals
- //----------------------------------------------------------------
- numRead = fread(mBaseNormals, 3*sizeof(float), numVertices, fp);
- llendianswizzle(mBaseNormals, sizeof(float), 3*numVertices);
- if (numRead != numVertices)
- {
- llerrs << " can't read Normals from " << fileName << llendl;
- return FALSE;
- }
-
- //----------------------------------------------------------------
- // Binormals
- //----------------------------------------------------------------
- numRead = fread(mBaseBinormals, 3*sizeof(float), numVertices, fp);
- llendianswizzle(mBaseBinormals, sizeof(float), 3*numVertices);
- if (numRead != numVertices)
- {
- llerrs << " can't read Binormals from " << fileName << llendl;
- return FALSE;
- }
-
-
- //----------------------------------------------------------------
- // TexCoords
- //----------------------------------------------------------------
- numRead = fread(mTexCoords, 2*sizeof(float), numVertices, fp);
- llendianswizzle(mTexCoords, sizeof(float), 2*numVertices);
- if (numRead != numVertices)
- {
- llerrs << "can't read TexCoords from " << fileName << llendl;
- return FALSE;
- }
-
- //----------------------------------------------------------------
- // DetailTexCoords
- //----------------------------------------------------------------
- if (mHasDetailTexCoords)
- {
- numRead = fread(mDetailTexCoords, 2*sizeof(float), numVertices, fp);
- llendianswizzle(mDetailTexCoords, sizeof(float), 2*numVertices);
- if (numRead != numVertices)
- {
- llerrs << "can't read DetailTexCoords from " << fileName << llendl;
- return FALSE;
- }
- }
-
- //----------------------------------------------------------------
- // Weights
- //----------------------------------------------------------------
- if (mHasWeights)
- {
- numRead = fread(mWeights, sizeof(float), numVertices, fp);
- llendianswizzle(mWeights, sizeof(float), numVertices);
- if (numRead != numVertices)
- {
- llerrs << "can't read Weights from " << fileName << llendl;
- return FALSE;
- }
- }
- }
-
- //----------------------------------------------------------------
- // NumFaces
- //----------------------------------------------------------------
- U16 numFaces;
- numRead = fread(&numFaces, sizeof(U16), 1, fp);
- llendianswizzle(&numFaces, sizeof(U16), 1);
- if (numRead != 1)
- {
- llerrs << "can't read NumFaces from " << fileName << llendl;
- return FALSE;
- }
- allocateFaceData( numFaces );
-
-
- //----------------------------------------------------------------
- // Faces
- //----------------------------------------------------------------
- U32 i;
- U32 numTris = 0;
- for (i = 0; i < numFaces; i++)
- {
- S16 face[3];
- numRead = fread(face, sizeof(U16), 3, fp);
- llendianswizzle(face, sizeof(U16), 3);
- if (numRead != 3)
- {
- llerrs << "can't read Face[" << i << "] from " << fileName << llendl;
- return FALSE;
- }
- if (mReferenceData)
- {
- llassert(face[0] < mReferenceData->mNumVertices);
- llassert(face[1] < mReferenceData->mNumVertices);
- llassert(face[2] < mReferenceData->mNumVertices);
- }
-
- if (isLOD())
- {
- // store largest index in case of LODs
- for (S32 j = 0; j < 3; j++)
- {
- if (face[j] > mNumVertices - 1)
- {
- mNumVertices = face[j] + 1;
- }
- }
- }
- mFaces[i][0] = face[0];
- mFaces[i][1] = face[1];
- mFaces[i][2] = face[2];
-
-// S32 j;
-// for(j = 0; j < 3; j++)
-// {
-// LLDynamicArray<S32> *face_list = mVertFaceMap.getIfThere(face[j]);
-// if (!face_list)
-// {
-// face_list = new LLDynamicArray<S32>;
-// mVertFaceMap.addData(face[j], face_list);
-// }
-// face_list->put(i);
-// }
-
- numTris++;
- }
-
- lldebugs << "verts: " << numVertices
- << ", faces: " << numFaces
- << ", tris: " << numTris
- << llendl;
-
- //----------------------------------------------------------------
- // NumSkinJoints
- //----------------------------------------------------------------
- if (!isLOD())
- {
- U16 numSkinJoints = 0;
- if ( mHasWeights )
- {
- numRead = fread(&numSkinJoints, sizeof(U16), 1, fp);
- llendianswizzle(&numSkinJoints, sizeof(U16), 1);
- if (numRead != 1)
- {
- llerrs << "can't read NumSkinJoints from " << fileName << llendl;
- return FALSE;
- }
- allocateJointNames( numSkinJoints );
- }
-
- //----------------------------------------------------------------
- // SkinJoints
- //----------------------------------------------------------------
- for (i=0; i < numSkinJoints; i++)
- {
- char jointName[64+1];
- numRead = fread(jointName, sizeof(jointName)-1, 1, fp);
- jointName[sizeof(jointName)-1] = '\0'; // ensure nul-termination
- if (numRead != 1)
- {
- llerrs << "can't read Skin[" << i << "].Name from " << fileName << llendl;
- return FALSE;
- }
-
- std::string *jn = &mJointNames[i];
- *jn = jointName;
- }
-
- //-------------------------------------------------------------------------
- // look for morph section
- //-------------------------------------------------------------------------
- char morphName[64+1];
- morphName[sizeof(morphName)-1] = '\0'; // ensure nul-termination
- while(fread(&morphName, sizeof(char), 64, fp) == 64)
- {
- if (!strcmp(morphName, "End Morphs"))
- {
- // we reached the end of the morphs
- break;
- }
- LLPolyMorphData* morph_data = new LLPolyMorphData(std::string(morphName));
-
- BOOL result = morph_data->loadBinary(fp, this);
-
- if (!result)
- {
- delete morph_data;
- continue;
- }
-
- mMorphData.insert(morph_data);
- }
-
- S32 numRemaps;
- if (fread(&numRemaps, sizeof(S32), 1, fp) == 1)
- {
- llendianswizzle(&numRemaps, sizeof(S32), 1);
- for (S32 i = 0; i < numRemaps; i++)
- {
- S32 remapSrc;
- S32 remapDst;
- if (fread(&remapSrc, sizeof(S32), 1, fp) != 1)
- {
- llerrs << "can't read source vertex in vertex remap data" << llendl;
- break;
- }
- if (fread(&remapDst, sizeof(S32), 1, fp) != 1)
- {
- llerrs << "can't read destination vertex in vertex remap data" << llendl;
- break;
- }
- llendianswizzle(&remapSrc, sizeof(S32), 1);
- llendianswizzle(&remapDst, sizeof(S32), 1);
-
- mSharedVerts[remapSrc] = remapDst;
- }
- }
- }
-
- status = TRUE;
- }
- else
- {
- llerrs << "invalid mesh file header: " << fileName << llendl;
- status = FALSE;
- }
-
- if (0 == mNumJointNames)
- {
- allocateJointNames(1);
- }
-
- fclose( fp );
-
- return status;
+ //-------------------------------------------------------------------------
+ // Open the file
+ //-------------------------------------------------------------------------
+ if(fileName.empty())
+ {
+ llerrs << "Filename is Empty!" << llendl;
+ return FALSE;
+ }
+ LLFILE* fp = LLFile::fopen(fileName, "rb"); /*Flawfinder: ignore*/
+ if (!fp)
+ {
+ llerrs << "can't open: " << fileName << llendl;
+ return FALSE;
+ }
+
+ //-------------------------------------------------------------------------
+ // Read a chunk
+ //-------------------------------------------------------------------------
+ char header[128]; /*Flawfinder: ignore*/
+ if (fread(header, sizeof(char), 128, fp) != 128)
+ {
+ llwarns << "Short read" << llendl;
+ }
+
+ //-------------------------------------------------------------------------
+ // Check for proper binary header
+ //-------------------------------------------------------------------------
+ BOOL status = FALSE;
+ if ( strncmp(header, HEADER_BINARY, strlen(HEADER_BINARY)) == 0 ) /*Flawfinder: ignore*/
+ {
+ lldebugs << "Loading " << fileName << llendl;
+
+ //----------------------------------------------------------------
+ // File Header (seek past it)
+ //----------------------------------------------------------------
+ fseek(fp, 24, SEEK_SET);
+
+ //----------------------------------------------------------------
+ // HasWeights
+ //----------------------------------------------------------------
+ U8 hasWeights;
+ size_t numRead = fread(&hasWeights, sizeof(U8), 1, fp);
+ if (numRead != 1)
+ {
+ llerrs << "can't read HasWeights flag from " << fileName << llendl;
+ return FALSE;
+ }
+ if (!isLOD())
+ {
+ mHasWeights = (hasWeights==0) ? FALSE : TRUE;
+ }
+
+ //----------------------------------------------------------------
+ // HasDetailTexCoords
+ //----------------------------------------------------------------
+ U8 hasDetailTexCoords;
+ numRead = fread(&hasDetailTexCoords, sizeof(U8), 1, fp);
+ if (numRead != 1)
+ {
+ llerrs << "can't read HasDetailTexCoords flag from " << fileName << llendl;
+ return FALSE;
+ }
+
+ //----------------------------------------------------------------
+ // Position
+ //----------------------------------------------------------------
+ LLVector3 position;
+ numRead = fread(position.mV, sizeof(float), 3, fp);
+ llendianswizzle(position.mV, sizeof(float), 3);
+ if (numRead != 3)
+ {
+ llerrs << "can't read Position from " << fileName << llendl;
+ return FALSE;
+ }
+ setPosition( position );
+
+ //----------------------------------------------------------------
+ // Rotation
+ //----------------------------------------------------------------
+ LLVector3 rotationAngles;
+ numRead = fread(rotationAngles.mV, sizeof(float), 3, fp);
+ llendianswizzle(rotationAngles.mV, sizeof(float), 3);
+ if (numRead != 3)
+ {
+ llerrs << "can't read RotationAngles from " << fileName << llendl;
+ return FALSE;
+ }
+
+ U8 rotationOrder;
+ numRead = fread(&rotationOrder, sizeof(U8), 1, fp);
+
+ if (numRead != 1)
+ {
+ llerrs << "can't read RotationOrder from " << fileName << llendl;
+ return FALSE;
+ }
+
+ rotationOrder = 0;
+
+ setRotation( mayaQ( rotationAngles.mV[0],
+ rotationAngles.mV[1],
+ rotationAngles.mV[2],
+ (LLQuaternion::Order)rotationOrder ) );
+
+ //----------------------------------------------------------------
+ // Scale
+ //----------------------------------------------------------------
+ LLVector3 scale;
+ numRead = fread(scale.mV, sizeof(float), 3, fp);
+ llendianswizzle(scale.mV, sizeof(float), 3);
+ if (numRead != 3)
+ {
+ llerrs << "can't read Scale from " << fileName << llendl;
+ return FALSE;
+ }
+ setScale( scale );
+
+ //-------------------------------------------------------------------------
+ // Release any existing mesh geometry
+ //-------------------------------------------------------------------------
+ freeMeshData();
+
+ U16 numVertices = 0;
+
+ //----------------------------------------------------------------
+ // NumVertices
+ //----------------------------------------------------------------
+ if (!isLOD())
+ {
+ numRead = fread(&numVertices, sizeof(U16), 1, fp);
+ llendianswizzle(&numVertices, sizeof(U16), 1);
+ if (numRead != 1)
+ {
+ llerrs << "can't read NumVertices from " << fileName << llendl;
+ return FALSE;
+ }
+
+ allocateVertexData( numVertices );
+
+ //----------------------------------------------------------------
+ // Coords
+ //----------------------------------------------------------------
+ numRead = fread(mBaseCoords, 3*sizeof(float), numVertices, fp);
+ llendianswizzle(mBaseCoords, sizeof(float), 3*numVertices);
+ if (numRead != numVertices)
+ {
+ llerrs << "can't read Coordinates from " << fileName << llendl;
+ return FALSE;
+ }
+
+ //----------------------------------------------------------------
+ // Normals
+ //----------------------------------------------------------------
+ numRead = fread(mBaseNormals, 3*sizeof(float), numVertices, fp);
+ llendianswizzle(mBaseNormals, sizeof(float), 3*numVertices);
+ if (numRead != numVertices)
+ {
+ llerrs << " can't read Normals from " << fileName << llendl;
+ return FALSE;
+ }
+
+ //----------------------------------------------------------------
+ // Binormals
+ //----------------------------------------------------------------
+ numRead = fread(mBaseBinormals, 3*sizeof(float), numVertices, fp);
+ llendianswizzle(mBaseBinormals, sizeof(float), 3*numVertices);
+ if (numRead != numVertices)
+ {
+ llerrs << " can't read Binormals from " << fileName << llendl;
+ return FALSE;
+ }
+
+
+ //----------------------------------------------------------------
+ // TexCoords
+ //----------------------------------------------------------------
+ numRead = fread(mTexCoords, 2*sizeof(float), numVertices, fp);
+ llendianswizzle(mTexCoords, sizeof(float), 2*numVertices);
+ if (numRead != numVertices)
+ {
+ llerrs << "can't read TexCoords from " << fileName << llendl;
+ return FALSE;
+ }
+
+ //----------------------------------------------------------------
+ // DetailTexCoords
+ //----------------------------------------------------------------
+ if (mHasDetailTexCoords)
+ {
+ numRead = fread(mDetailTexCoords, 2*sizeof(float), numVertices, fp);
+ llendianswizzle(mDetailTexCoords, sizeof(float), 2*numVertices);
+ if (numRead != numVertices)
+ {
+ llerrs << "can't read DetailTexCoords from " << fileName << llendl;
+ return FALSE;
+ }
+ }
+
+ //----------------------------------------------------------------
+ // Weights
+ //----------------------------------------------------------------
+ if (mHasWeights)
+ {
+ numRead = fread(mWeights, sizeof(float), numVertices, fp);
+ llendianswizzle(mWeights, sizeof(float), numVertices);
+ if (numRead != numVertices)
+ {
+ llerrs << "can't read Weights from " << fileName << llendl;
+ return FALSE;
+ }
+ }
+ }
+
+ //----------------------------------------------------------------
+ // NumFaces
+ //----------------------------------------------------------------
+ U16 numFaces;
+ numRead = fread(&numFaces, sizeof(U16), 1, fp);
+ llendianswizzle(&numFaces, sizeof(U16), 1);
+ if (numRead != 1)
+ {
+ llerrs << "can't read NumFaces from " << fileName << llendl;
+ return FALSE;
+ }
+ allocateFaceData( numFaces );
+
+
+ //----------------------------------------------------------------
+ // Faces
+ //----------------------------------------------------------------
+ U32 i;
+ U32 numTris = 0;
+ for (i = 0; i < numFaces; i++)
+ {
+ S16 face[3];
+ numRead = fread(face, sizeof(U16), 3, fp);
+ llendianswizzle(face, sizeof(U16), 3);
+ if (numRead != 3)
+ {
+ llerrs << "can't read Face[" << i << "] from " << fileName << llendl;
+ return FALSE;
+ }
+ if (mReferenceData)
+ {
+ llassert(face[0] < mReferenceData->mNumVertices);
+ llassert(face[1] < mReferenceData->mNumVertices);
+ llassert(face[2] < mReferenceData->mNumVertices);
+ }
+
+ if (isLOD())
+ {
+ // store largest index in case of LODs
+ for (S32 j = 0; j < 3; j++)
+ {
+ if (face[j] > mNumVertices - 1)
+ {
+ mNumVertices = face[j] + 1;
+ }
+ }
+ }
+ mFaces[i][0] = face[0];
+ mFaces[i][1] = face[1];
+ mFaces[i][2] = face[2];
+
+// S32 j;
+// for(j = 0; j < 3; j++)
+// {
+// LLDynamicArray<S32> *face_list = mVertFaceMap.getIfThere(face[j]);
+// if (!face_list)
+// {
+// face_list = new LLDynamicArray<S32>;
+// mVertFaceMap.addData(face[j], face_list);
+// }
+// face_list->put(i);
+// }
+
+ numTris++;
+ }
+
+ lldebugs << "verts: " << numVertices
+ << ", faces: " << numFaces
+ << ", tris: " << numTris
+ << llendl;
+
+ //----------------------------------------------------------------
+ // NumSkinJoints
+ //----------------------------------------------------------------
+ if (!isLOD())
+ {
+ U16 numSkinJoints = 0;
+ if ( mHasWeights )
+ {
+ numRead = fread(&numSkinJoints, sizeof(U16), 1, fp);
+ llendianswizzle(&numSkinJoints, sizeof(U16), 1);
+ if (numRead != 1)
+ {
+ llerrs << "can't read NumSkinJoints from " << fileName << llendl;
+ return FALSE;
+ }
+ allocateJointNames( numSkinJoints );
+ }
+
+ //----------------------------------------------------------------
+ // SkinJoints
+ //----------------------------------------------------------------
+ for (i=0; i < numSkinJoints; i++)
+ {
+ char jointName[64+1];
+ numRead = fread(jointName, sizeof(jointName)-1, 1, fp);
+ jointName[sizeof(jointName)-1] = '\0'; // ensure nul-termination
+ if (numRead != 1)
+ {
+ llerrs << "can't read Skin[" << i << "].Name from " << fileName << llendl;
+ return FALSE;
+ }
+
+ std::string *jn = &mJointNames[i];
+ *jn = jointName;
+ }
+
+ //-------------------------------------------------------------------------
+ // look for morph section
+ //-------------------------------------------------------------------------
+ char morphName[64+1];
+ morphName[sizeof(morphName)-1] = '\0'; // ensure nul-termination
+ while(fread(&morphName, sizeof(char), 64, fp) == 64)
+ {
+ if (!strcmp(morphName, "End Morphs"))
+ {
+ // we reached the end of the morphs
+ break;
+ }
+ LLPolyMorphData* morph_data = new LLPolyMorphData(std::string(morphName));
+
+ BOOL result = morph_data->loadBinary(fp, this);
+
+ if (!result)
+ {
+ delete morph_data;
+ continue;
+ }
+
+ mMorphData.insert(morph_data);
+
+ if (!strcmp(morphName, "Breast_Female_Cleavage"))
+ {
+ mMorphData.insert(clone_morph_param_cleavage(morph_data,
+ .75f,
+ "Breast_Physics_LeftRight_Driven"));
+ }
+
+ if (!strcmp(morphName, "Breast_Female_Cleavage"))
+ {
+ mMorphData.insert(clone_morph_param_duplicate(morph_data,
+ "Breast_Physics_InOut_Driven"));
+ }
+ if (!strcmp(morphName, "Breast_Gravity"))
+ {
+ mMorphData.insert(clone_morph_param_duplicate(morph_data,
+ "Breast_Physics_UpDown_Driven"));
+ }
+
+ if (!strcmp(morphName, "Big_Belly_Torso"))
+ {
+ mMorphData.insert(clone_morph_param_direction(morph_data,
+ LLVector3(0,0,0.05f),
+ "Belly_Physics_Torso_UpDown_Driven"));
+ }
+
+ if (!strcmp(morphName, "Big_Belly_Legs"))
+ {
+ mMorphData.insert(clone_morph_param_direction(morph_data,
+ LLVector3(0,0,0.05f),
+ "Belly_Physics_Legs_UpDown_Driven"));
+ }
+
+ if (!strcmp(morphName, "skirt_belly"))
+ {
+ mMorphData.insert(clone_morph_param_direction(morph_data,
+ LLVector3(0,0,0.05f),
+ "Belly_Physics_Skirt_UpDown_Driven"));
+ }
+
+ if (!strcmp(morphName, "Small_Butt"))
+ {
+ mMorphData.insert(clone_morph_param_direction(morph_data,
+ LLVector3(0,0,0.05f),
+ "Butt_Physics_UpDown_Driven"));
+ }
+ if (!strcmp(morphName, "Small_Butt"))
+ {
+ mMorphData.insert(clone_morph_param_direction(morph_data,
+ LLVector3(0,0.03f,0),
+ "Butt_Physics_LeftRight_Driven"));
+ }
+ }
+
+ S32 numRemaps;
+ if (fread(&numRemaps, sizeof(S32), 1, fp) == 1)
+ {
+ llendianswizzle(&numRemaps, sizeof(S32), 1);
+ for (S32 i = 0; i < numRemaps; i++)
+ {
+ S32 remapSrc;
+ S32 remapDst;
+ if (fread(&remapSrc, sizeof(S32), 1, fp) != 1)
+ {
+ llerrs << "can't read source vertex in vertex remap data" << llendl;
+ break;
+ }
+ if (fread(&remapDst, sizeof(S32), 1, fp) != 1)
+ {
+ llerrs << "can't read destination vertex in vertex remap data" << llendl;
+ break;
+ }
+ llendianswizzle(&remapSrc, sizeof(S32), 1);
+ llendianswizzle(&remapDst, sizeof(S32), 1);
+
+ mSharedVerts[remapSrc] = remapDst;
+ }
+ }
+ }
+
+ status = TRUE;
+ }
+ else
+ {
+ llerrs << "invalid mesh file header: " << fileName << llendl;
+ status = FALSE;
+ }
+
+ if (0 == mNumJointNames)
+ {
+ allocateJointNames(1);
+ }
+
+ fclose( fp );
+
+ return status;
}
//-----------------------------------------------------------------------------
@@ -653,11 +715,11 @@ BOOL LLPolyMeshSharedData::loadMesh( const std::string& fileName )
//-----------------------------------------------------------------------------
const S32 *LLPolyMeshSharedData::getSharedVert(S32 vert)
{
- if (mSharedVerts.count(vert) > 0)
- {
- return &mSharedVerts[vert];
- }
- return NULL;
+ if (mSharedVerts.count(vert) > 0)
+ {
+ return &mSharedVerts[vert];
+ }
+ return NULL;
}
//-----------------------------------------------------------------------------
@@ -665,17 +727,17 @@ const S32 *LLPolyMeshSharedData::getSharedVert(S32 vert)
//-----------------------------------------------------------------------------
const LLVector2 &LLPolyMeshSharedData::getUVs(U32 index)
{
- // TODO: convert all index variables to S32
- llassert((S32)index < mNumVertices);
+ // TODO: convert all index variables to S32
+ llassert((S32)index < mNumVertices);
- return mTexCoords[index];
+ return mTexCoords[index];
}
//-----------------------------------------------------------------------------
// LLPolyMesh()
//-----------------------------------------------------------------------------
LLPolyMesh::LLPolyMesh(LLPolyMeshSharedData *shared_data, LLPolyMesh *reference_mesh)
-{
+{
LLMemType mt(LLMemType::MTYPE_AVATAR_MESH);
llassert(shared_data);
@@ -703,29 +765,23 @@ LLPolyMesh::LLPolyMesh(LLPolyMeshSharedData *shared_data, LLPolyMesh *reference_
}
else
{
-#if 1 // Allocate memory without initializing every vector
+ // Allocate memory without initializing every vector
// NOTE: This makes asusmptions about the size of LLVector[234]
int nverts = mSharedData->mNumVertices;
- int nfloats = nverts * (3*5 + 2 + 4);
- mVertexData = new F32[nfloats];
+ int nfloats = nverts * (2*4 + 3*3 + 2 + 4);
+ //use 16 byte aligned vertex data to make LLPolyMesh SSE friendly
+ mVertexData = (F32*) ll_aligned_malloc_16(nfloats*4);
int offset = 0;
- mCoords = (LLVector3*)(mVertexData + offset); offset += 3*nverts;
- mNormals = (LLVector3*)(mVertexData + offset); offset += 3*nverts;
- mScaledNormals = (LLVector3*)(mVertexData + offset); offset += 3*nverts;
- mBinormals = (LLVector3*)(mVertexData + offset); offset += 3*nverts;
- mScaledBinormals = (LLVector3*)(mVertexData + offset); offset += 3*nverts;
- mTexCoords = (LLVector2*)(mVertexData + offset); offset += 2*nverts;
- mClothingWeights = (LLVector4*)(mVertexData + offset); offset += 4*nverts;
-#else
- mCoords = new LLVector3[mSharedData->mNumVertices];
- mNormals = new LLVector3[mSharedData->mNumVertices];
- mScaledNormals = new LLVector3[mSharedData->mNumVertices];
- mBinormals = new LLVector3[mSharedData->mNumVertices];
- mScaledBinormals = new LLVector3[mSharedData->mNumVertices];
- mTexCoords = new LLVector2[mSharedData->mNumVertices];
- mClothingWeights = new LLVector4[mSharedData->mNumVertices];
- memset(mClothingWeights, 0, sizeof(LLVector4) * mSharedData->mNumVertices);
-#endif
+ mCoords = (LLVector4*)(mVertexData + offset); offset += 4*nverts;
+ mNormals = (LLVector4*)(mVertexData + offset); offset += 4*nverts;
+ mClothingWeights = (LLVector4*)(mVertexData + offset); offset += 4*nverts;
+ mTexCoords = (LLVector2*)(mVertexData + offset); offset += 2*nverts;
+
+ // these members don't need to be 16-byte aligned, but the first one might be
+ // read during an aligned memcpy of mTexCoords
+ mScaledNormals = (LLVector3*)(mVertexData + offset); offset += 3*nverts;
+ mBinormals = (LLVector3*)(mVertexData + offset); offset += 3*nverts;
+ mScaledBinormals = (LLVector3*)(mVertexData + offset); offset += 3*nverts;
initializeForMorph();
}
}
@@ -736,23 +792,15 @@ LLPolyMesh::LLPolyMesh(LLPolyMeshSharedData *shared_data, LLPolyMesh *reference_
//-----------------------------------------------------------------------------
LLPolyMesh::~LLPolyMesh()
{
- S32 i;
- for (i = 0; i < mJointRenderData.count(); i++)
- {
- delete mJointRenderData[i];
- mJointRenderData[i] = NULL;
- }
-#if 0 // These are now allocated as one big uninitialized chunk
- delete [] mCoords;
- delete [] mNormals;
- delete [] mScaledNormals;
- delete [] mBinormals;
- delete [] mScaledBinormals;
- delete [] mClothingWeights;
- delete [] mTexCoords;
-#else
- delete [] mVertexData;
-#endif
+ S32 i;
+ for (i = 0; i < mJointRenderData.count(); i++)
+ {
+ delete mJointRenderData[i];
+ mJointRenderData[i] = NULL;
+ }
+
+ ll_aligned_free_16(mVertexData);
+
}
@@ -761,40 +809,40 @@ LLPolyMesh::~LLPolyMesh()
//-----------------------------------------------------------------------------
LLPolyMesh *LLPolyMesh::getMesh(const std::string &name, LLPolyMesh* reference_mesh)
{
- //-------------------------------------------------------------------------
- // search for an existing mesh by this name
- //-------------------------------------------------------------------------
- LLPolyMeshSharedData* meshSharedData = get_if_there(sGlobalSharedMeshList, name, (LLPolyMeshSharedData*)NULL);
- if (meshSharedData)
- {
-// llinfos << "Polymesh " << name << " found in global mesh table." << llendl;
- LLPolyMesh *poly_mesh = new LLPolyMesh(meshSharedData, reference_mesh);
- return poly_mesh;
- }
-
- //-------------------------------------------------------------------------
- // if not found, create a new one, add it to the list
- //-------------------------------------------------------------------------
- std::string full_path;
- full_path = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,name);
-
- LLPolyMeshSharedData *mesh_data = new LLPolyMeshSharedData();
- if (reference_mesh)
- {
- mesh_data->setupLOD(reference_mesh->getSharedData());
- }
- if ( ! mesh_data->loadMesh( full_path ) )
- {
- delete mesh_data;
- return NULL;
- }
-
- LLPolyMesh *poly_mesh = new LLPolyMesh(mesh_data, reference_mesh);
-
-// llinfos << "Polymesh " << name << " added to global mesh table." << llendl;
- sGlobalSharedMeshList[name] = poly_mesh->mSharedData;
-
- return poly_mesh;
+ //-------------------------------------------------------------------------
+ // search for an existing mesh by this name
+ //-------------------------------------------------------------------------
+ LLPolyMeshSharedData* meshSharedData = get_if_there(sGlobalSharedMeshList, name, (LLPolyMeshSharedData*)NULL);
+ if (meshSharedData)
+ {
+// llinfos << "Polymesh " << name << " found in global mesh table." << llendl;
+ LLPolyMesh *poly_mesh = new LLPolyMesh(meshSharedData, reference_mesh);
+ return poly_mesh;
+ }
+
+ //-------------------------------------------------------------------------
+ // if not found, create a new one, add it to the list
+ //-------------------------------------------------------------------------
+ std::string full_path;
+ full_path = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,name);
+
+ LLPolyMeshSharedData *mesh_data = new LLPolyMeshSharedData();
+ if (reference_mesh)
+ {
+ mesh_data->setupLOD(reference_mesh->getSharedData());
+ }
+ if ( ! mesh_data->loadMesh( full_path ) )
+ {
+ delete mesh_data;
+ return NULL;
+ }
+
+ LLPolyMesh *poly_mesh = new LLPolyMesh(mesh_data, reference_mesh);
+
+// llinfos << "Polymesh " << name << " added to global mesh table." << llendl;
+ sGlobalSharedMeshList[name] = poly_mesh->mSharedData;
+
+ return poly_mesh;
}
//-----------------------------------------------------------------------------
@@ -802,14 +850,14 @@ LLPolyMesh *LLPolyMesh::getMesh(const std::string &name, LLPolyMesh* reference_m
//-----------------------------------------------------------------------------
void LLPolyMesh::freeAllMeshes()
{
- // delete each item in the global lists
- for_each(sGlobalSharedMeshList.begin(), sGlobalSharedMeshList.end(), DeletePairedPointer());
- sGlobalSharedMeshList.clear();
+ // delete each item in the global lists
+ for_each(sGlobalSharedMeshList.begin(), sGlobalSharedMeshList.end(), DeletePairedPointer());
+ sGlobalSharedMeshList.clear();
}
LLPolyMeshSharedData *LLPolyMesh::getSharedData() const
{
- return mSharedData;
+ return mSharedData;
}
@@ -818,57 +866,57 @@ LLPolyMeshSharedData *LLPolyMesh::getSharedData() const
//--------------------------------------------------------------------
void LLPolyMesh::dumpDiagInfo()
{
- // keep track of totals
- U32 total_verts = 0;
- U32 total_faces = 0;
- U32 total_kb = 0;
-
- std::string buf;
-
- llinfos << "-----------------------------------------------------" << llendl;
- llinfos << " Global PolyMesh Table (DEBUG only)" << llendl;
- llinfos << " Verts Faces Mem(KB) Name" << llendl;
- llinfos << "-----------------------------------------------------" << llendl;
-
- // print each loaded mesh, and it's memory usage
- for(LLPolyMeshSharedDataTable::iterator iter = sGlobalSharedMeshList.begin();
- iter != sGlobalSharedMeshList.end(); ++iter)
- {
- const std::string& mesh_name = iter->first;
- LLPolyMeshSharedData* mesh = iter->second;
-
- S32 num_verts = mesh->mNumVertices;
- S32 num_faces = mesh->mNumFaces;
- U32 num_kb = mesh->getNumKB();
-
- buf = llformat("%8d %8d %8d %s", num_verts, num_faces, num_kb, mesh_name.c_str());
- llinfos << buf << llendl;
-
- total_verts += num_verts;
- total_faces += num_faces;
- total_kb += num_kb;
- }
-
- llinfos << "-----------------------------------------------------" << llendl;
- buf = llformat("%8d %8d %8d TOTAL", total_verts, total_faces, total_kb );
- llinfos << buf << llendl;
- llinfos << "-----------------------------------------------------" << llendl;
+ // keep track of totals
+ U32 total_verts = 0;
+ U32 total_faces = 0;
+ U32 total_kb = 0;
+
+ std::string buf;
+
+ llinfos << "-----------------------------------------------------" << llendl;
+ llinfos << " Global PolyMesh Table (DEBUG only)" << llendl;
+ llinfos << " Verts Faces Mem(KB) Name" << llendl;
+ llinfos << "-----------------------------------------------------" << llendl;
+
+ // print each loaded mesh, and it's memory usage
+ for(LLPolyMeshSharedDataTable::iterator iter = sGlobalSharedMeshList.begin();
+ iter != sGlobalSharedMeshList.end(); ++iter)
+ {
+ const std::string& mesh_name = iter->first;
+ LLPolyMeshSharedData* mesh = iter->second;
+
+ S32 num_verts = mesh->mNumVertices;
+ S32 num_faces = mesh->mNumFaces;
+ U32 num_kb = mesh->getNumKB();
+
+ buf = llformat("%8d %8d %8d %s", num_verts, num_faces, num_kb, mesh_name.c_str());
+ llinfos << buf << llendl;
+
+ total_verts += num_verts;
+ total_faces += num_faces;
+ total_kb += num_kb;
+ }
+
+ llinfos << "-----------------------------------------------------" << llendl;
+ buf = llformat("%8d %8d %8d TOTAL", total_verts, total_faces, total_kb );
+ llinfos << buf << llendl;
+ llinfos << "-----------------------------------------------------" << llendl;
}
//-----------------------------------------------------------------------------
// getWritableCoords()
//-----------------------------------------------------------------------------
-LLVector3 *LLPolyMesh::getWritableCoords()
+LLVector4 *LLPolyMesh::getWritableCoords()
{
- return mCoords;
+ return mCoords;
}
//-----------------------------------------------------------------------------
// getWritableNormals()
//-----------------------------------------------------------------------------
-LLVector3 *LLPolyMesh::getWritableNormals()
+LLVector4 *LLPolyMesh::getWritableNormals()
{
- return mNormals;
+ return mNormals;
}
//-----------------------------------------------------------------------------
@@ -876,24 +924,24 @@ LLVector3 *LLPolyMesh::getWritableNormals()
//-----------------------------------------------------------------------------
LLVector3 *LLPolyMesh::getWritableBinormals()
{
- return mBinormals;
+ return mBinormals;
}
//-----------------------------------------------------------------------------
// getWritableClothingWeights()
//-----------------------------------------------------------------------------
-LLVector4 *LLPolyMesh::getWritableClothingWeights()
+LLVector4 *LLPolyMesh::getWritableClothingWeights()
{
- return mClothingWeights;
+ return mClothingWeights;
}
//-----------------------------------------------------------------------------
// getWritableTexCoords()
//-----------------------------------------------------------------------------
-LLVector2 *LLPolyMesh::getWritableTexCoords()
+LLVector2 *LLPolyMesh::getWritableTexCoords()
{
- return mTexCoords;
+ return mTexCoords;
}
//-----------------------------------------------------------------------------
@@ -901,7 +949,7 @@ LLVector2 *LLPolyMesh::getWritableTexCoords()
//-----------------------------------------------------------------------------
LLVector3 *LLPolyMesh::getScaledNormals()
{
- return mScaledNormals;
+ return mScaledNormals;
}
//-----------------------------------------------------------------------------
@@ -909,7 +957,7 @@ LLVector3 *LLPolyMesh::getScaledNormals()
//-----------------------------------------------------------------------------
LLVector3 *LLPolyMesh::getScaledBinormals()
{
- return mScaledBinormals;
+ return mScaledBinormals;
}
@@ -918,11 +966,12 @@ LLVector3 *LLPolyMesh::getScaledBinormals()
//-----------------------------------------------------------------------------
void LLPolyMesh::initializeForMorph()
{
- if (!mSharedData)
- return;
+ for (U32 i = 0; i < mSharedData->mNumVertices; ++i)
+ {
+ mCoords[i] = LLVector4(mSharedData->mBaseCoords[i]);
+ mNormals[i] = LLVector4(mSharedData->mBaseNormals[i]);
+ }
- memcpy(mCoords, mSharedData->mBaseCoords, sizeof(LLVector3) * mSharedData->mNumVertices); /*Flawfinder: ignore*/
- memcpy(mNormals, mSharedData->mBaseNormals, sizeof(LLVector3) * mSharedData->mNumVertices); /*Flawfinder: ignore*/
memcpy(mScaledNormals, mSharedData->mBaseNormals, sizeof(LLVector3) * mSharedData->mNumVertices); /*Flawfinder: ignore*/
memcpy(mBinormals, mSharedData->mBaseBinormals, sizeof(LLVector3) * mSharedData->mNumVertices); /*Flawfinder: ignore*/
memcpy(mScaledBinormals, mSharedData->mBaseBinormals, sizeof(LLVector3) * mSharedData->mNumVertices); /*Flawfinder: ignore*/
@@ -933,51 +982,51 @@ void LLPolyMesh::initializeForMorph()
//-----------------------------------------------------------------------------
// getMorphData()
//-----------------------------------------------------------------------------
-LLPolyMorphData* LLPolyMesh::getMorphData(const std::string& morph_name)
+LLPolyMorphData* LLPolyMesh::getMorphData(const std::string& morph_name)
{
- if (!mSharedData)
- return NULL;
- for (LLPolyMeshSharedData::morphdata_list_t::iterator iter = mSharedData->mMorphData.begin();
- iter != mSharedData->mMorphData.end(); ++iter)
- {
- LLPolyMorphData *morph_data = *iter;
- if (morph_data->getName() == morph_name)
- {
- return morph_data;
- }
- }
- return NULL;
+ if (!mSharedData)
+ return NULL;
+ for (LLPolyMeshSharedData::morphdata_list_t::iterator iter = mSharedData->mMorphData.begin();
+ iter != mSharedData->mMorphData.end(); ++iter)
+ {
+ LLPolyMorphData *morph_data = *iter;
+ if (morph_data->getName() == morph_name)
+ {
+ return morph_data;
+ }
+ }
+ return NULL;
}
//-----------------------------------------------------------------------------
// removeMorphData()
//-----------------------------------------------------------------------------
// // erasing but not deleting seems bad, but fortunately we don't actually use this...
-// void LLPolyMesh::removeMorphData(LLPolyMorphData *morph_target)
+// void LLPolyMesh::removeMorphData(LLPolyMorphData *morph_target)
// {
-// if (!mSharedData)
-// return;
-// mSharedData->mMorphData.erase(morph_target);
+// if (!mSharedData)
+// return;
+// mSharedData->mMorphData.erase(morph_target);
// }
//-----------------------------------------------------------------------------
// deleteAllMorphData()
//-----------------------------------------------------------------------------
-// void LLPolyMesh::deleteAllMorphData()
+// void LLPolyMesh::deleteAllMorphData()
// {
-// if (!mSharedData)
-// return;
+// if (!mSharedData)
+// return;
-// for_each(mSharedData->mMorphData.begin(), mSharedData->mMorphData.end(), DeletePointer());
-// mSharedData->mMorphData.clear();
+// for_each(mSharedData->mMorphData.begin(), mSharedData->mMorphData.end(), DeletePointer());
+// mSharedData->mMorphData.clear();
// }
//-----------------------------------------------------------------------------
// getWritableWeights()
//-----------------------------------------------------------------------------
-F32* LLPolyMesh::getWritableWeights() const
+F32* LLPolyMesh::getWritableWeights() const
{
- return mSharedData->mWeights;
+ return mSharedData->mWeights;
}
//-----------------------------------------------------------------------------
@@ -989,58 +1038,58 @@ LLPolySkeletalDistortionInfo::LLPolySkeletalDistortionInfo()
BOOL LLPolySkeletalDistortionInfo::parseXml(LLXmlTreeNode* node)
{
- llassert( node->hasName( "param" ) && node->getChildByName( "param_skeleton" ) );
-
- if (!LLViewerVisualParamInfo::parseXml(node))
- return FALSE;
-
- LLXmlTreeNode* skeletalParam = node->getChildByName("param_skeleton");
-
- if (NULL == skeletalParam)
- {
- llwarns << "Failed to getChildByName(\"param_skeleton\")"
- << llendl;
- return FALSE;
- }
-
- for( LLXmlTreeNode* bone = skeletalParam->getFirstChild(); bone; bone = skeletalParam->getNextChild() )
- {
- if (bone->hasName("bone"))
- {
- std::string name;
- LLVector3 scale;
- LLVector3 pos;
- BOOL haspos = FALSE;
-
- static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
- if (!bone->getFastAttributeString(name_string, name))
- {
- llwarns << "No bone name specified for skeletal param." << llendl;
- continue;
- }
-
- static LLStdStringHandle scale_string = LLXmlTree::addAttributeString("scale");
- if (!bone->getFastAttributeVector3(scale_string, scale))
- {
- llwarns << "No scale specified for bone " << name << "." << llendl;
- continue;
- }
-
- // optional offset deformation (translation)
- static LLStdStringHandle offset_string = LLXmlTree::addAttributeString("offset");
- if (bone->getFastAttributeVector3(offset_string, pos))
- {
- haspos = TRUE;
- }
- mBoneInfoList.push_back(LLPolySkeletalBoneInfo(name, scale, pos, haspos));
- }
- else
- {
- llwarns << "Unrecognized element " << bone->getName() << " in skeletal distortion" << llendl;
- continue;
- }
- }
- return TRUE;
+ llassert( node->hasName( "param" ) && node->getChildByName( "param_skeleton" ) );
+
+ if (!LLViewerVisualParamInfo::parseXml(node))
+ return FALSE;
+
+ LLXmlTreeNode* skeletalParam = node->getChildByName("param_skeleton");
+
+ if (NULL == skeletalParam)
+ {
+ llwarns << "Failed to getChildByName(\"param_skeleton\")"
+ << llendl;
+ return FALSE;
+ }
+
+ for( LLXmlTreeNode* bone = skeletalParam->getFirstChild(); bone; bone = skeletalParam->getNextChild() )
+ {
+ if (bone->hasName("bone"))
+ {
+ std::string name;
+ LLVector3 scale;
+ LLVector3 pos;
+ BOOL haspos = FALSE;
+
+ static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
+ if (!bone->getFastAttributeString(name_string, name))
+ {
+ llwarns << "No bone name specified for skeletal param." << llendl;
+ continue;
+ }
+
+ static LLStdStringHandle scale_string = LLXmlTree::addAttributeString("scale");
+ if (!bone->getFastAttributeVector3(scale_string, scale))
+ {
+ llwarns << "No scale specified for bone " << name << "." << llendl;
+ continue;
+ }
+
+ // optional offset deformation (translation)
+ static LLStdStringHandle offset_string = LLXmlTree::addAttributeString("offset");
+ if (bone->getFastAttributeVector3(offset_string, pos))
+ {
+ haspos = TRUE;
+ }
+ mBoneInfoList.push_back(LLPolySkeletalBoneInfo(name, scale, pos, haspos));
+ }
+ else
+ {
+ llwarns << "Unrecognized element " << bone->getName() << " in skeletal distortion" << llendl;
+ continue;
+ }
+ }
+ return TRUE;
}
//-----------------------------------------------------------------------------
@@ -1048,8 +1097,8 @@ BOOL LLPolySkeletalDistortionInfo::parseXml(LLXmlTreeNode* node)
//-----------------------------------------------------------------------------
LLPolySkeletalDistortion::LLPolySkeletalDistortion(LLVOAvatar *avatarp)
{
- mAvatar = avatarp;
- mDefaultVec.setVec(0.001f, 0.001f, 0.001f);
+ mAvatar = avatarp;
+ mDefaultVec.setVec(0.001f, 0.001f, 0.001f);
}
//-----------------------------------------------------------------------------
@@ -1061,62 +1110,62 @@ LLPolySkeletalDistortion::~LLPolySkeletalDistortion()
BOOL LLPolySkeletalDistortion::setInfo(LLPolySkeletalDistortionInfo *info)
{
- llassert(mInfo == NULL);
- if (info->mID < 0)
- return FALSE;
- mInfo = info;
- mID = info->mID;
- setWeight(getDefaultWeight(), FALSE );
-
- LLPolySkeletalDistortionInfo::bone_info_list_t::iterator iter;
- for (iter = getInfo()->mBoneInfoList.begin(); iter != getInfo()->mBoneInfoList.end(); iter++)
- {
- LLPolySkeletalBoneInfo *bone_info = &(*iter);
- LLJoint* joint = mAvatar->getJoint(bone_info->mBoneName);
- if (!joint)
- {
- llwarns << "Joint " << bone_info->mBoneName << " not found." << llendl;
- continue;
- }
-
- if (mJointScales.find(joint) != mJointScales.end())
- {
- llwarns << "Scale deformation already supplied for joint " << joint->getName() << "." << llendl;
- }
-
- // store it
- mJointScales[joint] = bone_info->mScaleDeformation;
-
- // apply to children that need to inherit it
- for (LLJoint::child_list_t::iterator iter = joint->mChildren.begin();
- iter != joint->mChildren.end(); ++iter)
- {
- LLViewerJoint* child_joint = (LLViewerJoint*)(*iter);
- if (child_joint->inheritScale())
- {
- LLVector3 childDeformation = LLVector3(child_joint->getScale());
- childDeformation.scaleVec(bone_info->mScaleDeformation);
- mJointScales[child_joint] = childDeformation;
- }
- }
-
- if (bone_info->mHasPositionDeformation)
- {
- if (mJointOffsets.find(joint) != mJointOffsets.end())
- {
- llwarns << "Offset deformation already supplied for joint " << joint->getName() << "." << llendl;
- }
- mJointOffsets[joint] = bone_info->mPositionDeformation;
- }
- }
- return TRUE;
+ llassert(mInfo == NULL);
+ if (info->mID < 0)
+ return FALSE;
+ mInfo = info;
+ mID = info->mID;
+ setWeight(getDefaultWeight(), FALSE );
+
+ LLPolySkeletalDistortionInfo::bone_info_list_t::iterator iter;
+ for (iter = getInfo()->mBoneInfoList.begin(); iter != getInfo()->mBoneInfoList.end(); iter++)
+ {
+ LLPolySkeletalBoneInfo *bone_info = &(*iter);
+ LLJoint* joint = mAvatar->getJoint(bone_info->mBoneName);
+ if (!joint)
+ {
+ llwarns << "Joint " << bone_info->mBoneName << " not found." << llendl;
+ continue;
+ }
+
+ if (mJointScales.find(joint) != mJointScales.end())
+ {
+ llwarns << "Scale deformation already supplied for joint " << joint->getName() << "." << llendl;
+ }
+
+ // store it
+ mJointScales[joint] = bone_info->mScaleDeformation;
+
+ // apply to children that need to inherit it
+ for (LLJoint::child_list_t::iterator iter = joint->mChildren.begin();
+ iter != joint->mChildren.end(); ++iter)
+ {
+ LLViewerJoint* child_joint = (LLViewerJoint*)(*iter);
+ if (child_joint->inheritScale())
+ {
+ LLVector3 childDeformation = LLVector3(child_joint->getScale());
+ childDeformation.scaleVec(bone_info->mScaleDeformation);
+ mJointScales[child_joint] = childDeformation;
+ }
+ }
+
+ if (bone_info->mHasPositionDeformation)
+ {
+ if (mJointOffsets.find(joint) != mJointOffsets.end())
+ {
+ llwarns << "Offset deformation already supplied for joint " << joint->getName() << "." << llendl;
+ }
+ mJointOffsets[joint] = bone_info->mPositionDeformation;
+ }
+ }
+ return TRUE;
}
/*virtual*/ LLViewerVisualParam* LLPolySkeletalDistortion::cloneParam(LLWearable* wearable) const
{
- LLPolySkeletalDistortion *new_param = new LLPolySkeletalDistortion(mAvatar);
- *new_param = *this;
- return new_param;
+ LLPolySkeletalDistortion *new_param = new LLPolySkeletalDistortion(mAvatar);
+ *new_param = *this;
+ return new_param;
}
//-----------------------------------------------------------------------------
@@ -1124,38 +1173,89 @@ BOOL LLPolySkeletalDistortion::setInfo(LLPolySkeletalDistortionInfo *info)
//-----------------------------------------------------------------------------
void LLPolySkeletalDistortion::apply( ESex avatar_sex )
{
- F32 effective_weight = ( getSex() & avatar_sex ) ? mCurWeight : getDefaultWeight();
+ F32 effective_weight = ( getSex() & avatar_sex ) ? mCurWeight : getDefaultWeight();
+
+ LLJoint* joint;
+ joint_vec_map_t::iterator iter;
+
+ for (iter = mJointScales.begin();
+ iter != mJointScales.end();
+ iter++)
+ {
+ joint = iter->first;
+ LLVector3 newScale = joint->getScale();
+ LLVector3 scaleDelta = iter->second;
+ newScale = newScale + (effective_weight * scaleDelta) - (mLastWeight * scaleDelta);
+ joint->setScale(newScale);
+ }
+
+ for (iter = mJointOffsets.begin();
+ iter != mJointOffsets.end();
+ iter++)
+ {
+ joint = iter->first;
+ LLVector3 newPosition = joint->getPosition();
+ LLVector3 positionDelta = iter->second;
+ newPosition = newPosition + (effective_weight * positionDelta) - (mLastWeight * positionDelta);
+ joint->setPosition(newPosition);
+ }
+
+ if (mLastWeight != mCurWeight && !mIsAnimating)
+ {
+ mAvatar->setSkeletonSerialNum(mAvatar->getSkeletonSerialNum() + 1);
+ }
+ mLastWeight = mCurWeight;
+}
- LLJoint* joint;
- joint_vec_map_t::iterator iter;
- for (iter = mJointScales.begin();
- iter != mJointScales.end();
- iter++)
- {
- joint = iter->first;
- LLVector3 newScale = joint->getScale();
- LLVector3 scaleDelta = iter->second;
- newScale = newScale + (effective_weight * scaleDelta) - (mLastWeight * scaleDelta);
- joint->setScale(newScale);
- }
+LLPolyMorphData *clone_morph_param_duplicate(const LLPolyMorphData *src_data,
+ const std::string &name)
+{
+ LLPolyMorphData* cloned_morph_data = new LLPolyMorphData(*src_data);
+ cloned_morph_data->mName = name;
+ for (U32 v=0; v < cloned_morph_data->mNumIndices; v++)
+ {
+ cloned_morph_data->mCoords[v] = src_data->mCoords[v];
+ cloned_morph_data->mNormals[v] = src_data->mNormals[v];
+ cloned_morph_data->mBinormals[v] = src_data->mBinormals[v];
+ }
+ return cloned_morph_data;
+}
- for (iter = mJointOffsets.begin();
- iter != mJointOffsets.end();
- iter++)
- {
- joint = iter->first;
- LLVector3 newPosition = joint->getPosition();
- LLVector3 positionDelta = iter->second;
- newPosition = newPosition + (effective_weight * positionDelta) - (mLastWeight * positionDelta);
- joint->setPosition(newPosition);
- }
+LLPolyMorphData *clone_morph_param_direction(const LLPolyMorphData *src_data,
+ const LLVector3 &direction,
+ const std::string &name)
+{
+ LLPolyMorphData* cloned_morph_data = new LLPolyMorphData(*src_data);
+ cloned_morph_data->mName = name;
+ for (U32 v=0; v < cloned_morph_data->mNumIndices; v++)
+ {
+ cloned_morph_data->mCoords[v] = direction;
+ cloned_morph_data->mNormals[v] = LLVector3(0,0,0);
+ cloned_morph_data->mBinormals[v] = LLVector3(0,0,0);
+ }
+ return cloned_morph_data;
+}
- if (mLastWeight != mCurWeight && !mIsAnimating)
- {
- mAvatar->setSkeletonSerialNum(mAvatar->getSkeletonSerialNum() + 1);
- }
- mLastWeight = mCurWeight;
+LLPolyMorphData *clone_morph_param_cleavage(const LLPolyMorphData *src_data,
+ F32 scale,
+ const std::string &name)
+{
+ LLPolyMorphData* cloned_morph_data = new LLPolyMorphData(*src_data);
+ cloned_morph_data->mName = name;
+ for (U32 v=0; v < cloned_morph_data->mNumIndices; v++)
+ {
+ cloned_morph_data->mCoords[v] = src_data->mCoords[v]*scale;
+ cloned_morph_data->mNormals[v] = src_data->mNormals[v]*scale;
+ cloned_morph_data->mBinormals[v] = src_data->mBinormals[v]*scale;
+ if (cloned_morph_data->mCoords[v][1] < 0)
+ {
+ cloned_morph_data->mCoords[v][1] *= -1;
+ cloned_morph_data->mNormals[v][1] *= -1;
+ cloned_morph_data->mBinormals[v][1] *= -1;
+ }
+ }
+ return cloned_morph_data;
}
// End
diff --git a/indra/newview/llpolymesh.h b/indra/newview/llpolymesh.h
index 894cd307c4..ba2bf85570 100644
--- a/indra/newview/llpolymesh.h
+++ b/indra/newview/llpolymesh.h
@@ -217,15 +217,15 @@ public:
}
// Get coords
- const LLVector3 *getCoords() const{
+ const LLVector4 *getCoords() const{
return mCoords;
}
// non const version
- LLVector3 *getWritableCoords();
+ LLVector4 *getWritableCoords();
// Get normals
- const LLVector3 *getNormals() const{
+ const LLVector4 *getNormals() const{
return mNormals;
}
@@ -247,7 +247,7 @@ public:
}
// intermediate morphed normals and output normals
- LLVector3 *getWritableNormals();
+ LLVector4 *getWritableNormals();
LLVector3 *getScaledNormals();
LLVector3 *getWritableBinormals();
@@ -341,11 +341,11 @@ protected:
// Single array of floats for allocation / deletion
F32 *mVertexData;
// deformed vertices (resulting from application of morph targets)
- LLVector3 *mCoords;
+ LLVector4 *mCoords;
// deformed normals (resulting from application of morph targets)
LLVector3 *mScaledNormals;
// output normals (after normalization)
- LLVector3 *mNormals;
+ LLVector4 *mNormals;
// deformed binormals (resulting from application of morph targets)
LLVector3 *mScaledBinormals;
// output binormals (after normalization)
diff --git a/indra/newview/llpolymorph.cpp b/indra/newview/llpolymorph.cpp
index 0ffe1c635f..cefd7df3fe 100644
--- a/indra/newview/llpolymorph.cpp
+++ b/indra/newview/llpolymorph.cpp
@@ -59,6 +59,37 @@ LLPolyMorphData::LLPolyMorphData(const std::string& morph_name)
mMesh = NULL;
}
+LLPolyMorphData::LLPolyMorphData(const LLPolyMorphData &rhs) :
+ mName(rhs.mName),
+ mNumIndices(rhs.mNumIndices),
+ mTotalDistortion(rhs.mTotalDistortion),
+ mAvgDistortion(rhs.mAvgDistortion),
+ mMaxDistortion(rhs.mMaxDistortion),
+ mVertexIndices(NULL),
+ mCoords(NULL),
+ mNormals(NULL),
+ mBinormals(NULL),
+ mTexCoords(NULL)
+{
+ const S32 numVertices = mNumIndices;
+
+ mCoords = new LLVector3[numVertices];
+ mNormals = new LLVector3[numVertices];
+ mBinormals = new LLVector3[numVertices];
+ mTexCoords = new LLVector2[numVertices];
+ mVertexIndices = new U32[numVertices];
+
+ for (S32 v=0; v < numVertices; v++)
+ {
+ mCoords[v] = rhs.mCoords[v];
+ mNormals[v] = rhs.mNormals[v];
+ mBinormals[v] = rhs.mBinormals[v];
+ mTexCoords[v] = rhs.mTexCoords[v];
+ mVertexIndices[v] = rhs.mVertexIndices[v];
+ }
+}
+
+
//-----------------------------------------------------------------------------
// ~LLPolyMorphData()
//-----------------------------------------------------------------------------
@@ -287,10 +318,22 @@ BOOL LLPolyMorphTarget::setInfo(LLPolyMorphTargetInfo* info)
}
}
- mMorphData = mMesh->getMorphData(getInfo()->mMorphName);
+ std::string morph_param_name = getInfo()->mMorphName;
+
+ mMorphData = mMesh->getMorphData(morph_param_name);
+ if (!mMorphData)
+ {
+ const std::string driven_tag = "_Driven";
+ U32 pos = morph_param_name.find(driven_tag);
+ if (pos > 0)
+ {
+ morph_param_name = morph_param_name.substr(0,pos);
+ mMorphData = mMesh->getMorphData(morph_param_name);
+ }
+ }
if (!mMorphData)
{
- llwarns << "No morph target named " << getInfo()->mMorphName << " found in mesh." << llendl;
+ llwarns << "No morph target named " << morph_param_name << " found in mesh." << llendl;
return FALSE; // Continue, ignoring this tag
}
return TRUE;
@@ -447,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
@@ -455,10 +508,10 @@ void LLPolyMorphTarget::apply( ESex avatar_sex )
if (delta_weight != 0.f)
{
llassert(!mMesh->isLOD());
- LLVector3 *coords = mMesh->getWritableCoords();
+ LLVector4 *coords = mMesh->getWritableCoords();
LLVector3 *scaled_normals = mMesh->getScaledNormals();
- LLVector3 *normals = mMesh->getWritableNormals();
+ LLVector4 *normals = mMesh->getWritableNormals();
LLVector3 *scaled_binormals = mMesh->getScaledBinormals();
LLVector3 *binormals = mMesh->getWritableBinormals();
@@ -478,7 +531,8 @@ void LLPolyMorphTarget::apply( ESex avatar_sex )
maskWeight = maskWeightArray[vert_index_morph];
}
- coords[vert_index_mesh] += mMorphData->mCoords[vert_index_morph] * delta_weight * maskWeight;
+ coords[vert_index_mesh] += LLVector4(mMorphData->mCoords[vert_index_morph] * delta_weight * maskWeight);
+
if (getInfo()->mIsClothingMorph && clothing_weights)
{
LLVector3 clothing_offset = mMorphData->mCoords[vert_index_morph] * delta_weight * maskWeight;
@@ -493,7 +547,7 @@ void LLPolyMorphTarget::apply( ESex avatar_sex )
scaled_normals[vert_index_mesh] += mMorphData->mNormals[vert_index_morph] * delta_weight * maskWeight * NORMAL_SOFTEN_FACTOR;
LLVector3 normalized_normal = scaled_normals[vert_index_mesh];
normalized_normal.normVec();
- normals[vert_index_mesh] = normalized_normal;
+ normals[vert_index_mesh] = LLVector4(normalized_normal);
// calculate new binormals
scaled_binormals[vert_index_mesh] += mMorphData->mBinormals[vert_index_morph] * delta_weight * maskWeight * NORMAL_SOFTEN_FACTOR;
@@ -542,7 +596,7 @@ void LLPolyMorphTarget::applyMask(U8 *maskTextureData, S32 width, S32 height, S3
if (maskWeights)
{
- LLVector3 *coords = mMesh->getWritableCoords();
+ LLVector4 *coords = mMesh->getWritableCoords();
LLVector3 *scaled_normals = mMesh->getScaledNormals();
LLVector3 *scaled_binormals = mMesh->getScaledBinormals();
LLVector2 *tex_coords = mMesh->getWritableTexCoords();
@@ -553,7 +607,7 @@ void LLPolyMorphTarget::applyMask(U8 *maskTextureData, S32 width, S32 height, S3
S32 out_vert = mMorphData->mVertexIndices[vert];
// remove effect of existing masked morph
- coords[out_vert] -= mMorphData->mCoords[vert] * lastMaskWeight;
+ coords[out_vert] -= LLVector4(mMorphData->mCoords[vert]) * lastMaskWeight;
scaled_normals[out_vert] -= mMorphData->mNormals[vert] * lastMaskWeight * NORMAL_SOFTEN_FACTOR;
scaled_binormals[out_vert] -= mMorphData->mBinormals[vert] * lastMaskWeight * NORMAL_SOFTEN_FACTOR;
tex_coords[out_vert] -= mMorphData->mTexCoords[vert] * lastMaskWeight;
diff --git a/indra/newview/llpolymorph.h b/indra/newview/llpolymorph.h
index bc111882b7..8a024f2e9e 100644
--- a/indra/newview/llpolymorph.h
+++ b/indra/newview/llpolymorph.h
@@ -46,6 +46,7 @@ class LLPolyMorphData
public:
LLPolyMorphData(const std::string& morph_name);
~LLPolyMorphData();
+ LLPolyMorphData(const LLPolyMorphData &rhs);
BOOL loadBinary(LLFILE* fp, LLPolyMeshSharedData *mesh);
const std::string& getName() { return mName; }
diff --git a/indra/newview/llpopupview.cpp b/indra/newview/llpopupview.cpp
index 499b6a8f5f..9fbb67a63a 100644
--- a/indra/newview/llpopupview.cpp
+++ b/indra/newview/llpopupview.cpp
@@ -40,7 +40,8 @@ bool view_visible(LLView* viewp)
}
-LLPopupView::LLPopupView()
+LLPopupView::LLPopupView(const LLPopupView::Params& p)
+: LLPanel(p)
{
// register ourself as handler of UI popups
LLUI::setPopupFuncs(boost::bind(&LLPopupView::addPopup, this, _1), boost::bind(&LLPopupView::removePopup, this, _1), boost::bind(&LLPopupView::clearPopups, this));
@@ -137,64 +138,102 @@ BOOL LLPopupView::handleMouseEvent(boost::function<BOOL(LLView*, S32, S32)> func
BOOL LLPopupView::handleMouseDown(S32 x, S32 y, MASK mask)
{
- if (!handleMouseEvent(boost::bind(&LLMouseHandler::handleMouseDown, _1, _2, _3, mask), view_visible_and_enabled, x, y, true))
+ BOOL handled = handleMouseEvent(boost::bind(&LLMouseHandler::handleMouseDown, _1, _2, _3, mask), view_visible_and_enabled, x, y, true);
+ if (!handled)
{
- return FALSE;
+ handled = LLPanel::handleMouseDown(x, y, mask);
}
- return TRUE;
+ return handled;
}
BOOL LLPopupView::handleMouseUp(S32 x, S32 y, MASK mask)
{
- return handleMouseEvent(boost::bind(&LLMouseHandler::handleMouseUp, _1, _2, _3, mask), view_visible_and_enabled, x, y, false);
+ BOOL handled = handleMouseEvent(boost::bind(&LLMouseHandler::handleMouseUp, _1, _2, _3, mask), view_visible_and_enabled, x, y, false);
+ if (!handled)
+ {
+ handled = LLPanel::handleMouseUp(x, y, mask);
+ }
+ return handled;
}
BOOL LLPopupView::handleMiddleMouseDown(S32 x, S32 y, MASK mask)
{
- if (!handleMouseEvent(boost::bind(&LLMouseHandler::handleMiddleMouseDown, _1, _2, _3, mask), view_visible_and_enabled, x, y, true))
+ BOOL handled = handleMouseEvent(boost::bind(&LLMouseHandler::handleMiddleMouseDown, _1, _2, _3, mask), view_visible_and_enabled, x, y, true);
+ if (!handled)
{
- return FALSE;
+ handled = LLPanel::handleMiddleMouseDown(x, y, mask);
}
- return TRUE;
+ return handled;
}
BOOL LLPopupView::handleMiddleMouseUp(S32 x, S32 y, MASK mask)
{
- return handleMouseEvent(boost::bind(&LLMouseHandler::handleMiddleMouseUp, _1, _2, _3, mask), view_visible_and_enabled, x, y, false);
+ BOOL handled = handleMouseEvent(boost::bind(&LLMouseHandler::handleMiddleMouseUp, _1, _2, _3, mask), view_visible_and_enabled, x, y, false);
+ if (!handled)
+ {
+ handled = LLPanel::handleMiddleMouseUp(x, y, mask);
+ }
+ return handled;
}
BOOL LLPopupView::handleRightMouseDown(S32 x, S32 y, MASK mask)
{
- if (!handleMouseEvent(boost::bind(&LLMouseHandler::handleRightMouseDown, _1, _2, _3, mask), view_visible_and_enabled, x, y, true))
+ BOOL handled = handleMouseEvent(boost::bind(&LLMouseHandler::handleRightMouseDown, _1, _2, _3, mask), view_visible_and_enabled, x, y, true);
+ if (!handled)
{
- return FALSE;
+ handled = LLPanel::handleRightMouseDown(x, y, mask);
}
- return TRUE;
+ return handled;
}
BOOL LLPopupView::handleRightMouseUp(S32 x, S32 y, MASK mask)
{
- return handleMouseEvent(boost::bind(&LLMouseHandler::handleRightMouseUp, _1, _2, _3, mask), view_visible_and_enabled, x, y, false);
+ BOOL handled = handleMouseEvent(boost::bind(&LLMouseHandler::handleRightMouseUp, _1, _2, _3, mask), view_visible_and_enabled, x, y, false);
+ if (!handled)
+ {
+ handled = LLPanel::handleRightMouseUp(x, y, mask);
+ }
+ return handled;
}
BOOL LLPopupView::handleDoubleClick(S32 x, S32 y, MASK mask)
{
- return handleMouseEvent(boost::bind(&LLMouseHandler::handleDoubleClick, _1, _2, _3, mask), view_visible_and_enabled, x, y, false);
+ BOOL handled = handleMouseEvent(boost::bind(&LLMouseHandler::handleDoubleClick, _1, _2, _3, mask), view_visible_and_enabled, x, y, false);
+ if (!handled)
+ {
+ handled = LLPanel::handleDoubleClick(x, y, mask);
+ }
+ return handled;
}
BOOL LLPopupView::handleHover(S32 x, S32 y, MASK mask)
{
- return handleMouseEvent(boost::bind(&LLMouseHandler::handleHover, _1, _2, _3, mask), view_visible_and_enabled, x, y, false);
+ BOOL handled = handleMouseEvent(boost::bind(&LLMouseHandler::handleHover, _1, _2, _3, mask), view_visible_and_enabled, x, y, false);
+ if (!handled)
+ {
+ handled = LLPanel::handleHover(x, y, mask);
+ }
+ return handled;
}
BOOL LLPopupView::handleScrollWheel(S32 x, S32 y, S32 clicks)
{
- return handleMouseEvent(boost::bind(&LLMouseHandler::handleScrollWheel, _1, _2, _3, clicks), view_visible_and_enabled, x, y, false);
+ BOOL handled = handleMouseEvent(boost::bind(&LLMouseHandler::handleScrollWheel, _1, _2, _3, clicks), view_visible_and_enabled, x, y, false);
+ if (!handled)
+ {
+ handled = LLPanel::handleScrollWheel(x, y, clicks);
+ }
+ return handled;
}
BOOL LLPopupView::handleToolTip(S32 x, S32 y, MASK mask)
{
- return handleMouseEvent(boost::bind(&LLMouseHandler::handleToolTip, _1, _2, _3, mask), view_visible, x, y, false);
+ BOOL handled = handleMouseEvent(boost::bind(&LLMouseHandler::handleToolTip, _1, _2, _3, mask), view_visible, x, y, false);
+ if (!handled)
+ {
+ handled = LLPanel::handleToolTip(x, y, mask);
+ }
+ return handled;
}
void LLPopupView::addPopup(LLView* popup)
diff --git a/indra/newview/llpopupview.h b/indra/newview/llpopupview.h
index fec4afd79c..b378f61984 100644
--- a/indra/newview/llpopupview.h
+++ b/indra/newview/llpopupview.h
@@ -32,7 +32,7 @@
class LLPopupView : public LLPanel
{
public:
- LLPopupView();
+ LLPopupView(const Params& p = LLPanel::Params());
~LLPopupView();
/*virtual*/ void draw();
diff --git a/indra/newview/llpreview.cpp b/indra/newview/llpreview.cpp
index 69542764d2..a90f23d637 100644
--- a/indra/newview/llpreview.cpp
+++ b/indra/newview/llpreview.cpp
@@ -454,12 +454,13 @@ LLMultiPreview::LLMultiPreview()
{
// start with a rect in the top-left corner ; will get resized
LLRect rect;
- rect.setLeftTopAndSize(0, gViewerWindow->getWindowHeightScaled(), 200, 200);
+ rect.setLeftTopAndSize(0, gViewerWindow->getWindowHeightScaled(), 200, 400);
setRect(rect);
}
setTitle(LLTrans::getString("MultiPreviewTitle"));
buildTabContainer();
setCanResize(TRUE);
+ mAutoResize = FALSE;
}
void LLMultiPreview::onOpen(const LLSD& key)
diff --git a/indra/newview/llpreviewgesture.cpp b/indra/newview/llpreviewgesture.cpp
index 16284d1a7e..9f5c55bad1 100644
--- a/indra/newview/llpreviewgesture.cpp
+++ b/indra/newview/llpreviewgesture.cpp
@@ -34,6 +34,7 @@
#include "llassetuploadresponders.h"
#include "llcheckboxctrl.h"
#include "llcombobox.h"
+#include "lldatapacker.h"
#include "lldelayedgestureerror.h"
#include "llfloaterreg.h"
#include "llgesturemgr.h"
@@ -1597,7 +1598,7 @@ std::string LLPreviewGesture::getLabel(std::vector<std::string> labels)
if(v_labels[0]=="Chat")
{
- result=LLTrans::getString("Chat");
+ result=LLTrans::getString("Chat Message");
}
else if(v_labels[0]=="Sound")
{
diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp
index cf2ea38288..b19bf5d234 100644
--- a/indra/newview/llpreviewscript.cpp
+++ b/indra/newview/llpreviewscript.cpp
@@ -34,11 +34,13 @@
#include "llcheckboxctrl.h"
#include "llcombobox.h"
#include "lldir.h"
+#include "llexternaleditor.h"
#include "llfloaterreg.h"
#include "llinventorydefines.h"
#include "llinventorymodel.h"
#include "llkeyboard.h"
#include "lllineeditor.h"
+#include "lllivefile.h"
#include "llhelp.h"
#include "llnotificationsutil.h"
#include "llresmgr.h"
@@ -116,6 +118,50 @@ static bool have_script_upload_cap(LLUUID& object_id)
}
/// ---------------------------------------------------------------------------
+/// LLLiveLSLFile
+/// ---------------------------------------------------------------------------
+class LLLiveLSLFile : public LLLiveFile
+{
+public:
+ typedef boost::function<bool (const std::string& filename)> change_callback_t;
+
+ LLLiveLSLFile(std::string file_path, change_callback_t change_cb);
+ ~LLLiveLSLFile();
+
+ void ignoreNextUpdate() { mIgnoreNextUpdate = true; }
+
+protected:
+ /*virtual*/ bool loadFile();
+
+ change_callback_t mOnChangeCallback;
+ bool mIgnoreNextUpdate;
+};
+
+LLLiveLSLFile::LLLiveLSLFile(std::string file_path, change_callback_t change_cb)
+: mOnChangeCallback(change_cb)
+, mIgnoreNextUpdate(false)
+, LLLiveFile(file_path, 1.0)
+{
+ llassert(mOnChangeCallback);
+}
+
+LLLiveLSLFile::~LLLiveLSLFile()
+{
+ LLFile::remove(filename());
+}
+
+bool LLLiveLSLFile::loadFile()
+{
+ if (mIgnoreNextUpdate)
+ {
+ mIgnoreNextUpdate = false;
+ return true;
+ }
+
+ return mOnChangeCallback(filename());
+}
+
+/// ---------------------------------------------------------------------------
/// LLFloaterScriptSearch
/// ---------------------------------------------------------------------------
class LLFloaterScriptSearch : public LLFloater
@@ -277,6 +323,7 @@ struct LLSECKeywordCompare
};
LLScriptEdCore::LLScriptEdCore(
+ LLScriptEdContainer* container,
const std::string& sample,
const LLHandle<LLFloater>& floater_handle,
void (*load_callback)(void*),
@@ -296,12 +343,15 @@ LLScriptEdCore::LLScriptEdCore(
mLastHelpToken(NULL),
mLiveHelpHistorySize(0),
mEnableSave(FALSE),
+ mLiveFile(NULL),
+ mContainer(container),
mHasScriptData(FALSE)
{
setFollowsAll();
setBorderVisible(FALSE);
setXMLFilename("panel_script_ed.xml");
+ llassert_always(mContainer != NULL);
}
LLScriptEdCore::~LLScriptEdCore()
@@ -315,6 +365,8 @@ LLScriptEdCore::~LLScriptEdCore()
script_search->closeFloater();
delete script_search;
}
+
+ delete mLiveFile;
}
BOOL LLScriptEdCore::postBuild()
@@ -329,6 +381,7 @@ BOOL LLScriptEdCore::postBuild()
childSetCommitCallback("lsl errors", &LLScriptEdCore::onErrorList, this);
childSetAction("Save_btn", boost::bind(&LLScriptEdCore::doSave,this,FALSE));
+ childSetAction("Edit_btn", boost::bind(&LLScriptEdCore::openInExternalEditor, this));
initMenu();
@@ -461,6 +514,79 @@ void LLScriptEdCore::setScriptText(const std::string& text, BOOL is_valid)
}
}
+bool LLScriptEdCore::loadScriptText(const std::string& filename)
+{
+ if (filename.empty())
+ {
+ llwarns << "Empty file name" << llendl;
+ return false;
+ }
+
+ LLFILE* file = LLFile::fopen(filename, "rb"); /*Flawfinder: ignore*/
+ if (!file)
+ {
+ llwarns << "Error opening " << filename << llendl;
+ return false;
+ }
+
+ // read in the whole file
+ fseek(file, 0L, SEEK_END);
+ size_t file_length = (size_t) ftell(file);
+ fseek(file, 0L, SEEK_SET);
+ char* buffer = new char[file_length+1];
+ size_t nread = fread(buffer, 1, file_length, file);
+ if (nread < file_length)
+ {
+ llwarns << "Short read" << llendl;
+ }
+ buffer[nread] = '\0';
+ fclose(file);
+
+ mEditor->setText(LLStringExplicit(buffer));
+ delete[] buffer;
+
+ return true;
+}
+
+bool LLScriptEdCore::writeToFile(const std::string& filename)
+{
+ LLFILE* fp = LLFile::fopen(filename, "wb");
+ if (!fp)
+ {
+ llwarns << "Unable to write to " << filename << llendl;
+
+ LLSD row;
+ row["columns"][0]["value"] = "Error writing to local file. Is your hard drive full?";
+ row["columns"][0]["font"] = "SANSSERIF_SMALL";
+ mErrorList->addElement(row);
+ return false;
+ }
+
+ std::string utf8text = mEditor->getText();
+
+ // Special case for a completely empty script - stuff in one space so it can store properly. See SL-46889
+ if (utf8text.size() == 0)
+ {
+ utf8text = " ";
+ }
+
+ fputs(utf8text.c_str(), fp);
+ fclose(fp);
+ return true;
+}
+
+void LLScriptEdCore::sync()
+{
+ // Sync with external editor.
+ std::string tmp_file = mContainer->getTmpFileName();
+ llstat s;
+ if (LLFile::stat(tmp_file, &s) == 0) // file exists
+ {
+ if (mLiveFile) mLiveFile->ignoreNextUpdate();
+ writeToFile(tmp_file);
+ }
+}
+
bool LLScriptEdCore::hasChanged()
{
if (!mEditor) return false;
@@ -637,6 +763,12 @@ BOOL LLScriptEdCore::canClose()
}
}
+void LLScriptEdCore::setEnableEditing(bool enable)
+{
+ mEditor->setEnabled(enable);
+ getChildView("Edit_btn")->setEnabled(enable);
+}
+
bool LLScriptEdCore::handleSaveChangesDialog(const LLSD& notification, const LLSD& response )
{
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
@@ -809,6 +941,48 @@ void LLScriptEdCore::doSave( BOOL close_after_save )
}
}
+void LLScriptEdCore::openInExternalEditor()
+{
+ delete mLiveFile; // deletes file
+
+ // Save the script to a temporary file.
+ std::string filename = mContainer->getTmpFileName();
+ writeToFile(filename);
+
+ // Start watching file changes.
+ mLiveFile = new LLLiveLSLFile(filename, boost::bind(&LLScriptEdContainer::onExternalChange, mContainer, _1));
+ mLiveFile->addToEventTimer();
+
+ // Open it in external editor.
+ {
+ LLExternalEditor ed;
+ LLExternalEditor::EErrorCode status;
+ std::string msg;
+
+ status = ed.setCommand("LL_SCRIPT_EDITOR");
+ if (status != LLExternalEditor::EC_SUCCESS)
+ {
+ if (status == LLExternalEditor::EC_NOT_SPECIFIED) // Use custom message for this error.
+ {
+ msg = getString("external_editor_not_set");
+ }
+ else
+ {
+ msg = LLExternalEditor::getErrorMessage(status);
+ }
+
+ LLNotificationsUtil::add("GenericAlert", LLSD().with("MESSAGE", msg));
+ return;
+ }
+
+ status = ed.run(filename);
+ if (status != LLExternalEditor::EC_SUCCESS)
+ {
+ msg = LLExternalEditor::getErrorMessage(status);
+ LLNotificationsUtil::add("GenericAlert", LLSD().with("MESSAGE", msg));
+ }
+ }
+}
void LLScriptEdCore::onBtnUndoChanges()
{
@@ -923,6 +1097,43 @@ BOOL LLScriptEdCore::handleKeyHere(KEY key, MASK mask)
}
/// ---------------------------------------------------------------------------
+/// LLScriptEdContainer
+/// ---------------------------------------------------------------------------
+
+LLScriptEdContainer::LLScriptEdContainer(const LLSD& key)
+: LLPreview(key)
+, mScriptEd(NULL)
+{
+}
+
+std::string LLScriptEdContainer::getTmpFileName()
+{
+ // Take script inventory item id (within the object inventory)
+ // to consideration so that it's possible to edit multiple scripts
+ // in the same object inventory simultaneously (STORM-781).
+ std::string script_id = mObjectUUID.asString() + "_" + mItemUUID.asString();
+
+ // Use MD5 sum to make the file name shorter and not exceed maximum path length.
+ char script_id_hash_str[33]; /* Flawfinder: ignore */
+ LLMD5 script_id_hash((const U8 *)script_id.c_str());
+ script_id_hash.hex_digest(script_id_hash_str);
+
+ return std::string(LLFile::tmpdir()) + "sl_script_" + script_id_hash_str + ".lsl";
+}
+
+bool LLScriptEdContainer::onExternalChange(const std::string& filename)
+{
+ if (!mScriptEd->loadScriptText(filename))
+ {
+ return false;
+ }
+
+ // Disable sync to avoid recursive load->save->load calls.
+ saveIfNeeded(false);
+ return true;
+}
+
+/// ---------------------------------------------------------------------------
/// LLPreviewLSL
/// ---------------------------------------------------------------------------
@@ -945,6 +1156,7 @@ void* LLPreviewLSL::createScriptEdPanel(void* userdata)
LLPreviewLSL *self = (LLPreviewLSL*)userdata;
self->mScriptEd = new LLScriptEdCore(
+ self,
HELLO_LSL,
self->getHandle(),
LLPreviewLSL::onLoad,
@@ -958,7 +1170,7 @@ void* LLPreviewLSL::createScriptEdPanel(void* userdata)
LLPreviewLSL::LLPreviewLSL(const LLSD& key )
- : LLPreview( key ),
+: LLScriptEdContainer(key),
mPendingUploads(0)
{
mFactoryMap["script panel"] = LLCallbackMap(LLPreviewLSL::createScriptEdPanel, this);
@@ -1049,7 +1261,6 @@ void LLPreviewLSL::loadAsset()
{
mScriptEd->setScriptText(mScriptEd->getString("can_not_view"), FALSE);
mScriptEd->mEditor->makePristine();
- mScriptEd->mEditor->setEnabled(FALSE);
mScriptEd->mFunctions->setEnabled(FALSE);
mAssetStatus = PREVIEW_ASSET_LOADED;
}
@@ -1059,6 +1270,7 @@ void LLPreviewLSL::loadAsset()
else
{
mScriptEd->setScriptText(std::string(HELLO_LSL), TRUE);
+ mScriptEd->setEnableEditing(TRUE);
mAssetStatus = PREVIEW_ASSET_LOADED;
}
}
@@ -1105,7 +1317,7 @@ void LLPreviewLSL::onSave(void* userdata, BOOL close_after_save)
// Save needs to compile the text in the buffer. If the compile
// succeeds, then save both assets out to the database. If the compile
// fails, go ahead and save the text anyway.
-void LLPreviewLSL::saveIfNeeded()
+void LLPreviewLSL::saveIfNeeded(bool sync /*= true*/)
{
// llinfos << "LLPreviewLSL::saveIfNeeded()" << llendl;
if(!mScriptEd->hasChanged())
@@ -1124,23 +1336,13 @@ void LLPreviewLSL::saveIfNeeded()
std::string filepath = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,asset_id.asString());
std::string filename = filepath + ".lsl";
- LLFILE* fp = LLFile::fopen(filename, "wb");
- if(!fp)
- {
- llwarns << "Unable to write to " << filename << llendl;
+ mScriptEd->writeToFile(filename);
- LLSD row;
- row["columns"][0]["value"] = "Error writing to local file. Is your hard drive full?";
- row["columns"][0]["font"] = "SANSSERIF_SMALL";
- mScriptEd->mErrorList->addElement(row);
- return;
+ if (sync)
+ {
+ mScriptEd->sync();
}
- std::string utf8text = mScriptEd->mEditor->getText();
- fputs(utf8text.c_str(), fp);
- fclose(fp);
- fp = NULL;
-
const LLInventoryItem *inv_item = getItem();
// save it out to asset server
std::string url = gAgent.getRegion()->getCapability("UpdateScriptAgent");
@@ -1372,7 +1574,7 @@ void LLPreviewLSL::onLoadComplete( LLVFS *vfs, const LLUUID& asset_uuid, LLAsset
{
is_modifiable = TRUE;
}
- preview->mScriptEd->mEditor->setEnabled(is_modifiable);
+ preview->mScriptEd->setEnableEditing(is_modifiable);
preview->mAssetStatus = PREVIEW_ASSET_LOADED;
}
else
@@ -1413,6 +1615,7 @@ void* LLLiveLSLEditor::createScriptEdPanel(void* userdata)
LLLiveLSLEditor *self = (LLLiveLSLEditor*)userdata;
self->mScriptEd = new LLScriptEdCore(
+ self,
HELLO_LSL,
self->getHandle(),
&LLLiveLSLEditor::onLoad,
@@ -1426,8 +1629,7 @@ void* LLLiveLSLEditor::createScriptEdPanel(void* userdata)
LLLiveLSLEditor::LLLiveLSLEditor(const LLSD& key) :
- LLPreview(key),
- mScriptEd(NULL),
+ LLScriptEdContainer(key),
mAskedForRunningInfo(FALSE),
mHaveRunningInfo(FALSE),
mCloseAfterSave(FALSE),
@@ -1456,10 +1658,6 @@ BOOL LLLiveLSLEditor::postBuild()
return LLPreview::postBuild();
}
-LLLiveLSLEditor::~LLLiveLSLEditor()
-{
-}
-
// virtual
void LLLiveLSLEditor::callbackLSLCompileSucceeded(const LLUUID& task_id,
const LLUUID& item_id,
@@ -1516,7 +1714,6 @@ void LLLiveLSLEditor::loadAsset()
mItem = new LLViewerInventoryItem(item);
mScriptEd->setScriptText(getString("not_allowed"), FALSE);
mScriptEd->mEditor->makePristine();
- mScriptEd->mEditor->setEnabled(FALSE);
mScriptEd->enableSave(FALSE);
mAssetStatus = PREVIEW_ASSET_LOADED;
}
@@ -1554,10 +1751,6 @@ void LLLiveLSLEditor::loadAsset()
mIsModifiable = item && gAgent.allowOperation(PERM_MODIFY,
item->getPermissions(),
GP_OBJECT_MANIPULATE);
- if(!mIsModifiable)
- {
- mScriptEd->mEditor->setEnabled(FALSE);
- }
// This is commented out, because we don't completely
// handle script exports yet.
@@ -1613,6 +1806,7 @@ void LLLiveLSLEditor::onLoadComplete(LLVFS *vfs, const LLUUID& asset_id,
if( LL_ERR_NOERR == status )
{
instance->loadScriptText(vfs, asset_id, type);
+ instance->mScriptEd->setEnableEditing(TRUE);
instance->mAssetStatus = PREVIEW_ASSET_LOADED;
}
else
@@ -1639,39 +1833,6 @@ void LLLiveLSLEditor::onLoadComplete(LLVFS *vfs, const LLUUID& asset_id,
delete xored_id;
}
-// unused
-// void LLLiveLSLEditor::loadScriptText(const std::string& filename)
-// {
-// if(!filename)
-// {
-// llerrs << "Filename is Empty!" << llendl;
-// return;
-// }
-// LLFILE* file = LLFile::fopen(filename, "rb"); /*Flawfinder: ignore*/
-// if(file)
-// {
-// // read in the whole file
-// fseek(file, 0L, SEEK_END);
-// long file_length = ftell(file);
-// fseek(file, 0L, SEEK_SET);
-// char* buffer = new char[file_length+1];
-// size_t nread = fread(buffer, 1, file_length, file);
-// if (nread < (size_t) file_length)
-// {
-// llwarns << "Short read" << llendl;
-// }
-// buffer[nread] = '\0';
-// fclose(file);
-// mScriptEd->mEditor->setText(LLStringExplicit(buffer));
-// mScriptEd->mEditor->makePristine();
-// delete[] buffer;
-// }
-// else
-// {
-// llwarns << "Error opening " << filename << llendl;
-// }
-// }
-
void LLLiveLSLEditor::loadScriptText(LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType type)
{
LLVFile file(vfs, uuid, type);
@@ -1825,9 +1986,9 @@ LLLiveLSLSaveData::LLLiveLSLSaveData(const LLUUID& id,
mItem = new LLViewerInventoryItem(item);
}
-void LLLiveLSLEditor::saveIfNeeded()
+// virtual
+void LLLiveLSLEditor::saveIfNeeded(bool sync /*= true*/)
{
- llinfos << "LLLiveLSLEditor::saveIfNeeded()" << llendl;
LLViewerObject* object = gObjectList.findObject(mObjectUUID);
if(!object)
{
@@ -1877,29 +2038,12 @@ void LLLiveLSLEditor::saveIfNeeded()
mItem->setAssetUUID(asset_id);
mItem->setTransactionID(tid);
- // write out the data, and store it in the asset database
- LLFILE* fp = LLFile::fopen(filename, "wb");
- if(!fp)
- {
- llwarns << "Unable to write to " << filename << llendl;
+ mScriptEd->writeToFile(filename);
- LLSD row;
- row["columns"][0]["value"] = "Error writing to local file. Is your hard drive full?";
- row["columns"][0]["font"] = "SANSSERIF_SMALL";
- mScriptEd->mErrorList->addElement(row);
- return;
- }
- std::string utf8text = mScriptEd->mEditor->getText();
-
- // Special case for a completely empty script - stuff in one space so it can store properly. See SL-46889
- if ( utf8text.size() == 0 )
+ if (sync)
{
- utf8text = " ";
+ mScriptEd->sync();
}
-
- fputs(utf8text.c_str(), fp);
- fclose(fp);
- fp = NULL;
// save it out to asset server
std::string url = object->getRegion()->getCapability("UpdateScriptTask");
@@ -2138,6 +2282,7 @@ void LLLiveLSLEditor::onSave(void* userdata, BOOL close_after_save)
self->saveIfNeeded();
}
+
// static
void LLLiveLSLEditor::processScriptRunningReply(LLMessageSystem* msg, void**)
{
diff --git a/indra/newview/llpreviewscript.h b/indra/newview/llpreviewscript.h
index f4b31e5962..f86be615c4 100644
--- a/indra/newview/llpreviewscript.h
+++ b/indra/newview/llpreviewscript.h
@@ -35,6 +35,7 @@
#include "lliconctrl.h"
#include "llframetimer.h"
+class LLLiveLSLFile;
class LLMessageSystem;
class LLTextEditor;
class LLButton;
@@ -47,6 +48,7 @@ class LLFloaterScriptSearch;
class LLKeywordToken;
class LLVFS;
class LLViewerInventoryItem;
+class LLScriptEdContainer;
// Inner, implementation class. LLPreviewScript and LLLiveLSLEditor each own one of these.
class LLScriptEdCore : public LLPanel
@@ -55,9 +57,12 @@ class LLScriptEdCore : public LLPanel
friend class LLPreviewLSL;
friend class LLLiveLSLEditor;
friend class LLFloaterScriptSearch;
+ friend class LLScriptEdContainer;
-public:
+protected:
+ // Supposed to be invoked only by the container.
LLScriptEdCore(
+ LLScriptEdContainer* container,
const std::string& sample,
const LLHandle<LLFloater>& floater_handle,
void (*load_callback)(void* userdata),
@@ -65,6 +70,7 @@ public:
void (*search_replace_callback)(void* userdata),
void* userdata,
S32 bottom_pad = 0); // pad below bottom row of buttons
+public:
~LLScriptEdCore();
void initMenu();
@@ -72,14 +78,20 @@ public:
virtual void draw();
/*virtual*/ BOOL postBuild();
BOOL canClose();
+ void setEnableEditing(bool enable);
void setScriptText(const std::string& text, BOOL is_valid);
+ bool loadScriptText(const std::string& filename);
+ bool writeToFile(const std::string& filename);
+ void sync();
void doSave( BOOL close_after_save );
bool handleSaveChangesDialog(const LLSD& notification, const LLSD& response);
bool handleReloadFromServerDialog(const LLSD& notification, const LLSD& response);
+ void openInExternalEditor();
+
static void onCheckLock(LLUICtrl*, void*);
static void onHelpComboCommit(LLUICtrl* ctrl, void* userdata);
static void onClickBack(void* userdata);
@@ -127,11 +139,28 @@ private:
S32 mLiveHelpHistorySize;
BOOL mEnableSave;
BOOL mHasScriptData;
+ LLLiveLSLFile* mLiveFile;
+
+ LLScriptEdContainer* mContainer; // parent view
};
+class LLScriptEdContainer : public LLPreview
+{
+ friend class LLScriptEdCore;
+
+public:
+ LLScriptEdContainer(const LLSD& key);
+
+protected:
+ std::string getTmpFileName();
+ bool onExternalChange(const std::string& filename);
+ virtual void saveIfNeeded(bool sync = true) = 0;
+
+ LLScriptEdCore* mScriptEd;
+};
// Used to view and edit a LSL from your inventory.
-class LLPreviewLSL : public LLPreview
+class LLPreviewLSL : public LLScriptEdContainer
{
public:
LLPreviewLSL(const LLSD& key );
@@ -145,7 +174,7 @@ protected:
void closeIfNeeded();
virtual void loadAsset();
- void saveIfNeeded();
+ /*virtual*/ void saveIfNeeded(bool sync = true);
void uploadAssetViaCaps(const std::string& url,
const std::string& filename,
const LLUUID& item_id);
@@ -169,7 +198,6 @@ protected:
protected:
- LLScriptEdCore* mScriptEd;
// Can safely close only after both text and bytecode are uploaded
S32 mPendingUploads;
@@ -177,11 +205,11 @@ protected:
// Used to view and edit an LSL that is attached to an object.
-class LLLiveLSLEditor : public LLPreview
+class LLLiveLSLEditor : public LLScriptEdContainer
{
+ friend class LLLiveLSLFile;
public:
LLLiveLSLEditor(const LLSD& key);
- ~LLLiveLSLEditor();
static void processScriptRunningReply(LLMessageSystem* msg, void**);
@@ -202,7 +230,7 @@ private:
virtual void loadAsset();
void loadAsset(BOOL is_new);
- void saveIfNeeded();
+ /*virtual*/ void saveIfNeeded(bool sync = true);
void uploadAssetViaCaps(const std::string& url,
const std::string& filename,
const LLUUID& task_id,
@@ -227,7 +255,6 @@ private:
static void onRunningCheckboxClicked(LLUICtrl*, void* userdata);
static void onReset(void* userdata);
-// void loadScriptText(const std::string& filename); // unused
void loadScriptText(LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType type);
static void onErrorList(LLUICtrl*, void* user_data);
@@ -238,7 +265,6 @@ private:
private:
bool mIsNew;
- LLScriptEdCore* mScriptEd;
//LLUUID mTransmitID;
LLCheckBoxCtrl* mRunningCheckbox;
BOOL mAskedForRunningInfo;
diff --git a/indra/newview/llpreviewtexture.cpp b/indra/newview/llpreviewtexture.cpp
index fd6b326ef1..18d6731fcb 100644
--- a/indra/newview/llpreviewtexture.cpp
+++ b/indra/newview/llpreviewtexture.cpp
@@ -143,10 +143,7 @@ void LLPreviewTexture::onSaveAsBtn(void* data)
void LLPreviewTexture::draw()
{
- if (mUpdateDimensions)
- {
- updateDimensions();
- }
+ updateDimensions();
LLPreview::draw();
@@ -273,6 +270,8 @@ void LLPreviewTexture::saveAs()
mSaveFileName = file_picker.getFirstFile();
mLoadingFullImage = TRUE;
getWindow()->incBusyCount();
+
+ mImage->forceToSaveRawImage(0) ;//re-fetch the raw image if the old one is removed.
mImage->setLoadedCallback( LLPreviewTexture::onFileLoadedForSave,
0, TRUE, FALSE, new LLUUID( mItemUUID ), &mCallbackTextureList );
}
@@ -318,7 +317,7 @@ void LLPreviewTexture::reshape(S32 width, S32 height, BOOL called_from_parent)
}
}
- mClientRect.setLeftTopAndSize(client_rect.getCenterX() - (client_width / 2), client_rect.getCenterY() + (client_height / 2), client_width, client_height);
+ mClientRect.setLeftTopAndSize(client_rect.getCenterX() - (client_width / 2), client_rect.getCenterY() + (client_height / 2), client_width, client_height);
}
@@ -394,96 +393,32 @@ void LLPreviewTexture::onFileLoadedForSave(BOOL success,
void LLPreviewTexture::updateDimensions()
{
if (!mImage)
+ {
return;
-
- if(mImage->getFullWidth() == 0 || mImage->getFullHeight() == 0)
+ }
+ if ((mImage->getFullWidth() * mImage->getFullHeight()) == 0)
{
return;
}
-
- mUpdateDimensions = FALSE;
-
- getChild<LLUICtrl>("dimensions")->setTextArg("[WIDTH]", llformat("%d", mImage->getFullWidth()));
+ // Update the width/height display every time
+ getChild<LLUICtrl>("dimensions")->setTextArg("[WIDTH]", llformat("%d", mImage->getFullWidth()));
getChild<LLUICtrl>("dimensions")->setTextArg("[HEIGHT]", llformat("%d", mImage->getFullHeight()));
-
- LLRect dim_rect(getChildView("dimensions")->getRect());
-
- S32 horiz_pad = 2 * (LLPANEL_BORDER_WIDTH + PREVIEW_PAD) + PREVIEW_RESIZE_HANDLE_SIZE;
-
- // add space for dimensions and aspect ratio
- S32 info_height = dim_rect.mTop + CLIENT_RECT_VPAD;
-
- S32 screen_width = gFloaterView->getSnapRect().getWidth();
- S32 screen_height = gFloaterView->getSnapRect().getHeight();
-
- S32 max_image_width = screen_width - 2*horiz_pad;
- S32 max_image_height = screen_height - (PREVIEW_HEADER_SIZE + CLIENT_RECT_VPAD)
- - (PREVIEW_BORDER + CLIENT_RECT_VPAD + info_height);
-
- S32 client_width = llmin(max_image_width,mImage->getFullWidth());
- S32 client_height = llmin(max_image_height,mImage->getFullHeight());
-
- if (mAspectRatio > 0.f)
- {
- if(mAspectRatio > 1.f)
- {
- client_height = llceil((F32)client_width / mAspectRatio);
- if(client_height > max_image_height)
- {
- client_height = max_image_height;
- client_width = llceil((F32)client_height * mAspectRatio);
- }
- }
- else//mAspectRatio < 1.f
- {
- client_width = llceil((F32)client_height * mAspectRatio);
- if(client_width > max_image_width)
- {
- client_width = max_image_width;
- client_height = llceil((F32)client_width / mAspectRatio);
- }
- }
- }
- else
+ // Reshape the floater only when required
+ if (mUpdateDimensions)
{
-
- if(client_height > max_image_height)
- {
- F32 ratio = (F32)max_image_height/client_height;
- client_height = max_image_height;
- client_width = llceil((F32)client_height * ratio);
- }
+ mUpdateDimensions = FALSE;
- if(client_width > max_image_width)
- {
- F32 ratio = (F32)max_image_width/client_width;
- client_width = max_image_width;
- client_height = llceil((F32)client_width * ratio);
- }
- }
-
- //now back to whole floater
- S32 floater_width = llmax(getMinWidth(),client_width + 2*horiz_pad);
- S32 floater_height = llmax(getMinHeight(),client_height + (PREVIEW_HEADER_SIZE + CLIENT_RECT_VPAD)
- + (PREVIEW_BORDER + CLIENT_RECT_VPAD + info_height));
+ //reshape floater
+ reshape(getRect().getWidth(), getRect().getHeight());
- //reshape floater
- reshape( floater_width, floater_height );
- gFloaterView->adjustToFitScreen(this, FALSE);
+ gFloaterView->adjustToFitScreen(this, FALSE);
- //setup image rect...
- LLRect client_rect(horiz_pad, getRect().getHeight(), getRect().getWidth() - horiz_pad, 0);
- client_rect.mTop -= (PREVIEW_HEADER_SIZE + CLIENT_RECT_VPAD);
- client_rect.mBottom += PREVIEW_BORDER + CLIENT_RECT_VPAD + info_height ;
-
- mClientRect.setLeftTopAndSize(client_rect.getCenterX() - (client_width / 2), client_rect.getCenterY() + (client_height / 2), client_width, client_height);
-
- // Hide the aspect ratio label if the window is too narrow
- // Assumes the label should be to the right of the dimensions
- LLRect aspect_label_rect(getChildView("aspect_ratio")->getRect());
- getChildView("aspect_ratio")->setVisible( dim_rect.mRight < aspect_label_rect.mLeft);
+ LLRect dim_rect(getChildView("dimensions")->getRect());
+ LLRect aspect_label_rect(getChildView("aspect_ratio")->getRect());
+ getChildView("aspect_ratio")->setVisible( dim_rect.mRight < aspect_label_rect.mLeft);
+ }
}
diff --git a/indra/newview/llprogressview.cpp b/indra/newview/llprogressview.cpp
index e9504cbba0..31fde5d58a 100644
--- a/indra/newview/llprogressview.cpp
+++ b/indra/newview/llprogressview.cpp
@@ -133,13 +133,13 @@ void LLProgressView::setVisible(BOOL visible)
mFadeTimer.start();
}
// showing progress view
- else if (!getVisible() && visible)
+ else if (visible && (!getVisible() || mFadeTimer.getStarted()))
{
setFocus(TRUE);
mFadeTimer.stop();
mProgressTimer.start();
LLPanel::setVisible(TRUE);
- }
+ }
}
@@ -207,7 +207,7 @@ void LLProgressView::setText(const std::string& text)
void LLProgressView::setPercent(const F32 percent)
{
- mProgressBar->setPercent(percent);
+ mProgressBar->setValue(percent);
}
void LLProgressView::setMessage(const std::string& msg)
diff --git a/indra/newview/llrecentpeople.cpp b/indra/newview/llrecentpeople.cpp
index 959fd51bbf..7689cd1a52 100644
--- a/indra/newview/llrecentpeople.cpp
+++ b/indra/newview/llrecentpeople.cpp
@@ -33,7 +33,7 @@
using namespace LLOldEvents;
-bool LLRecentPeople::add(const LLUUID& id)
+bool LLRecentPeople::add(const LLUUID& id, const LLSD& userdata)
{
if (id == gAgent.getID())
return false;
@@ -42,10 +42,16 @@ bool LLRecentPeople::add(const LLUUID& id)
if (is_not_group_id)
{
- LLDate date_added = LLDate::now();
+ // For each avaline call the id of caller is different even if
+ // the phone number is the same.
+ // To avoid duplication of avaline list items in the recent list
+ // of panel People, deleting id's with similar phone number.
+ const LLUUID& caller_id = getIDByPhoneNumber(userdata);
+ if (caller_id.notNull())
+ mPeople.erase(caller_id);
- //[] instead of insert to replace existing id->date with new date value
- mPeople[id] = date_added;
+ //[] instead of insert to replace existing id->llsd["date"] with new date value
+ mPeople[id] = userdata;
mChangedSignal();
}
@@ -64,15 +70,55 @@ void LLRecentPeople::get(uuid_vec_t& result) const
result.push_back((*pos).first);
}
-const LLDate& LLRecentPeople::getDate(const LLUUID& id) const
+const LLDate LLRecentPeople::getDate(const LLUUID& id) const
{
recent_people_t::const_iterator it = mPeople.find(id);
- if (it!= mPeople.end()) return (*it).second;
+ if (it!= mPeople.end()) return it->second["date"].asDate();
static LLDate no_date = LLDate();
return no_date;
}
+const LLSD& LLRecentPeople::getData(const LLUUID& id) const
+{
+ recent_people_t::const_iterator it = mPeople.find(id);
+
+ if (it != mPeople.end())
+ return it->second;
+
+ static LLSD no_data = LLSD();
+ return no_data;
+}
+
+bool LLRecentPeople::isAvalineCaller(const LLUUID& id) const
+{
+ recent_people_t::const_iterator it = mPeople.find(id);
+
+ if (it != mPeople.end())
+ {
+ const LLSD& user = it->second;
+ return user["avaline_call"].asBoolean();
+ }
+
+ return false;
+}
+
+const LLUUID& LLRecentPeople::getIDByPhoneNumber(const LLSD& userdata)
+{
+ if (!userdata["avaline_call"].asBoolean())
+ return LLUUID::null;
+
+ for (recent_people_t::const_iterator it = mPeople.begin(); it != mPeople.end(); ++it)
+ {
+ const LLSD& user_info = it->second;
+
+ if (user_info["call_number"].asString() == userdata["call_number"].asString())
+ return it->first;
+ }
+
+ return LLUUID::null;
+}
+
// virtual
bool LLRecentPeople::handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
{
diff --git a/indra/newview/llrecentpeople.h b/indra/newview/llrecentpeople.h
index 852a92ff80..d0d6376867 100644
--- a/indra/newview/llrecentpeople.h
+++ b/indra/newview/llrecentpeople.h
@@ -58,9 +58,15 @@ public:
* Add specified avatar to the list if it's not there already.
*
* @param id avatar to add.
+ *
+ * @param userdata additional information about last interaction party.
+ * For example when last interaction party is not an avatar
+ * but an avaline caller, additional info (such as phone
+ * number, session id and etc.) should be added.
+ *
* @return false if the avatar is in the list already, true otherwise
*/
- bool add(const LLUUID& id);
+ bool add(const LLUUID& id, const LLSD& userdata = LLSD().with("date", LLDate::now()));
/**
* @param id avatar to search.
@@ -75,7 +81,25 @@ public:
*/
void get(uuid_vec_t& result) const;
- const LLDate& getDate(const LLUUID& id) const;
+ /**
+ * Returns last interaction time with specified participant
+ *
+ */
+ const LLDate getDate(const LLUUID& id) const;
+
+ /**
+ * Returns data about specified participant
+ *
+ * @param id identifier of specific participant
+ */
+ const LLSD& getData(const LLUUID& id) const;
+
+ /**
+ * Checks whether specific participant is an avaline caller
+ *
+ * @param id identifier of specific participant
+ */
+ bool isAvalineCaller(const LLUUID& id) const;
/**
* Set callback to be called when the list changed.
@@ -92,7 +116,10 @@ public:
/*virtual*/ bool handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata);
private:
- typedef std::map<LLUUID, LLDate> recent_people_t;
+
+ const LLUUID& getIDByPhoneNumber(const LLSD& userdata);
+
+ typedef std::map<LLUUID, LLSD> recent_people_t;
recent_people_t mPeople;
signal_t mChangedSignal;
};
diff --git a/indra/newview/llremoteparcelrequest.cpp b/indra/newview/llremoteparcelrequest.cpp
index d63a48647d..3862dac340 100644
--- a/indra/newview/llremoteparcelrequest.cpp
+++ b/indra/newview/llremoteparcelrequest.cpp
@@ -33,6 +33,7 @@
#include "llpanel.h"
#include "llhttpclient.h"
#include "llsdserialize.h"
+#include "llurlentry.h"
#include "llviewerregion.h"
#include "llview.h"
@@ -77,23 +78,20 @@ void LLRemoteParcelRequestResponder::error(U32 status, const std::string& reason
void LLRemoteParcelInfoProcessor::addObserver(const LLUUID& parcel_id, LLRemoteParcelInfoObserver* observer)
{
- // Check if the observer is already in observers list for this UUID
observer_multimap_t::iterator it;
+ observer_multimap_t::iterator start = mObservers.lower_bound(parcel_id);
+ observer_multimap_t::iterator end = mObservers.upper_bound(parcel_id);
- it = mObservers.find(parcel_id);
- while (it != mObservers.end())
+ // Check if the observer is already in observers list for this UUID
+ for(it = start; it != end; ++it)
{
- if (it->second == observer)
+ if (it->second.get() == observer)
{
return;
}
- else
- {
- ++it;
- }
}
- mObservers.insert(std::pair<LLUUID, LLRemoteParcelInfoObserver*>(parcel_id, observer));
+ mObservers.insert(std::make_pair(parcel_id, observer->getObserverHandle()));
}
void LLRemoteParcelInfoProcessor::removeObserver(const LLUUID& parcel_id, LLRemoteParcelInfoObserver* observer)
@@ -104,19 +102,16 @@ void LLRemoteParcelInfoProcessor::removeObserver(const LLUUID& parcel_id, LLRemo
}
observer_multimap_t::iterator it;
+ observer_multimap_t::iterator start = mObservers.lower_bound(parcel_id);
+ observer_multimap_t::iterator end = mObservers.upper_bound(parcel_id);
- it = mObservers.find(parcel_id);
- while (it != mObservers.end())
+ for(it = start; it != end; ++it)
{
- if (it->second == observer)
+ if (it->second.get() == observer)
{
mObservers.erase(it);
break;
}
- else
- {
- ++it;
- }
}
}
@@ -141,14 +136,51 @@ void LLRemoteParcelInfoProcessor::processParcelInfoReply(LLMessageSystem* msg, v
msg->getS32 ("Data", "SalePrice", parcel_data.sale_price);
msg->getS32 ("Data", "AuctionID", parcel_data.auction_id);
- LLRemoteParcelInfoProcessor::observer_multimap_t observers = LLRemoteParcelInfoProcessor::getInstance()->mObservers;
+ LLRemoteParcelInfoProcessor::observer_multimap_t & observers = LLRemoteParcelInfoProcessor::getInstance()->mObservers;
- observer_multimap_t::iterator oi = observers.find(parcel_data.parcel_id);
+ typedef std::vector<observer_multimap_t::iterator> deadlist_t;
+ deadlist_t dead_iters;
+
+ observer_multimap_t::iterator oi = observers.lower_bound(parcel_data.parcel_id);
observer_multimap_t::iterator end = observers.upper_bound(parcel_data.parcel_id);
- for (; oi != end; ++oi)
+
+ while (oi != end)
{
- oi->second->processParcelInfo(parcel_data);
+ // increment the loop iterator now since it may become invalid below
+ observer_multimap_t::iterator cur_oi = oi++;
+
+ LLRemoteParcelInfoObserver * observer = cur_oi->second.get();
+ if(observer)
+ {
+ // may invalidate cur_oi if the observer removes itself
+ observer->processParcelInfo(parcel_data);
+ }
+ else
+ {
+ // the handle points to an expired observer, so don't keep it
+ // around anymore
+ dead_iters.push_back(cur_oi);
+ }
}
+
+ deadlist_t::iterator i;
+ deadlist_t::iterator end_dead = dead_iters.end();
+ for(i = dead_iters.begin(); i != end_dead; ++i)
+ {
+ observers.erase(*i);
+ }
+
+ LLUrlEntryParcel::LLParcelData url_data;
+ url_data.parcel_id = parcel_data.parcel_id;
+ url_data.name = parcel_data.name;
+ url_data.sim_name = parcel_data.sim_name;
+ url_data.global_x = parcel_data.global_x;
+ url_data.global_y = parcel_data.global_y;
+ url_data.global_z = parcel_data.global_z;
+
+ // Pass the parcel data to LLUrlEntryParcel to render
+ // human readable parcel name.
+ LLUrlEntryParcel::processParcelInfo(url_data);
}
void LLRemoteParcelInfoProcessor::sendParcelInfoRequest(const LLUUID& parcel_id)
diff --git a/indra/newview/llremoteparcelrequest.h b/indra/newview/llremoteparcelrequest.h
index a6c62995a9..74cf1616df 100644
--- a/indra/newview/llremoteparcelrequest.h
+++ b/indra/newview/llremoteparcelrequest.h
@@ -98,7 +98,7 @@ public:
static void processParcelInfoReply(LLMessageSystem* msg, void**);
private:
- typedef std::multimap<LLUUID, LLRemoteParcelInfoObserver*> observer_multimap_t;
+ typedef std::multimap<LLUUID, LLHandle<LLRemoteParcelInfoObserver> > observer_multimap_t;
observer_multimap_t mObservers;
};
diff --git a/indra/newview/llrootview.h b/indra/newview/llrootview.h
index 4b1ba15a0b..5223a314f3 100644
--- a/indra/newview/llrootview.h
+++ b/indra/newview/llrootview.h
@@ -42,27 +42,5 @@ public:
LLRootView(const Params& p)
: LLView(p)
{}
-
- // added to provide possibility to handle mouse click event inside all application
- // window without creating any floater
- typedef boost::signals2::signal<void(S32 x, S32 y, MASK mask)>
- mouse_signal_t;
-
- private:
- mouse_signal_t mMouseDownSignal;
-
- public:
- /*virtual*/
- BOOL handleMouseDown(S32 x, S32 y, MASK mask)
- {
- mMouseDownSignal(x, y, mask);
- return LLView::handleMouseDown(x, y, mask);
- }
-
- boost::signals2::connection addMouseDownCallback(
- const mouse_signal_t::slot_type& cb)
- {
- return mMouseDownSignal.connect(cb);
- }
};
#endif //LL_LLROOTVIEW_H
diff --git a/indra/newview/llsceneview.cpp b/indra/newview/llsceneview.cpp
new file mode 100644
index 0000000000..8e8fc9dd25
--- /dev/null
+++ b/indra/newview/llsceneview.cpp
@@ -0,0 +1,429 @@
+/**
+ * @file llsceneview.cpp
+ * @brief LLSceneView class implementation
+ *
+ * $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 "llsceneview.h"
+#include "llviewerwindow.h"
+#include "pipeline.h"
+#include "llviewerobjectlist.h"
+#include "llviewerregion.h"
+#include "llagent.h"
+#include "llvolumemgr.h"
+
+LLSceneView* gSceneView = NULL;
+
+//borrow this helper function from llfasttimerview.cpp
+template <class VEC_TYPE>
+void removeOutliers(std::vector<VEC_TYPE>& data, F32 k);
+
+
+LLSceneView::LLSceneView(const LLRect& rect)
+ : LLFloater(LLSD())
+{
+ setRect(rect);
+ setVisible(FALSE);
+
+ setCanMinimize(false);
+ setCanClose(true);
+}
+
+void LLSceneView::onClickCloseBtn()
+{
+ setVisible(false);
+}
+
+
+void LLSceneView::draw()
+{
+ S32 margin = 10;
+ S32 height = (S32) (gViewerWindow->getWindowRectScaled().getHeight()*0.75f);
+ S32 width = (S32) (gViewerWindow->getWindowRectScaled().getWidth() * 0.75f);
+
+ LLRect new_rect;
+ new_rect.setLeftTopAndSize(getRect().mLeft, getRect().mTop, width, height);
+ setRect(new_rect);
+
+ // Draw the window background
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0, LLColor4(0.f, 0.f, 0.f, 0.25f));
+
+
+ //aggregate some statistics
+
+ //object sizes
+ std::vector<F32> size[2];
+
+ //triangle counts
+ std::vector<S32> triangles[2];
+ std::vector<S32> visible_triangles[2];
+ S32 total_visible_triangles[] = {0, 0};
+ S32 total_triangles[] = {0, 0};
+
+ //streaming cost
+ std::vector<F32> streaming_cost[2];
+ F32 total_streaming[] = { 0.f, 0.f };
+
+ //physics cost
+ std::vector<F32> physics_cost[2];
+ F32 total_physics[] = { 0.f, 0.f };
+
+
+ U32 object_count = 0;
+
+ LLViewerRegion* region = gAgent.getRegion();
+ if (region)
+ {
+ for (U32 i = 0; i < gObjectList.getNumObjects(); ++i)
+ {
+ LLViewerObject* object = gObjectList.getObject(i);
+
+ if (object &&
+ object->getVolume()&&
+ object->getRegion() == region)
+ {
+ U32 idx = object->isAttachment() ? 1 : 0;
+
+ LLVolume* volume = object->getVolume();
+ object_count++;
+
+ F32 radius = object->getScale().magVec();
+ size[idx].push_back(radius);
+
+ S32 visible = volume->getNumTriangles();
+ S32 high_triangles = object->getHighLODTriangleCount();
+
+ total_visible_triangles[idx] += visible;
+ total_triangles[idx] += high_triangles;
+
+ visible_triangles[idx].push_back(visible);
+ triangles[idx].push_back(high_triangles);
+
+ F32 streaming = object->getStreamingCost();
+ total_streaming[idx] += streaming;
+ streaming_cost[idx].push_back(streaming);
+
+ F32 physics = object->getPhysicsCost();
+ total_physics[idx] += physics;
+ physics_cost[idx].push_back(physics);
+ }
+ }
+ }
+
+ const char* category[] =
+ {
+ "Region",
+ "Attachment"
+ };
+
+ S32 graph_pos[4];
+
+ for (U32 i = 0; i < 4; ++i)
+ {
+ graph_pos[i] = new_rect.getHeight()/4*(i+1);
+ }
+
+ for (U32 idx = 0; idx < 2; idx++)
+ {
+ if (!size[idx].empty())
+ { //display graph of object sizes
+ std::sort(size[idx].begin(), size[idx].end());
+
+ ll_remove_outliers(size[idx], 1.f);
+
+ LLRect size_rect;
+
+ if (idx == 0)
+ {
+ size_rect = LLRect(margin, graph_pos[0]-margin, new_rect.getWidth()/2-margin, margin*2);
+ }
+ else
+ {
+ size_rect = LLRect(margin+new_rect.getWidth()/2, graph_pos[0]-margin, new_rect.getWidth()-margin, margin*2);
+ }
+
+ gl_rect_2d(size_rect, LLColor4::white, false);
+
+ F32 size_domain[] = { 128.f, 0.f };
+
+ //get domain of sizes
+ for (U32 i = 0; i < size[idx].size(); ++i)
+ {
+ size_domain[0] = llmin(size_domain[0], size[idx][i]);
+ size_domain[1] = llmax(size_domain[1], size[idx][i]);
+ }
+
+ F32 size_range = size_domain[1]-size_domain[0];
+
+ U32 count = size[idx].size();
+
+ F32 total = 0.f;
+
+ gGL.begin(LLRender::LINE_STRIP);
+
+ for (U32 i = 0; i < count; ++i)
+ {
+ F32 rad = size[idx][i];
+ total += rad;
+ F32 y = (rad-size_domain[0])/size_range*size_rect.getHeight()+size_rect.mBottom;
+ F32 x = (F32) i / count * size_rect.getWidth() + size_rect.mLeft;
+
+ gGL.vertex2f(x,y);
+
+ if (i%4096 == 0)
+ {
+ gGL.end();
+ gGL.flush();
+ gGL.begin(LLRender::LINE_STRIP);
+ }
+ }
+
+ gGL.end();
+ gGL.flush();
+
+ std::string label = llformat("%s Object Sizes (m) -- [%.1f, %.1f] Mean: %.1f Median: %.1f -- %d samples",
+ category[idx], size_domain[0], size_domain[1], total/count, size[idx][count/2], count);
+
+ LLFontGL::getFontMonospace()->renderUTF8(label,
+ 0 , size_rect.mLeft, size_rect.mTop+margin, LLColor4::white, LLFontGL::LEFT, LLFontGL::TOP);
+
+ }
+ }
+
+ for (U32 idx = 0; idx < 2; ++idx)
+ {
+ if (!triangles[idx].empty())
+ { //plot graph of visible/total triangles
+ std::sort(triangles[idx].begin(), triangles[idx].end());
+
+ ll_remove_outliers(triangles[idx], 1.f);
+
+ LLRect tri_rect;
+ if (idx == 0)
+ {
+ tri_rect = LLRect(margin, graph_pos[1]-margin, new_rect.getWidth()/2-margin, graph_pos[0]+margin);
+ }
+ else
+ {
+ tri_rect = LLRect(new_rect.getWidth()/2+margin, graph_pos[1]-margin, new_rect.getWidth()-margin, graph_pos[0]+margin);
+ }
+
+ gl_rect_2d(tri_rect, LLColor4::white, false);
+
+ S32 tri_domain[] = { 65536, 0 };
+
+ //get domain of triangle counts
+ for (U32 i = 0; i < triangles[idx].size(); ++i)
+ {
+ tri_domain[0] = llmin(tri_domain[0], triangles[idx][i]);
+ tri_domain[1] = llmax(tri_domain[1], triangles[idx][i]);
+ }
+
+ U32 triangle_range = tri_domain[1]-tri_domain[0];
+
+ U32 count = triangles[idx].size();
+
+ U32 total = 0;
+
+ gGL.begin(LLRender::LINE_STRIP);
+ //plot triangles
+ for (U32 i = 0; i < count; ++i)
+ {
+ U32 tri_count = triangles[idx][i];
+ total += tri_count;
+ F32 y = (F32) (tri_count-tri_domain[0])/triangle_range*tri_rect.getHeight()+tri_rect.mBottom;
+ F32 x = (F32) i / count * tri_rect.getWidth() + tri_rect.mLeft;
+
+ gGL.vertex2f(x,y);
+
+ if (i%4096 == 0)
+ {
+ gGL.end();
+ gGL.flush();
+ gGL.begin(LLRender::LINE_STRIP);
+ }
+ }
+
+ gGL.end();
+ gGL.flush();
+
+ U32 total_visible = 0;
+ count = visible_triangles[idx].size();
+
+ for (U32 i = 0; i < count; ++i)
+ {
+ U32 tri_count = visible_triangles[idx][i];
+ total_visible += tri_count;
+ }
+
+ std::string label = llformat("%s Object Triangle Counts (Ktris) -- [%.2f, %.2f] Mean: %.2f Median: %.2f Visible: %.2f/%.2f",
+ category[idx], tri_domain[0]/1024.f, tri_domain[1]/1024.f, (total/count)/1024.f, triangles[idx][count/2]/1024.f, total_visible_triangles[idx]/1024.f, total_triangles[idx]/1024.f);
+
+ LLFontGL::getFontMonospace()->renderUTF8(label,
+ 0 , tri_rect.mLeft, tri_rect.mTop+margin, LLColor4::white, LLFontGL::LEFT, LLFontGL::TOP);
+
+ }
+ }
+
+ for (U32 idx = 0; idx < 2; ++idx)
+ {
+ if (!streaming_cost[idx].empty())
+ { //plot graph of streaming cost
+ std::sort(streaming_cost[idx].begin(), streaming_cost[idx].end());
+
+ ll_remove_outliers(streaming_cost[idx], 1.f);
+
+ LLRect tri_rect;
+ if (idx == 0)
+ {
+ tri_rect = LLRect(margin, graph_pos[2]-margin, new_rect.getWidth()/2-margin, graph_pos[1]+margin);
+ }
+ else
+ {
+ tri_rect = LLRect(new_rect.getWidth()/2+margin, graph_pos[2]-margin, new_rect.getWidth()-margin, graph_pos[1]+margin);
+ }
+
+ gl_rect_2d(tri_rect, LLColor4::white, false);
+
+ F32 streaming_domain[] = { 65536, 0 };
+
+ //get domain of triangle counts
+ for (U32 i = 0; i < streaming_cost[idx].size(); ++i)
+ {
+ streaming_domain[0] = llmin(streaming_domain[0], streaming_cost[idx][i]);
+ streaming_domain[1] = llmax(streaming_domain[1], streaming_cost[idx][i]);
+ }
+
+ F32 cost_range = streaming_domain[1]-streaming_domain[0];
+
+ U32 count = streaming_cost[idx].size();
+
+ F32 total = 0;
+
+ gGL.begin(LLRender::LINE_STRIP);
+ //plot triangles
+ for (U32 i = 0; i < count; ++i)
+ {
+ F32 sc = streaming_cost[idx][i];
+ total += sc;
+ F32 y = (F32) (sc-streaming_domain[0])/cost_range*tri_rect.getHeight()+tri_rect.mBottom;
+ F32 x = (F32) i / count * tri_rect.getWidth() + tri_rect.mLeft;
+
+ gGL.vertex2f(x,y);
+
+ if (i%4096 == 0)
+ {
+ gGL.end();
+ gGL.flush();
+ gGL.begin(LLRender::LINE_STRIP);
+ }
+ }
+
+ gGL.end();
+ gGL.flush();
+
+ std::string label = llformat("%s Object Streaming Cost -- [%.2f, %.2f] Mean: %.2f Total: %.2f",
+ category[idx], streaming_domain[0], streaming_domain[1], total/count, total_streaming[idx]);
+
+ LLFontGL::getFontMonospace()->renderUTF8(label,
+ 0 , tri_rect.mLeft, tri_rect.mTop+margin, LLColor4::white, LLFontGL::LEFT, LLFontGL::TOP);
+
+ }
+ }
+
+ for (U32 idx = 0; idx < 2; ++idx)
+ {
+ if (!physics_cost[idx].empty())
+ { //plot graph of physics cost
+ std::sort(physics_cost[idx].begin(), physics_cost[idx].end());
+
+ ll_remove_outliers(physics_cost[idx], 1.f);
+
+ LLRect tri_rect;
+ if (idx == 0)
+ {
+ tri_rect = LLRect(margin, graph_pos[3]-margin, new_rect.getWidth()/2-margin, graph_pos[2]+margin);
+ }
+ else
+ {
+ tri_rect = LLRect(new_rect.getWidth()/2+margin, graph_pos[3]-margin, new_rect.getWidth()-margin, graph_pos[2]+margin);
+ }
+
+ gl_rect_2d(tri_rect, LLColor4::white, false);
+
+ F32 physics_domain[] = { 65536, 0 };
+
+ //get domain of triangle counts
+ for (U32 i = 0; i < physics_cost[idx].size(); ++i)
+ {
+ physics_domain[0] = llmin(physics_domain[0], physics_cost[idx][i]);
+ physics_domain[1] = llmax(physics_domain[1], physics_cost[idx][i]);
+ }
+
+ F32 cost_range = physics_domain[1]-physics_domain[0];
+
+ U32 count = physics_cost[idx].size();
+
+ F32 total = 0;
+
+ gGL.begin(LLRender::LINE_STRIP);
+ //plot triangles
+ for (U32 i = 0; i < count; ++i)
+ {
+ F32 pc = physics_cost[idx][i];
+ total += pc;
+ F32 y = (F32) (pc-physics_domain[0])/cost_range*tri_rect.getHeight()+tri_rect.mBottom;
+ F32 x = (F32) i / count * tri_rect.getWidth() + tri_rect.mLeft;
+
+ gGL.vertex2f(x,y);
+
+ if (i%4096 == 0)
+ {
+ gGL.end();
+ gGL.flush();
+ gGL.begin(LLRender::LINE_STRIP);
+ }
+ }
+
+ gGL.end();
+ gGL.flush();
+
+ std::string label = llformat("%s Object Physics Cost -- [%.2f, %.2f] Mean: %.2f Total: %.2f",
+ category[idx], physics_domain[0], physics_domain[1], total/count, total_physics[idx]);
+
+ LLFontGL::getFontMonospace()->renderUTF8(label,
+ 0 , tri_rect.mLeft, tri_rect.mTop+margin, LLColor4::white, LLFontGL::LEFT, LLFontGL::TOP);
+
+ }
+ }
+
+
+
+
+ LLView::draw();
+}
+
+
diff --git a/indra/newview/llsceneview.h b/indra/newview/llsceneview.h
new file mode 100644
index 0000000000..2a3a14bbee
--- /dev/null
+++ b/indra/newview/llsceneview.h
@@ -0,0 +1,48 @@
+/**
+ * @file llsceneview.h
+ * @brief LLSceneView class header file
+ *
+ * $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_LLSCENEVIEW_H
+#define LL_LLSCENEVIEW_H
+
+#include "llfloater.h"
+
+
+class LLSceneView : public LLFloater
+{
+public:
+ LLSceneView(const LLRect& rect);
+
+ virtual void draw();
+
+protected:
+ virtual void onClickCloseBtn();
+
+
+};
+
+extern LLSceneView* gSceneView;
+
+#endif // LL_LLSCENEVIEW_H
diff --git a/indra/newview/llscreenchannel.cpp b/indra/newview/llscreenchannel.cpp
index 18c9ac28c1..e3bc67a414 100644
--- a/indra/newview/llscreenchannel.cpp
+++ b/indra/newview/llscreenchannel.cpp
@@ -83,11 +83,10 @@ bool LLScreenChannelBase::isHovering()
return mHoveredToast->isHovered();
}
-bool LLScreenChannelBase::resetPositionAndSize(const LLSD& newvalue)
+void LLScreenChannelBase::resetPositionAndSize()
{
LLRect rc = gViewerWindow->getWorldViewRectScaled();
updatePositionAndSize(rc, rc);
- return true;
}
void LLScreenChannelBase::updatePositionAndSize(LLRect old_world_rect, LLRect new_world_rect)
@@ -99,10 +98,7 @@ void LLScreenChannelBase::updatePositionAndSize(LLRect old_world_rect, LLRect ne
if (gSavedSettings.getBOOL("SidebarCameraMovement") == FALSE
&& LLSideTray::instanceCreated ())
{
- LLSideTray* side_bar = LLSideTray::getInstance();
-
- if (side_bar->getVisible() && !side_bar->getCollapsed())
- world_rect_padding += side_bar->getRect().getWidth();
+ world_rect_padding += LLSideTray::getInstance()->getVisibleWidth();
}
@@ -133,15 +129,25 @@ void LLScreenChannelBase::init(S32 channel_left, S32 channel_right)
if(LLSideTray::instanceCreated())
{
LLSideTray* side_bar = LLSideTray::getInstance();
- side_bar->getCollapseSignal().connect(boost::bind(&LLScreenChannelBase::resetPositionAndSize, this, _2));
+ side_bar->setVisibleWidthChangeCallback(boost::bind(&LLScreenChannelBase::resetPositionAndSize, this));
}
+ // top and bottom set by updateBottom()
+ setRect(LLRect(channel_left, 0, channel_right, 0));
+ updateBottom();
+ setVisible(TRUE);
+}
+
+void LLScreenChannelBase::updateBottom()
+{
S32 channel_top = gViewerWindow->getWorldViewRectScaled().getHeight();
- S32 channel_bottom = gViewerWindow->getWorldViewRectScaled().mBottom + gSavedSettings.getS32("ChannelBottomPanelMargin");
+ S32 channel_bottom = gSavedSettings.getS32("ChannelBottomPanelMargin");
+ S32 channel_left = getRect().mLeft;
+ S32 channel_right = getRect().mRight;
setRect(LLRect(channel_left, channel_top, channel_right, channel_bottom));
- setVisible(TRUE);
}
+
//--------------------------------------------------------------------------
//////////////////////
// LLScreenChannel
@@ -204,10 +210,7 @@ void LLScreenChannel::updatePositionAndSize(LLRect old_world_rect, LLRect new_wo
if (gSavedSettings.getBOOL("SidebarCameraMovement") == FALSE
&& LLSideTray::instanceCreated ())
{
- LLSideTray* side_bar = LLSideTray::getInstance();
-
- if (side_bar->getVisible() && !side_bar->getCollapsed())
- world_rect_padding += side_bar->getRect().getWidth();
+ world_rect_padding += LLSideTray::getInstance()->getVisibleWidth();
}
@@ -253,8 +256,8 @@ void LLScreenChannel::addToast(const LLToast::Params& p)
if(mControlHovering)
{
new_toast_elem.toast->setOnToastHoverCallback(boost::bind(&LLScreenChannel::onToastHover, this, _1, _2));
- new_toast_elem.toast->setMouseEnterCallback(boost::bind(&LLScreenChannel::stopFadingToast, this, new_toast_elem.toast));
- new_toast_elem.toast->setMouseLeaveCallback(boost::bind(&LLScreenChannel::startFadingToast, this, new_toast_elem.toast));
+ new_toast_elem.toast->setMouseEnterCallback(boost::bind(&LLScreenChannel::stopToastTimer, this, new_toast_elem.toast));
+ new_toast_elem.toast->setMouseLeaveCallback(boost::bind(&LLScreenChannel::startToastTimer, this, new_toast_elem.toast));
}
if(show_toast)
@@ -369,7 +372,7 @@ void LLScreenChannel::loadStoredToastsToChannel()
for(it = mStoredToastList.begin(); it != mStoredToastList.end(); ++it)
{
(*it).toast->setIsHidden(false);
- (*it).toast->resetTimer();
+ (*it).toast->startTimer();
mToastList.push_back((*it));
}
@@ -394,7 +397,7 @@ void LLScreenChannel::loadStoredToastByNotificationIDToChannel(LLUUID id)
}
toast->setIsHidden(false);
- toast->resetTimer();
+ toast->startTimer();
mToastList.push_back((*it));
redrawToasts();
@@ -477,7 +480,7 @@ void LLScreenChannel::modifyToastByNotificationID(LLUUID id, LLPanel* panel)
toast->removeChild(old_panel);
delete old_panel;
toast->insertPanel(panel);
- toast->resetTimer();
+ toast->startTimer();
redrawToasts();
}
}
@@ -485,7 +488,7 @@ void LLScreenChannel::modifyToastByNotificationID(LLUUID id, LLPanel* panel)
//--------------------------------------------------------------------------
void LLScreenChannel::redrawToasts()
{
- if(mToastList.size() == 0 || isHovering())
+ if(mToastList.size() == 0)
return;
switch(mToastAlignment)
@@ -511,6 +514,8 @@ void LLScreenChannel::showToastsBottom()
S32 toast_margin = 0;
std::vector<ToastElem>::reverse_iterator it;
+ updateBottom();
+
LLDockableFloater* floater = dynamic_cast<LLDockableFloater*>(LLDockableFloater::getInstanceHandle().get());
for(it = mToastList.rbegin(); it != mToastList.rend(); ++it)
@@ -583,20 +588,15 @@ void LLScreenChannel::showToastsBottom()
}
}
+ // Dismiss toasts we don't have space for (STORM-391).
if(it != mToastList.rend())
{
mHiddenToastsNum = 0;
for(; it != mToastList.rend(); it++)
{
- (*it).toast->stopTimer();
- (*it).toast->setVisible(FALSE);
- mHiddenToastsNum++;
+ (*it).toast->hide();
}
}
- else
- {
- closeOverflowToastPanel();
- }
}
//--------------------------------------------------------------------------
@@ -697,15 +697,15 @@ void LLScreenChannel::closeStartUpToast()
}
}
-void LLNotificationsUI::LLScreenChannel::stopFadingToast(LLToast* toast)
+void LLNotificationsUI::LLScreenChannel::stopToastTimer(LLToast* toast)
{
if (!toast || toast != mHoveredToast) return;
// Pause fade timer of the hovered toast.
- toast->stopFading();
+ toast->stopTimer();
}
-void LLNotificationsUI::LLScreenChannel::startFadingToast(LLToast* toast)
+void LLNotificationsUI::LLScreenChannel::startToastTimer(LLToast* toast)
{
if (!toast || toast == mHoveredToast)
{
@@ -713,13 +713,12 @@ void LLNotificationsUI::LLScreenChannel::startFadingToast(LLToast* toast)
}
// Reset its fade timer.
- toast->startFading();
+ toast->startTimer();
}
//--------------------------------------------------------------------------
void LLScreenChannel::hideToastsFromScreen()
{
- closeOverflowToastPanel();
for(std::vector<ToastElem>::iterator it = mToastList.begin(); it != mToastList.end(); it++)
(*it).toast->setVisible(FALSE);
}
@@ -835,8 +834,7 @@ void LLScreenChannel::onToastHover(LLToast* toast, bool mouse_enter)
}
}
- if(!isHovering())
- redrawToasts();
+ redrawToasts();
}
//--------------------------------------------------------------------------
@@ -850,13 +848,7 @@ void LLScreenChannel::updateShowToastsState()
return;
}
- S32 channel_bottom = gViewerWindow->getWorldViewRectScaled().mBottom + gSavedSettings.getS32("ChannelBottomPanelMargin");;
- LLRect this_rect = getRect();
-
- if(channel_bottom != this_rect.mBottom)
- {
- setRect(LLRect(this_rect.mLeft, this_rect.mTop, this_rect.mRight, channel_bottom));
- }
+ updateBottom();
}
//--------------------------------------------------------------------------
diff --git a/indra/newview/llscreenchannel.h b/indra/newview/llscreenchannel.h
index a1fdd6e32c..d207d13981 100644
--- a/indra/newview/llscreenchannel.h
+++ b/indra/newview/llscreenchannel.h
@@ -59,8 +59,8 @@ public:
// Channel's outfit-functions
// update channel's size and position in the World View
virtual void updatePositionAndSize(LLRect old_world_rect, LLRect new_world_rect);
+ void resetPositionAndSize();
- bool resetPositionAndSize(const LLSD& newvalue);
// initialization of channel's shape and position
virtual void init(S32 channel_left, S32 channel_right);
@@ -81,9 +81,6 @@ public:
// show all toasts in a channel
virtual void redrawToasts() {};
- virtual void closeOverflowToastPanel() {};
- virtual void hideOverflowToastPanel() {};
-
// Channel's behavior-functions
// set whether a channel will control hovering inside itself or not
@@ -111,6 +108,8 @@ public:
LLUUID getChannelID() { return mID; }
protected:
+ void updateBottom();
+
// Channel's flags
bool mControlHovering;
LLToast* mHoveredToast;
@@ -194,10 +193,10 @@ public:
/** Stop fading given toast */
- virtual void stopFadingToast(LLToast* toast);
+ virtual void stopToastTimer(LLToast* toast);
/** Start fading given toast */
- virtual void startFadingToast(LLToast* toast);
+ virtual void startToastTimer(LLToast* toast);
// get StartUp Toast's state
static bool getStartUpToastShown() { return mWasStartUpToastShown; }
diff --git a/indra/newview/llscriptfloater.cpp b/indra/newview/llscriptfloater.cpp
index 2334f0cde5..170e23e4c5 100644
--- a/indra/newview/llscriptfloater.cpp
+++ b/indra/newview/llscriptfloater.cpp
@@ -32,11 +32,13 @@
#include "llchannelmanager.h"
#include "llchiclet.h"
#include "llfloaterreg.h"
+#include "lllslconstants.h"
#include "llnotifications.h"
#include "llnotificationsutil.h"
#include "llscreenchannel.h"
#include "llsyswellwindow.h"
#include "lltoastnotifypanel.h"
+#include "lltoastscripttextbox.h"
#include "lltrans.h"
#include "llviewerwindow.h"
#include "llimfloater.h"
@@ -151,10 +153,18 @@ void LLScriptFloater::createForm(const LLUUID& notification_id)
// create new form
LLRect toast_rect = getRect();
- // LLToastNotifyPanel will fit own content in vertical direction,
- // but it needs an initial rect to properly calculate its width
- // Use an initial rect of the script floater to make the floater window more configurable.
- mScriptForm = new LLToastNotifyPanel(notification, toast_rect);
+ if (isScriptTextbox(notification))
+ {
+ mScriptForm = new LLToastScriptTextbox(notification);
+ }
+ else
+ {
+ // LLToastNotifyPanel will fit own content in vertical direction,
+ // but it needs an initial rect to properly calculate its width
+ // Use an initial rect of the script floater to make the floater
+ // window more configurable.
+ mScriptForm = new LLToastNotifyPanel(notification, toast_rect);
+ }
addChild(mScriptForm);
// position form on floater
@@ -564,4 +574,32 @@ void LLScriptFloaterManager::setFloaterVisible(const LLUUID& notification_id, bo
}
}
+//////////////////////////////////////////////////////////////////
+
+bool LLScriptFloater::isScriptTextbox(LLNotificationPtr notification)
+{
+ // get a form for the notification
+ LLNotificationFormPtr form(notification->getForm());
+
+ if (form)
+ {
+ // get number of elements in the form
+ int num_options = form->getNumElements();
+
+ // if ANY of the buttons have the magic lltextbox string as
+ // name, then treat the whole dialog as a simple text entry
+ // box (i.e. mixed button and textbox forms are not supported)
+ for (int i=0; i<num_options; ++i)
+ {
+ LLSD form_element = form->getElement(i);
+ if (form_element["name"].asString() == TEXTBOX_MAGIC_TOKEN)
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
// EOF
diff --git a/indra/newview/llscriptfloater.h b/indra/newview/llscriptfloater.h
index da70bb4334..8e959a3d0e 100644
--- a/indra/newview/llscriptfloater.h
+++ b/indra/newview/llscriptfloater.h
@@ -28,8 +28,9 @@
#define LL_SCRIPTFLOATER_H
#include "lltransientdockablefloater.h"
+#include "llnotificationptr.h"
-class LLToastNotifyPanel;
+class LLToastPanel;
/**
* Handles script notifications ("ScriptDialog" and "ScriptDialogGroup")
@@ -203,7 +204,9 @@ protected:
void dockToChiclet(bool dock);
private:
- LLToastNotifyPanel* mScriptForm;
+ bool isScriptTextbox(LLNotificationPtr notification);
+
+ LLToastPanel* mScriptForm;
LLUUID mNotificationId;
LLUUID mObjectId;
bool mSaveFloaterPosition;
diff --git a/indra/newview/llscrollingpanelparam.cpp b/indra/newview/llscrollingpanelparam.cpp
index 05b273cd29..05b82ba967 100644
--- a/indra/newview/llscrollingpanelparam.cpp
+++ b/indra/newview/llscrollingpanelparam.cpp
@@ -50,14 +50,9 @@ const S32 LLScrollingPanelParam::PARAM_HINT_HEIGHT = 128;
S32 LLScrollingPanelParam::sUpdateDelayFrames = 0;
LLScrollingPanelParam::LLScrollingPanelParam( const LLPanel::Params& panel_params,
- LLViewerJointMesh* mesh, LLViewerVisualParam* param, BOOL allow_modify, LLWearable* wearable, LLJoint* jointp )
- : LLScrollingPanel( panel_params ),
- mParam(param),
- mAllowModify(allow_modify),
- mWearable(wearable)
+ LLViewerJointMesh* mesh, LLViewerVisualParam* param, BOOL allow_modify, LLWearable* wearable, LLJoint* jointp, BOOL use_hints )
+ : LLScrollingPanelParamBase( panel_params, mesh, param, allow_modify, wearable, jointp, use_hints)
{
- buildFromFile( "panel_scrolling_param.xml");
-
// *HACK To avoid hard coding texture position, lets use border's position for texture.
LLViewBorder* left_border = getChild<LLViewBorder>("left_border");
@@ -73,12 +68,6 @@ LLScrollingPanelParam::LLScrollingPanelParam( const LLPanel::Params& panel_param
mHintMin->setAllowsUpdates( FALSE );
mHintMax->setAllowsUpdates( FALSE );
- getChild<LLUICtrl>("param slider")->setValue(weightToPercent(param->getWeight()));
-
- std::string display_name = LLTrans::getString(param->getDisplayName());
- getChild<LLUICtrl>("param slider")->setLabelArg("[DESC]", display_name);
- getChildView("param slider")->setEnabled(mAllowModify);
- childSetCommitCallback("param slider", LLScrollingPanelParam::onSliderMoved, this);
std::string min_name = LLTrans::getString(param->getMinDisplayName());
std::string max_name = LLTrans::getString(param->getMaxDisplayName());
@@ -112,20 +101,15 @@ LLScrollingPanelParam::~LLScrollingPanelParam()
}
void LLScrollingPanelParam::updatePanel(BOOL allow_modify)
{
- LLViewerVisualParam* param = mHintMin->getVisualParam();
-
if (!mWearable)
{
// not editing a wearable just now, no update necessary
return;
}
- F32 current_weight = mWearable->getVisualParamWeight( param->getID() );
- getChild<LLUICtrl>("param slider")->setValue(weightToPercent( current_weight ) );
+ LLScrollingPanelParamBase::updatePanel(allow_modify);
+
mHintMin->requestUpdate( sUpdateDelayFrames++ );
mHintMax->requestUpdate( sUpdateDelayFrames++ );
-
- mAllowModify = allow_modify;
- getChildView("param slider")->setEnabled(mAllowModify);
getChildView("less")->setEnabled(mAllowModify);
getChildView("more")->setEnabled(mAllowModify);
}
@@ -135,13 +119,17 @@ void LLScrollingPanelParam::setVisible( BOOL visible )
if( getVisible() != visible )
{
LLPanel::setVisible( visible );
- mHintMin->setAllowsUpdates( visible );
- mHintMax->setAllowsUpdates( visible );
+ if (mHintMin)
+ mHintMin->setAllowsUpdates( visible );
+ if (mHintMax)
+ mHintMax->setAllowsUpdates( visible );
if( visible )
{
- mHintMin->setUpdateDelayFrames( sUpdateDelayFrames++ );
- mHintMax->setUpdateDelayFrames( sUpdateDelayFrames++ );
+ if (mHintMin)
+ mHintMin->setUpdateDelayFrames( sUpdateDelayFrames++ );
+ if (mHintMax)
+ mHintMax->setUpdateDelayFrames( sUpdateDelayFrames++ );
}
}
}
@@ -164,13 +152,17 @@ void LLScrollingPanelParam::draw()
getChildView("min param text")->setVisible( FALSE );
getChildView("max param text")->setVisible( FALSE );
LLPanel::draw();
+
+ // If we're in a focused floater, don't apply the floater's alpha to visual param hint,
+ // making its behavior similar to texture controls'.
+ F32 alpha = getTransparencyType() == TT_ACTIVE ? 1.0f : getCurrentTransparency();
// Draw the hints over the "less" and "more" buttons.
gGL.pushUIMatrix();
{
const LLRect& r = mHintMin->getRect();
gGL.translateUI((F32)r.mLeft, (F32)r.mBottom, 0.f);
- mHintMin->draw();
+ mHintMin->draw(alpha);
}
gGL.popUIMatrix();
@@ -178,7 +170,7 @@ void LLScrollingPanelParam::draw()
{
const LLRect& r = mHintMax->getRect();
gGL.translateUI((F32)r.mLeft, (F32)r.mBottom, 0.f);
- mHintMax->draw();
+ mHintMax->draw(alpha);
}
gGL.popUIMatrix();
@@ -192,23 +184,6 @@ void LLScrollingPanelParam::draw()
}
// static
-void LLScrollingPanelParam::onSliderMoved(LLUICtrl* ctrl, void* userdata)
-{
- LLSliderCtrl* slider = (LLSliderCtrl*) ctrl;
- LLScrollingPanelParam* self = (LLScrollingPanelParam*) userdata;
- LLViewerVisualParam* param = self->mParam;
-
- F32 current_weight = self->mWearable->getVisualParamWeight( param->getID() );
- F32 new_weight = self->percentToWeight( (F32)slider->getValue().asReal() );
- if (current_weight != new_weight )
- {
- self->mWearable->setVisualParamWeight( param->getID(), new_weight, FALSE );
- self->mWearable->writeToAvatar();
- gAgentAvatarp->updateVisualParams();
- }
-}
-
-// static
void LLScrollingPanelParam::onSliderMouseDown(LLUICtrl* ctrl, void* userdata)
{
}
@@ -217,7 +192,6 @@ void LLScrollingPanelParam::onSliderMouseDown(LLUICtrl* ctrl, void* userdata)
void LLScrollingPanelParam::onSliderMouseUp(LLUICtrl* ctrl, void* userdata)
{
LLScrollingPanelParam* self = (LLScrollingPanelParam*) userdata;
-
LLVisualParamHint::requestHintUpdates( self->mHintMin, self->mHintMax );
}
diff --git a/indra/newview/llscrollingpanelparam.h b/indra/newview/llscrollingpanelparam.h
index 1cbc64f45a..c7a47d5c7a 100644
--- a/indra/newview/llscrollingpanelparam.h
+++ b/indra/newview/llscrollingpanelparam.h
@@ -28,8 +28,7 @@
#ifndef LL_SCROLLINGPANELPARAM_H
#define LL_SCROLLINGPANELPARAM_H
-#include "llpanel.h"
-#include "llscrollingpanellist.h"
+#include "llscrollingpanelparambase.h"
class LLViewerJointMesh;
class LLViewerVisualParam;
@@ -38,11 +37,11 @@ class LLVisualParamHint;
class LLViewerVisualParam;
class LLJoint;
-class LLScrollingPanelParam : public LLScrollingPanel
+class LLScrollingPanelParam : public LLScrollingPanelParamBase
{
public:
LLScrollingPanelParam( const LLPanel::Params& panel_params,
- LLViewerJointMesh* mesh, LLViewerVisualParam* param, BOOL allow_modify, LLWearable* wearable, LLJoint* jointp );
+ LLViewerJointMesh* mesh, LLViewerVisualParam* param, BOOL allow_modify, LLWearable* wearable, LLJoint* jointp, BOOL use_hints = TRUE );
virtual ~LLScrollingPanelParam();
virtual void draw();
@@ -50,7 +49,6 @@ public:
virtual void updatePanel(BOOL allow_modify);
static void onSliderMouseDown(LLUICtrl* ctrl, void* userdata);
- static void onSliderMoved(LLUICtrl* ctrl, void* userdata);
static void onSliderMouseUp(LLUICtrl* ctrl, void* userdata);
static void onHintMinMouseDown(void* userdata);
@@ -74,7 +72,6 @@ public:
const static S32 PARAM_HINT_HEIGHT;
public:
- LLViewerVisualParam* mParam;
LLPointer<LLVisualParamHint> mHintMin;
LLPointer<LLVisualParamHint> mHintMax;
static S32 sUpdateDelayFrames;
@@ -82,9 +79,7 @@ public:
protected:
LLTimer mMouseDownTimer; // timer for how long mouse has been held down on a hint.
F32 mLastHeldTime;
-
BOOL mAllowModify;
- LLWearable *mWearable;
};
#endif
diff --git a/indra/newview/llscrollingpanelparambase.cpp b/indra/newview/llscrollingpanelparambase.cpp
new file mode 100644
index 0000000000..62e3039d2f
--- /dev/null
+++ b/indra/newview/llscrollingpanelparambase.cpp
@@ -0,0 +1,112 @@
+/**
+ * @file llscrollingpanelparam.cpp
+ * @brief UI panel for a list of visual param panels
+ *
+ * $LicenseInfo:firstyear=2009&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 "llscrollingpanelparambase.h"
+#include "llviewerjointmesh.h"
+#include "llviewervisualparam.h"
+#include "llwearable.h"
+#include "llviewervisualparam.h"
+#include "lltoolmorph.h"
+#include "lltrans.h"
+#include "llbutton.h"
+#include "llsliderctrl.h"
+#include "llagent.h"
+#include "llviewborder.h"
+#include "llvoavatarself.h"
+
+LLScrollingPanelParamBase::LLScrollingPanelParamBase( const LLPanel::Params& panel_params,
+ LLViewerJointMesh* mesh, LLViewerVisualParam* param, BOOL allow_modify, LLWearable* wearable, LLJoint* jointp, BOOL use_hints)
+ : LLScrollingPanel( panel_params ),
+ mParam(param),
+ mAllowModify(allow_modify),
+ mWearable(wearable)
+{
+ if (use_hints)
+ buildFromFile( "panel_scrolling_param.xml");
+ else
+ buildFromFile( "panel_scrolling_param_base.xml");
+
+ getChild<LLUICtrl>("param slider")->setValue(weightToPercent(param->getWeight()));
+
+ std::string display_name = LLTrans::getString(param->getDisplayName());
+ getChild<LLUICtrl>("param slider")->setLabelArg("[DESC]", display_name);
+ getChildView("param slider")->setEnabled(mAllowModify);
+ childSetCommitCallback("param slider", LLScrollingPanelParamBase::onSliderMoved, this);
+
+ setVisible(FALSE);
+ setBorderVisible( FALSE );
+}
+
+LLScrollingPanelParamBase::~LLScrollingPanelParamBase()
+{
+}
+
+void LLScrollingPanelParamBase::updatePanel(BOOL allow_modify)
+{
+ LLViewerVisualParam* param = mParam;
+
+ if (!mWearable)
+ {
+ // not editing a wearable just now, no update necessary
+ return;
+ }
+
+ F32 current_weight = mWearable->getVisualParamWeight( param->getID() );
+ getChild<LLUICtrl>("param slider")->setValue(weightToPercent( current_weight ) );
+ mAllowModify = allow_modify;
+ getChildView("param slider")->setEnabled(mAllowModify);
+}
+
+// static
+void LLScrollingPanelParamBase::onSliderMoved(LLUICtrl* ctrl, void* userdata)
+{
+ LLSliderCtrl* slider = (LLSliderCtrl*) ctrl;
+ LLScrollingPanelParamBase* self = (LLScrollingPanelParamBase*) userdata;
+ LLViewerVisualParam* param = self->mParam;
+
+ F32 current_weight = self->mWearable->getVisualParamWeight( param->getID() );
+ F32 new_weight = self->percentToWeight( (F32)slider->getValue().asReal() );
+ if (current_weight != new_weight )
+ {
+ self->mWearable->setVisualParamWeight( param->getID(), new_weight, FALSE );
+ self->mWearable->writeToAvatar();
+ gAgentAvatarp->updateVisualParams();
+ }
+}
+
+F32 LLScrollingPanelParamBase::weightToPercent( F32 weight )
+{
+ LLViewerVisualParam* param = mParam;
+ return (weight - param->getMinWeight()) / (param->getMaxWeight() - param->getMinWeight()) * 100.f;
+}
+
+F32 LLScrollingPanelParamBase::percentToWeight( F32 percent )
+{
+ LLViewerVisualParam* param = mParam;
+ return percent / 100.f * (param->getMaxWeight() - param->getMinWeight()) + param->getMinWeight();
+}
diff --git a/indra/newview/llscrollingpanelparambase.h b/indra/newview/llscrollingpanelparambase.h
new file mode 100644
index 0000000000..9538826251
--- /dev/null
+++ b/indra/newview/llscrollingpanelparambase.h
@@ -0,0 +1,62 @@
+/**
+ * @file llscrollingpanelparam.h
+ * @brief the scrolling panel containing a list of visual param
+ * panels
+ *
+ * $LicenseInfo:firstyear=2009&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_SCROLLINGPANELPARAMBASE_H
+#define LL_SCROLLINGPANELPARAMBASE_H
+
+#include "llpanel.h"
+#include "llscrollingpanellist.h"
+
+class LLViewerJointMesh;
+class LLViewerVisualParam;
+class LLWearable;
+class LLVisualParamHint;
+class LLViewerVisualParam;
+class LLJoint;
+
+class LLScrollingPanelParamBase : public LLScrollingPanel
+{
+public:
+ LLScrollingPanelParamBase( const LLPanel::Params& panel_params,
+ LLViewerJointMesh* mesh, LLViewerVisualParam* param, BOOL allow_modify, LLWearable* wearable, LLJoint* jointp, BOOL use_hints = FALSE );
+ virtual ~LLScrollingPanelParamBase();
+
+ virtual void updatePanel(BOOL allow_modify);
+
+ static void onSliderMoved(LLUICtrl* ctrl, void* userdata);
+
+ F32 weightToPercent( F32 weight );
+ F32 percentToWeight( F32 percent );
+
+public:
+ LLViewerVisualParam* mParam;
+protected:
+ BOOL mAllowModify;
+ LLWearable *mWearable;
+};
+
+#endif
diff --git a/indra/newview/llsearchcombobox.cpp b/indra/newview/llsearchcombobox.cpp
index db531b5695..6558c9a7fa 100644
--- a/indra/newview/llsearchcombobox.cpp
+++ b/indra/newview/llsearchcombobox.cpp
@@ -131,6 +131,9 @@ void LLSearchComboBox::focusTextEntry()
if (mTextEntry)
{
gFocusMgr.setKeyboardFocus(mTextEntry);
+
+ // Let the editor handle editing hotkeys (STORM-431).
+ LLEditMenuHandler::gEditMenuHandler = mTextEntry;
}
}
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index da891d1c51..9b264b81c7 100644
--- a/indra/newview/llselectmgr.cpp
+++ b/indra/newview/llselectmgr.cpp
@@ -64,7 +64,9 @@
#include "llhudmanager.h"
#include "llinventorymodel.h"
#include "llmenugl.h"
+#include "llmeshrepository.h"
#include "llmutelist.h"
+#include "llnotificationsutil.h"
#include "llsidepaneltaskinfo.h"
#include "llslurl.h"
#include "llstatusbar.h"
@@ -175,7 +177,6 @@ LLObjectSelection *get_null_object_selection()
// Build time optimization, generate this function once here
template class LLSelectMgr* LLSingleton<class LLSelectMgr>::getInstance();
-
//-----------------------------------------------------------------------------
// LLSelectMgr()
//-----------------------------------------------------------------------------
@@ -516,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
@@ -562,6 +561,103 @@ BOOL LLSelectMgr::removeObjectFromSelections(const LLUUID &id)
return object_found;
}
+bool LLSelectMgr::linkObjects()
+{
+ if (!LLSelectMgr::getInstance()->selectGetAllRootsValid())
+ {
+ LLNotificationsUtil::add("UnableToLinkWhileDownloading");
+ return true;
+ }
+
+ S32 object_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount();
+ if (object_count > MAX_CHILDREN_PER_TASK + 1)
+ {
+ LLSD args;
+ args["COUNT"] = llformat("%d", object_count);
+ int max = MAX_CHILDREN_PER_TASK+1;
+ args["MAX"] = llformat("%d", max);
+ LLNotificationsUtil::add("UnableToLinkObjects", args);
+ return true;
+ }
+
+ if (LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() < 2)
+ {
+ LLNotificationsUtil::add("CannotLinkIncompleteSet");
+ return true;
+ }
+
+ if (!LLSelectMgr::getInstance()->selectGetRootsModify())
+ {
+ LLNotificationsUtil::add("CannotLinkModify");
+ return true;
+ }
+
+ LLUUID owner_id;
+ std::string owner_name;
+ if (!LLSelectMgr::getInstance()->selectGetOwner(owner_id, owner_name))
+ {
+ // we don't actually care if you're the owner, but novices are
+ // the most likely to be stumped by this one, so offer the
+ // easiest and most likely solution.
+ LLNotificationsUtil::add("CannotLinkDifferentOwners");
+ return true;
+ }
+
+ LLSelectMgr::getInstance()->sendLink();
+
+ return true;
+}
+
+bool LLSelectMgr::unlinkObjects()
+{
+ LLSelectMgr::getInstance()->sendDelink();
+ return true;
+}
+
+// in order to link, all objects must have the same owner, and the
+// agent must have the ability to modify all of the objects. However,
+// we're not answering that question with this method. The question
+// we're answering is: does the user have a reasonable expectation
+// that a link operation should work? If so, return true, false
+// otherwise. this allows the handle_link method to more finely check
+// the selection and give an error message when the uer has a
+// reasonable expectation for the link to work, but it will fail.
+bool LLSelectMgr::enableLinkObjects()
+{
+ bool new_value = false;
+ // check if there are at least 2 objects selected, and that the
+ // user can modify at least one of the selected objects.
+
+ // in component mode, can't link
+ if (!gSavedSettings.getBOOL("EditLinkedParts"))
+ {
+ if(LLSelectMgr::getInstance()->selectGetAllRootsValid() && LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() >= 2)
+ {
+ struct f : public LLSelectedObjectFunctor
+ {
+ virtual bool apply(LLViewerObject* object)
+ {
+ return object->permModify();
+ }
+ } func;
+ const bool firstonly = true;
+ new_value = LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, firstonly);
+ }
+ }
+ return new_value;
+}
+
+bool LLSelectMgr::enableUnlinkObjects()
+{
+ LLViewerObject* first_editable_object = LLSelectMgr::getInstance()->getSelection()->getFirstEditableObject();
+
+ bool new_value = LLSelectMgr::getInstance()->selectGetAllRootsValid() &&
+ first_editable_object &&
+ !first_editable_object->isAttachment();
+
+ return new_value;
+}
+
void LLSelectMgr::deselectObjectAndFamily(LLViewerObject* object, BOOL send_to_sim, BOOL include_entire_object)
{
// bail if nothing selected or if object wasn't selected in the first place
@@ -1095,8 +1191,8 @@ void LLSelectMgr::getGrid(LLVector3& origin, LLQuaternion &rotation, LLVector3 &
mGridRotation = first_grid_object->getRenderRotation();
LLVector3 first_grid_obj_pos = first_grid_object->getRenderPosition();
- LLVector3 min_extents(F32_MAX, F32_MAX, F32_MAX);
- LLVector3 max_extents(-F32_MAX, -F32_MAX, -F32_MAX);
+ LLVector4a min_extents(F32_MAX);
+ LLVector4a max_extents(-F32_MAX);
BOOL grid_changed = FALSE;
for (LLObjectSelection::iterator iter = mGridObjects.begin();
iter != mGridObjects.end(); ++iter)
@@ -1105,7 +1201,7 @@ void LLSelectMgr::getGrid(LLVector3& origin, LLQuaternion &rotation, LLVector3 &
LLDrawable* drawable = object->mDrawable;
if (drawable)
{
- const LLVector3* ext = drawable->getSpatialExtents();
+ const LLVector4a* ext = drawable->getSpatialExtents();
update_min_max(min_extents, max_extents, ext[0]);
update_min_max(min_extents, max_extents, ext[1]);
grid_changed = TRUE;
@@ -1113,13 +1209,19 @@ void LLSelectMgr::getGrid(LLVector3& origin, LLQuaternion &rotation, LLVector3 &
}
if (grid_changed)
{
- mGridOrigin = lerp(min_extents, max_extents, 0.5f);
+ LLVector4a center, size;
+ center.setAdd(min_extents, max_extents);
+ center.mul(0.5f);
+ size.setSub(max_extents, min_extents);
+ size.mul(0.5f);
+
+ mGridOrigin.set(center.getF32ptr());
LLDrawable* drawable = first_grid_object->mDrawable;
if (drawable && drawable->isActive())
{
mGridOrigin = mGridOrigin * first_grid_object->getRenderMatrix();
}
- mGridScale = (max_extents - min_extents) * 0.5f;
+ mGridScale.set(size.getF32ptr());
}
}
else // GRID_MODE_WORLD or just plain default
@@ -1883,6 +1985,103 @@ BOOL LLSelectMgr::selectionGetGlow(F32 *glow)
return identical;
}
+
+void LLSelectMgr::selectionSetPhysicsType(U8 type)
+{
+ struct f : public LLSelectedObjectFunctor
+ {
+ U8 mType;
+ f(const U8& t) : mType(t) {}
+ virtual bool apply(LLViewerObject* object)
+ {
+ if (object->permModify())
+ {
+ object->setPhysicsShapeType(mType);
+ object->updateFlags();
+ }
+ return true;
+ }
+ } sendfunc(type);
+ getSelection()->applyToObjects(&sendfunc);
+}
+
+void LLSelectMgr::selectionSetFriction(F32 friction)
+{
+ struct f : public LLSelectedObjectFunctor
+ {
+ F32 mFriction;
+ f(const F32& friction) : mFriction(friction) {}
+ virtual bool apply(LLViewerObject* object)
+ {
+ if (object->permModify())
+ {
+ object->setPhysicsFriction(mFriction);
+ object->updateFlags();
+ }
+ return true;
+ }
+ } sendfunc(friction);
+ getSelection()->applyToObjects(&sendfunc);
+}
+
+void LLSelectMgr::selectionSetGravity(F32 gravity )
+{
+ struct f : public LLSelectedObjectFunctor
+ {
+ F32 mGravity;
+ f(const F32& gravity) : mGravity(gravity) {}
+ virtual bool apply(LLViewerObject* object)
+ {
+ if (object->permModify())
+ {
+ object->setPhysicsGravity(mGravity);
+ object->updateFlags();
+ }
+ return true;
+ }
+ } sendfunc(gravity);
+ getSelection()->applyToObjects(&sendfunc);
+}
+
+void LLSelectMgr::selectionSetDensity(F32 density )
+{
+ struct f : public LLSelectedObjectFunctor
+ {
+ F32 mDensity;
+ f(const F32& density ) : mDensity(density) {}
+ virtual bool apply(LLViewerObject* object)
+ {
+ if (object->permModify())
+ {
+ object->setPhysicsDensity(mDensity);
+ object->updateFlags();
+ }
+ return true;
+ }
+ } sendfunc(density);
+ getSelection()->applyToObjects(&sendfunc);
+}
+
+void LLSelectMgr::selectionSetRestitution(F32 restitution)
+{
+ struct f : public LLSelectedObjectFunctor
+ {
+ F32 mRestitution;
+ f(const F32& restitution ) : mRestitution(restitution) {}
+ virtual bool apply(LLViewerObject* object)
+ {
+ if (object->permModify())
+ {
+ object->setPhysicsRestitution(mRestitution);
+ object->updateFlags();
+ }
+ return true;
+ }
+ } sendfunc(restitution);
+ getSelection()->applyToObjects(&sendfunc);
+}
+
+
//-----------------------------------------------------------------------------
// selectionSetMaterial()
//-----------------------------------------------------------------------------
@@ -3532,7 +3731,7 @@ void LLSelectMgr::deselectAllIfTooFar()
{
if (mDebugSelectMgr)
{
- llinfos << "Selection manager: auto-deselecting, select_dist = " << fsqrtf(select_dist_sq) << llendl;
+ llinfos << "Selection manager: auto-deselecting, select_dist = " << (F32) sqrt(select_dist_sq) << llendl;
llinfos << "agent pos global = " << gAgent.getPositionGlobal() << llendl;
llinfos << "selection pos global = " << selectionCenter << llendl;
}
@@ -3701,6 +3900,26 @@ void LLSelectMgr::sendDelink()
return;
}
+ struct f : public LLSelectedObjectFunctor
+ { //on delink, any modifyable object should
+ f() {}
+
+ virtual bool apply(LLViewerObject* object)
+ {
+ if (object->permModify())
+ {
+ if (object->getPhysicsShapeType() == LLViewerObject::PHYSICS_SHAPE_NONE)
+ {
+ object->setPhysicsShapeType(LLViewerObject::PHYSICS_SHAPE_CONVEX_HULL);
+ object->updateFlags();
+ }
+ }
+ return true;
+ }
+ } sendfunc;
+ getSelection()->applyToObjects(&sendfunc);
+
+
// Delink needs to send individuals so you can unlink a single object from
// a linked set.
sendListToRegions(
@@ -3930,7 +4149,6 @@ void LLSelectMgr::selectionUpdateCastShadows(BOOL cast_shadows)
getSelection()->applyToObjects(&func);
}
-
//----------------------------------------------------------------------
// Helpful packing functions for sendObjectMessage()
//----------------------------------------------------------------------
@@ -4619,7 +4837,6 @@ void LLSelectMgr::processForceObjectSelect(LLMessageSystem* msg, void**)
LLSelectMgr::getInstance()->highlightObjectAndFamily(objects);
}
-
extern LLGLdouble gGLModelView[16];
void LLSelectMgr::updateSilhouettes()
@@ -5103,7 +5320,6 @@ LLSelectNode::LLSelectNode(const LLSelectNode& nodep)
mSilhouetteVertices = nodep.mSilhouetteVertices;
mSilhouetteNormals = nodep.mSilhouetteNormals;
- mSilhouetteSegments = nodep.mSilhouetteSegments;
mSilhouetteExists = nodep.mSilhouetteExists;
mObject = nodep.mObject;
@@ -5337,6 +5553,111 @@ BOOL LLSelectNode::allowOperationOnNode(PermissionBit op, U64 group_proxy_power)
return (mPermissions->allowOperationBy(op, proxy_agent_id, group_id));
}
+
+//helper function for pushing relevant vertices from drawable to GL
+void pushWireframe(LLDrawable* drawable)
+{
+ if (drawable->isState(LLDrawable::RIGGED))
+ { //render straight from rigged volume if this is a rigged attachment
+ LLVOVolume* vobj = drawable->getVOVolume();
+ if (vobj)
+ {
+ vobj->updateRiggedVolume();
+ LLRiggedVolume* rigged_volume = vobj->getRiggedVolume();
+ if (rigged_volume)
+ {
+ LLVertexBuffer::unbind();
+ gGL.pushMatrix();
+ glMultMatrixf((F32*) vobj->getRelativeXform().mMatrix);
+ for (S32 i = 0; i < rigged_volume->getNumVolumeFaces(); ++i)
+ {
+ const LLVolumeFace& face = rigged_volume->getVolumeFace(i);
+ glVertexPointer(3, GL_FLOAT, 16, face.mPositions);
+ glDrawElements(GL_TRIANGLES, face.mNumIndices, GL_UNSIGNED_SHORT, face.mIndices);
+ }
+ gGL.popMatrix();
+ }
+ }
+ }
+ else
+ {
+ for (S32 i = 0; i < drawable->getNumFaces(); ++i)
+ {
+ LLFace* face = drawable->getFace(i);
+ if (face->verify())
+ {
+ pushVerts(face, LLVertexBuffer::MAP_VERTEX);
+ }
+ }
+ }
+}
+
+void LLSelectNode::renderOneWireframe(const LLColor4& color)
+{
+ LLViewerObject* objectp = getObject();
+ if (!objectp)
+ {
+ return;
+ }
+
+ LLDrawable* drawable = objectp->mDrawable;
+ if(!drawable)
+ {
+ return;
+ }
+
+ glMatrixMode(GL_MODELVIEW);
+ gGL.pushMatrix();
+
+ BOOL is_hud_object = objectp->isHUDAttachment();
+
+ if (drawable->isActive())
+ {
+ glLoadMatrixd(gGLModelView);
+ glMultMatrixf((F32*) objectp->getRenderMatrix().mMatrix);
+ }
+ else if (!is_hud_object)
+ {
+ glLoadIdentity();
+ glMultMatrixd(gGLModelView);
+ LLVector3 trans = objectp->getRegion()->getOriginAgent();
+ glTranslatef(trans.mV[0], trans.mV[1], trans.mV[2]);
+ }
+
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+
+ if (LLSelectMgr::sRenderHiddenSelections) // && gFloaterTools && gFloaterTools->getVisible())
+ {
+ gGL.blendFunc(LLRender::BF_SOURCE_COLOR, LLRender::BF_ONE);
+ LLGLEnable fog(GL_FOG);
+ glFogi(GL_FOG_MODE, GL_LINEAR);
+ float d = (LLViewerCamera::getInstance()->getPointOfInterest()-LLViewerCamera::getInstance()->getOrigin()).magVec();
+ LLColor4 fogCol = color * (F32)llclamp((LLSelectMgr::getInstance()->getSelectionCenterGlobal()-gAgentCamera.getCameraPositionGlobal()).magVec()/(LLSelectMgr::getInstance()->getBBoxOfSelection().getExtentLocal().magVec()*4), 0.0, 1.0);
+ glFogf(GL_FOG_START, d);
+ glFogf(GL_FOG_END, d*(1 + (LLViewerCamera::getInstance()->getView() / LLViewerCamera::getInstance()->getDefaultFOV())));
+ glFogfv(GL_FOG_COLOR, fogCol.mV);
+
+ LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE, GL_GEQUAL);
+ gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
+ {
+ glColor4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], 0.4f);
+ pushWireframe(drawable);
+ }
+ }
+
+ gGL.flush();
+ gGL.setSceneBlendType(LLRender::BT_ALPHA);
+
+ glColor4f(color.mV[VRED]*2, color.mV[VGREEN]*2, color.mV[VBLUE]*2, LLSelectMgr::sHighlightAlpha*2);
+ LLGLEnable offset(GL_POLYGON_OFFSET_LINE);
+ glPolygonOffset(3.f, 3.f);
+ glLineWidth(3.f);
+ pushWireframe(drawable);
+ glLineWidth(1.f);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ gGL.popMatrix();
+}
+
//-----------------------------------------------------------------------------
// renderOneSilhouette()
//-----------------------------------------------------------------------------
@@ -5354,6 +5675,13 @@ void LLSelectNode::renderOneSilhouette(const LLColor4 &color)
return;
}
+ LLVOVolume* vobj = drawable->getVOVolume();
+ if (vobj && vobj->isMesh())
+ {
+ renderOneWireframe(color);
+ return;
+ }
+
if (!mSilhouetteExists)
{
return;
@@ -5418,17 +5746,15 @@ void LLSelectNode::renderOneSilhouette(const LLColor4 &color)
gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
gGL.begin(LLRender::LINES);
{
- S32 i = 0;
- for (S32 seg_num = 0; seg_num < (S32)mSilhouetteSegments.size(); seg_num++)
+ for(S32 i = 0; i < mSilhouetteVertices.size(); i += 2)
{
- for(; i < mSilhouetteSegments[seg_num]; i++)
- {
- u_coord += u_divisor * LLSelectMgr::sHighlightUScale;
-
- gGL.color4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], 0.4f);
- gGL.texCoord2f( u_coord, v_coord );
- gGL.vertex3fv( mSilhouetteVertices[i].mV );
- }
+ u_coord += u_divisor * LLSelectMgr::sHighlightUScale;
+ gGL.color4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], 0.4f);
+ gGL.texCoord2f( u_coord, v_coord );
+ gGL.vertex3fv( mSilhouetteVertices[i].mV);
+ u_coord += u_divisor * LLSelectMgr::sHighlightUScale;
+ gGL.texCoord2f( u_coord, v_coord );
+ gGL.vertex3fv(mSilhouetteVertices[i+1].mV);
}
}
gGL.end();
@@ -5439,51 +5765,50 @@ void LLSelectNode::renderOneSilhouette(const LLColor4 &color)
gGL.setSceneBlendType(LLRender::BT_ALPHA);
gGL.begin(LLRender::TRIANGLES);
{
- S32 i = 0;
- for (S32 seg_num = 0; seg_num < (S32)mSilhouetteSegments.size(); seg_num++)
+ for(S32 i = 0; i < mSilhouetteVertices.size(); i+=2)
{
- S32 first_i = i;
- LLVector3 v;
- LLVector2 t;
+ if (!mSilhouetteNormals[i].isFinite() ||
+ !mSilhouetteNormals[i+1].isFinite())
+ { //skip skewed segments
+ continue;
+ }
- for(; i < mSilhouetteSegments[seg_num]; i++)
- {
+ LLVector3 v[4];
+ LLVector2 tc[4];
+ v[0] = mSilhouetteVertices[i] + (mSilhouetteNormals[i] * silhouette_thickness);
+ tc[0].set(u_coord, v_coord + LLSelectMgr::sHighlightVScale);
- if (i == first_i) {
- LLVector3 vert = (mSilhouetteNormals[i]) * silhouette_thickness;
- vert += mSilhouetteVertices[i];
+ v[1] = mSilhouetteVertices[i];
+ tc[1].set(u_coord, v_coord);
- gGL.color4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], 0.0f); //LLSelectMgr::sHighlightAlpha);
- gGL.texCoord2f( u_coord, v_coord + LLSelectMgr::sHighlightVScale );
- gGL.vertex3fv( vert.mV );
-
- u_coord += u_divisor * LLSelectMgr::sHighlightUScale;
+ u_coord += u_divisor * LLSelectMgr::sHighlightUScale;
- gGL.color4f(color.mV[VRED]*2, color.mV[VGREEN]*2, color.mV[VBLUE]*2, LLSelectMgr::sHighlightAlpha*2);
- gGL.texCoord2f( u_coord, v_coord );
- gGL.vertex3fv( mSilhouetteVertices[i].mV );
+ v[2] = mSilhouetteVertices[i+1] + (mSilhouetteNormals[i+1] * silhouette_thickness);
+ tc[2].set(u_coord, v_coord + LLSelectMgr::sHighlightVScale);
+
+ v[3] = mSilhouetteVertices[i+1];
+ tc[3].set(u_coord,v_coord);
- v = mSilhouetteVertices[i];
- t = LLVector2(u_coord, v_coord);
- }
- else {
- LLVector3 vert = (mSilhouetteNormals[i]) * silhouette_thickness;
- vert += mSilhouetteVertices[i];
-
- gGL.color4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], 0.0f); //LLSelectMgr::sHighlightAlpha);
- gGL.texCoord2f( u_coord, v_coord + LLSelectMgr::sHighlightVScale );
- gGL.vertex3fv( vert.mV );
- gGL.vertex3fv( vert.mV );
-
- gGL.texCoord2fv(t.mV);
- u_coord += u_divisor * LLSelectMgr::sHighlightUScale;
- gGL.color4f(color.mV[VRED]*2, color.mV[VGREEN]*2, color.mV[VBLUE]*2, LLSelectMgr::sHighlightAlpha*2);
- gGL.vertex3fv(v.mV);
- gGL.texCoord2f( u_coord, v_coord );
- gGL.vertex3fv( mSilhouetteVertices[i].mV );
+ gGL.color4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], 0.0f); //LLSelectMgr::sHighlightAlpha);
+ gGL.texCoord2fv(tc[0].mV);
+ gGL.vertex3fv( v[0].mV );
+
+ gGL.color4f(color.mV[VRED]*2, color.mV[VGREEN]*2, color.mV[VBLUE]*2, LLSelectMgr::sHighlightAlpha*2);
+ gGL.texCoord2fv( tc[1].mV );
+ gGL.vertex3fv( v[1].mV );
- }
- }
+ gGL.color4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], 0.0f); //LLSelectMgr::sHighlightAlpha);
+ gGL.texCoord2fv( tc[2].mV );
+ gGL.vertex3fv( v[2].mV );
+
+ gGL.vertex3fv( v[2].mV );
+
+ gGL.color4f(color.mV[VRED]*2, color.mV[VGREEN]*2, color.mV[VBLUE]*2, LLSelectMgr::sHighlightAlpha*2);
+ gGL.texCoord2fv( tc[1].mV );
+ gGL.vertex3fv( v[1].mV );
+
+ gGL.texCoord2fv( tc[3].mV );
+ gGL.vertex3fv( v[3].mV );
}
}
gGL.end();
@@ -6051,9 +6376,178 @@ S32 LLObjectSelection::getObjectCount()
{
cleanupNodes();
S32 count = mList.size();
+
return count;
}
+F32 LLObjectSelection::getSelectedObjectCost()
+{
+ cleanupNodes();
+ F32 cost = 0.f;
+
+ for (list_t::iterator iter = mList.begin(); iter != mList.end(); ++iter)
+ {
+ LLSelectNode* node = *iter;
+ LLViewerObject* object = node->getObject();
+
+ if (object)
+ {
+ cost += object->getObjectCost();
+ }
+ }
+
+ return cost;
+}
+
+F32 LLObjectSelection::getSelectedLinksetCost()
+{
+ cleanupNodes();
+ F32 cost = 0.f;
+
+ std::set<LLViewerObject*> me_roots;
+
+ for (list_t::iterator iter = mList.begin(); iter != mList.end(); ++iter)
+ {
+ LLSelectNode* node = *iter;
+ LLViewerObject* object = node->getObject();
+
+ if (object)
+ {
+ LLViewerObject* root = static_cast<LLViewerObject*>(object->getRoot());
+ if (root)
+ {
+ if (me_roots.find(root) == me_roots.end())
+ {
+ me_roots.insert(root);
+ cost += root->getLinksetCost();
+ }
+ }
+ }
+ }
+
+ return cost;
+}
+
+F32 LLObjectSelection::getSelectedPhysicsCost()
+{
+ cleanupNodes();
+ F32 cost = 0.f;
+
+ for (list_t::iterator iter = mList.begin(); iter != mList.end(); ++iter)
+ {
+ LLSelectNode* node = *iter;
+ LLViewerObject* object = node->getObject();
+
+ if (object)
+ {
+ cost += object->getPhysicsCost();
+ }
+ }
+
+ return cost;
+}
+
+F32 LLObjectSelection::getSelectedLinksetPhysicsCost()
+{
+ cleanupNodes();
+ F32 cost = 0.f;
+
+ std::set<LLViewerObject*> me_roots;
+
+ for (list_t::iterator iter = mList.begin(); iter != mList.end(); ++iter)
+ {
+ LLSelectNode* node = *iter;
+ LLViewerObject* object = node->getObject();
+
+ if (object)
+ {
+ LLViewerObject* root = static_cast<LLViewerObject*>(object->getRoot());
+ if (root)
+ {
+ if (me_roots.find(root) == me_roots.end())
+ {
+ me_roots.insert(root);
+ cost += root->getLinksetPhysicsCost();
+ }
+ }
+ }
+ }
+
+ return cost;
+}
+
+F32 LLObjectSelection::getSelectedObjectStreamingCost(S32* total_bytes, S32* visible_bytes)
+{
+ F32 cost = 0.f;
+ for (list_t::iterator iter = mList.begin(); iter != mList.end(); ++iter)
+ {
+ LLSelectNode* node = *iter;
+ LLViewerObject* object = node->getObject();
+
+ if (object)
+ {
+ S32 bytes = 0;
+ S32 visible = 0;
+ cost += object->getStreamingCost(&bytes, &visible);
+
+ if (total_bytes)
+ {
+ *total_bytes += bytes;
+ }
+
+ if (visible_bytes)
+ {
+ *visible_bytes += visible;
+ }
+ }
+ }
+
+ return cost;
+}
+
+U32 LLObjectSelection::getSelectedObjectTriangleCount()
+{
+ U32 count = 0;
+ for (list_t::iterator iter = mList.begin(); iter != mList.end(); ++iter)
+ {
+ LLSelectNode* node = *iter;
+ LLViewerObject* object = node->getObject();
+
+ if (object)
+ {
+ count += object->getTriangleCount();
+ }
+ }
+
+ return count;
+}
+
+/*S32 LLObjectSelection::getSelectedObjectRenderCost()
+{
+ S32 cost = 0;
+ LLVOVolume::texture_cost_t textures;
+ for (list_t::iterator iter = mList.begin(); iter != mList.end(); ++iter)
+ {
+ LLSelectNode* node = *iter;
+ LLVOVolume* object = (LLVOVolume*)node->getObject();
+
+ if (object)
+ {
+ cost += object->getRenderCost(textures);
+ }
+
+ for (LLVOVolume::texture_cost_t::iterator iter = textures.begin(); iter != textures.end(); ++iter)
+ {
+ // add the cost of each individual texture in the linkset
+ cost += iter->second;
+ }
+ textures.clear();
+ }
+
+
+ return cost;
+}*/
+
//-----------------------------------------------------------------------------
// getTECount()
@@ -6472,26 +6966,27 @@ bool LLSelectMgr::selectionMove(const LLVector3& displ,
if (update_position)
{
// calculate the distance of the object closest to the camera origin
- F32 min_dist = 1e+30f;
+ F32 min_dist_squared = F32_MAX; // value will be overridden in the loop
+
LLVector3 obj_pos;
for (LLObjectSelection::root_iterator it = getSelection()->root_begin();
it != getSelection()->root_end(); ++it)
{
obj_pos = (*it)->getObject()->getPositionEdit();
- F32 obj_dist = dist_vec(obj_pos, LLViewerCamera::getInstance()->getOrigin());
- if (obj_dist < min_dist)
+ F32 obj_dist_squared = dist_vec_squared(obj_pos, LLViewerCamera::getInstance()->getOrigin());
+ if (obj_dist_squared < min_dist_squared)
{
- min_dist = obj_dist;
+ min_dist_squared = obj_dist_squared;
}
}
- // factor the distance inside the displacement vector. This will get us
+ // factor the distance into the displacement vector. This will get us
// equally visible movements for both close and far away selections.
- min_dist = sqrt(min_dist) / 2;
- displ_global.setVec(displ.mV[0]*min_dist,
- displ.mV[1]*min_dist,
- displ.mV[2]*min_dist);
+ F32 min_dist = sqrt((F32) sqrtf(min_dist_squared)) / 2;
+ displ_global.setVec(displ.mV[0] * min_dist,
+ displ.mV[1] * min_dist,
+ displ.mV[2] * min_dist);
// equates to: Displ_global = Displ * M_cam_axes_in_global_frame
displ_global = LLViewerCamera::getInstance()->rotateToAbsolute(displ_global);
diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h
index 7478ed5f9a..166616e13e 100644
--- a/indra/newview/llselectmgr.h
+++ b/indra/newview/llselectmgr.h
@@ -134,6 +134,7 @@ public:
BOOL isTESelected(S32 te_index);
S32 getLastSelectedTE();
S32 getTESelectMask() { return mTESelectMask; }
+ void renderOneWireframe(const LLColor4& color);
void renderOneSilhouette(const LLColor4 &color);
void setTransient(BOOL transient) { mTransient = transient; }
BOOL isTransient() { return mTransient; }
@@ -181,7 +182,6 @@ public:
std::vector<LLVector3> mTextureScaleRatios;
std::vector<LLVector3> mSilhouetteVertices; // array of vertices to render silhouette of object
std::vector<LLVector3> mSilhouetteNormals; // array of normals to render silhouette of object
- std::vector<S32> mSilhouetteSegments; // array of normals to render silhouette of object
BOOL mSilhouetteExists; // need to generate silhouette?
protected:
@@ -235,7 +235,7 @@ public:
{
bool operator()(LLSelectNode* node);
};
- typedef boost::filter_iterator<is_root, list_t::iterator > valid_root_iterator;
+ typedef boost::filter_iterator<is_valid_root, list_t::iterator > valid_root_iterator;
valid_root_iterator valid_root_begin() { return valid_root_iterator(mList.begin(), mList.end()); }
valid_root_iterator valid_root_end() { return valid_root_iterator(mList.end(), mList.end()); }
@@ -279,6 +279,15 @@ public:
// count members
S32 getObjectCount();
+ F32 getSelectedObjectCost();
+ F32 getSelectedLinksetCost();
+ F32 getSelectedPhysicsCost();
+ F32 getSelectedLinksetPhysicsCost();
+ S32 getSelectedObjectRenderCost();
+
+ F32 getSelectedObjectStreamingCost(S32* total_bytes = NULL, S32* visible_bytes = NULL);
+ U32 getSelectedObjectTriangleCount();
+
S32 getTECount();
S32 getRootObjectCount();
@@ -440,6 +449,17 @@ public:
BOOL removeObjectFromSelections(const LLUUID &id);
////////////////////////////////////////////////////////////////
+ // Selection editing
+ ////////////////////////////////////////////////////////////////
+ bool linkObjects();
+
+ bool unlinkObjects();
+
+ bool enableLinkObjects();
+
+ bool enableUnlinkObjects();
+
+ ////////////////////////////////////////////////////////////////
// Selection accessors
////////////////////////////////////////////////////////////////
LLObjectSelectionHandle getSelection() { return mSelectedObjects; }
@@ -489,6 +509,11 @@ public:
bool selectionGetIncludeInSearch(bool* include_in_search_out); // true if all selected objects have same
BOOL selectionGetGlow(F32 *glow);
+ void selectionSetPhysicsType(U8 type);
+ void selectionSetGravity(F32 gravity);
+ void selectionSetFriction(F32 friction);
+ void selectionSetDensity(F32 density);
+ void selectionSetRestitution(F32 restitution);
void selectionSetMaterial(U8 material);
void selectionSetImage(const LLUUID& imageid); // could be item or asset id
void selectionSetColor(const LLColor4 &color);
diff --git a/indra/newview/llshareavatarhandler.cpp b/indra/newview/llshareavatarhandler.cpp
new file mode 100644
index 0000000000..6b4f1d3dc6
--- /dev/null
+++ b/indra/newview/llshareavatarhandler.cpp
@@ -0,0 +1,67 @@
+/**
+ * @file llshareavatarhandler.cpp
+ * @brief slapp to handle sharing with an avatar
+ *
+ * $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 "llcommandhandler.h"
+#include "llavataractions.h"
+#include "llnotificationsutil.h"
+#include "llui.h"
+
+class LLShareWithAvatarHandler : public LLCommandHandler
+{
+public:
+ // requires trusted browser to trigger
+ LLShareWithAvatarHandler() : LLCommandHandler("sharewithavatar", UNTRUSTED_THROTTLE)
+ {
+ }
+
+ bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web)
+ {
+ if (!LLUI::sSettingGroups["config"]->getBOOL("EnableAvatarShare"))
+ {
+ LLNotificationsUtil::add("NoAvatarShare", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit"));
+ return true;
+ }
+
+ //Make sure we have some parameters
+ if (params.size() == 0)
+ {
+ return false;
+ }
+
+ //Get the ID
+ LLUUID id;
+ if (!id.set( params[0], FALSE ))
+ {
+ return false;
+ }
+
+ //instigate share with this avatar
+ LLAvatarActions::share( id );
+ return true;
+ }
+};
+LLShareWithAvatarHandler gShareWithAvatar;
diff --git a/indra/newview/llsidepanelappearance.cpp b/indra/newview/llsidepanelappearance.cpp
index 1999f14828..16729f045a 100644
--- a/indra/newview/llsidepanelappearance.cpp
+++ b/indra/newview/llsidepanelappearance.cpp
@@ -183,25 +183,38 @@ void LLSidepanelAppearance::onOpen(const LLSD& key)
void LLSidepanelAppearance::onVisibilityChange(const LLSD &new_visibility)
{
- updateToVisibility(new_visibility);
+ LLSD visibility;
+ visibility["visible"] = new_visibility.asBoolean();
+ visibility["reset_accordion"] = false;
+ updateToVisibility(visibility);
}
void LLSidepanelAppearance::updateToVisibility(const LLSD &new_visibility)
{
- if (new_visibility.asBoolean())
+ if (new_visibility["visible"].asBoolean())
{
- bool is_outfit_edit_visible = mOutfitEdit && mOutfitEdit->getVisible();
- bool is_wearable_edit_visible = mEditWearable && mEditWearable->getVisible();
+ const BOOL is_outfit_edit_visible = mOutfitEdit && mOutfitEdit->getVisible();
+ const BOOL is_wearable_edit_visible = mEditWearable && mEditWearable->getVisible();
if (is_outfit_edit_visible || is_wearable_edit_visible)
{
- if (!gAgentCamera.cameraCustomizeAvatar() && gSavedSettings.getBOOL("AppearanceCameraMovement"))
+ const LLWearable *wearable_ptr = mEditWearable->getWearable();
+ if (!wearable_ptr)
+ {
+ llwarns << "Visibility change to invalid wearable" << llendl;
+ return;
+ }
+ // Disable camera switch is currently just for WT_PHYSICS type since we don't want to freeze the avatar
+ // when editing its physics.
+ const BOOL disable_camera_motion = LLWearableType::getDisableCameraSwitch(wearable_ptr->getType());
+ if (!gAgentCamera.cameraCustomizeAvatar() &&
+ !disable_camera_motion &&
+ gSavedSettings.getBOOL("AppearanceCameraMovement"))
{
gAgentCamera.changeCameraToCustomizeAvatar();
}
if (is_wearable_edit_visible)
{
- LLWearable *wearable_ptr = mEditWearable->getWearable();
if (gAgentWearables.getWearableIndex(wearable_ptr) == LLAgentWearables::MAX_CLOTHING_PER_TYPE)
{
// we're no longer wearing the wearable we were last editing, switch back to outfit editor
@@ -209,7 +222,7 @@ void LLSidepanelAppearance::updateToVisibility(const LLSD &new_visibility)
}
}
- if (is_outfit_edit_visible)
+ if (is_outfit_edit_visible && new_visibility["reset_accordion"].asBoolean())
{
mOutfitEdit->resetAccordionState();
}
@@ -286,7 +299,7 @@ void LLSidepanelAppearance::showOutfitsInventoryPanel()
{
toggleWearableEditPanel(FALSE);
toggleOutfitEditPanel(FALSE);
- togglMyOutfitsPanel(TRUE);
+ toggleMyOutfitsPanel(TRUE);
}
void LLSidepanelAppearance::showOutfitEditPanel()
@@ -302,19 +315,28 @@ void LLSidepanelAppearance::showOutfitEditPanel()
mOutfitEdit->resetAccordionState();
}
- togglMyOutfitsPanel(FALSE);
+ // If we're exiting the edit wearable view, and the camera was not focused on the avatar
+ // (e.g. such as if we were editing a physics param), then skip the outfits edit mode since
+ // otherwise this would trigger the camera focus mode.
+ if (mEditWearable != NULL && mEditWearable->getVisible() && !gAgentCamera.cameraCustomizeAvatar())
+ {
+ showOutfitsInventoryPanel();
+ return;
+ }
+
+ toggleMyOutfitsPanel(FALSE);
toggleWearableEditPanel(FALSE, NULL, TRUE); // don't switch out of edit appearance mode
toggleOutfitEditPanel(TRUE);
}
-void LLSidepanelAppearance::showWearableEditPanel(LLWearable *wearable /* = NULL*/)
+void LLSidepanelAppearance::showWearableEditPanel(LLWearable *wearable /* = NULL*/, BOOL disable_camera_switch)
{
- togglMyOutfitsPanel(FALSE);
+ toggleMyOutfitsPanel(FALSE);
toggleOutfitEditPanel(FALSE, TRUE); // don't switch out of edit appearance mode
- toggleWearableEditPanel(TRUE, wearable);
+ toggleWearableEditPanel(TRUE, wearable, disable_camera_switch);
}
-void LLSidepanelAppearance::togglMyOutfitsPanel(BOOL visible)
+void LLSidepanelAppearance::toggleMyOutfitsPanel(BOOL visible)
{
if (!mPanelOutfitsInventory || mPanelOutfitsInventory->getVisible() == visible)
{
@@ -387,7 +409,7 @@ void LLSidepanelAppearance::toggleWearableEditPanel(BOOL visible, LLWearable *we
{
gAgentCamera.changeCameraToCustomizeAvatar();
}
- mEditWearable->setWearable(wearable);
+ mEditWearable->setWearable(wearable, disable_camera_switch);
mEditWearable->onOpen(LLSD()); // currently no-op, just for consistency
}
else
@@ -431,14 +453,14 @@ void LLSidepanelAppearance::refreshCurrentOutfitName(const std::string& name)
}
//static
-void LLSidepanelAppearance::editWearable(LLWearable *wearable, LLView *data)
+void LLSidepanelAppearance::editWearable(LLWearable *wearable, LLView *data, BOOL disable_camera_switch)
{
LLSideTray::getInstance()->showPanel("sidepanel_appearance");
LLSidepanelAppearance *panel = dynamic_cast<LLSidepanelAppearance*>(data);
if (panel)
{
- panel->showWearableEditPanel(wearable);
+ panel->showWearableEditPanel(wearable, disable_camera_switch);
}
}
diff --git a/indra/newview/llsidepanelappearance.h b/indra/newview/llsidepanelappearance.h
index 2a83dfbc9d..6dd3520266 100644
--- a/indra/newview/llsidepanelappearance.h
+++ b/indra/newview/llsidepanelappearance.h
@@ -51,7 +51,7 @@ public:
void refreshCurrentOutfitName(const std::string& name = "");
- static void editWearable(LLWearable *wearable, LLView *data);
+ static void editWearable(LLWearable *wearable, LLView *data, BOOL disable_camera_switch = FALSE);
void fetchInventory();
void inventoryFetched();
@@ -59,7 +59,7 @@ public:
void showOutfitsInventoryPanel();
void showOutfitEditPanel();
- void showWearableEditPanel(LLWearable *wearable = NULL);
+ void showWearableEditPanel(LLWearable *wearable = NULL, BOOL disable_camera_switch = FALSE);
void setWearablesLoading(bool val);
void showDefaultSubpart();
void updateScrollingPanelList();
@@ -72,7 +72,7 @@ private:
void onOpenOutfitButtonClicked();
void onEditAppearanceButtonClicked();
- void togglMyOutfitsPanel(BOOL visible);
+ void toggleMyOutfitsPanel(BOOL visible);
void toggleOutfitEditPanel(BOOL visible, BOOL disable_camera_switch = FALSE);
void toggleWearableEditPanel(BOOL visible, LLWearable* wearable = NULL, BOOL disable_camera_switch = FALSE);
diff --git a/indra/newview/llsidepaneliteminfo.cpp b/indra/newview/llsidepaneliteminfo.cpp
index f9c0fd398e..fbd2f7ca83 100644
--- a/indra/newview/llsidepaneliteminfo.cpp
+++ b/indra/newview/llsidepaneliteminfo.cpp
@@ -39,6 +39,7 @@
#include "llinventoryobserver.h"
#include "lllineeditor.h"
#include "llradiogroup.h"
+#include "llslurl.h"
#include "llviewercontrol.h"
#include "llviewerinventory.h"
#include "llviewerobjectlist.h"
@@ -68,10 +69,22 @@ private:
void LLItemPropertiesObserver::changed(U32 mask)
{
- // if there's a change we're interested in.
- if((mask & (LLInventoryObserver::LABEL | LLInventoryObserver::INTERNAL | LLInventoryObserver::REMOVE)) != 0)
+ const std::set<LLUUID>& mChangedItemIDs = gInventory.getChangedIDs();
+ std::set<LLUUID>::const_iterator it;
+
+ const LLUUID& item_id = mFloater->getItemID();
+
+ for (it = mChangedItemIDs.begin(); it != mChangedItemIDs.end(); it++)
{
- mFloater->dirty();
+ // set dirty for 'item profile panel' only if changed item is the item for which 'item profile panel' is shown (STORM-288)
+ if (*it == item_id)
+ {
+ // if there's a change we're interested in.
+ if((mask & (LLInventoryObserver::LABEL | LLInventoryObserver::INTERNAL | LLInventoryObserver::REMOVE)) != 0)
+ {
+ mFloater->dirty();
+ }
+ }
}
}
@@ -179,6 +192,16 @@ void LLSidepanelItemInfo::setItemID(const LLUUID& item_id)
mItemID = item_id;
}
+const LLUUID& LLSidepanelItemInfo::getObjectID() const
+{
+ return mObjectID;
+}
+
+const LLUUID& LLSidepanelItemInfo::getItemID() const
+{
+ return mItemID;
+}
+
void LLSidepanelItemInfo::reset()
{
LLSidepanelInventorySubpanel::reset();
diff --git a/indra/newview/llsidepaneliteminfo.h b/indra/newview/llsidepaneliteminfo.h
index 10e93dd7de..25be145f64 100644
--- a/indra/newview/llsidepaneliteminfo.h
+++ b/indra/newview/llsidepaneliteminfo.h
@@ -54,6 +54,9 @@ public:
void setItemID(const LLUUID& item_id);
void setEditMode(BOOL edit);
+ const LLUUID& getObjectID() const;
+ const LLUUID& getItemID() const;
+
protected:
/*virtual*/ void refresh();
/*virtual*/ void save();
diff --git a/indra/newview/llsidepaneltaskinfo.cpp b/indra/newview/llsidepaneltaskinfo.cpp
index 47d904dfcc..8774482acd 100644
--- a/indra/newview/llsidepaneltaskinfo.cpp
+++ b/indra/newview/llsidepaneltaskinfo.cpp
@@ -1120,17 +1120,17 @@ void LLSidepanelTaskInfo::updateVerbs()
*/
LLSafeHandle<LLObjectSelection> object_selection = LLSelectMgr::getInstance()->getSelection();
- const BOOL multi_select = (object_selection->getNumNodes() > 1);
+ const BOOL any_selected = (object_selection->getNumNodes() > 0);
- mOpenBtn->setVisible(!multi_select);
- mPayBtn->setVisible(!multi_select);
- mBuyBtn->setVisible(!multi_select);
- mDetailsBtn->setVisible(multi_select);
- mDetailsBtn->setEnabled(multi_select);
+ mOpenBtn->setVisible(true);
+ mPayBtn->setVisible(true);
+ mBuyBtn->setVisible(true);
+ mDetailsBtn->setVisible(true);
mOpenBtn->setEnabled(enable_object_open());
mPayBtn->setEnabled(enable_pay_object());
mBuyBtn->setEnabled(enable_buy_object());
+ mDetailsBtn->setEnabled(any_selected);
}
void LLSidepanelTaskInfo::onOpenButtonClicked()
diff --git a/indra/newview/llsidetray.cpp b/indra/newview/llsidetray.cpp
index 81b2fc0ae0..631b244785 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()
{
@@ -96,6 +100,7 @@ bool LLSideTray::instanceCreated ()
class LLSideTrayTab: public LLPanel
{
+ LOG_CLASS(LLSideTrayTab);
friend class LLUICtrlFactory;
friend class LLSideTray;
public:
@@ -118,7 +123,7 @@ public:
protected:
LLSideTrayTab(const Params& params);
- void dock();
+ void dock(LLFloater* floater_tab);
void undock(LLFloater* floater_tab);
LLSideTray* getSideTray();
@@ -139,7 +144,11 @@ public:
void onOpen (const LLSD& key);
- void toggleTabDocked();
+ void toggleTabDocked(bool toggle_floater = true);
+ void setDocked(bool dock);
+ bool isDocked() const;
+
+ BOOL handleScrollWheel(S32 x, S32 y, S32 clicks);
LLPanel *getPanel();
private:
@@ -159,8 +168,6 @@ LLSideTrayTab::LLSideTrayTab(const Params& p)
mDescription(p.description),
mMainPanel(NULL)
{
- // Necessary for focus movement among child controls
- setFocusRoot(TRUE);
}
LLSideTrayTab::~LLSideTrayTab()
@@ -186,8 +193,8 @@ BOOL LLSideTrayTab::postBuild()
title_panel->getChild<LLTextBox>(TAB_PANEL_CAPTION_TITLE_BOX)->setValue(mTabTitle);
- getChild<LLButton>("undock")->setCommitCallback(boost::bind(&LLSideTrayTab::toggleTabDocked, this));
- getChild<LLButton>("dock")->setCommitCallback(boost::bind(&LLSideTrayTab::toggleTabDocked, this));
+ getChild<LLButton>("undock")->setCommitCallback(boost::bind(&LLSideTrayTab::setDocked, this, false));
+ getChild<LLButton>("dock")->setCommitCallback(boost::bind(&LLSideTrayTab::setDocked, this, true));
return true;
}
@@ -243,14 +250,16 @@ LLSideTray* LLSideTrayTab::getSideTray()
return side_tray;
}
-void LLSideTrayTab::toggleTabDocked()
+void LLSideTrayTab::toggleTabDocked(bool toggle_floater /* = true */)
{
+ // *FIX: Calling this method twice per frame would crash the viewer.
+
std::string tab_name = getName();
LLFloater* floater_tab = LLFloaterReg::getInstance("side_bar_tab", tab_name);
if (!floater_tab) return;
- bool docking = LLFloater::isShown(floater_tab);
+ bool docking = !isDocked();
// Hide the "Tear Off" button when a tab gets undocked
// and show "Dock" button instead.
@@ -259,7 +268,7 @@ void LLSideTrayTab::toggleTabDocked()
if (docking)
{
- dock();
+ dock(floater_tab);
}
else
{
@@ -268,14 +277,46 @@ void LLSideTrayTab::toggleTabDocked()
// Open/close the floater *after* we reparent the tab panel,
// so that it doesn't receive redundant visibility change notifications.
- LLFloaterReg::toggleInstance("side_bar_tab", tab_name);
+ if (toggle_floater)
+ {
+ LLFloaterReg::toggleInstance("side_bar_tab", tab_name);
+ }
}
-void LLSideTrayTab::dock()
+// Same as toggleTabDocked() apart from making sure that we do exactly what we want.
+void LLSideTrayTab::setDocked(bool dock)
+{
+ if (isDocked() == dock)
+ {
+ llwarns << "Tab " << getName() << " is already " << (dock ? "docked" : "undocked") << llendl;
+ return;
+ }
+
+ toggleTabDocked();
+}
+
+bool LLSideTrayTab::isDocked() const
+{
+ return dynamic_cast<LLSideTray*>(getParent()) != NULL;
+}
+
+BOOL LLSideTrayTab::handleScrollWheel(S32 x, S32 y, S32 clicks)
+{
+ // Let children handle the event
+ LLUICtrl::handleScrollWheel(x, y, clicks);
+
+ // and then eat it to prevent in-world scrolling (STORM-351).
+ return TRUE;
+}
+
+void LLSideTrayTab::dock(LLFloater* floater_tab)
{
LLSideTray* side_tray = getSideTray();
if (!side_tray) return;
+ // Before docking the tab, reset its (and its children's) transparency to default (STORM-688).
+ floater_tab->updateTransparency(TT_DEFAULT);
+
if (!side_tray->addTab(this))
{
llwarns << "Failed to add tab " << getName() << " to side tray" << llendl;
@@ -298,7 +339,11 @@ static void on_minimize(LLSidepanelAppearance* panel, LLSD minimized)
{
if (!panel) return;
bool visible = !minimized.asBoolean();
- panel->updateToVisibility(LLSD(visible));
+ LLSD visibility;
+ visibility["visible"] = visible;
+ // Do not reset accordion state on minimize (STORM-375)
+ visibility["reset_accordion"] = false;
+ panel->updateToVisibility(visibility);
}
void LLSideTrayTab::undock(LLFloater* floater_tab)
@@ -401,6 +446,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.
@@ -448,7 +498,7 @@ public:
LLSideTrayTab* tab = side_tray->getTab(getName());
if (!tab) return FALSE;
- tab->toggleTabDocked();
+ tab->setDocked(false);
LLFloater* floater_tab = LLFloaterReg::getInstance("side_bar_tab", tab->getName());
if (!floater_tab) return FALSE;
@@ -493,8 +543,8 @@ private:
LLSideTray::Params::Params()
: collapsed("collapsed",false),
- tab_btn_image_normal("tab_btn_image",LLUI::getUIImage("sidebar_tab_left.tga")),
- tab_btn_image_selected("tab_btn_image_selected",LLUI::getUIImage("button_enabled_selected_32x128.tga")),
+ tab_btn_image_normal("tab_btn_image",LLUI::getUIImage("taskpanel/TaskPanel_Tab_Off.png")),
+ tab_btn_image_selected("tab_btn_image_selected",LLUI::getUIImage("taskpanel/TaskPanel_Tab_Selected.png")),
default_button_width("tab_btn_width",32),
default_button_height("tab_btn_height",32),
default_button_margin("tab_btn_margin",0)
@@ -514,6 +564,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)
@@ -556,7 +608,7 @@ BOOL LLSideTray::postBuild()
{
if ((*it).channel)
{
- getCollapseSignal().connect(boost::bind(&LLScreenChannelBase::resetPositionAndSize, (*it).channel, _2));
+ setVisibleWidthChangeCallback(boost::bind(&LLScreenChannelBase::resetPositionAndSize, (*it).channel));
}
}
@@ -613,8 +665,16 @@ LLPanel* LLSideTray::openChildPanel(LLSideTrayTab* tab, const std::string& panel
std::string tab_name = tab->getName();
+ bool tab_attached = isTabAttached(tab_name);
+
+ if (tab_attached && LLUI::sSettingGroups["config"]->getBOOL("OpenSidePanelsInFloaters"))
+ {
+ tab->setDocked(false);
+ tab_attached = false;
+ }
+
// Select tab and expand Side Tray only when a tab is attached.
- if (isTabAttached(tab_name))
+ if (tab_attached)
{
selectTabByName(tab_name);
if (mCollapsed)
@@ -625,14 +685,7 @@ LLPanel* LLSideTray::openChildPanel(LLSideTrayTab* tab, const std::string& panel
LLFloater* floater_tab = LLFloaterReg::getInstance("side_bar_tab", tab_name);
if (!floater_tab) return NULL;
- // Restore the floater if it was minimized.
- if (floater_tab->isMinimized())
- {
- floater_tab->setMinimized(FALSE);
- }
-
- // Send the floater to the front.
- floater_tab->setFrontmost();
+ floater_tab->openFloater(tab_name);
}
LLSideTrayPanelContainer* container = dynamic_cast<LLSideTrayPanelContainer*>(view->getParent());
@@ -910,7 +963,6 @@ void LLSideTray::createButtons ()
}
}
LLHints::registerHintTarget("inventory_btn", mTabButtons["sidebar_inventory"]->getHandle());
- LLHints::registerHintTarget("dest_guide_btn", mTabButtons["sidebar_places"]->getHandle());
}
void LLSideTray::processTriState ()
@@ -964,21 +1016,9 @@ void LLSideTray::reflectCollapseChange()
{
updateSidetrayVisibility();
- if(mCollapsed)
- {
- gFloaterView->setSnapOffsetRight(0);
- setFocus(FALSE);
- }
- else
- {
- gFloaterView->setSnapOffsetRight(getRect().getWidth());
- setFocus(TRUE);
- }
+ setFocus(!mCollapsed);
gFloaterView->refresh();
-
- LLSD new_value = mCollapsed;
- mCollapseSignal(this,new_value);
}
void LLSideTray::arrange()
@@ -1028,7 +1068,8 @@ void LLSideTray::arrange()
}
// The tab buttons should be shown only if there is at least one non-detached tab.
- mButtonsPanel->setVisible(hasTabs());
+ // Also hide them in mouse-look mode.
+ mButtonsPanel->setVisible(hasTabs() && !gAgentCamera.cameraMouselook());
}
// Detach those tabs that were detached when the viewer exited last time.
@@ -1049,7 +1090,7 @@ void LLSideTray::detachTabs()
if (!is_visible) continue;
llassert(isTabAttached(tab->getName()));
- tab->toggleTabDocked();
+ tab->setDocked(false);
}
}
@@ -1139,6 +1180,38 @@ void LLSideTray::reshape(S32 width, S32 height, BOOL called_from_parent)
arrange();
}
+// This is just LLView::findChildView specialized to restrict the search to LLPanels.
+// Optimization for EXT-4068 to avoid searching down to the individual item level
+// when inventories are large.
+LLPanel *findChildPanel(LLPanel *panel, const std::string& name, bool recurse)
+{
+ for (LLView::child_list_const_iter_t child_it = panel->beginChild();
+ child_it != panel->endChild(); ++child_it)
+ {
+ LLPanel *child_panel = dynamic_cast<LLPanel*>(*child_it);
+ if (!child_panel)
+ continue;
+ if (child_panel->getName() == name)
+ return child_panel;
+ }
+ if (recurse)
+ {
+ for (LLView::child_list_const_iter_t child_it = panel->beginChild();
+ child_it != panel->endChild(); ++child_it)
+ {
+ LLPanel *child_panel = dynamic_cast<LLPanel*>(*child_it);
+ if (!child_panel)
+ continue;
+ LLPanel *found_panel = findChildPanel(child_panel,name,recurse);
+ if (found_panel)
+ {
+ return found_panel;
+ }
+ }
+ }
+ return NULL;
+}
+
/**
* Activate tab with "panel_name" panel
* if no such tab - return false, otherwise true.
@@ -1148,21 +1221,68 @@ void LLSideTray::reshape(S32 width, S32 height, BOOL called_from_parent)
*/
LLPanel* LLSideTray::showPanel (const std::string& panel_name, const LLSD& params)
{
+ LLPanel* new_panel = NULL;
+
// Look up the tab in the list of detached tabs.
child_vector_const_iter_t child_it;
for ( child_it = mDetachedTabs.begin(); child_it != mDetachedTabs.end(); ++child_it)
{
- LLPanel* panel = openChildPanel(*child_it, panel_name, params);
- if (panel) return panel;
- }
+ new_panel = openChildPanel(*child_it, panel_name, params);
+ if (new_panel) break;
+ }
// Look up the tab in the list of attached tabs.
for ( child_it = mTabs.begin(); child_it != mTabs.end(); ++child_it)
+ {
+ new_panel = openChildPanel(*child_it, panel_name, params);
+ if (new_panel) break;
+ }
+
+ return new_panel;
+}
+
+bool LLSideTray::hidePanel(const std::string& panel_name)
+{
+ bool panelHidden = false;
+
+ LLPanel* panelp = getPanel(panel_name);
+
+ if (panelp)
+ {
+ LLView* parentp = panelp->getParent();
+
+ // Collapse the side bar if the panel or the panel's parent is an attached tab
+ if (isTabAttached(panel_name) || (parentp && isTabAttached(parentp->getName())))
+ {
+ collapseSideBar();
+ panelHidden = true;
+ }
+ else
+ {
+ panelHidden = LLFloaterReg::hideInstance("side_bar_tab", panel_name);
+
+ if (!panelHidden)
{
- LLPanel* panel = openChildPanel(*child_it, panel_name, params);
- if (panel) return panel;
+ // Look up the panel in the list of detached tabs.
+ for (child_vector_const_iter_t child_it = mDetachedTabs.begin(); child_it != mDetachedTabs.end(); ++child_it)
+ {
+ LLPanel *detached_panel = dynamic_cast<LLPanel*>(*child_it);
+
+ if (detached_panel)
+ {
+ // Hide this detached panel if it is a parent of our panel
+ if (findChildPanel(detached_panel, panel_name, true) != NULL)
+ {
+ panelHidden = LLFloaterReg::hideInstance("side_bar_tab", detached_panel->getName());
+ break;
+ }
+ }
+ }
+ }
+ }
}
- return NULL;
+
+ return panelHidden;
}
void LLSideTray::togglePanel(LLPanel* &sub_panel, const std::string& panel_name, const LLSD& params)
@@ -1182,38 +1302,6 @@ void LLSideTray::togglePanel(LLPanel* &sub_panel, const std::string& panel_name,
}
}
-// This is just LLView::findChildView specialized to restrict the search to LLPanels.
-// Optimization for EXT-4068 to avoid searching down to the individual item level
-// when inventories are large.
-LLPanel *findChildPanel(LLPanel *panel, const std::string& name, bool recurse)
-{
- for (LLView::child_list_const_iter_t child_it = panel->beginChild();
- child_it != panel->endChild(); ++child_it)
- {
- LLPanel *child_panel = dynamic_cast<LLPanel*>(*child_it);
- if (!child_panel)
- continue;
- if (child_panel->getName() == name)
- return child_panel;
- }
- if (recurse)
- {
- for (LLView::child_list_const_iter_t child_it = panel->beginChild();
- child_it != panel->endChild(); ++child_it)
- {
- LLPanel *child_panel = dynamic_cast<LLPanel*>(*child_it);
- if (!child_panel)
- continue;
- LLPanel *found_panel = findChildPanel(child_panel,name,recurse);
- if (found_panel)
- {
- return found_panel;
- }
- }
- }
- return NULL;
-}
-
LLPanel* LLSideTray::getPanel(const std::string& panel_name)
{
// Look up the panel in the list of detached tabs.
@@ -1254,12 +1342,61 @@ bool LLSideTray::isPanelActive(const std::string& panel_name)
return (panel->getName() == panel_name);
}
+void LLSideTray::setTabDocked(const std::string& tab_name, bool dock, bool toggle_floater /* = true*/)
+{
+ // Lookup tab by name.
+ LLSideTrayTab* tab = getTab(tab_name);
+ if (!tab)
+ { // not a docked tab, look through detached tabs
+ for(child_vector_iter_t tab_it = mDetachedTabs.begin(), tab_end_it = mDetachedTabs.end();
+ tab_it != tab_end_it;
+ ++tab_it)
+ {
+ if ((*tab_it)->getName() == tab_name)
+ {
+ tab = *tab_it;
+ break;
+ }
+ }
+
+ }
+
+ llassert(tab != NULL);
+
+ // Toggle its dock state.
+ if (tab && tab->isDocked() != dock)
+ {
+ tab->toggleTabDocked(toggle_floater);
+ }
+}
+
+
void LLSideTray::updateSidetrayVisibility()
{
// set visibility of parent container based on collapsed state
- if (getParent())
+ LLView* parent = getParent();
+ if (parent)
{
- getParent()->setVisible(!mCollapsed && !gAgentCamera.cameraMouselook());
+ bool old_visibility = parent->getVisible();
+ bool new_visibility = !mCollapsed && !gAgentCamera.cameraMouselook();
+
+ if (old_visibility != new_visibility)
+ {
+ parent->setVisible(new_visibility);
+
+ // Signal change of visible width.
+ llinfos << "Visible: " << new_visibility << llendl;
+ mVisibleWidthChangeSignal(this, new_visibility);
+ }
}
}
+S32 LLSideTray::getVisibleWidth()
+{
+ return (isInVisibleChain() && !mCollapsed) ? getRect().getWidth() : 0;
+}
+
+void LLSideTray::setVisibleWidthChangeCallback(const commit_signal_t::slot_type& cb)
+{
+ mVisibleWidthChangeSignal.connect(cb);
+}
diff --git a/indra/newview/llsidetray.h b/indra/newview/llsidetray.h
index 4c23a1920b..24882411f4 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.
@@ -40,6 +47,8 @@ class LLSideTray : public LLPanel, private LLDestroyClass<LLSideTray>
{
friend class LLUICtrlFactory;
friend class LLDestroyClass<LLSideTray>;
+ friend class LLSideTrayTab;
+ friend class LLSideTrayButton;
public:
LOG_CLASS(LLSideTray);
@@ -95,6 +104,8 @@ public:
*/
LLPanel* showPanel (const std::string& panel_name, const LLSD& params = LLSD());
+ bool hidePanel (const std::string& panel_name);
+
/**
* Toggling Side Tray tab which contains "sub_panel" child of "panel_name" panel.
* If "sub_panel" is not visible Side Tray is opened to display it,
@@ -110,6 +121,8 @@ public:
LLPanel* getActivePanel ();
bool isPanelActive (const std::string& panel_name);
+ void setTabDocked(const std::string& tab_name, bool dock, bool toggle_floater = true);
+
/*
* get the panel of given type T (don't show it or do anything else with it)
*/
@@ -126,11 +139,6 @@ public:
}
/*
- * get currently active tab
- */
- const LLSideTrayTab* getActiveTab() const { return mActiveTab; }
-
- /*
* collapse SideBar, hiding visible tab and moving tab buttons
* to the right corner of the screen
*/
@@ -163,32 +171,37 @@ public:
virtual BOOL postBuild();
- void onTabButtonClick(std::string name);
- void onToggleCollapse();
-
- bool addChild (LLView* view, S32 tab_group);
- bool removeTab (LLSideTrayTab* tab); // Used to detach tabs temporarily
- bool addTab (LLSideTrayTab* tab); // Used to re-attach tabs
-
BOOL handleMouseDown (S32 x, S32 y, MASK mask);
void reshape (S32 width, S32 height, BOOL called_from_parent = TRUE);
- void processTriState ();
-
- void updateSidetrayVisibility();
- commit_signal_t& getCollapseSignal() { return mCollapseSignal; }
+ /**
+ * @return side tray width if it's visible and expanded, 0 otherwise.
+ *
+ * Not that width of the tab buttons is not included.
+ *
+ * @see setVisibleWidthChangeCallback()
+ */
+ S32 getVisibleWidth();
+
+ void setVisibleWidthChangeCallback(const commit_signal_t::slot_type& cb);
- void handleLoginComplete();
+ void updateSidetrayVisibility();
- LLSideTrayTab* getTab (const std::string& name);
+ void handleLoginComplete();
bool isTabAttached (const std::string& name);
protected:
+ bool addChild (LLView* view, S32 tab_group);
+ bool removeTab (LLSideTrayTab* tab); // Used to detach tabs temporarily
+ bool addTab (LLSideTrayTab* tab); // Used to re-attach tabs
bool hasTabs ();
+ const LLSideTrayTab* getActiveTab() const { return mActiveTab; }
+ LLSideTrayTab* getTab(const std::string& name);
+
void createButtons ();
LLButton* createButton (const std::string& name,const std::string& image,const std::string& tooltip,
@@ -196,11 +209,15 @@ protected:
void arrange ();
void detachTabs ();
void reflectCollapseChange();
+ void processTriState ();
void toggleTabButton (LLSideTrayTab* tab);
LLPanel* openChildPanel (LLSideTrayTab* tab, const std::string& panel_name, const LLSD& params);
+ void onTabButtonClick(std::string name);
+ void onToggleCollapse();
+
private:
// Implementation of LLDestroyClass<LLSideTray>
static void destroyClass()
@@ -209,8 +226,11 @@ private:
if (LLSideTray::instanceCreated())
LLSideTray::getInstance()->setEnabled(FALSE);
}
-
+
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;
@@ -219,7 +239,7 @@ private:
tab_order_vector_t mOriginalTabOrder;
LLSideTrayTab* mActiveTab;
- commit_signal_t mCollapseSignal;
+ commit_signal_t mVisibleWidthChangeSignal;
LLButton* mCollapseButton;
bool mCollapsed;
diff --git a/indra/newview/llsidetraylistener.cpp b/indra/newview/llsidetraylistener.cpp
new file mode 100644
index 0000000000..cd6fa28948
--- /dev/null
+++ b/indra/newview/llsidetraylistener.cpp
@@ -0,0 +1,179 @@
+/**
+ * @file llsidetraylistener.cpp
+ * @author Nat Goodspeed
+ * @date 2011-02-15
+ * @brief Implementation for llsidetraylistener.
+ *
+ * $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$
+ */
+
+// 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..51e2137762
--- /dev/null
+++ b/indra/newview/llsidetraylistener.h
@@ -0,0 +1,53 @@
+/**
+ * @file llsidetraylistener.h
+ * @author Nat Goodspeed
+ * @date 2011-02-15
+ * @brief
+ *
+ * $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$
+ */
+
+#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/llsimplestat.h b/indra/newview/llsimplestat.h
new file mode 100644
index 0000000000..9d7780c4f9
--- /dev/null
+++ b/indra/newview/llsimplestat.h
@@ -0,0 +1,152 @@
+/**
+ * @file llsimplestat.h
+ * @brief Runtime statistics accumulation.
+ *
+ * $LicenseInfo:firstyear=2010&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_SIMPLESTAT_H
+#define LL_SIMPLESTAT_H
+
+// History
+//
+// The original source for this code is the server repositories'
+// llcommon/llstat.h file. This particular code was added after the
+// viewer/server code schism but before the effort to convert common
+// code to libraries was complete. Rather than add to merge issues,
+// the needed code was cut'n'pasted into this new header as it isn't
+// too awful a burden. Post-modularization, we can look at removing
+// this redundancy.
+
+
+/**
+ * @class LLSimpleStatCounter
+ * @brief Just counts events.
+ *
+ * Really not needed but have a pattern in mind in the future.
+ * Interface limits what can be done at that's just fine.
+ *
+ * *TODO: Update/transfer unit tests
+ * Unit tests: indra/test/llcommon_llstat_tut.cpp
+ */
+class LLSimpleStatCounter
+{
+public:
+ inline LLSimpleStatCounter() { reset(); }
+ // Default destructor and assignment operator are valid
+
+ inline void reset() { mCount = 0; }
+
+ inline void merge(const LLSimpleStatCounter & src)
+ { mCount += src.mCount; }
+
+ inline U32 operator++() { return ++mCount; }
+
+ inline U32 getCount() const { return mCount; }
+
+protected:
+ U32 mCount;
+};
+
+
+/**
+ * @class LLSimpleStatMMM
+ * @brief Templated collector of min, max and mean data for stats.
+ *
+ * Fed a stream of data samples, keeps a running account of the
+ * min, max and mean seen since construction or the last reset()
+ * call. A freshly-constructed or reset instance returns counts
+ * and values of zero.
+ *
+ * Overflows and underflows (integer, inf or -inf) and NaN's
+ * are the caller's problem. As is loss of precision when
+ * the running sum's exponent (when parameterized by a floating
+ * point of some type) differs from a given data sample's.
+ *
+ * Unit tests: indra/test/llcommon_llstat_tut.cpp
+ */
+template <typename VALUE_T = F32>
+class LLSimpleStatMMM
+{
+public:
+ typedef VALUE_T Value;
+
+public:
+ LLSimpleStatMMM() { reset(); }
+ // Default destructor and assignment operator are valid
+
+ /**
+ * Resets the object returning all counts and derived
+ * values back to zero.
+ */
+ void reset()
+ {
+ mCount = 0;
+ mMin = Value(0);
+ mMax = Value(0);
+ mTotal = Value(0);
+ }
+
+ void record(Value v)
+ {
+ if (mCount)
+ {
+ mMin = llmin(mMin, v);
+ mMax = llmax(mMax, v);
+ }
+ else
+ {
+ mMin = v;
+ mMax = v;
+ }
+ mTotal += v;
+ ++mCount;
+ }
+
+ void merge(const LLSimpleStatMMM<VALUE_T> & src)
+ {
+ if (! mCount)
+ {
+ *this = src;
+ }
+ else if (src.mCount)
+ {
+ mMin = llmin(mMin, src.mMin);
+ mMax = llmax(mMax, src.mMax);
+ mCount += src.mCount;
+ mTotal += src.mTotal;
+ }
+ }
+
+ inline U32 getCount() const { return mCount; }
+ inline Value getMin() const { return mMin; }
+ inline Value getMax() const { return mMax; }
+ inline Value getMean() const { return mCount ? mTotal / mCount : mTotal; }
+
+protected:
+ U32 mCount;
+ Value mMin;
+ Value mMax;
+ Value mTotal;
+};
+
+#endif // LL_SIMPLESTAT_H
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index fb984a7c62..fa329eb0ae 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -32,15 +32,19 @@
#include "llviewerobjectlist.h"
#include "llvovolume.h"
#include "llvolume.h"
+#include "llvolumeoctree.h"
#include "llviewercamera.h"
#include "llface.h"
#include "llviewercontrol.h"
#include "llviewerregion.h"
#include "llcamera.h"
#include "pipeline.h"
+#include "llmeshrepository.h"
#include "llrender.h"
#include "lloctree.h"
+#include "llphysicsshapebuilderutil.h"
#include "llvoavatar.h"
+#include "llvolumemgr.h"
#include "lltextureatlas.h"
static LLFastTimer::DeclareTimer FTM_FRUSTUM_CULL("Frustum Culling");
@@ -60,6 +64,12 @@ const F32 SG_OCCLUSION_FUDGE = 0.25f;
static U32 sZombieGroups = 0;
U32 LLSpatialGroup::sNodeCount = 0;
+
+#define LL_TRACK_PENDING_OCCLUSION_QUERIES 0
+
+std::set<GLuint> LLSpatialGroup::sPendingQueries;
+
+
BOOL LLSpatialGroup::sNoDelete = FALSE;
static F32 sLastMaxTexPriority = 1.f;
@@ -77,6 +87,9 @@ protected:
virtual void releaseName(GLuint name)
{
+#if LL_TRACK_PENDING_OCCLUSION_QUERIES
+ LLSpatialGroup::sPendingQueries.erase(name);
+#endif
glDeleteQueriesARB(1, &name);
}
};
@@ -95,23 +108,6 @@ void sg_assert(BOOL expr)
#endif
}
-#if LL_DEBUG
-void validate_drawable(LLDrawable* drawablep)
-{
- F64 rad = drawablep->getBinRadius();
- const LLVector3* ext = drawablep->getSpatialExtents();
-
- if (rad < 0 || rad > 4096 ||
- (ext[1]-ext[0]).magVec() > 4096)
- {
- llwarns << "Invalid drawable found in octree." << llendl;
- }
-}
-#else
-#define validate_drawable(x)
-#endif
-
-
S32 AABBSphereIntersect(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &rad)
{
return AABBSphereIntersectR2(min, max, origin, rad*rad);
@@ -151,6 +147,55 @@ S32 AABBSphereIntersectR2(const LLVector3& min, const LLVector3& max, const LLVe
}
+S32 AABBSphereIntersect(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &rad)
+{
+ return AABBSphereIntersectR2(min, max, origin, rad*rad);
+}
+
+S32 AABBSphereIntersectR2(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &r)
+{
+ F32 d = 0.f;
+ F32 t;
+
+ LLVector4a origina;
+ origina.load3(origin.mV);
+
+ LLVector4a v;
+ v.setSub(min, origina);
+
+ if (v.dot3(v) < r)
+ {
+ v.setSub(max, origina);
+ if (v.dot3(v) < r)
+ {
+ return 2;
+ }
+ }
+
+
+ for (U32 i = 0; i < 3; i++)
+ {
+ if (origin.mV[i] < min[i])
+ {
+ t = min[i] - origin.mV[i];
+ d += t*t;
+ }
+ else if (origin.mV[i] > max[i])
+ {
+ t = origin.mV[i] - max[i];
+ d += t*t;
+ }
+
+ if (d > r)
+ {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+
typedef enum
{
b000 = 0x00,
@@ -168,76 +213,113 @@ typedef enum
//gives you a triangle fan index array
static U8 sOcclusionIndices[] =
{
- // 000
+ //000
b111, b110, b010, b011, b001, b101, b100, b110,
- //001
- b110, b000, b010, b011, b111, b101, b100, b000,
+ //001
+ b011, b010, b000, b001, b101, b111, b110, b010,
//010
b101, b100, b110, b111, b011, b001, b000, b100,
//011
- b100, b010, b110, b111, b101, b001, b000, b010,
- //100
- b011, b010, b000, b001, b101, b111, b110, b010,
+ b001, b000, b100, b101, b111, b011, b010, b000,
+ //100
+ b110, b000, b010, b011, b111, b101, b100, b000,
//101
b010, b100, b000, b001, b011, b111, b110, b100,
//110
- b001, b000, b100, b101, b111, b011, b010, b000,
+ b100, b010, b110, b111, b101, b001, b000, b010,
//111
b000, b110, b100, b101, b001, b011, b010, b110,
};
-U8* get_box_fan_indices(LLCamera* camera, const LLVector3& center)
+U32 get_box_fan_indices(LLCamera* camera, const LLVector4a& center)
{
- LLVector3 d = center - camera->getOrigin();
+ LLVector4a origin;
+ origin.load3(camera->getOrigin().mV);
- U8 cypher = 0;
- if (d.mV[0] > 0)
- {
- cypher |= b100;
- }
- if (d.mV[1] > 0)
- {
- cypher |= b010;
- }
- if (d.mV[2] > 0)
- {
- cypher |= b001;
- }
+ S32 cypher = center.greaterThan(origin).getGatheredBits() & 0x7;
+
+ return cypher*8;
+}
+U8* get_box_fan_indices_ptr(LLCamera* camera, const LLVector4a& center)
+{
+ LLVector4a origin;
+ origin.load3(camera->getOrigin().mV);
+
+ S32 cypher = center.greaterThan(origin).getGatheredBits() & 0x7;
+
return sOcclusionIndices+cypher*8;
}
-
+
+
+static LLFastTimer::DeclareTimer FTM_BUILD_OCCLUSION("Build Occlusion");
+
void LLSpatialGroup::buildOcclusion()
{
- if (!mOcclusionVerts)
+ if (mOcclusionVerts.isNull())
{
- mOcclusionVerts = new F32[8*3];
+
+ mOcclusionVerts = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX,
+ LLVertexBuffer::sUseStreamDraw ? mBufferUsage : 0); //if GL has a hard time with VBOs, don't use them for occlusion culling.
+ mOcclusionVerts->allocateBuffer(8, 64, true);
+
+ LLStrider<U16> idx;
+ mOcclusionVerts->getIndexStrider(idx);
+ for (U32 i = 0; i < 64; i++)
+ {
+ *idx++ = sOcclusionIndices[i];
+ }
}
- LLVector3 r = mBounds[1] + LLVector3(SG_OCCLUSION_FUDGE, SG_OCCLUSION_FUDGE, SG_OCCLUSION_FUDGE);
+ LLVector4a fudge;
+ fudge.splat(SG_OCCLUSION_FUDGE);
+
+ LLVector4a r;
+ r.setAdd(mBounds[1], fudge);
- for (U32 k = 0; k < 3; k++)
+ LLStrider<LLVector3> pos;
+
{
- r.mV[k] = llmin(mBounds[1].mV[k]+0.25f, r.mV[k]);
+ LLFastTimer t(FTM_BUILD_OCCLUSION);
+ mOcclusionVerts->getVertexStrider(pos);
}
- F32* v = mOcclusionVerts;
- F32* c = mBounds[0].mV;
- F32* s = r.mV;
+ {
+ LLVector4a* v = (LLVector4a*) pos.get();
+
+ const LLVector4a& c = mBounds[0];
+ const LLVector4a& s = r;
+
+ static const LLVector4a octant[] =
+ {
+ LLVector4a(-1.f, -1.f, -1.f),
+ LLVector4a(-1.f, -1.f, 1.f),
+ LLVector4a(-1.f, 1.f, -1.f),
+ LLVector4a(-1.f, 1.f, 1.f),
+
+ LLVector4a(1.f, -1.f, -1.f),
+ LLVector4a(1.f, -1.f, 1.f),
+ LLVector4a(1.f, 1.f, -1.f),
+ LLVector4a(1.f, 1.f, 1.f),
+ };
+
+ //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
+
+ for (S32 i = 0; i < 8; ++i)
+ {
+ LLVector4a p;
+ p.setMul(s, octant[i]);
+ p.add(c);
+ v[i] = p;
+ }
+ }
- //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[0]; v[1] = c[1]-s[1]; v[2] = c[2]-s[2]; // 0 - 0000
- v[3] = c[0]-s[0]; v[4] = c[1]-s[1]; v[5] = c[2]+s[2]; // 1 - 0001
- v[6] = c[0]-s[0]; v[7] = c[1]+s[1]; v[8] = c[2]-s[2]; // 2 - 0010
- v[9] = c[0]-s[0]; v[10] = c[1]+s[1]; v[11] = c[2]+s[2]; // 3 - 0011
-
- v[12] = c[0]+s[0]; v[13] = c[1]-s[1]; v[14] = c[2]-s[2]; // 4 - 0100
- v[15] = c[0]+s[0]; v[16] = c[1]-s[1]; v[17] = c[2]+s[2]; // 5 - 0101
- v[18] = c[0]+s[0]; v[19] = c[1]+s[1]; v[20] = c[2]-s[2]; // 6 - 0110
- v[21] = c[0]+s[0]; v[22] = c[1]+s[1]; v[23] = c[2]+s[2]; // 7 - 0111
+ {
+ mOcclusionVerts->setBuffer(0);
+ }
clearState(LLSpatialGroup::OCCLUSION_DIRTY);
}
@@ -281,6 +363,11 @@ LLSpatialGroup::~LLSpatialGroup()
llerrs << "Illegal deletion of LLSpatialGroup!" << llendl;
}*/
+ if (gDebugGL)
+ {
+ gPipeline.checkReferences(this);
+ }
+
if (isState(DEAD))
{
sZombieGroups--;
@@ -288,12 +375,17 @@ LLSpatialGroup::~LLSpatialGroup()
sNodeCount--;
- if (gGLManager.mHasOcclusionQuery && mOcclusionQuery[LLViewerCamera::sCurCameraID])
+ if (gGLManager.mHasOcclusionQuery)
{
- sQueryPool.release(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
+ for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; ++i)
+ {
+ if (mOcclusionQuery[i])
+ {
+ sQueryPool.release(mOcclusionQuery[i]);
+ }
+ }
}
- delete [] mOcclusionVerts;
mOcclusionVerts = NULL;
LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
@@ -435,7 +527,7 @@ BOOL LLSpatialGroup::isRecentlyVisible() const
BOOL LLSpatialGroup::isVisible() const
{
- return mVisible[LLViewerCamera::sCurCameraID] == LLDrawable::getCurrentFrame() ? TRUE : FALSE;
+ return mVisible[LLViewerCamera::sCurCameraID] >= LLDrawable::getCurrentFrame() ? TRUE : FALSE;
}
void LLSpatialGroup::setVisible()
@@ -450,8 +542,10 @@ void LLSpatialGroup::validate()
sg_assert(!isState(DIRTY));
sg_assert(!isDead());
- LLVector3 myMin = mBounds[0] - mBounds[1];
- LLVector3 myMax = mBounds[0] + mBounds[1];
+ LLVector4a myMin;
+ myMin.setSub(mBounds[0], mBounds[1]);
+ LLVector4a myMax;
+ myMax.setAdd(mBounds[0], mBounds[1]);
validateDrawMap();
@@ -483,16 +577,18 @@ void LLSpatialGroup::validate()
group->validate();
//ensure all children are enclosed in this node
- LLVector3 center = group->mBounds[0];
- LLVector3 size = group->mBounds[1];
+ LLVector4a center = group->mBounds[0];
+ LLVector4a size = group->mBounds[1];
- LLVector3 min = center - size;
- LLVector3 max = center + size;
+ LLVector4a min;
+ min.setSub(center, size);
+ LLVector4a max;
+ max.setAdd(center, size);
for (U32 j = 0; j < 3; j++)
{
- sg_assert(min.mV[j] >= myMin.mV[j]-0.02f);
- sg_assert(max.mV[j] <= myMax.mV[j]+0.02f);
+ sg_assert(min[j] >= myMin[j]-0.02f);
+ sg_assert(max[j] <= myMax[j]+0.02f);
}
}
@@ -502,52 +598,8 @@ void LLSpatialGroup::validate()
void LLSpatialGroup::checkStates()
{
#if LL_OCTREE_PARANOIA_CHECK
- LLOctreeStateCheck checker;
- checker.traverse(mOctreeNode);
-#endif
-}
-
-void validate_draw_info(LLDrawInfo& params)
-{
-#if LL_OCTREE_PARANOIA_CHECK
- if (params.mVertexBuffer.isNull())
- {
- llerrs << "Draw batch has no vertex buffer." << llendl;
- }
-
- //bad range
- if (params.mStart >= params.mEnd)
- {
- llerrs << "Draw batch has invalid range." << llendl;
- }
-
- if (params.mEnd >= (U32) params.mVertexBuffer->getNumVerts())
- {
- llerrs << "Draw batch has buffer overrun error." << llendl;
- }
-
- if (params.mOffset + params.mCount > (U32) params.mVertexBuffer->getNumIndices())
- {
- llerrs << "Draw batch has index buffer ovverrun error." << llendl;
- }
-
- //bad indices
- U16* indicesp = (U16*) params.mVertexBuffer->getIndicesPointer();
- if (indicesp)
- {
- for (U32 i = params.mOffset; i < params.mOffset+params.mCount; i++)
- {
- if (indicesp[i] < (U16)params.mStart)
- {
- llerrs << "Draw batch has vertex buffer index out of range error (index too low)." << llendl;
- }
-
- if (indicesp[i] > (U16)params.mEnd)
- {
- llerrs << "Draw batch has vertex buffer index out of range error (index too high)." << llendl;
- }
- }
- }
+ //LLOctreeStateCheck checker;
+ //checker.traverse(mOctreeNode);
#endif
}
@@ -560,8 +612,8 @@ void LLSpatialGroup::validateDrawMap()
for (drawmap_elem_t::iterator j = draw_vec.begin(); j != draw_vec.end(); ++j)
{
LLDrawInfo& params = **j;
-
- validate_draw_info(params);
+
+ params.validate();
}
}
#endif
@@ -572,19 +624,17 @@ BOOL LLSpatialGroup::updateInGroup(LLDrawable *drawablep, BOOL immediate)
LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
drawablep->updateSpatialExtents();
- validate_drawable(drawablep);
OctreeNode* parent = mOctreeNode->getOctParent();
if (mOctreeNode->isInside(drawablep->getPositionGroup()) &&
(mOctreeNode->contains(drawablep) ||
- (drawablep->getBinRadius() > mOctreeNode->getSize().mdV[0] &&
+ (drawablep->getBinRadius() > mOctreeNode->getSize()[0] &&
parent && parent->getElementCount() >= LL_OCTREE_MAX_CAPACITY)))
{
unbound();
setState(OBJECT_DIRTY);
//setState(GEOM_DIRTY);
- validate_drawable(drawablep);
return TRUE;
}
@@ -602,7 +652,6 @@ BOOL LLSpatialGroup::addObject(LLDrawable *drawablep, BOOL add_all, BOOL from_oc
else
{
drawablep->setSpatialGroup(this);
- validate_drawable(drawablep);
setState(OBJECT_DIRTY | GEOM_DIRTY);
setOcclusionState(LLSpatialGroup::DISCARD_QUERY, LLSpatialGroup::STATE_MODE_ALL_CAMERAS);
gPipeline.markRebuild(this, TRUE);
@@ -703,7 +752,7 @@ void LLSpatialPartition::rebuildMesh(LLSpatialGroup* group)
}
-BOOL LLSpatialGroup::boundObjects(BOOL empty, LLVector3& minOut, LLVector3& maxOut)
+BOOL LLSpatialGroup::boundObjects(BOOL empty, LLVector4a& minOut, LLVector4a& maxOut)
{
const OctreeNode* node = mOctreeNode;
@@ -716,8 +765,8 @@ BOOL LLSpatialGroup::boundObjects(BOOL empty, LLVector3& minOut, LLVector3& maxO
return FALSE;
}
- LLVector3& newMin = mObjectExtents[0];
- LLVector3& newMax = mObjectExtents[1];
+ LLVector4a& newMin = mObjectExtents[0];
+ LLVector4a& newMax = mObjectExtents[1];
if (isState(OBJECT_DIRTY))
{ //calculate new bounding box
@@ -726,10 +775,10 @@ BOOL LLSpatialGroup::boundObjects(BOOL empty, LLVector3& minOut, LLVector3& maxO
//initialize bounding box to first element
OctreeNode::const_element_iter i = node->getData().begin();
LLDrawable* drawablep = *i;
- const LLVector3* minMax = drawablep->getSpatialExtents();
+ const LLVector4a* minMax = drawablep->getSpatialExtents();
- newMin.setVec(minMax[0]);
- newMax.setVec(minMax[1]);
+ newMin = minMax[0];
+ newMax = minMax[1];
for (++i; i != node->getData().end(); ++i)
{
@@ -753,8 +802,10 @@ BOOL LLSpatialGroup::boundObjects(BOOL empty, LLVector3& minOut, LLVector3& maxO
}*/
}
- mObjectBounds[0] = (newMin + newMax) * 0.5f;
- mObjectBounds[1] = (newMax - newMin) * 0.5f;
+ mObjectBounds[0].setAdd(newMin, newMax);
+ mObjectBounds[0].mul(0.5f);
+ mObjectBounds[1].setSub(newMax, newMin);
+ mObjectBounds[1].mul(0.5f);
}
if (empty)
@@ -764,17 +815,8 @@ BOOL LLSpatialGroup::boundObjects(BOOL empty, LLVector3& minOut, LLVector3& maxO
}
else
{
- for (U32 i = 0; i < 3; i++)
- {
- if (newMin.mV[i] < minOut.mV[i])
- {
- minOut.mV[i] = newMin.mV[i];
- }
- if (newMax.mV[i] > maxOut.mV[i])
- {
- maxOut.mV[i] = newMax.mV[i];
- }
- }
+ minOut.setMin(minOut, newMin);
+ maxOut.setMax(maxOut, newMax);
}
return TRUE;
@@ -865,18 +907,19 @@ BOOL LLSpatialGroup::removeObject(LLDrawable *drawablep, BOOL from_octree)
return TRUE;
}
-void LLSpatialGroup::shift(const LLVector3 &offset)
+void LLSpatialGroup::shift(const LLVector4a &offset)
{
LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
- LLVector3d offsetd(offset);
- mOctreeNode->setCenter(mOctreeNode->getCenter()+offsetd);
+ LLVector4a t = mOctreeNode->getCenter();
+ t.add(offset);
+ mOctreeNode->setCenter(t);
mOctreeNode->updateMinMax();
- mBounds[0] += offset;
- mExtents[0] += offset;
- mExtents[1] += offset;
- mObjectBounds[0] += offset;
- mObjectExtents[0] += offset;
- mObjectExtents[1] += offset;
+ mBounds[0].add(offset);
+ mExtents[0].add(offset);
+ mExtents[1].add(offset);
+ mObjectBounds[0].add(offset);
+ mObjectExtents[0].add(offset);
+ mObjectExtents[1].add(offset);
//if (!mSpatialPartition->mRenderByGroup)
{
@@ -884,15 +927,9 @@ void LLSpatialGroup::shift(const LLVector3 &offset)
gPipeline.markRebuild(this, TRUE);
}
- if (mOcclusionVerts)
+ if (mOcclusionVerts.notNull())
{
- for (U32 i = 0; i < 8; i++)
- {
- F32* v = mOcclusionVerts+i*3;
- v[0] += offset.mV[0];
- v[1] += offset.mV[1];
- v[2] += offset.mV[2];
- }
+ setState(OCCLUSION_DIRTY);
}
}
@@ -1079,12 +1116,23 @@ void LLSpatialGroup::setOcclusionState(U32 state, S32 mode)
for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
{
mOcclusionState[i] |= state;
+
+ if ((state & DISCARD_QUERY) && mOcclusionQuery[i])
+ {
+ sQueryPool.release(mOcclusionQuery[i]);
+ mOcclusionQuery[i] = 0;
+ }
}
}
}
else
{
mOcclusionState[LLViewerCamera::sCurCameraID] |= state;
+ if ((state & DISCARD_QUERY) && mOcclusionQuery[LLViewerCamera::sCurCameraID])
+ {
+ sQueryPool.release(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
+ mOcclusionQuery[LLViewerCamera::sCurCameraID] = 0;
+ }
}
}
@@ -1152,13 +1200,11 @@ LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) :
mOctreeNode(node),
mSpatialPartition(part),
mVertexBuffer(NULL),
- mBufferUsage(GL_STATIC_DRAW_ARB),
+ mBufferUsage(part->mBufferUsage),
mDistance(0.f),
mDepth(0.f),
mLastUpdateDistance(-1.f),
mLastUpdateTime(gFrameTimeSeconds),
- mViewAngle(0.f),
- mLastUpdateViewAngle(-1.f),
mAtlasList(4),
mCurUpdatingTime(0),
mCurUpdatingSlotp(NULL),
@@ -1167,13 +1213,18 @@ LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) :
sNodeCount++;
LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+ mViewAngle.splat(0.f);
+ mLastUpdateViewAngle.splat(-1.f);
+ mExtents[0] = mExtents[1] = mObjectBounds[0] = mObjectBounds[0] = mObjectBounds[1] =
+ mObjectExtents[0] = mObjectExtents[1] = mViewAngle;
+
sg_assert(mOctreeNode->getListenerCount() == 0);
mOctreeNode->addListener(this);
setState(SG_INITIAL_STATE_MASK);
gPipeline.markRebuild(this, TRUE);
- mBounds[0] = LLVector3(node->getCenter());
- mBounds[1] = LLVector3(node->getSize());
+ mBounds[0] = node->getCenter();
+ mBounds[1] = node->getSize();
part->mLODSeed = (part->mLODSeed+1)%part->mLODPeriod;
mLODHash = part->mLODSeed;
@@ -1210,8 +1261,8 @@ void LLSpatialGroup::updateDistance(LLCamera &camera)
#endif
if (!getData().empty())
{
- mRadius = mSpatialPartition->mRenderByGroup ? mObjectBounds[1].magVec() :
- (F32) mOctreeNode->getSize().magVec();
+ mRadius = mSpatialPartition->mRenderByGroup ? mObjectBounds[1].getLength3().getF32() :
+ (F32) mOctreeNode->getSize().getLength3().getF32();
mDistance = mSpatialPartition->calcDistance(this, camera);
mPixelArea = mSpatialPartition->calcPixelArea(this, camera);
}
@@ -1219,24 +1270,31 @@ void LLSpatialGroup::updateDistance(LLCamera &camera)
F32 LLSpatialPartition::calcDistance(LLSpatialGroup* group, LLCamera& camera)
{
- LLVector3 eye = group->mObjectBounds[0] - camera.getOrigin();
+ LLVector4a eye;
+ LLVector4a origin;
+ origin.load3(camera.getOrigin().mV);
+
+ eye.setSub(group->mObjectBounds[0], origin);
F32 dist = 0.f;
if (group->mDrawMap.find(LLRenderPass::PASS_ALPHA) != group->mDrawMap.end())
{
- LLVector3 v = eye;
- dist = eye.normVec();
+ LLVector4a v = eye;
+
+ dist = eye.getLength3().getF32();
+ eye.normalize3fast();
if (!group->isState(LLSpatialGroup::ALPHA_DIRTY))
{
if (!group->mSpatialPartition->isBridge())
{
- LLVector3 view_angle = LLVector3(eye * LLVector3(1,0,0),
- eye * LLVector3(0,1,0),
- eye * LLVector3(0,0,1));
+ LLVector4a view_angle = eye;
- if ((view_angle-group->mLastUpdateViewAngle).magVec() > 0.64f)
+ LLVector4a diff;
+ diff.setSub(view_angle, group->mLastUpdateViewAngle);
+
+ if (diff.getLength3().getF32() > 0.64f)
{
group->mViewAngle = view_angle;
group->mLastUpdateViewAngle = view_angle;
@@ -1253,17 +1311,20 @@ F32 LLSpatialPartition::calcDistance(LLSpatialGroup* group, LLCamera& camera)
LLVector3 at = camera.getAtAxis();
- //front of bounding box
- for (U32 i = 0; i < 3; i++)
- {
- v.mV[i] -= group->mObjectBounds[1].mV[i]*0.25f * at.mV[i];
- }
+ LLVector4a ata;
+ ata.load3(at.mV);
- group->mDepth = v * at;
+ LLVector4a t = ata;
+ //front of bounding box
+ t.mul(0.25f);
+ t.mul(group->mObjectBounds[1]);
+ v.sub(t);
+
+ group->mDepth = v.dot3(ata).getF32();
}
else
{
- dist = eye.magVec();
+ dist = eye.getLength3().getF32();
}
if (dist < 16.f)
@@ -1289,7 +1350,8 @@ F32 LLSpatialGroup::getUpdateUrgency() const
}
else
{
- return (gFrameTimeSeconds - mLastUpdateTime+4.f)/mDistance;
+ F32 time = gFrameTimeSeconds-mLastUpdateTime+4.f;
+ return time + (mObjectBounds[1].dot3(mObjectBounds[1]).getF32()+1.f)/mDistance;
}
}
@@ -1300,8 +1362,8 @@ BOOL LLSpatialGroup::needsUpdate()
BOOL LLSpatialGroup::changeLOD()
{
- if (isState(ALPHA_DIRTY))
- { ///an alpha sort is going to happen, update distance and LOD
+ if (isState(ALPHA_DIRTY | OBJECT_DIRTY))
+ { ///a rebuild is going to happen, update distance and LoD
return TRUE;
}
@@ -1314,7 +1376,7 @@ BOOL LLSpatialGroup::changeLOD()
return TRUE;
}
- if (mDistance > mRadius)
+ if (mDistance > mRadius*2.f)
{
return FALSE;
}
@@ -1416,7 +1478,6 @@ void LLSpatialGroup::destroyGL()
}
}
- delete [] mOcclusionVerts;
mOcclusionVerts = NULL;
for (LLSpatialGroup::element_iter i = getData().begin(); i != getData().end(); ++i)
@@ -1425,8 +1486,7 @@ void LLSpatialGroup::destroyGL()
for (S32 j = 0; j < drawable->getNumFaces(); j++)
{
LLFace* facep = drawable->getFace(j);
- facep->mVertexBuffer = NULL;
- facep->mLastVertexBuffer = NULL;
+ facep->clearVertexBuffer();
}
}
}
@@ -1459,8 +1519,8 @@ BOOL LLSpatialGroup::rebound()
}
else
{
- LLVector3& newMin = mExtents[0];
- LLVector3& newMax = mExtents[1];
+ LLVector4a& newMin = mExtents[0];
+ LLVector4a& newMax = mExtents[1];
LLSpatialGroup* group = (LLSpatialGroup*) mOctreeNode->getChild(0)->getListener(0);
group->clearState(SKIP_FRUSTUM_CHECK);
group->rebound();
@@ -1474,26 +1534,19 @@ BOOL LLSpatialGroup::rebound()
group = (LLSpatialGroup*) mOctreeNode->getChild(i)->getListener(0);
group->clearState(SKIP_FRUSTUM_CHECK);
group->rebound();
- const LLVector3& max = group->mExtents[1];
- const LLVector3& min = group->mExtents[0];
+ const LLVector4a& max = group->mExtents[1];
+ const LLVector4a& min = group->mExtents[0];
- for (U32 j = 0; j < 3; j++)
- {
- if (max.mV[j] > newMax.mV[j])
- {
- newMax.mV[j] = max.mV[j];
- }
- if (min.mV[j] < newMin.mV[j])
- {
- newMin.mV[j] = min.mV[j];
- }
- }
+ newMax.setMax(newMax, max);
+ newMin.setMin(newMin, min);
}
boundObjects(FALSE, newMin, newMax);
- mBounds[0] = (newMin + newMax)*0.5f;
- mBounds[1] = (newMax - newMin)*0.5f;
+ mBounds[0].setAdd(newMin, newMax);
+ mBounds[0].mul(0.5f);
+ mBounds[1].setSub(newMax, newMin);
+ mBounds[1].mul(0.5f);
}
setState(OCCLUSION_DIRTY);
@@ -1516,31 +1569,53 @@ void LLSpatialGroup::checkOcclusion()
}
else if (isOcclusionState(QUERY_PENDING))
{ //otherwise, if a query is pending, read it back
- GLuint res = 1;
- if (!isOcclusionState(DISCARD_QUERY) && mOcclusionQuery[LLViewerCamera::sCurCameraID])
- {
- glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_ARB, &res);
- }
- if (isOcclusionState(DISCARD_QUERY))
+ GLuint available = 0;
+ if (mOcclusionQuery[LLViewerCamera::sCurCameraID])
{
- res = 2;
- }
-
- if (res > 0)
- {
- assert_states_valid(this);
- clearOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF);
- assert_states_valid(this);
+ glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_AVAILABLE_ARB, &available);
}
else
{
- assert_states_valid(this);
- setOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF);
- assert_states_valid(this);
+ available = 1;
}
- clearOcclusionState(QUERY_PENDING | DISCARD_QUERY);
+ if (available)
+ { //result is available, read it back, otherwise wait until next frame
+ GLuint res = 1;
+ if (!isOcclusionState(DISCARD_QUERY) && mOcclusionQuery[LLViewerCamera::sCurCameraID])
+ {
+ glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_ARB, &res);
+#if LL_TRACK_PENDING_OCCLUSION_QUERIES
+ sPendingQueries.erase(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
+#endif
+ }
+ else if (mOcclusionQuery[LLViewerCamera::sCurCameraID])
+ { //delete the query to avoid holding onto hundreds of pending queries
+ sQueryPool.release(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
+ mOcclusionQuery[LLViewerCamera::sCurCameraID] = 0;
+ }
+
+ if (isOcclusionState(DISCARD_QUERY))
+ {
+ res = 2;
+ }
+
+ if (res > 0)
+ {
+ assert_states_valid(this);
+ clearOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF);
+ assert_states_valid(this);
+ }
+ else
+ {
+ assert_states_valid(this);
+ setOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF);
+ assert_states_valid(this);
+ }
+
+ clearOcclusionState(QUERY_PENDING | DISCARD_QUERY);
+ }
}
else if (mSpatialPartition->isOcclusionEnabled() && isOcclusionState(LLSpatialGroup::OCCLUDED))
{ //check occlusion has been issued for occluded node that has not had a query issued
@@ -1551,12 +1626,18 @@ void LLSpatialGroup::checkOcclusion()
}
}
+static LLFastTimer::DeclareTimer FTM_PUSH_OCCLUSION_VERTS("Push Occlusion");
+static LLFastTimer::DeclareTimer FTM_SET_OCCLUSION_STATE("Occlusion State");
+static LLFastTimer::DeclareTimer FTM_OCCLUSION_EARLY_FAIL("Occlusion Early Fail");
+
void LLSpatialGroup::doOcclusion(LLCamera* camera)
{
if (mSpatialPartition->isOcclusionEnabled() && LLPipeline::sUseOcclusion > 1)
{
+ // Don't cull hole/edge water, unless we have the GL_ARB_depth_clamp extension
if (earlyFail(camera, this))
{
+ LLFastTimer t(FTM_OCCLUSION_EARLY_FAIL);
setOcclusionState(LLSpatialGroup::DISCARD_QUERY);
assert_states_valid(this);
clearOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF);
@@ -1564,38 +1645,82 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera)
}
else
{
+ if (!isOcclusionState(QUERY_PENDING) || isOcclusionState(DISCARD_QUERY))
{
- LLFastTimer t(FTM_RENDER_OCCLUSION);
+ { //no query pending, or previous query to be discarded
+ LLFastTimer t(FTM_RENDER_OCCLUSION);
- if (!mOcclusionQuery[LLViewerCamera::sCurCameraID])
- {
- mOcclusionQuery[LLViewerCamera::sCurCameraID] = sQueryPool.allocate();
- }
+ if (!mOcclusionQuery[LLViewerCamera::sCurCameraID])
+ {
+ mOcclusionQuery[LLViewerCamera::sCurCameraID] = sQueryPool.allocate();
+ }
- if (!mOcclusionVerts || isState(LLSpatialGroup::OCCLUSION_DIRTY))
- {
- buildOcclusion();
- }
+ if (mOcclusionVerts.isNull() || isState(LLSpatialGroup::OCCLUSION_DIRTY))
+ {
+ buildOcclusion();
+ }
+
+ // Depth clamp all water to avoid it being culled as a result of being
+ // behind the far clip plane, and in the case of edge water to avoid
+ // it being culled while still visible.
+ bool const use_depth_clamp = gGLManager.mHasDepthClamp &&
+ (mSpatialPartition->mDrawableType == LLDrawPool::POOL_WATER ||
+ mSpatialPartition->mDrawableType == LLDrawPool::POOL_VOIDWATER);
+
+ LLGLEnable clamp(use_depth_clamp ? GL_DEPTH_CLAMP : 0);
+
+#if !LL_DARWIN
+ U32 mode = gGLManager.mHasOcclusionQuery2 ? GL_ANY_SAMPLES_PASSED : GL_SAMPLES_PASSED_ARB;
+#else
+ U32 mode = GL_SAMPLES_PASSED_ARB;
+#endif
+
+#if LL_TRACK_PENDING_OCCLUSION_QUERIES
+ sPendingQueries.insert(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
+#endif
- glBeginQueryARB(GL_SAMPLES_PASSED_ARB, mOcclusionQuery[LLViewerCamera::sCurCameraID]);
- glVertexPointer(3, GL_FLOAT, 0, mOcclusionVerts);
- if (camera->getOrigin().isExactlyZero())
- { //origin is invalid, draw entire box
- glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8,
- GL_UNSIGNED_BYTE, sOcclusionIndices);
- glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8,
- GL_UNSIGNED_BYTE, sOcclusionIndices+b111*8);
+ {
+ LLFastTimer t(FTM_PUSH_OCCLUSION_VERTS);
+ glBeginQueryARB(mode, mOcclusionQuery[LLViewerCamera::sCurCameraID]);
+
+ mOcclusionVerts->setBuffer(LLVertexBuffer::MAP_VERTEX);
+
+ if (!use_depth_clamp && mSpatialPartition->mDrawableType == LLDrawPool::POOL_VOIDWATER)
+ {
+ LLGLSquashToFarClip squash(glh_get_current_projection(), 1);
+ if (camera->getOrigin().isExactlyZero())
+ { //origin is invalid, draw entire box
+ mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0);
+ mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8);
+ }
+ else
+ {
+ mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, mBounds[0]));
+ }
+ }
+ else
+ {
+ if (camera->getOrigin().isExactlyZero())
+ { //origin is invalid, draw entire box
+ mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0);
+ mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8);
+ }
+ else
+ {
+ mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, mBounds[0]));
+ }
+ }
+
+ glEndQueryARB(mode);
+ }
}
- else
+
{
- glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8,
- GL_UNSIGNED_BYTE, get_box_fan_indices(camera, mBounds[0]));
+ LLFastTimer t(FTM_SET_OCCLUSION_STATE);
+ setOcclusionState(LLSpatialGroup::QUERY_PENDING);
+ clearOcclusionState(LLSpatialGroup::DISCARD_QUERY);
}
- glEndQueryARB(GL_SAMPLES_PASSED_ARB);
}
-
- setOcclusionState(LLSpatialGroup::QUERY_PENDING);
- clearOcclusionState(LLSpatialGroup::DISCARD_QUERY);
}
}
}
@@ -1617,10 +1742,11 @@ LLSpatialPartition::LLSpatialPartition(U32 data_mask, BOOL render_by_group, U32
mSlopRatio = 0.25f;
mInfiniteFarClip = FALSE;
- LLGLNamePool::registerPool(&sQueryPool);
+ LLVector4a center, size;
+ center.splat(0.f);
+ size.splat(1.f);
- mOctree = new LLSpatialGroup::OctreeRoot(LLVector3d(0,0,0),
- LLVector3d(1,1,1),
+ mOctree = new LLSpatialGroup::OctreeRoot(center,size,
NULL);
new LLSpatialGroup(mOctree, this);
}
@@ -1640,7 +1766,6 @@ LLSpatialGroup *LLSpatialPartition::put(LLDrawable *drawablep, BOOL was_visible)
LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
drawablep->updateSpatialExtents();
- validate_drawable(drawablep);
//keep drawable from being garbage collected
LLPointer<LLDrawable> ptr = drawablep;
@@ -1724,16 +1849,16 @@ void LLSpatialPartition::move(LLDrawable *drawablep, LLSpatialGroup *curp, BOOL
class LLSpatialShift : public LLSpatialGroup::OctreeTraveler
{
public:
- LLSpatialShift(LLVector3 offset) : mOffset(offset) { }
+ const LLVector4a& mOffset;
+
+ LLSpatialShift(const LLVector4a& offset) : mOffset(offset) { }
virtual void visit(const LLSpatialGroup::OctreeNode* branch)
{
((LLSpatialGroup*) branch->getListener(0))->shift(mOffset);
}
-
- LLVector3 mOffset;
};
-void LLSpatialPartition::shift(const LLVector3 &offset)
+void LLSpatialPartition::shift(const LLVector4a &offset)
{ //shift octree node bounding boxes by offset
LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
LLSpatialShift shifter(offset);
@@ -1895,7 +2020,7 @@ public:
class LLOctreeCullVisExtents: public LLOctreeCullShadow
{
public:
- LLOctreeCullVisExtents(LLCamera* camera, LLVector3& min, LLVector3& max)
+ LLOctreeCullVisExtents(LLCamera* camera, LLVector4a& min, LLVector4a& max)
: LLOctreeCullShadow(camera), mMin(min), mMax(max), mEmpty(TRUE) { }
virtual bool earlyFail(LLSpatialGroup* group)
@@ -1962,8 +2087,8 @@ public:
}
BOOL mEmpty;
- LLVector3& mMin;
- LLVector3& mMax;
+ LLVector4a& mMin;
+ LLVector4a& mMax;
};
class LLOctreeCullDetectVisible: public LLOctreeCullShadow
@@ -2032,6 +2157,8 @@ public:
void drawBox(const LLVector3& c, const LLVector3& r)
{
+ LLVertexBuffer::unbind();
+
gGL.begin(LLRender::TRIANGLE_STRIP);
//left front
gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,-1))).mV);
@@ -2067,6 +2194,11 @@ void drawBox(const LLVector3& c, const LLVector3& r)
gGL.end();
}
+void drawBox(const LLVector4a& c, const LLVector4a& r)
+{
+ drawBox(reinterpret_cast<const LLVector3&>(c), reinterpret_cast<const LLVector3&>(r));
+}
+
void drawBoxOutline(const LLVector3& pos, const LLVector3& size)
{
LLVector3 v1 = size.scaledVec(LLVector3( 1, 1,1));
@@ -2113,6 +2245,11 @@ void drawBoxOutline(const LLVector3& pos, const LLVector3& size)
gGL.end();
}
+void drawBoxOutline(const LLVector4a& pos, const LLVector4a& size)
+{
+ drawBoxOutline(reinterpret_cast<const LLVector3&>(pos), reinterpret_cast<const LLVector3&>(size));
+}
+
class LLOctreeDirty : public LLOctreeTraveler<LLDrawable>
{
public:
@@ -2156,14 +2293,21 @@ BOOL LLSpatialPartition::isOcclusionEnabled()
BOOL LLSpatialPartition::getVisibleExtents(LLCamera& camera, LLVector3& visMin, LLVector3& visMax)
{
+ LLVector4a visMina, visMaxa;
+ visMina.load3(visMin.mV);
+ visMaxa.load3(visMax.mV);
+
{
LLFastTimer ftm(FTM_CULL_REBOUND);
LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0);
group->rebound();
}
- LLOctreeCullVisExtents vis(&camera, visMin, visMax);
+ LLOctreeCullVisExtents vis(&camera, visMina, visMaxa);
vis.traverse(mOctree);
+
+ visMin.set(visMina.getF32ptr());
+ visMax.set(visMaxa.getF32ptr());
return vis.mEmpty;
}
@@ -2226,25 +2370,36 @@ BOOL earlyFail(LLCamera* camera, LLSpatialGroup* group)
}
const F32 vel = SG_OCCLUSION_FUDGE*2.f;
- LLVector3 c = group->mBounds[0];
- LLVector3 r = group->mBounds[1] + LLVector3(vel,vel,vel);
-
+ LLVector4a fudge;
+ fudge.splat(vel);
+
+ const LLVector4a& c = group->mBounds[0];
+ LLVector4a r;
+ r.setAdd(group->mBounds[1], fudge);
+
/*if (r.magVecSquared() > 1024.0*1024.0)
{
return TRUE;
}*/
- LLVector3 e = camera->getOrigin();
+ LLVector4a e;
+ e.load3(camera->getOrigin().mV);
- LLVector3 min = c - r;
- LLVector3 max = c + r;
+ LLVector4a min;
+ min.setSub(c,r);
+ LLVector4a max;
+ max.setAdd(c,r);
- for (U32 j = 0; j < 3; j++)
+ S32 lt = e.lessThan(min).getGatheredBits() & 0x7;
+ if (lt)
{
- if (e.mV[j] < min.mV[j] || e.mV[j] > max.mV[j])
- {
- return FALSE;
- }
+ return FALSE;
+ }
+
+ S32 gt = e.greaterThan(max).getGatheredBits() & 0x7;
+ if (gt)
+ {
+ return FALSE;
}
return TRUE;
@@ -2275,7 +2430,9 @@ void pushVerts(LLSpatialGroup* group, U32 mask)
void pushVerts(LLFace* face, U32 mask)
{
- LLVertexBuffer* buffer = face->mVertexBuffer;
+ llassert(face->verify());
+
+ LLVertexBuffer* buffer = face->getVertexBuffer();
if (buffer)
{
@@ -2286,7 +2443,25 @@ void pushVerts(LLFace* face, U32 mask)
U16 offset = face->getIndicesStart();
buffer->drawRange(LLRender::TRIANGLES, start, end, count, offset);
}
+}
+void pushVerts(LLDrawable* drawable, U32 mask)
+{
+ for (S32 i = 0; i < drawable->getNumFaces(); ++i)
+ {
+ pushVerts(drawable->getFace(i), mask);
+ }
+}
+
+void pushVerts(LLVolume* volume)
+{
+ LLVertexBuffer::unbind();
+ for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
+ {
+ const LLVolumeFace& face = volume->getVolumeFace(i);
+ glVertexPointer(3, GL_FLOAT, 16, face.mPositions);
+ glDrawElements(GL_TRIANGLES, face.mNumIndices, GL_UNSIGNED_SHORT, face.mIndices);
+ }
}
void pushBufferVerts(LLVertexBuffer* buffer, U32 mask)
@@ -2364,7 +2539,6 @@ void renderOctree(LLSpatialGroup* group)
{
//render solid object bounding box, color
//coded by buffer usage and activity
- LLGLDepthTest depth(GL_TRUE, GL_FALSE);
gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA);
LLVector4 col;
if (group->mBuilt > 0.f)
@@ -2405,7 +2579,7 @@ void renderOctree(LLSpatialGroup* group)
for (S32 j = 0; j < drawable->getNumFaces(); j++)
{
LLFace* face = drawable->getFace(j);
- if (face->mVertexBuffer.notNull())
+ if (face->getVertexBuffer())
{
if (gFrameTimeSeconds - face->mLastUpdateTime < 0.5f)
{
@@ -2420,10 +2594,10 @@ void renderOctree(LLSpatialGroup* group)
continue;
}
- face->mVertexBuffer->setBuffer(LLVertexBuffer::MAP_VERTEX);
+ face->getVertexBuffer()->setBuffer(LLVertexBuffer::MAP_VERTEX);
//drawBox((face->mExtents[0] + face->mExtents[1])*0.5f,
// (face->mExtents[1]-face->mExtents[0])*0.5f);
- face->mVertexBuffer->draw(LLRender::TRIANGLES, face->getIndicesCount(), face->getIndicesStart());
+ face->getVertexBuffer()->draw(LLRender::TRIANGLES, face->getIndicesCount(), face->getIndicesStart());
}
}
@@ -2450,7 +2624,16 @@ void renderOctree(LLSpatialGroup* group)
}
gGL.color4fv(col.mV);
- drawBox(group->mObjectBounds[0], group->mObjectBounds[1]*1.01f+LLVector3(0.001f, 0.001f, 0.001f));
+ LLVector4a fudge;
+ fudge.splat(0.001f);
+ LLVector4a size = group->mObjectBounds[1];
+ size.mul(1.01f);
+ size.add(fudge);
+
+ {
+ LLGLDepthTest depth(GL_TRUE, GL_FALSE);
+ drawBox(group->mObjectBounds[0], fudge);
+ }
gGL.setSceneBlendType(LLRender::BT_ALPHA);
@@ -2481,8 +2664,12 @@ void renderOctree(LLSpatialGroup* group)
for (LLSpatialGroup::drawmap_elem_t::iterator j = i->second.begin(); j != i->second.end(); ++j)
{
LLDrawInfo* draw_info = *j;
- LLVector3 center = (draw_info->mExtents[1] + draw_info->mExtents[0])*0.5f;
- LLVector3 size = (draw_info->mExtents[1] - draw_info->mExtents[0])*0.5f;
+ LLVector4a center;
+ center.setAdd(draw_info->mExtents[1], draw_info->mExtents[0]);
+ center.mul(0.5f);
+ LLVector4a size;
+ size.setSub(draw_info->mExtents[1], draw_info->mExtents[0]);
+ size.mul(0.5f);
drawBoxOutline(center, size);
}
}
@@ -2529,17 +2716,17 @@ void renderVisibility(LLSpatialGroup* group, LLCamera* camera)
gGL.color4f(0.f, 0.75f, 0.f, 0.5f);
pushBufferVerts(group, LLVertexBuffer::MAP_VERTEX);
}
- else if (camera && group->mOcclusionVerts)
+ else if (camera && group->mOcclusionVerts.notNull())
{
LLVertexBuffer::unbind();
- glVertexPointer(3, GL_FLOAT, 0, group->mOcclusionVerts);
-
+ group->mOcclusionVerts->setBuffer(LLVertexBuffer::MAP_VERTEX);
+
glColor4f(1.0f, 0.f, 0.f, 0.5f);
- glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8, GL_UNSIGNED_BYTE, get_box_fan_indices(camera, group->mBounds[0]));
+ group->mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, group->mBounds[0]));
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glColor4f(1.0f, 1.f, 1.f, 1.0f);
- glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8, GL_UNSIGNED_BYTE, get_box_fan_indices(camera, group->mBounds[0]));
+ group->mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, group->mBounds[0]));
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
}
@@ -2560,6 +2747,49 @@ void renderCrossHairs(LLVector3 position, F32 size, LLColor4 color)
gGL.end();
}
+void renderUpdateType(LLDrawable* drawablep)
+{
+ LLViewerObject* vobj = drawablep->getVObj();
+ if (!vobj || OUT_UNKNOWN == vobj->getLastUpdateType())
+ {
+ return;
+ }
+ LLGLEnable blend(GL_BLEND);
+ switch (vobj->getLastUpdateType())
+ {
+ case OUT_FULL:
+ glColor4f(0,1,0,0.5f);
+ break;
+ case OUT_TERSE_IMPROVED:
+ glColor4f(0,1,1,0.5f);
+ break;
+ case OUT_FULL_COMPRESSED:
+ if (vobj->getLastUpdateCached())
+ {
+ glColor4f(1,0,0,0.5f);
+ }
+ else
+ {
+ glColor4f(1,1,0,0.5f);
+ }
+ break;
+ case OUT_FULL_CACHED:
+ glColor4f(0,0,1,0.5f);
+ break;
+ default:
+ llwarns << "Unknown update_type " << vobj->getLastUpdateType() << llendl;
+ break;
+ };
+ S32 num_faces = drawablep->getNumFaces();
+ if (num_faces)
+ {
+ for (S32 i = 0; i < num_faces; ++i)
+ {
+ pushVerts(drawablep->getFace(i), LLVertexBuffer::MAP_VERTEX);
+ }
+ }
+}
+
void renderBoundingBox(LLDrawable* drawable, BOOL set_color = TRUE)
{
@@ -2591,9 +2821,10 @@ void renderBoundingBox(LLDrawable* drawable, BOOL set_color = TRUE)
gGL.color4f(0.5f,0.5f,0.5f,1.0f);
break;
case LLViewerObject::LL_VO_PART_GROUP:
- case LLViewerObject::LL_VO_HUD_PART_GROUP:
+ case LLViewerObject::LL_VO_HUD_PART_GROUP:
gGL.color4f(0,0,1,1);
break;
+ case LLViewerObject::LL_VO_VOID_WATER:
case LLViewerObject::LL_VO_WATER:
gGL.color4f(0,0.5f,1,1);
break;
@@ -2611,8 +2842,8 @@ void renderBoundingBox(LLDrawable* drawable, BOOL set_color = TRUE)
}
}
- const LLVector3* ext;
- LLVector3 pos, size;
+ const LLVector4a* ext;
+ LLVector4a pos, size;
//render face bounding boxes
for (S32 i = 0; i < drawable->getNumFaces(); i++)
@@ -2621,20 +2852,21 @@ void renderBoundingBox(LLDrawable* drawable, BOOL set_color = TRUE)
ext = facep->mExtents;
- if (ext[0].isExactlyZero() && ext[1].isExactlyZero())
- {
- continue;
- }
- pos = (ext[0] + ext[1]) * 0.5f;
- size = (ext[1] - ext[0]) * 0.5f;
+ pos.setAdd(ext[0], ext[1]);
+ pos.mul(0.5f);
+ size.setSub(ext[1], ext[0]);
+ size.mul(0.5f);
+
drawBoxOutline(pos,size);
}
//render drawable bounding box
ext = drawable->getSpatialExtents();
- pos = (ext[0] + ext[1]) * 0.5f;
- size = (ext[1] - ext[0]) * 0.5f;
+ pos.setAdd(ext[0], ext[1]);
+ pos.mul(0.5f);
+ size.setSub(ext[1], ext[0]);
+ size.mul(0.5f);
LLViewerObject* vobj = drawable->getVObj();
if (vobj && vobj->onActiveList())
@@ -2651,7 +2883,506 @@ void renderBoundingBox(LLDrawable* drawable, BOOL set_color = TRUE)
{
drawBoxOutline(pos,size);
}
+}
+
+void renderNormals(LLDrawable* drawablep)
+{
+ LLVertexBuffer::unbind();
+
+ LLVOVolume* vol = drawablep->getVOVolume();
+ if (vol)
+ {
+ LLVolume* volume = vol->getVolume();
+ gGL.pushMatrix();
+ glMultMatrixf((F32*) vol->getRelativeXform().mMatrix);
+
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+ LLVector4a scale(gSavedSettings.getF32("RenderDebugNormalScale"));
+
+ for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
+ {
+ const LLVolumeFace& face = volume->getVolumeFace(i);
+
+ gGL.begin(LLRender::LINES);
+
+ for (S32 j = 0; j < face.mNumVertices; ++j)
+ {
+ LLVector4a n,p;
+
+ n.setMul(face.mNormals[j], scale);
+ p.setAdd(face.mPositions[j], n);
+
+ gGL.color4f(1,1,1,1);
+ gGL.vertex3fv(face.mPositions[j].getF32ptr());
+ gGL.vertex3fv(p.getF32ptr());
+
+ if (face.mBinormals)
+ {
+ n.setMul(face.mBinormals[j], scale);
+ p.setAdd(face.mPositions[j], n);
+
+ gGL.color4f(0,1,1,1);
+ gGL.vertex3fv(face.mPositions[j].getF32ptr());
+ gGL.vertex3fv(p.getF32ptr());
+ }
+ }
+
+ gGL.end();
+ }
+
+ gGL.popMatrix();
+ }
+}
+
+S32 get_physics_detail(const LLVolumeParams& volume_params, const LLVector3& scale)
+{
+ const S32 DEFAULT_DETAIL = 1;
+ const F32 LARGE_THRESHOLD = 5.f;
+ const F32 MEGA_THRESHOLD = 25.f;
+
+ S32 detail = DEFAULT_DETAIL;
+ F32 avg_scale = (scale[0]+scale[1]+scale[2])/3.f;
+
+ if (avg_scale > LARGE_THRESHOLD)
+ {
+ detail += 1;
+ if (avg_scale > MEGA_THRESHOLD)
+ {
+ detail += 1;
+ }
+ }
+
+ return detail;
+}
+
+void renderMeshBaseHull(LLVOVolume* volume, U32 data_mask, LLColor4& color, LLColor4& line_color)
+{
+ LLUUID mesh_id = volume->getVolume()->getParams().getSculptID();
+ LLModel::Decomposition* decomp = gMeshRepo.getDecomposition(mesh_id);
+
+ const LLVector3 center(0,0,0);
+ const LLVector3 size(0.25f,0.25f,0.25f);
+
+ if (decomp)
+ {
+ if (!decomp->mBaseHullMesh.empty())
+ {
+ glColor4fv(color.mV);
+ LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mBaseHullMesh.mPositions, decomp->mBaseHullMesh.mNormals);
+ }
+ else
+ {
+ gMeshRepo.buildPhysicsMesh(*decomp);
+ gGL.color3f(0,1,1);
+ drawBoxOutline(center, size);
+ }
+
+ }
+ else
+ {
+ gGL.color3f(1,0,1);
+ drawBoxOutline(center, size);
+ }
+}
+
+void render_hull(LLModel::PhysicsMesh& mesh, const LLColor4& color, const LLColor4& line_color)
+{
+ glColor4fv(color.mV);
+ LLVertexBuffer::drawArrays(LLRender::TRIANGLES, mesh.mPositions, mesh.mNormals);
+ LLGLEnable offset(GL_POLYGON_OFFSET_LINE);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ glPolygonOffset(3.f, 3.f);
+ glLineWidth(3.f);
+ glColor4fv(line_color.mV);
+ LLVertexBuffer::drawArrays(LLRender::TRIANGLES, mesh.mPositions, mesh.mNormals);
+ glLineWidth(1.f);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+}
+
+void renderPhysicsShape(LLDrawable* drawable, LLVOVolume* volume)
+{
+ if (volume->isSelected())
+ {
+ LLVector3 construct_me(5,5,5);
+ construct_me.normalize();
+ }
+
+ U8 physics_type = volume->getPhysicsShapeType();
+
+ if (physics_type == LLViewerObject::PHYSICS_SHAPE_NONE || volume->isFlexible())
+ {
+ return;
+ }
+
+ //not allowed to return at this point without rendering *something*
+
+ F32 threshold = gSavedSettings.getF32("ObjectCostHighThreshold");
+ F32 cost = volume->getObjectCost();
+
+ LLColor4 low = gSavedSettings.getColor4("ObjectCostLowColor");
+ LLColor4 mid = gSavedSettings.getColor4("ObjectCostMidColor");
+ LLColor4 high = gSavedSettings.getColor4("ObjectCostHighColor");
+
+ F32 normalizedCost = 1.f - exp( -(cost / threshold) );
+
+ LLColor4 color;
+ if ( normalizedCost <= 0.5f )
+ {
+ color = lerp( low, mid, 2.f * normalizedCost );
+ }
+ else
+ {
+ color = lerp( mid, high, 2.f * ( normalizedCost - 0.5f ) );
+ }
+
+ LLColor4 line_color = color*0.5f;
+
+ U32 data_mask = LLVertexBuffer::MAP_VERTEX;
+
+ LLVolumeParams volume_params = volume->getVolume()->getParams();
+
+ LLPhysicsVolumeParams physics_params(volume_params,
+ physics_type == LLViewerObject::PHYSICS_SHAPE_CONVEX_HULL);
+
+ LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification physics_spec;
+ LLPhysicsShapeBuilderUtil::determinePhysicsShape(physics_params, volume->getScale(), physics_spec);
+
+ U32 type = physics_spec.getType();
+
+ LLVector3 center(0,0,0);
+ LLVector3 size(0.25f,0.25f,0.25f);
+
+ gGL.pushMatrix();
+ glMultMatrixf((F32*) volume->getRelativeXform().mMatrix);
+
+ if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::USER_MESH)
+ {
+ LLUUID mesh_id = volume->getVolume()->getParams().getSculptID();
+ LLModel::Decomposition* decomp = gMeshRepo.getDecomposition(mesh_id);
+
+ if (decomp)
+ { //render a physics based mesh
+
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+ if (!decomp->mHull.empty())
+ { //decomposition exists, use that
+
+ if (decomp->mMesh.empty())
+ {
+ gMeshRepo.buildPhysicsMesh(*decomp);
+ }
+
+ for (U32 i = 0; i < decomp->mMesh.size(); ++i)
+ {
+ render_hull(decomp->mMesh[i], color, line_color);
+ }
+ }
+ else if (!decomp->mPhysicsShapeMesh.empty())
+ {
+ //decomp has physics mesh, render that mesh
+ glColor4fv(color.mV);
+ LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mPhysicsShapeMesh.mPositions, decomp->mPhysicsShapeMesh.mNormals);
+
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ glColor4fv(line_color.mV);
+ LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mPhysicsShapeMesh.mPositions, decomp->mPhysicsShapeMesh.mNormals);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ }
+ else
+ { //no mesh or decomposition, render base hull
+ renderMeshBaseHull(volume, data_mask, color, line_color);
+
+ if (decomp->mPhysicsShapeMesh.empty())
+ {
+ //attempt to fetch physics shape mesh if available
+ gMeshRepo.fetchPhysicsShape(mesh_id);
+ }
+ }
+ }
+ else
+ {
+ gGL.color3f(1,1,0);
+ drawBoxOutline(center, size);
+ }
+ }
+ else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::USER_CONVEX ||
+ type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::PRIM_CONVEX)
+ {
+ if (volume->isMesh())
+ {
+ renderMeshBaseHull(volume, data_mask, color, line_color);
+ }
+#if LL_WINDOWS
+ else
+ {
+ LLVolumeParams volume_params = volume->getVolume()->getParams();
+ S32 detail = get_physics_detail(volume_params, volume->getScale());
+ LLVolume* phys_volume = LLPrimitive::sVolumeManager->refVolume(volume_params, detail);
+
+ if (!phys_volume->mHullPoints)
+ { //build convex hull
+ std::vector<LLVector3> pos;
+ std::vector<U16> index;
+
+ S32 index_offset = 0;
+
+ for (S32 i = 0; i < phys_volume->getNumVolumeFaces(); ++i)
+ {
+ const LLVolumeFace& face = phys_volume->getVolumeFace(i);
+ if (index_offset + face.mNumVertices > 65535)
+ {
+ continue;
+ }
+
+ for (S32 j = 0; j < face.mNumVertices; ++j)
+ {
+ pos.push_back(LLVector3(face.mPositions[j].getF32ptr()));
+ }
+
+ for (S32 j = 0; j < face.mNumIndices; ++j)
+ {
+ index.push_back(face.mIndices[j]+index_offset);
+ }
+
+ index_offset += face.mNumVertices;
+ }
+
+ if (!pos.empty() && !index.empty())
+ {
+ LLCDMeshData mesh;
+ mesh.mIndexBase = &index[0];
+ mesh.mVertexBase = pos[0].mV;
+ mesh.mNumVertices = pos.size();
+ mesh.mVertexStrideBytes = 12;
+ mesh.mIndexStrideBytes = 6;
+ mesh.mIndexType = LLCDMeshData::INT_16;
+
+ mesh.mNumTriangles = index.size()/3;
+
+ LLCDMeshData res;
+
+ LLConvexDecomposition::getInstance()->generateSingleHullMeshFromMesh( &mesh, &res );
+
+ //copy res into phys_volume
+ phys_volume->mHullPoints = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*res.mNumVertices);
+ phys_volume->mNumHullPoints = res.mNumVertices;
+
+ S32 idx_size = (res.mNumTriangles*3*2+0xF) & ~0xF;
+ phys_volume->mHullIndices = (U16*) ll_aligned_malloc_16(idx_size);
+ phys_volume->mNumHullIndices = res.mNumTriangles*3;
+
+ const F32* v = res.mVertexBase;
+
+ for (S32 i = 0; i < res.mNumVertices; ++i)
+ {
+ F32* p = (F32*) ((U8*)v+i*res.mVertexStrideBytes);
+ phys_volume->mHullPoints[i].load3(p);
+ }
+
+ if (res.mIndexType == LLCDMeshData::INT_16)
+ {
+ for (S32 i = 0; i < res.mNumTriangles; ++i)
+ {
+ U16* idx = (U16*) (((U8*)res.mIndexBase)+i*res.mIndexStrideBytes);
+
+ phys_volume->mHullIndices[i*3+0] = idx[0];
+ phys_volume->mHullIndices[i*3+1] = idx[1];
+ phys_volume->mHullIndices[i*3+2] = idx[2];
+ }
+ }
+ else
+ {
+ for (S32 i = 0; i < res.mNumTriangles; ++i)
+ {
+ U32* idx = (U32*) (((U8*)res.mIndexBase)+i*res.mIndexStrideBytes);
+
+ phys_volume->mHullIndices[i*3+0] = (U16) idx[0];
+ phys_volume->mHullIndices[i*3+1] = (U16) idx[1];
+ phys_volume->mHullIndices[i*3+2] = (U16) idx[2];
+ }
+ }
+ }
+ }
+
+ if (phys_volume->mHullPoints)
+ {
+ //render hull
+
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+
+ glColor4fv(line_color.mV);
+ LLVertexBuffer::unbind();
+
+ glVertexPointer(3, GL_FLOAT, 16, phys_volume->mHullPoints);
+ glDrawElements(GL_TRIANGLES, phys_volume->mNumHullIndices, GL_UNSIGNED_SHORT, phys_volume->mHullIndices);
+
+ glColor4fv(color.mV);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ glDrawElements(GL_TRIANGLES, phys_volume->mNumHullIndices, GL_UNSIGNED_SHORT, phys_volume->mHullIndices);
+ }
+ else
+ {
+ gGL.color3f(1,0,1);
+ drawBoxOutline(center, size);
+ }
+
+ LLPrimitive::sVolumeManager->unrefVolume(phys_volume);
+ }
+#endif //LL_WINDOWS
+ }
+ else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::BOX)
+ {
+ LLVector3 center = physics_spec.getCenter();
+ LLVector3 scale = physics_spec.getScale();
+ LLVector3 vscale = volume->getScale()*2.f;
+ scale.set(scale[0]/vscale[0], scale[1]/vscale[1], scale[2]/vscale[2]);
+
+ gGL.color4fv(color.mV);
+ drawBox(center, scale);
+ }
+ else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::SPHERE)
+ {
+ LLVolumeParams volume_params;
+ volume_params.setType( LL_PCODE_PROFILE_CIRCLE_HALF, LL_PCODE_PATH_CIRCLE );
+ volume_params.setBeginAndEndS( 0.f, 1.f );
+ volume_params.setBeginAndEndT( 0.f, 1.f );
+ volume_params.setRatio ( 1, 1 );
+ volume_params.setShear ( 0, 0 );
+ LLVolume* sphere = LLPrimitive::sVolumeManager->refVolume(volume_params, 3);
+
+ glColor4fv(color.mV);
+ pushVerts(sphere);
+ LLPrimitive::sVolumeManager->unrefVolume(sphere);
+ }
+ else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::CYLINDER)
+ {
+ LLVolumeParams volume_params;
+ volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE );
+ volume_params.setBeginAndEndS( 0.f, 1.f );
+ volume_params.setBeginAndEndT( 0.f, 1.f );
+ volume_params.setRatio ( 1, 1 );
+ volume_params.setShear ( 0, 0 );
+ LLVolume* cylinder = LLPrimitive::sVolumeManager->refVolume(volume_params, 3);
+
+ glColor4fv(color.mV);
+ pushVerts(cylinder);
+ LLPrimitive::sVolumeManager->unrefVolume(cylinder);
+ }
+ else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::PRIM_MESH)
+ {
+ LLVolumeParams volume_params = volume->getVolume()->getParams();
+ S32 detail = get_physics_detail(volume_params, volume->getScale());
+
+ LLVolume* phys_volume = LLPrimitive::sVolumeManager->refVolume(volume_params, detail);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+
+ glColor4fv(line_color.mV);
+ pushVerts(phys_volume);
+
+ glColor4fv(color.mV);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ pushVerts(phys_volume);
+ LLPrimitive::sVolumeManager->unrefVolume(phys_volume);
+ }
+ else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::PRIM_CONVEX)
+ {
+ LLVolumeParams volume_params = volume->getVolume()->getParams();
+ S32 detail = get_physics_detail(volume_params, volume->getScale());
+
+ LLVolume* phys_volume = LLPrimitive::sVolumeManager->refVolume(volume_params, detail);
+
+ if (phys_volume->mHullPoints && phys_volume->mHullIndices)
+ {
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+
+ LLVertexBuffer::unbind();
+ glVertexPointer(3, GL_FLOAT, 16, phys_volume->mHullPoints);
+ glColor4fv(line_color.mV);
+ glDrawElements(GL_TRIANGLES, phys_volume->mNumHullIndices, GL_UNSIGNED_SHORT, phys_volume->mHullIndices);
+
+ glColor4fv(color.mV);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ glDrawElements(GL_TRIANGLES, phys_volume->mNumHullIndices, GL_UNSIGNED_SHORT, phys_volume->mHullIndices);
+ }
+ else
+ {
+ gGL.color3f(1,0,1);
+ drawBoxOutline(center, size);
+ gMeshRepo.buildHull(volume_params, detail);
+ }
+ LLPrimitive::sVolumeManager->unrefVolume(phys_volume);
+ }
+ else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::SCULPT)
+ {
+ //TODO: implement sculpted prim physics display
+ }
+ else
+ {
+ llerrs << "Unhandled type" << llendl;
+ }
+
+ gGL.popMatrix();
+
+ /*{ //analytical shape, just push visual rep.
+ glColor3fv(color.mV);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ pushVerts(drawable, data_mask);
+ glColor4fv(color.mV);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ pushVerts(drawable, data_mask);
+ }*/
+}
+
+void renderPhysicsShapes(LLSpatialGroup* group)
+{
+ for (LLSpatialGroup::OctreeNode::const_element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
+ {
+ LLDrawable* drawable = *i;
+ LLVOVolume* volume = drawable->getVOVolume();
+ if (volume && !volume->isAttachment() && volume->getPhysicsShapeType() != LLViewerObject::PHYSICS_SHAPE_NONE )
+ {
+ if (!group->mSpatialPartition->isBridge())
+ {
+ gGL.pushMatrix();
+ LLVector3 trans = drawable->getRegion()->getOriginAgent();
+ glTranslatef(trans.mV[0], trans.mV[1], trans.mV[2]);
+ renderPhysicsShape(drawable, volume);
+ gGL.popMatrix();
+ }
+ else
+ {
+ renderPhysicsShape(drawable, volume);
+ }
+ }
+ else
+ {
+ LLViewerObject* object = drawable->getVObj();
+ if (object && object->getPCode() == LLViewerObject::LL_VO_SURFACE_PATCH)
+ {
+ //push face vertices for terrain
+ for (S32 i = 0; i < drawable->getNumFaces(); ++i)
+ {
+ LLFace* face = drawable->getFace(i);
+ LLVertexBuffer* buff = face->getVertexBuffer();
+ if (buff)
+ {
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+
+ buff->setBuffer(LLVertexBuffer::MAP_VERTEX);
+ glColor3f(0.2f, 0.5f, 0.3f);
+ buff->draw(LLRender::TRIANGLES, buff->getRequestedIndices(), 0);
+
+ glColor3f(0.2f, 1.f, 0.3f);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ buff->draw(LLRender::TRIANGLES, buff->getRequestedIndices(), 0);
+ }
+ }
+ }
+ }
+ }
}
void renderTexturePriority(LLDrawable* drawable)
@@ -2690,8 +3421,13 @@ void renderTexturePriority(LLDrawable* drawable)
// gGL.color4f(1,0,1,1);
//}
- LLVector3 center = (facep->mExtents[1]+facep->mExtents[0])*0.5f;
- LLVector3 size = (facep->mExtents[1]-facep->mExtents[0])*0.5f + LLVector3(0.01f, 0.01f, 0.01f);
+ LLVector4a center;
+ center.setAdd(facep->mExtents[1],facep->mExtents[0]);
+ center.mul(0.5f);
+ LLVector4a size;
+ size.setSub(facep->mExtents[1],facep->mExtents[0]);
+ size.mul(0.5f);
+ size.add(LLVector4a(0.01f));
drawBox(center, size);
/*S32 boost = imagep->getBoostLevel();
@@ -2715,7 +3451,6 @@ void renderPoints(LLDrawable* drawablep)
{
gGL.begin(LLRender::POINTS);
gGL.color3f(1,1,1);
- LLVector3 center(drawablep->getPositionGroup());
for (S32 i = 0; i < drawablep->getNumFaces(); i++)
{
gGL.vertex3fv(drawablep->getFace(i)->mCenterLocal.mV);
@@ -2747,8 +3482,12 @@ void renderShadowFrusta(LLDrawInfo* params)
LLGLEnable blend(GL_BLEND);
gGL.setSceneBlendType(LLRender::BT_ADD);
- LLVector3 center = (params->mExtents[1]+params->mExtents[0])*0.5f;
- LLVector3 size = (params->mExtents[1]-params->mExtents[0])*0.5f;
+ LLVector4a center;
+ center.setAdd(params->mExtents[1], params->mExtents[0]);
+ center.mul(0.5f);
+ LLVector4a size;
+ size.setSub(params->mExtents[1],params->mExtents[0]);
+ size.mul(0.5f);
if (gPipeline.mShadowCamera[4].AABBInFrustum(center, size))
{
@@ -2792,10 +3531,14 @@ void renderLights(LLDrawable* drawablep)
pushVerts(drawablep->getFace(i), LLVertexBuffer::MAP_VERTEX);
}
- const LLVector3* ext = drawablep->getSpatialExtents();
+ const LLVector4a* ext = drawablep->getSpatialExtents();
- LLVector3 pos = (ext[0] + ext[1]) * 0.5f;
- LLVector3 size = (ext[1] - ext[0]) * 0.5f;
+ LLVector4a pos;
+ pos.setAdd(ext[0], ext[1]);
+ pos.mul(0.5f);
+ LLVector4a size;
+ size.setSub(ext[1], ext[0]);
+ size.mul(0.5f);
{
LLGLDepthTest depth(GL_FALSE, GL_TRUE);
@@ -2805,65 +3548,206 @@ void renderLights(LLDrawable* drawablep)
gGL.color4f(1,1,0,1);
F32 rad = drawablep->getVOVolume()->getLightRadius();
- drawBoxOutline(pos, LLVector3(rad,rad,rad));
+ drawBoxOutline(pos, LLVector4a(rad));
}
}
-
-void renderRaycast(LLDrawable* drawablep)
+class LLRenderOctreeRaycast : public LLOctreeTriangleRayIntersect
{
- if (drawablep->getVObj() != gDebugRaycastObject)
+public:
+
+
+ LLRenderOctreeRaycast(const LLVector4a& start, const LLVector4a& dir, F32* closest_t)
+ : LLOctreeTriangleRayIntersect(start, dir, NULL, closest_t, NULL, NULL, NULL, NULL)
{
- return;
+
}
-
+
+ void visit(const LLOctreeNode<LLVolumeTriangle>* branch)
+ {
+ LLVolumeOctreeListener* vl = (LLVolumeOctreeListener*) branch->getListener(0);
+
+ LLVector3 center, size;
+
+ if (branch->getData().empty())
+ {
+ gGL.color3f(1.f,0.2f,0.f);
+ center.set(branch->getCenter().getF32ptr());
+ size.set(branch->getSize().getF32ptr());
+ }
+ else
+ {
+ gGL.color3f(0.75f, 1.f, 0.f);
+ center.set(vl->mBounds[0].getF32ptr());
+ size.set(vl->mBounds[1].getF32ptr());
+ }
+
+ drawBoxOutline(center, size);
+
+ for (U32 i = 0; i < 2; i++)
+ {
+ LLGLDepthTest depth(GL_TRUE, GL_FALSE, i == 1 ? GL_LEQUAL : GL_GREATER);
+
+ if (i == 1)
+ {
+ gGL.color4f(0,1,1,0.5f);
+ }
+ else
+ {
+ gGL.color4f(0,0.5f,0.5f, 0.25f);
+ drawBoxOutline(center, size);
+ }
+
+ if (i == 1)
+ {
+ gGL.flush();
+ glLineWidth(3.f);
+ }
+
+ gGL.begin(LLRender::TRIANGLES);
+ for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter = branch->getData().begin();
+ iter != branch->getData().end();
+ ++iter)
+ {
+ const LLVolumeTriangle* tri = *iter;
+
+ gGL.vertex3fv(tri->mV[0]->getF32ptr());
+ gGL.vertex3fv(tri->mV[1]->getF32ptr());
+ gGL.vertex3fv(tri->mV[2]->getF32ptr());
+ }
+ gGL.end();
+
+ if (i == 1)
+ {
+ gGL.flush();
+ glLineWidth(1.f);
+ }
+ }
+ }
+};
+
+void renderRaycast(LLDrawable* drawablep)
+{
if (drawablep->getNumFaces())
{
LLGLEnable blend(GL_BLEND);
gGL.color4f(0,1,1,0.5f);
- if (drawablep->getVOVolume() && gDebugRaycastFaceHit != -1)
+ if (drawablep->getVOVolume())
{
- glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
- pushVerts(drawablep->getFace(gDebugRaycastFaceHit), LLVertexBuffer::MAP_VERTEX);
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ //pushVerts(drawablep->getFace(gDebugRaycastFaceHit), LLVertexBuffer::MAP_VERTEX);
+ //glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+
+ LLVOVolume* vobj = drawablep->getVOVolume();
+ LLVolume* volume = vobj->getVolume();
+
+ bool transform = true;
+ if (drawablep->isState(LLDrawable::RIGGED))
+ {
+ volume = vobj->getRiggedVolume();
+ transform = false;
+ }
+
+ if (volume)
+ {
+ LLVector3 trans = drawablep->getRegion()->getOriginAgent();
+
+ for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
+ {
+ const LLVolumeFace& face = volume->getVolumeFace(i);
+ if (!face.mOctree)
+ {
+ ((LLVolumeFace*) &face)->createOctree();
+ }
+
+ gGL.pushMatrix();
+ glTranslatef(trans.mV[0], trans.mV[1], trans.mV[2]);
+ glMultMatrixf((F32*) vobj->getRelativeXform().mMatrix);
+
+ LLVector3 start, end;
+ if (transform)
+ {
+ start = vobj->agentPositionToVolume(gDebugRaycastStart);
+ end = vobj->agentPositionToVolume(gDebugRaycastEnd);
+ }
+ else
+ {
+ start = gDebugRaycastStart;
+ end = gDebugRaycastEnd;
+ }
+
+ LLVector4a starta, enda;
+ starta.load3(start.mV);
+ enda.load3(end.mV);
+ LLVector4a dir;
+ dir.setSub(enda, starta);
+
+ F32 t = 1.f;
+
+ LLRenderOctreeRaycast render(starta, dir, &t);
+ gGL.flush();
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+
+ {
+ //render face positions
+ LLVertexBuffer::unbind();
+ glColor4f(0,1,1,0.5f);
+ glVertexPointer(3, GL_FLOAT, sizeof(LLVector4a), face.mPositions);
+ glDrawElements(GL_TRIANGLES, face.mNumIndices, GL_UNSIGNED_SHORT, face.mIndices);
+ }
+
+ render.traverse(face.mOctree);
+ gGL.popMatrix();
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ }
+ }
}
else if (drawablep->isAvatar())
{
- LLGLDepthTest depth(GL_FALSE);
- LLVOAvatar* av = (LLVOAvatar*) drawablep->getVObj().get();
- av->renderCollisionVolumes();
- }
-
- // draw intersection point
- glPushMatrix();
- glLoadMatrixd(gGLModelView);
- LLVector3 translate = gDebugRaycastIntersection;
- glTranslatef(translate.mV[0], translate.mV[1], translate.mV[2]);
- LLCoordFrame orient;
- orient.lookDir(gDebugRaycastNormal, gDebugRaycastBinormal);
- LLMatrix4 rotation;
- orient.getRotMatrixToParent(rotation);
- glMultMatrixf((float*)rotation.mMatrix);
-
- gGL.color4f(1,0,0,0.5f);
- drawBox(LLVector3(0, 0, 0), LLVector3(0.1f, 0.022f, 0.022f));
- gGL.color4f(0,1,0,0.5f);
- drawBox(LLVector3(0, 0, 0), LLVector3(0.021f, 0.1f, 0.021f));
- gGL.color4f(0,0,1,0.5f);
- drawBox(LLVector3(0, 0, 0), LLVector3(0.02f, 0.02f, 0.1f));
- glPopMatrix();
-
- // draw bounding box of prim
- const LLVector3* ext = drawablep->getSpatialExtents();
-
- LLVector3 pos = (ext[0] + ext[1]) * 0.5f;
- LLVector3 size = (ext[1] - ext[0]) * 0.5f;
+ if (drawablep->getVObj() == gDebugRaycastObject)
+ {
+ LLGLDepthTest depth(GL_FALSE);
+ LLVOAvatar* av = (LLVOAvatar*) drawablep->getVObj().get();
+ av->renderCollisionVolumes();
+ }
+ }
- LLGLDepthTest depth(GL_FALSE, GL_TRUE);
- gGL.color4f(0,0.5f,0.5f,1);
- drawBoxOutline(pos, size);
+ if (drawablep->getVObj() == gDebugRaycastObject)
+ {
+ // draw intersection point
+ glPushMatrix();
+ glLoadMatrixd(gGLModelView);
+ LLVector3 translate = gDebugRaycastIntersection;
+ glTranslatef(translate.mV[0], translate.mV[1], translate.mV[2]);
+ LLCoordFrame orient;
+ orient.lookDir(gDebugRaycastNormal, gDebugRaycastBinormal);
+ LLMatrix4 rotation;
+ orient.getRotMatrixToParent(rotation);
+ glMultMatrixf((float*)rotation.mMatrix);
+
+ gGL.color4f(1,0,0,0.5f);
+ drawBox(LLVector3(0, 0, 0), LLVector3(0.1f, 0.022f, 0.022f));
+ gGL.color4f(0,1,0,0.5f);
+ drawBox(LLVector3(0, 0, 0), LLVector3(0.021f, 0.1f, 0.021f));
+ gGL.color4f(0,0,1,0.5f);
+ drawBox(LLVector3(0, 0, 0), LLVector3(0.02f, 0.02f, 0.1f));
+ glPopMatrix();
+
+ // draw bounding box of prim
+ const LLVector4a* ext = drawablep->getSpatialExtents();
+
+ LLVector4a pos;
+ pos.setAdd(ext[0], ext[1]);
+ pos.mul(0.5f);
+ LLVector4a size;
+ size.setSub(ext[1], ext[0]);
+ size.mul(0.5f);
+ LLGLDepthTest depth(GL_FALSE, GL_TRUE);
+ gGL.color4f(0,0.5f,0.5f,1);
+ drawBoxOutline(pos, size);
+ }
}
}
@@ -2885,7 +3769,6 @@ void renderAgentTarget(LLVOAvatar* avatar)
}
}
-
class LLOctreeRenderNonOccluded : public LLOctreeTraveler<LLDrawable>
{
public:
@@ -2945,8 +3828,8 @@ public:
return;
}
- LLVector3 nodeCenter = group->mBounds[0];
- LLVector3 octCenter = LLVector3(group->mOctreeNode->getCenter());
+ LLVector4a nodeCenter = group->mBounds[0];
+ LLVector4a octCenter = group->mOctreeNode->getCenter();
group->rebuildGeom();
group->rebuildMesh();
@@ -2969,14 +3852,25 @@ public:
{
renderBoundingBox(drawable);
}
+
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_NORMALS))
+ {
+ renderNormals(drawable);
+ }
if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BUILD_QUEUE))
{
if (drawable->isState(LLDrawable::IN_REBUILD_Q2))
{
gGL.color4f(0.6f, 0.6f, 0.1f, 1.f);
- const LLVector3* ext = drawable->getSpatialExtents();
- drawBoxOutline((ext[0]+ext[1])*0.5f, (ext[1]-ext[0])*0.5f);
+ const LLVector4a* ext = drawable->getSpatialExtents();
+ LLVector4a center;
+ center.setAdd(ext[0], ext[1]);
+ center.mul(0.5f);
+ LLVector4a size;
+ size.setSub(ext[1], ext[0]);
+ size.mul(0.5f);
+ drawBoxOutline(center, size);
}
}
@@ -2999,6 +3893,10 @@ public:
{
renderRaycast(drawable);
}
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_UPDATE_TYPE))
+ {
+ renderUpdateType(drawable);
+ }
LLVOAvatar* avatar = dynamic_cast<LLVOAvatar*>(drawable->getVObj().get());
@@ -3037,6 +3935,41 @@ public:
}
};
+
+class LLOctreeRenderPhysicsShapes : public LLOctreeTraveler<LLDrawable>
+{
+public:
+ LLCamera* mCamera;
+ LLOctreeRenderPhysicsShapes(LLCamera* camera): mCamera(camera) {}
+
+ virtual void traverse(const LLSpatialGroup::OctreeNode* node)
+ {
+ LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
+
+ if (!mCamera || mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]))
+ {
+ node->accept(this);
+ stop_glerror();
+
+ for (U32 i = 0; i < node->getChildCount(); i++)
+ {
+ traverse(node->getChild(i));
+ stop_glerror();
+ }
+
+ group->rebuildGeom();
+ group->rebuildMesh();
+
+ renderPhysicsShapes(group);
+ }
+ }
+
+ virtual void visit(const LLSpatialGroup::OctreeNode* branch)
+ {
+
+ }
+};
+
class LLOctreePushBBoxVerts : public LLOctreeTraveler<LLDrawable>
{
public:
@@ -3155,20 +4088,41 @@ public:
};
+void LLSpatialPartition::renderPhysicsShapes()
+{
+ LLSpatialBridge* bridge = asBridge();
+ LLCamera* camera = LLViewerCamera::getInstance();
+
+ if (bridge)
+ {
+ camera = NULL;
+ }
+
+ gGL.flush();
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ glLineWidth(3.f);
+ LLOctreeRenderPhysicsShapes render_physics(camera);
+ render_physics.traverse(mOctree);
+ gGL.flush();
+ glLineWidth(1.f);
+}
+
void LLSpatialPartition::renderDebug()
{
if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCTREE |
LLPipeline::RENDER_DEBUG_OCCLUSION |
LLPipeline::RENDER_DEBUG_LIGHTS |
LLPipeline::RENDER_DEBUG_BATCH_SIZE |
+ LLPipeline::RENDER_DEBUG_UPDATE_TYPE |
LLPipeline::RENDER_DEBUG_BBOXES |
+ LLPipeline::RENDER_DEBUG_NORMALS |
LLPipeline::RENDER_DEBUG_POINTS |
LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY |
LLPipeline::RENDER_DEBUG_TEXTURE_ANIM |
LLPipeline::RENDER_DEBUG_RAYCAST |
LLPipeline::RENDER_DEBUG_AVATAR_VOLUME |
LLPipeline::RENDER_DEBUG_AGENT_TARGET |
- LLPipeline::RENDER_DEBUG_BUILD_QUEUE |
+ //LLPipeline::RENDER_DEBUG_BUILD_QUEUE |
LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
{
return;
@@ -3207,7 +4161,11 @@ void LLSpatialPartition::renderDebug()
void LLSpatialGroup::drawObjectBox(LLColor4 col)
{
gGL.color4fv(col.mV);
- drawBox(mObjectBounds[0], mObjectBounds[1]*1.01f+LLVector3(0.001f, 0.001f, 0.001f));
+ LLVector4a size;
+ size = mObjectBounds[1];
+ size.mul(1.01f);
+ size.add(LLVector4a(0.001f));
+ drawBox(mObjectBounds[0], size);
}
@@ -3267,8 +4225,8 @@ public:
LLSpatialGroup* group = (LLSpatialGroup*) child->getListener(0);
- LLVector3 size;
- LLVector3 center;
+ LLVector4a size;
+ LLVector4a center;
size = group->mBounds[1];
center = group->mBounds[0];
@@ -3285,7 +4243,11 @@ public:
local_end = mEnd * local_matrix;
}
- if (LLLineSegmentBoxIntersect(local_start, local_end, center, size))
+ LLVector4a start, end;
+ start.load3(local_start.mV);
+ end.load3(local_end.mV);
+
+ if (LLLineSegmentBoxIntersect(start, end, center, size))
{
check(child);
}
@@ -3375,18 +4337,9 @@ LLDrawInfo::LLDrawInfo(U16 start, U16 end, U32 count, U32 offset,
mDistance(0.f),
mDrawMode(LLRender::TRIANGLES)
{
+ mVertexBuffer->validateRange(mStart, mEnd, mCount, mOffset);
+
mDebugColor = (rand() << 16) + rand();
- if (mStart >= mVertexBuffer->getRequestedVerts() ||
- mEnd >= mVertexBuffer->getRequestedVerts())
- {
- llerrs << "Invalid draw info vertex range." << llendl;
- }
-
- if (mOffset >= (U32) mVertexBuffer->getRequestedIndices() ||
- mOffset + mCount > (U32) mVertexBuffer->getRequestedIndices())
- {
- llerrs << "Invalid draw info index range." << llendl;
- }
}
LLDrawInfo::~LLDrawInfo()
@@ -3400,6 +4353,16 @@ LLDrawInfo::~LLDrawInfo()
{
mFace->setDrawInfo(NULL);
}
+
+ if (gDebugGL)
+ {
+ gPipeline.checkReferences(this);
+ }
+}
+
+void LLDrawInfo::validate()
+{
+ mVertexBuffer->validateRange(mStart, mEnd, mCount, mOffset);
}
LLVertexBuffer* LLGeometryManager::createVertexBuffer(U32 type_mask, U32 usage)
diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h
index 1a25f3f85d..0d9cad914a 100644
--- a/indra/newview/llspatialpartition.h
+++ b/indra/newview/llspatialpartition.h
@@ -39,7 +39,7 @@
#include "lldrawpool.h"
#include "llface.h"
#include "llviewercamera.h"
-
+#include "llvector4a.h"
#include <queue>
#define SG_STATE_INHERIT_MASK (OCCLUDED)
@@ -51,11 +51,16 @@ class LLSpatialGroup;
class LLTextureAtlas;
class LLTextureAtlasSlot;
+S32 AABBSphereIntersect(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &rad);
+S32 AABBSphereIntersectR2(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &radius_squared);
+
S32 AABBSphereIntersect(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &rad);
S32 AABBSphereIntersectR2(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &radius_squared);
+void pushVerts(LLFace* face, U32 mask);
// get index buffer for binary encoded axis vertex buffer given a box at center being viewed by given camera
-U8* get_box_fan_indices(LLCamera* camera, const LLVector3& center);
+U32 get_box_fan_indices(LLCamera* camera, const LLVector4a& center);
+U8* get_box_fan_indices_ptr(LLCamera* camera, const LLVector4a& center);
class LLDrawInfo : public LLRefCount
{
@@ -63,11 +68,27 @@ protected:
~LLDrawInfo();
public:
+
+ LLDrawInfo(const LLDrawInfo& rhs)
+ {
+ *this = rhs;
+ }
+
+ const LLDrawInfo& operator=(const LLDrawInfo& rhs)
+ {
+ llerrs << "Illegal operation!" << llendl;
+ return *this;
+ }
+
LLDrawInfo(U16 start, U16 end, U32 count, U32 offset,
LLViewerTexture* image, LLVertexBuffer* buffer,
BOOL fullbright = FALSE, U8 bump = 0, BOOL particle = FALSE, F32 part_size = 0);
+ void validate();
+
+ LLVector4a mExtents[2];
+
LLPointer<LLVertexBuffer> mVertexBuffer;
LLPointer<LLViewerTexture> mTexture;
LLColor4U mGlowColor;
@@ -86,7 +107,6 @@ public:
LLSpatialGroup* mGroup;
LLFace* mFace; //associated face
F32 mDistance;
- LLVector3 mExtents[2];
U32 mDrawMode;
struct CompareTexture
@@ -128,6 +148,17 @@ public:
};
+ struct CompareMatrixTexturePtr
+ {
+ bool operator()(const LLPointer<LLDrawInfo>& lhs, const LLPointer<LLDrawInfo>& rhs)
+ {
+ return lhs.get() != rhs.get()
+ && (lhs.isNull() || (rhs.notNull() && (lhs->mModelMatrix > rhs->mModelMatrix ||
+ (lhs->mModelMatrix == rhs->mModelMatrix && lhs->mTexture.get() > rhs->mTexture.get()))));
+ }
+
+ };
+
struct CompareBump
{
bool operator()(const LLPointer<LLDrawInfo>& lhs, const LLPointer<LLDrawInfo>& rhs)
@@ -149,11 +180,25 @@ public:
};
};
+LL_ALIGN_PREFIX(64)
class LLSpatialGroup : public LLOctreeListener<LLDrawable>
{
friend class LLSpatialPartition;
friend class LLOctreeStateCheck;
public:
+
+ LLSpatialGroup(const LLSpatialGroup& rhs)
+ {
+ *this = rhs;
+ }
+
+ const LLSpatialGroup& operator=(const LLSpatialGroup& rhs)
+ {
+ llerrs << "Illegal operation!" << llendl;
+ return *this;
+ }
+
+ static std::set<GLuint> sPendingQueries; //pending occlusion queries
static U32 sNodeCount;
static BOOL sNoDelete; //deletion of spatial groups and draw info not allowed if TRUE
@@ -262,8 +307,8 @@ public:
BOOL isVisible() const;
BOOL isRecentlyVisible() const;
void setVisible();
- void shift(const LLVector3 &offset);
- BOOL boundObjects(BOOL empty, LLVector3& newMin, LLVector3& newMax);
+ void shift(const LLVector4a &offset);
+ BOOL boundObjects(BOOL empty, LLVector4a& newMin, LLVector4a& newMax);
void unbound();
BOOL rebound();
void buildOcclusion(); //rebuild mOcclusionVerts
@@ -311,6 +356,27 @@ public:
void addAtlas(LLTextureAtlas* atlasp, S8 recursive_level = 3) ;
void removeAtlas(LLTextureAtlas* atlasp, BOOL remove_group = TRUE, S8 recursive_level = 3) ;
void clearAtlasList() ;
+
+public:
+
+ typedef enum
+ {
+ BOUNDS = 0,
+ EXTENTS = 2,
+ OBJECT_BOUNDS = 4,
+ OBJECT_EXTENTS = 6,
+ VIEW_ANGLE = 8,
+ LAST_VIEW_ANGLE = 9,
+ V4_COUNT = 10
+ } eV4Index;
+
+ LLVector4a mBounds[2]; // bounding box (center, size) of this node and all its children (tight fit to objects)
+ LLVector4a mExtents[2]; // extents (min, max) of this node and all its children
+ LLVector4a mObjectExtents[2]; // extents (min, max) of objects in this node
+ LLVector4a mObjectBounds[2]; // bounding box (center, size) of objects in this node
+ LLVector4a mViewAngle;
+ LLVector4a mLastUpdateViewAngle;
+
private:
U32 mCurUpdatingTime ;
//do not make the below two to use LLPointer
@@ -338,14 +404,9 @@ public:
F32 mBuilt;
OctreeNode* mOctreeNode;
LLSpatialPartition* mSpatialPartition;
- LLVector3 mBounds[2]; // bounding box (center, size) of this node and all its children (tight fit to objects)
- LLVector3 mExtents[2]; // extents (min, max) of this node and all its children
- LLVector3 mObjectExtents[2]; // extents (min, max) of objects in this node
- LLVector3 mObjectBounds[2]; // bounding box (center, size) of objects in this node
-
LLPointer<LLVertexBuffer> mVertexBuffer;
- F32* mOcclusionVerts;
+ LLPointer<LLVertexBuffer> mOcclusionVerts;
GLuint mOcclusionQuery[LLViewerCamera::NUM_CAMERAS];
U32 mBufferUsage;
@@ -356,13 +417,10 @@ public:
F32 mDepth;
F32 mLastUpdateDistance;
F32 mLastUpdateTime;
-
- LLVector3 mViewAngle;
- LLVector3 mLastUpdateViewAngle;
F32 mPixelArea;
F32 mRadius;
-};
+} LL_ALIGN_POSTFIX(64);
class LLGeometryManager
{
@@ -398,7 +456,7 @@ public:
// If the drawable moves, move it here.
virtual void move(LLDrawable *drawablep, LLSpatialGroup *curp, BOOL immediate = FALSE);
- virtual void shift(const LLVector3 &offset);
+ virtual void shift(const LLVector4a &offset);
virtual F32 calcDistance(LLSpatialGroup* group, LLCamera& camera);
virtual F32 calcPixelArea(LLSpatialGroup* group, LLCamera& camera);
@@ -414,6 +472,7 @@ public:
virtual LLSpatialBridge* asBridge() { return NULL; }
virtual BOOL isBridge() { return asBridge() != NULL; }
+ void renderPhysicsShapes();
void renderDebug();
void renderIntersectingBBoxes(LLCamera* camera);
void restoreGL();
@@ -456,7 +515,7 @@ public:
virtual void makeActive();
virtual void move(LLDrawable *drawablep, LLSpatialGroup *curp, BOOL immediate = FALSE);
virtual BOOL updateMove();
- virtual void shiftPos(const LLVector3& vec);
+ virtual void shiftPos(const LLVector4a& vec);
virtual void cleanupReferences();
virtual LLSpatialPartition* asPartition() { return this; }
virtual LLSpatialBridge* asBridge() { return this; }
@@ -484,6 +543,7 @@ public:
sg_list_t::iterator beginAlphaGroups();
sg_list_t::iterator endAlphaGroups();
+ bool hasOcclusionGroups() { return mOcclusionGroupsSize > 0; }
sg_list_t::iterator beginOcclusionGroups();
sg_list_t::iterator endOcclusionGroups();
@@ -551,6 +611,13 @@ public:
virtual void addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32& index_count) { }
};
+//spatial partition for hole and edge water (implemented in LLVOWater.cpp)
+class LLVoidWaterPartition : public LLWaterPartition
+{
+public:
+ LLVoidWaterPartition();
+};
+
//spatial partition for terrain (impelmented in LLVOSurfacePatch.cpp)
class LLTerrainPartition : public LLSpatialPartition
{
@@ -606,6 +673,13 @@ public:
class LLVolumeGeometryManager: public LLGeometryManager
{
public:
+ typedef enum
+ {
+ NONE = 0,
+ BATCH_SORT,
+ DISTANCE_SORT
+ } eSortType;
+
virtual ~LLVolumeGeometryManager() { }
virtual void rebuildGeom(LLSpatialGroup* group);
virtual void rebuildMesh(LLSpatialGroup* group);
@@ -640,7 +714,7 @@ class LLHUDBridge : public LLVolumeBridge
{
public:
LLHUDBridge(LLDrawable* drawablep);
- virtual void shiftPos(const LLVector3& vec);
+ virtual void shiftPos(const LLVector4a& vec);
virtual F32 calcPixelArea(LLSpatialGroup* group, LLCamera& camera);
};
@@ -657,11 +731,9 @@ class LLHUDPartition : public LLBridgePartition
{
public:
LLHUDPartition();
- virtual void shift(const LLVector3 &offset);
+ virtual void shift(const LLVector4a &offset);
};
-void validate_draw_info(LLDrawInfo& params);
-
extern const F32 SG_BOX_SIDE;
extern const F32 SG_BOX_OFFSET;
extern const F32 SG_BOX_RAD;
diff --git a/indra/newview/llspeakbutton.cpp b/indra/newview/llspeakbutton.cpp
index 3dce66f394..d3e96f8dfb 100644
--- a/indra/newview/llspeakbutton.cpp
+++ b/indra/newview/llspeakbutton.cpp
@@ -38,6 +38,7 @@
#include "llspeakbutton.h"
#include "llbottomtray.h"
+#include "llfirstuse.h"
static LLDefaultChildRegistry::Register<LLSpeakButton> t1("talk_button");
@@ -53,26 +54,6 @@ LLSpeakButton::Params::Params()
// See widgets/talk_button.xml
}
-void LLSpeakButton::draw()
-{
- // LLVoiceClient::getInstance() is the authoritative global source of info regarding our open-mic state, we merely reflect that state.
- bool openmic = LLVoiceClient::getInstance()->getUserPTTState();
- bool voiceenabled = LLVoiceClient::getInstance()->voiceEnabled();
- mSpeakBtn->setToggleState(openmic && voiceenabled);
- mOutputMonitor->setIsMuted(!voiceenabled);
- LLUICtrl::draw();
-}
-void LLSpeakButton::setSpeakBtnEnabled(bool enabled)
-{
- LLButton* speak_btn = getChild<LLButton>("speak_btn");
- speak_btn->setEnabled(enabled);
-}
-void LLSpeakButton::setFlyoutBtnEnabled(bool enabled)
-{
- LLButton* show_btn = getChild<LLBottomtrayButton>("speak_flyout_btn");
- show_btn->setEnabled(enabled);
-}
-
LLSpeakButton::LLSpeakButton(const Params& p)
: LLUICtrl(p)
, mOutputMonitor(NULL)
@@ -134,8 +115,11 @@ LLSpeakButton::LLSpeakButton(const Params& p)
LLSpeakButton::~LLSpeakButton()
{
- LLTransientFloaterMgr::getInstance()->removeControlView(mSpeakBtn);
- LLTransientFloaterMgr::getInstance()->removeControlView(mShowBtn);
+ if(LLTransientFloaterMgr::instanceExists())
+ {
+ LLTransientFloaterMgr::getInstance()->removeControlView(mSpeakBtn);
+ LLTransientFloaterMgr::getInstance()->removeControlView(mShowBtn);
+ }
}
void LLSpeakButton::setSpeakToolTip(const std::string& msg)
@@ -173,6 +157,7 @@ void LLSpeakButton::onMouseDown_SpeakBtn()
{
bool down = true;
LLVoiceClient::getInstance()->inputUserControlState(down); // this method knows/care about whether this translates into a toggle-to-talk or down-to-talk
+ LLFirstUse::speak(false);
}
void LLSpeakButton::onMouseUp_SpeakBtn()
{
diff --git a/indra/newview/llspeakbutton.h b/indra/newview/llspeakbutton.h
index 2fdf80c1f2..7db01112ef 100644
--- a/indra/newview/llspeakbutton.h
+++ b/indra/newview/llspeakbutton.h
@@ -53,12 +53,7 @@ public:
};
/*virtual*/ ~LLSpeakButton();
- /*virtual*/ void draw();
- // methods for enabling/disabling right and left parts of speak button separately(EXT-4648)
- void setSpeakBtnEnabled(bool enabled);
- void setFlyoutBtnEnabled(bool enabled);
-
// *HACK: Need to put tooltips in a translatable location,
// the panel that contains this button.
void setSpeakToolTip(const std::string& msg);
diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp
index 40aea05839..c588bd8fb4 100644
--- a/indra/newview/llspeakers.cpp
+++ b/indra/newview/llspeakers.cpp
@@ -920,7 +920,7 @@ void LLLocalSpeakerMgr::updateSpeakerList()
if (speakerp->mStatus == LLSpeaker::STATUS_TEXT_ONLY)
{
LLVOAvatar* avatarp = (LLVOAvatar*)gObjectList.findObject(speaker_id);
- if (!avatarp || dist_vec(avatarp->getPositionAgent(), gAgent.getPositionAgent()) > CHAT_NORMAL_RADIUS)
+ if (!avatarp || dist_vec_squared(avatarp->getPositionAgent(), gAgent.getPositionAgent()) > CHAT_NORMAL_RADIUS_SQUARED)
{
setSpeakerNotInChannel(speakerp);
}
diff --git a/indra/newview/llspeakingindicatormanager.cpp b/indra/newview/llspeakingindicatormanager.cpp
index ede1d6bebe..9b38bf22ff 100644
--- a/indra/newview/llspeakingindicatormanager.cpp
+++ b/indra/newview/llspeakingindicatormanager.cpp
@@ -308,7 +308,10 @@ void LLSpeakingIndicatorManager::registerSpeakingIndicator(const LLUUID& speaker
void LLSpeakingIndicatorManager::unregisterSpeakingIndicator(const LLUUID& speaker_id, const LLSpeakingIndicator* const speaking_indicator)
{
- SpeakingIndicatorManager::instance().unregisterSpeakingIndicator(speaker_id, speaking_indicator);
+ if(SpeakingIndicatorManager::instanceExists())
+ {
+ SpeakingIndicatorManager::instance().unregisterSpeakingIndicator(speaker_id, speaking_indicator);
+ }
}
// EOF
diff --git a/indra/newview/llsprite.cpp b/indra/newview/llsprite.cpp
index a69592b61c..4bde2dfcab 100644
--- a/indra/newview/llsprite.cpp
+++ b/indra/newview/llsprite.cpp
@@ -186,14 +186,15 @@ void LLSprite::updateFace(LLFace &face)
U16 index_offset;
// Setup face
- if (face.mVertexBuffer.isNull())
+ if (!face.getVertexBuffer())
{
- face.mVertexBuffer = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX |
+ LLVertexBuffer* buff = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX |
LLVertexBuffer::MAP_TEXCOORD0,
GL_STREAM_DRAW_ARB);
- face.mVertexBuffer->allocateBuffer(4, 12, TRUE);
+ buff->allocateBuffer(4, 12, TRUE);
face.setGeomIndex(0);
face.setIndicesIndex(0);
+ face.setVertexBuffer(buff);
}
index_offset = face.getGeometry(verticesp,normalsp,tex_coordsp, indicesp);
@@ -242,7 +243,7 @@ void LLSprite::updateFace(LLFace &face)
*indicesp++ = 3 + index_offset;
}
- face.mVertexBuffer->setBuffer(0);
+ face.getVertexBuffer()->setBuffer(0);
face.mCenterAgent = mPosition;
}
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 5ee4599200..141a81c717 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -139,6 +139,7 @@
#include "lltrans.h"
#include "llui.h"
#include "llurldispatcher.h"
+#include "llurlentry.h"
#include "llslurl.h"
#include "llurlhistory.h"
#include "llurlwhitelist.h"
@@ -198,6 +199,7 @@
// exported globals
//
bool gAgentMovementCompleted = false;
+S32 gMaxAgentGroups;
std::string SCREEN_HOME_FILENAME = "screen_home.bmp";
std::string SCREEN_LAST_FILENAME = "screen_last.bmp";
@@ -232,6 +234,8 @@ static LLHost gFirstSim;
static std::string gFirstSimSeedCap;
static LLVector3 gAgentStartLookAt(1.0f, 0.f, 0.f);
static std::string gAgentStartLocation = "safe";
+static bool mLoginStatePastUI = false;
+
boost::scoped_ptr<LLEventPump> LLStartUp::sStateWatcher(new LLEventStream("StartupState"));
boost::scoped_ptr<LLStartupListener> LLStartUp::sListener(new LLStartupListener());
@@ -350,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() )
{
@@ -420,7 +421,7 @@ bool idle_startup()
//
// Load autopilot and stats stuff
- gAgentPilot.load(gSavedSettings.getString("StatsPilotFile"));
+ gAgentPilot.load();
//gErrorStream.setTime(gSavedSettings.getBOOL("LogTimestamps"));
@@ -669,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;
@@ -705,11 +707,21 @@ bool idle_startup()
if (STATE_LOGIN_SHOW == LLStartUp::getStartupState())
{
LL_DEBUGS("AppInit") << "Initializing Window" << LL_ENDL;
-
+
+ // if we've gone backwards in the login state machine, to this state where we show the UI
+ // AND the debug setting to exit in this case is true, then go ahead and bail quickly
+ if ( mLoginStatePastUI && gSavedSettings.getBOOL("QuitOnLoginActivated") )
+ {
+ // no requirement for notification here - just exit
+ LLAppViewer::instance()->earlyExitNoNotify();
+ }
+
gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW);
timeout_count = 0;
+ initialize_edit_menu();
+
if (show_connect_box)
{
// Load all the name information out of the login view
@@ -719,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
@@ -737,8 +747,6 @@ bool idle_startup()
}
LLPanelLogin::giveFocus();
- gSavedSettings.setBOOL("FirstRunThisInstall", FALSE);
-
LLStartUp::setStartupState( STATE_LOGIN_WAIT ); // Wait for user input
}
else
@@ -763,6 +771,7 @@ bool idle_startup()
gViewerWindow->setNormalControlsVisible( FALSE );
gLoginMenuBarView->setVisible( TRUE );
gLoginMenuBarView->setEnabled( TRUE );
+ show_debug_menus();
// Hide the splash screen
LLSplashScreen::hide();
@@ -783,6 +792,11 @@ bool idle_startup()
if (STATE_LOGIN_WAIT == LLStartUp::getStartupState())
{
+ // when we get to this state, we've already been past the login UI
+ // (possiblely automatically) - flag this so we can test in the
+ // STATE_LOGIN_SHOW state if we've gone backwards
+ mLoginStatePastUI = true;
+
// Don't do anything. Wait for the login view to call the login_callback,
// which will push us to the next state.
@@ -809,6 +823,11 @@ bool idle_startup()
gKeyboard->resetKeys();
}
+ // when we get to this state, we've already been past the login UI
+ // (possiblely automatically) - flag this so we can test in the
+ // STATE_LOGIN_SHOW state if we've gone backwards
+ mLoginStatePastUI = true;
+
// save the credentials
std::string userid = "unknown";
if(gUserCredential.notNull())
@@ -919,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);
@@ -953,13 +969,7 @@ 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->setUserInteraction(show_connect_box);
login->setSerialNumber(LLAppViewer::instance()->getSerialNumber());
login->setLastExecEvent(gLastExecEvent);
login->setUpdaterLauncher(boost::bind(&LLAppViewer::launchUpdater, LLAppViewer::instance()));
@@ -985,6 +995,7 @@ bool idle_startup()
if(STATE_LOGIN_PROCESS_RESPONSE == LLStartUp::getStartupState())
{
+ // Generic failure message
std::ostringstream emsg;
emsg << LLTrans::getString("LoginFailed") << "\n";
if(LLLoginInstance::getInstance()->authFailure())
@@ -993,25 +1004,33 @@ bool idle_startup()
<< LLLoginInstance::getInstance()->getResponse() << LL_ENDL;
LLSD response = LLLoginInstance::getInstance()->getResponse();
// Still have error conditions that may need some
- // sort of handling.
+ // sort of handling - dig up specific message
std::string reason_response = response["reason"];
std::string message_response = response["message"];
-
- if(!message_response.empty())
+ std::string message_id = response["message_id"];
+ std::string message; // actual string to show the user
+
+ if(!message_id.empty() && LLTrans::findString(message, message_id, response["message_args"]))
{
- // XUI: fix translation for strings returned during login
- // We need a generic table for translations
- std::string big_reason = LLAgent::sTeleportErrorMessages[ message_response ];
- if ( big_reason.size() == 0 )
- {
- emsg << message_response;
- }
- else
- {
- emsg << big_reason;
- }
+ // message will be filled in with the template and arguments
+ }
+ else if(!message_response.empty())
+ {
+ // *HACK: "no_inventory_host" sent as the message itself.
+ // Remove this clause when server is sending message_id as well.
+ message = LLAgent::sTeleportErrorMessages[ message_response ];
+ }
+
+ if (message.empty())
+ {
+ // Fallback to server-supplied string; necessary since server
+ // may add strings that this viewer is not yet aware of
+ message = message_response;
}
+ emsg << message;
+
+
if(reason_response == "key")
{
// Couldn't login because user/password is wrong
@@ -1244,14 +1263,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
@@ -1279,7 +1295,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();
@@ -1331,18 +1347,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.
@@ -1682,9 +1695,6 @@ bool idle_startup()
// Set the show start location to true, now that the user has logged
// on with this install.
gSavedSettings.setBOOL("ShowStartLocation", TRUE);
-
- LLSideTray::getInstance()->showPanel("panel_home", LLSD());
-
}
// We're successfully logged in.
@@ -1705,46 +1715,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;
@@ -1765,13 +1772,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
@@ -1968,7 +1968,7 @@ bool idle_startup()
}
// Start automatic replay if the flag is set.
- if (gSavedSettings.getBOOL("StatsAutoRun") || LLAgentPilot::sReplaySession)
+ if (gSavedSettings.getBOOL("StatsAutoRun") || gAgentPilot.getReplaySession())
{
LLUUID id;
LL_DEBUGS("AppInit") << "Starting automatic playback" << LL_ENDL;
@@ -2700,7 +2700,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;
@@ -2861,9 +2861,17 @@ bool process_login_success_response()
if(!text.empty()) gAgentID.set(text);
gDebugInfo["AgentID"] = text;
+ // Agent id needed for parcel info request in LLUrlEntryParcel
+ // to resolve parcel name.
+ LLUrlEntryParcel::setAgentID(gAgentID);
+
text = response["session_id"].asString();
if(!text.empty()) gAgentSessionID.set(text);
gDebugInfo["SessionID"] = text;
+
+ // Session id needed for parcel info request in LLUrlEntryParcel
+ // to resolve parcel name.
+ LLUrlEntryParcel::setSessionID(gAgentSessionID);
text = response["secure_session_id"].asString();
if(!text.empty()) gAgent.mSecureSessionID.set(text);
@@ -3071,10 +3079,24 @@ bool process_login_success_response()
}
// Request the map server url
+ // Non-agni grids have a different default location.
+ if (!LLGridManager::getInstance()->isInProductionGrid())
+ {
+ gSavedSettings.setString("MapServerURL", "http://test.map.secondlife.com.s3.amazonaws.com/");
+ }
std::string map_server_url = response["map-server-url"];
if(!map_server_url.empty())
{
- gSavedSettings.setString("MapServerURL", map_server_url);
+ // We got an answer from the grid -> use that for map for the current session
+ gSavedSettings.setString("CurrentMapServerURL", map_server_url);
+ LL_INFOS("LLStartup") << "map-server-url : we got an answer from the grid : " << map_server_url << LL_ENDL;
+ }
+ else
+ {
+ // No answer from the grid -> use the default setting for current session
+ map_server_url = gSavedSettings.getString("MapServerURL");
+ gSavedSettings.setString("CurrentMapServerURL", map_server_url);
+ LL_INFOS("LLStartup") << "map-server-url : no map-server-url answer, we use the default setting for the map : " << map_server_url << LL_ENDL;
}
// Default male and female avatars allowing the user to choose their avatar on first login.
@@ -3151,6 +3173,18 @@ bool process_login_success_response()
LLViewerMedia::openIDSetup(openid_url, openid_token);
}
+ if(response.has("max-agent-groups")) {
+ std::string max_agent_groups(response["max-agent-groups"]);
+ gMaxAgentGroups = atoi(max_agent_groups.c_str());
+ LL_INFOS("LLStartup") << "gMaxAgentGroups read from login.cgi: "
+ << gMaxAgentGroups << LL_ENDL;
+ }
+ else {
+ gMaxAgentGroups = DEFAULT_MAX_AGENT_GROUPS;
+ LL_INFOS("LLStartup") << "using gMaxAgentGroups default: "
+ << gMaxAgentGroups << LL_ENDL;
+ }
+
bool success = false;
// JC: gesture loading done below, when we have an asset system
// in place. Don't delete/clear gUserCredentials until then.
@@ -3168,7 +3202,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/llstartup.h b/indra/newview/llstartup.h
index be1043cf91..b3d9ef1dcc 100644
--- a/indra/newview/llstartup.h
+++ b/indra/newview/llstartup.h
@@ -70,6 +70,7 @@ typedef enum {
// exported symbols
extern bool gAgentMovementCompleted;
+extern S32 gMaxAgentGroups;
extern LLPointer<LLViewerTexture> gStartTexture;
class LLStartUp
diff --git a/indra/newview/llstatusbar.cpp b/indra/newview/llstatusbar.cpp
index e9fc25404a..1b8be7a5b2 100644
--- a/indra/newview/llstatusbar.cpp
+++ b/indra/newview/llstatusbar.cpp
@@ -115,6 +115,7 @@ LLStatusBar::LLStatusBar(const LLRect& rect)
mSGBandwidth(NULL),
mSGPacketLoss(NULL),
mBtnVolume(NULL),
+ mBoxBalance(NULL),
mBalance(0),
mHealth(100),
mSquareMetersCredit(0),
@@ -168,6 +169,9 @@ BOOL LLStatusBar::postBuild()
getChild<LLUICtrl>("buyL")->setCommitCallback(
boost::bind(&LLStatusBar::onClickBuyCurrency, this));
+ mBoxBalance = getChild<LLTextBox>("balance");
+ mBoxBalance->setClickedCallback( &LLStatusBar::onClickBalance, this );
+
mBtnVolume = getChild<LLButton>( "volume_btn" );
mBtnVolume->setClickedCallback( onClickVolume, this );
mBtnVolume->setMouseEnterCallback(boost::bind(&LLStatusBar::onMouseEnterVolume, this));
@@ -304,6 +308,7 @@ void LLStatusBar::setVisibleForMouselook(bool visible)
{
mTextTime->setVisible(visible);
getChild<LLUICtrl>("balance_bg")->setVisible(visible);
+ mBoxBalance->setVisible(visible);
mBtnVolume->setVisible(visible);
mMediaToggle->setVisible(visible);
mSGBandwidth->setVisible(visible);
@@ -330,16 +335,15 @@ void LLStatusBar::setBalance(S32 balance)
std::string money_str = LLResMgr::getInstance()->getMonetaryString( balance );
- LLTextBox* balance_box = getChild<LLTextBox>("balance");
LLStringUtil::format_map_t string_args;
string_args["[AMT]"] = llformat("%s", money_str.c_str());
std::string label_str = getString("buycurrencylabel", string_args);
- balance_box->setValue(label_str);
+ mBoxBalance->setValue(label_str);
// Resize the L$ balance background to be wide enough for your balance plus the buy button
{
const S32 HPAD = 24;
- LLRect balance_rect = balance_box->getTextBoundingRect();
+ LLRect balance_rect = mBoxBalance->getTextBoundingRect();
LLRect buy_rect = getChildView("buyL")->getRect();
LLView* balance_bg_view = getChildView("balance_bg");
LLRect balance_bg_rect = balance_bg_view->getRect();
@@ -506,6 +510,14 @@ static void onClickVolume(void* data)
}
//static
+void LLStatusBar::onClickBalance(void* )
+{
+ // Force a balance request message:
+ LLStatusBar::sendMoneyBalanceRequest();
+ // The refresh of the display (call to setBalance()) will be done by process_money_balance_reply()
+}
+
+//static
void LLStatusBar::onClickMediaToggle(void* data)
{
LLStatusBar *status_bar = (LLStatusBar*)data;
diff --git a/indra/newview/llstatusbar.h b/indra/newview/llstatusbar.h
index 2388aeb0c8..4ea3183d18 100644
--- a/indra/newview/llstatusbar.h
+++ b/indra/newview/llstatusbar.h
@@ -94,6 +94,7 @@ private:
void onClickScreen(S32 x, S32 y);
static void onClickMediaToggle(void* data);
+ static void onClickBalance(void* data);
private:
LLTextBox *mTextTime;
@@ -102,6 +103,7 @@ private:
LLStatGraph *mSGPacketLoss;
LLButton *mBtnVolume;
+ LLTextBox *mBoxBalance;
LLButton *mMediaToggle;
LLView* mScriptOut;
LLFrameTimer mClockUpdateTimer;
diff --git a/indra/newview/llsurface.cpp b/indra/newview/llsurface.cpp
index af4d9fa7b9..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;
@@ -1162,8 +1157,13 @@ void LLSurface::setWaterHeight(F32 height)
if (!mWaterObjp.isNull())
{
LLVector3 water_pos_region = mWaterObjp->getPositionRegion();
+ bool changed = water_pos_region.mV[VZ] != height;
water_pos_region.mV[VZ] = height;
mWaterObjp->setPositionRegion(water_pos_region);
+ if (changed)
+ {
+ LLWorld::getInstance()->updateWaterObjects();
+ }
}
else
{
diff --git a/indra/newview/llsurfacepatch.cpp b/indra/newview/llsurfacepatch.cpp
index 1d57e27616..5077c2c7e1 100644
--- a/indra/newview/llsurfacepatch.cpp
+++ b/indra/newview/llsurfacepatch.cpp
@@ -854,8 +854,10 @@ void LLSurfacePatch::updateVisibility()
F32 stride_per_distance = DEFAULT_DELTA_ANGLE / mSurfacep->getMetersPerGrid();
U32 grids_per_patch_edge = mSurfacep->getGridsPerPatchEdge();
- LLVector3 center = mCenterRegion + mSurfacep->getOriginAgent();
- LLVector3 radius = LLVector3(mRadius, mRadius, mRadius);
+ LLVector4a center;
+ center.load3( (mCenterRegion + mSurfacep->getOriginAgent()).mV);
+ LLVector4a radius;
+ radius.splat(mRadius);
// sphere in frustum on global coordinates
if (LLViewerCamera::getInstance()->AABBInFrustumNoFarClip(center, radius))
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/lltexturecache.cpp b/indra/newview/lltexturecache.cpp
index 6a213309a0..7fb52c1939 100644
--- a/indra/newview/lltexturecache.cpp
+++ b/indra/newview/lltexturecache.cpp
@@ -326,6 +326,7 @@ bool LLTextureCacheRemoteWorker::doRead()
// First state / stage : find out if the file is local
if (mState == INIT)
{
+#if 0
std::string filename = mCache->getLocalFileName(mID);
// Is it a JPEG2000 file?
{
@@ -360,6 +361,11 @@ bool LLTextureCacheRemoteWorker::doRead()
}
// Determine the next stage: if we found a file, then LOCAL else CACHE
mState = (local_size > 0 ? LOCAL : CACHE);
+
+ llassert_always(mState == CACHE) ;
+#else
+ mState = CACHE;
+#endif
}
// Second state / stage : if the file is local, load it and leave
@@ -1413,22 +1419,21 @@ void LLTextureCache::readHeaderCache()
}
}
}
- if (num_entries > sCacheMaxEntries)
+ if (num_entries - empty_entries > sCacheMaxEntries)
{
// Special case: cache size was reduced, need to remove entries
// Note: After we prune entries, we will call this again and create the LRU
- U32 entries_to_purge = (num_entries-empty_entries) - sCacheMaxEntries;
+ U32 entries_to_purge = (num_entries - empty_entries) - sCacheMaxEntries;
llinfos << "Texture Cache Entries: " << num_entries << " Max: " << sCacheMaxEntries << " Empty: " << empty_entries << " Purging: " << entries_to_purge << llendl;
- if (entries_to_purge > 0)
+ // We can exit the following loop with the given condition, since if we'd reach the end of the lru set we'd have:
+ // purge_list.size() = lru.size() = num_entries - empty_entries = entries_to_purge + sCacheMaxEntries >= entries_to_purge
+ // So, it's certain that iter will never reach lru.end() first.
+ std::set<lru_data_t>::iterator iter = lru.begin();
+ while (purge_list.size() < entries_to_purge)
{
- for (std::set<lru_data_t>::iterator iter = lru.begin(); iter != lru.end(); ++iter)
- {
- purge_list.insert(iter->second);
- if (purge_list.size() >= entries_to_purge)
- break;
- }
+ purge_list.insert(iter->second);
+ ++iter;
}
- llassert_always(purge_list.size() >= entries_to_purge);
}
else
{
@@ -1592,7 +1597,7 @@ void LLTextureCache::purgeTextures(bool validate)
if (validate)
{
validate_idx = gSavedSettings.getU32("CacheValidateCounter");
- U32 next_idx = (++validate_idx) % 256;
+ U32 next_idx = (validate_idx + 1) % 256;
gSavedSettings.setU32("CacheValidateCounter", next_idx);
LL_DEBUGS("TextureCache") << "TEXTURE CACHE: Validating: " << validate_idx << LL_ENDL;
}
@@ -1858,8 +1863,22 @@ void LLTextureCache::removeCachedTexture(const LLUUID& id)
//called after mHeaderMutex is locked.
void LLTextureCache::removeEntry(S32 idx, Entry& entry, std::string& filename)
{
+ bool file_maybe_exists = true; // Always attempt to remove when idx is invalid.
+
if(idx >= 0) //valid entry
{
+ if (entry.mBodySize == 0) // Always attempt to remove when mBodySize > 0.
+ {
+ if (LLAPRFile::isExist(filename, getLocalAPRFilePool())) // Sanity check. Shouldn't exist when body size is 0.
+ {
+ LL_WARNS("TextureCache") << "Entry has body size of zero but file " << filename << " exists. Deleting this file, too." << LL_ENDL;
+ }
+ else
+ {
+ file_maybe_exists = false;
+ }
+ }
+
entry.mImageSize = -1;
entry.mBodySize = 0;
mHeaderIDMap.erase(entry.mID);
@@ -1869,7 +1888,10 @@ void LLTextureCache::removeEntry(S32 idx, Entry& entry, std::string& filename)
mFreeList.insert(idx);
}
- LLAPRFile::remove(filename, getLocalAPRFilePool());
+ if (file_maybe_exists)
+ {
+ LLAPRFile::remove(filename, getLocalAPRFilePool());
+ }
}
bool LLTextureCache::removeFromCache(const LLUUID& id)
diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp
index 328298bda4..1023a4339b 100644
--- a/indra/newview/lltexturectrl.cpp
+++ b/indra/newview/lltexturectrl.cpp
@@ -289,7 +289,9 @@ BOOL LLFloaterTexturePicker::handleDragAndDrop(
{
BOOL handled = FALSE;
- if (cargo_type == DAD_TEXTURE)
+ bool is_mesh = cargo_type == DAD_MESH;
+
+ if ((cargo_type == DAD_TEXTURE) || is_mesh)
{
LLInventoryItem *item = (LLInventoryItem *)cargo_data;
@@ -564,25 +566,27 @@ void LLFloaterTexturePicker::draw()
LLRect interior = border;
interior.stretch( -1 );
+ // If the floater is focused, don't apply its alpha to the texture (STORM-677).
+ const F32 alpha = getTransparencyType() == TT_ACTIVE ? 1.0f : getCurrentTransparency();
if( mTexturep )
{
if( mTexturep->getComponents() == 4 )
{
- gl_rect_2d_checkerboard( interior );
+ gl_rect_2d_checkerboard( interior, alpha );
}
- gl_draw_scaled_image( interior.mLeft, interior.mBottom, interior.getWidth(), interior.getHeight(), mTexturep );
+ gl_draw_scaled_image( interior.mLeft, interior.mBottom, interior.getWidth(), interior.getHeight(), mTexturep, UI_VERTEX_COLOR % alpha );
// Pump the priority
mTexturep->addTextureStats( (F32)(interior.getWidth() * interior.getHeight()) );
}
else if (!mFallbackImage.isNull())
{
- mFallbackImage->draw(interior);
+ mFallbackImage->draw(interior, UI_VERTEX_COLOR % alpha);
}
else
{
- gl_rect_2d( interior, LLColor4::grey, TRUE );
+ gl_rect_2d( interior, LLColor4::grey % alpha, TRUE );
// Draw X
gl_draw_x(interior, LLColor4::black );
@@ -1204,7 +1208,11 @@ BOOL LLTextureCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask,
// returns true, then the cast was valid, and we can perform
// the third test without problems.
LLInventoryItem* item = (LLInventoryItem*)cargo_data;
- if (getEnabled() && (cargo_type == DAD_TEXTURE) && allowDrop(item))
+ bool is_mesh = cargo_type == DAD_MESH;
+
+ if (getEnabled() &&
+ ((cargo_type == DAD_TEXTURE) || is_mesh) &&
+ allowDrop(item))
{
if (drop)
{
@@ -1263,23 +1271,25 @@ void LLTextureCtrl::draw()
LLRect interior = border;
interior.stretch( -1 );
+ // If we're in a focused floater, don't apply the floater's alpha to the texture (STORM-677).
+ const F32 alpha = getTransparencyType() == TT_ACTIVE ? 1.0f : getCurrentTransparency();
if( mTexturep )
{
if( mTexturep->getComponents() == 4 )
{
- gl_rect_2d_checkerboard( interior );
+ gl_rect_2d_checkerboard( interior, alpha );
}
- gl_draw_scaled_image( interior.mLeft, interior.mBottom, interior.getWidth(), interior.getHeight(), mTexturep);
+ gl_draw_scaled_image( interior.mLeft, interior.mBottom, interior.getWidth(), interior.getHeight(), mTexturep, UI_VERTEX_COLOR % alpha);
mTexturep->addTextureStats( (F32)(interior.getWidth() * interior.getHeight()) );
}
else if (!mFallbackImage.isNull())
{
- mFallbackImage->draw(interior);
+ mFallbackImage->draw(interior, UI_VERTEX_COLOR % alpha);
}
else
{
- gl_rect_2d( interior, LLColor4::grey, TRUE );
+ gl_rect_2d( interior, LLColor4::grey % alpha, TRUE );
// Draw X
gl_draw_x( interior, LLColor4::black );
diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index fafef84aa2..18c3a3b87d 100644
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -27,6 +27,7 @@
#include "llviewerprecompiledheaders.h"
#include <iostream>
+#include <map>
#include "llstl.h"
@@ -49,6 +50,7 @@
#include "llviewertexture.h"
#include "llviewerregion.h"
#include "llviewerstats.h"
+#include "llviewerassetstats.h"
#include "llworld.h"
//////////////////////////////////////////////////////////////////////////////
@@ -143,7 +145,7 @@ public:
/*virtual*/ bool deleteOK(); // called from update() (WORK THREAD)
~LLTextureFetchWorker();
- void relese() { --mActiveCount; }
+ // void relese() { --mActiveCount; }
S32 callbackHttpGet(const LLChannelDescriptors& channels,
const LLIOPipe::buffer_ptr_t& buffer,
@@ -161,9 +163,11 @@ public:
mGetReason = reason;
}
- void setCanUseHTTP(bool can_use_http) {mCanUseHTTP = can_use_http;}
- bool getCanUseHTTP()const {return mCanUseHTTP ;}
+ void setCanUseHTTP(bool can_use_http) { mCanUseHTTP = can_use_http; }
+ bool getCanUseHTTP() const { return mCanUseHTTP; }
+ LLTextureFetch & getFetcher() { return *mFetcher; }
+
protected:
LLTextureFetchWorker(LLTextureFetch* fetcher, const std::string& url, const LLUUID& id, const LLHost& host,
F32 priority, S32 discard, S32 size);
@@ -277,6 +281,8 @@ private:
S32 mLastPacket;
U16 mTotalPackets;
U8 mImageCodec;
+
+ LLViewerAssetStats::duration_t mMetricsStartTime;
};
//////////////////////////////////////////////////////////////////////////////
@@ -299,6 +305,7 @@ public:
{
static LLCachedControl<bool> log_to_viewer_log(gSavedSettings,"LogTextureDownloadsToViewerLog");
static LLCachedControl<bool> log_to_sim(gSavedSettings,"LogTextureDownloadsToSimulator");
+ static LLCachedControl<bool> log_texture_traffic(gSavedSettings,"LogTextureNetworkTraffic") ;
if (log_to_viewer_log || log_to_sim)
{
@@ -332,7 +339,29 @@ public:
}
S32 data_size = worker->callbackHttpGet(channels, buffer, partial, success);
+
+ if(log_texture_traffic && data_size > 0)
+ {
+ LLViewerTexture* tex = LLViewerTextureManager::findTexture(mID) ;
+ if(tex)
+ {
+ gTotalTextureBytesPerBoostLevel[tex->getBoostLevel()] += data_size ;
+ }
+ }
+
mFetcher->removeFromHTTPQueue(mID, data_size);
+
+ if (worker->mMetricsStartTime)
+ {
+ LLViewerAssetStatsFF::record_response_thread1(LLViewerAssetType::AT_TEXTURE,
+ true,
+ LLImageBase::TYPE_AVATAR_BAKE == worker->mType,
+ LLViewerAssetStatsFF::get_timestamp() - worker->mMetricsStartTime);
+ worker->mMetricsStartTime = 0;
+ }
+ LLViewerAssetStatsFF::record_dequeue_thread1(LLViewerAssetType::AT_TEXTURE,
+ true,
+ LLImageBase::TYPE_AVATAR_BAKE == worker->mType);
}
else
{
@@ -357,6 +386,229 @@ private:
//////////////////////////////////////////////////////////////////////////////
+// Cross-thread messaging for asset metrics.
+
+/**
+ * @brief Base class for cross-thread requests made of the fetcher
+ *
+ * I believe the intent of the LLQueuedThread class was to
+ * have these operations derived from LLQueuedThread::QueuedRequest
+ * but the texture fetcher has elected to manage the queue
+ * in its own manner. So these are free-standing objects which are
+ * managed in simple FIFO order on the mCommands queue of the
+ * LLTextureFetch object.
+ *
+ * What each represents is a simple command sent from an
+ * outside thread into the TextureFetch thread to be processed
+ * in order and in a timely fashion (though not an absolute
+ * higher priority than other operations of the thread).
+ * Each operation derives a new class from the base customizing
+ * members, constructors and the doWork() method to effect
+ * the command.
+ *
+ * The flow is one-directional. There are two global instances
+ * of the LLViewerAssetStats collector, one for the main program's
+ * thread pointed to by gViewerAssetStatsMain and one for the
+ * TextureFetch thread pointed to by gViewerAssetStatsThread1.
+ * Common operations has each thread recording metrics events
+ * into the respective collector unconcerned with locking and
+ * the state of any other thread. But when the agent moves into
+ * a different region or the metrics timer expires and a report
+ * needs to be sent back to the grid, messaging across threads
+ * is required to distribute data and perform global actions.
+ * In pseudo-UML, it looks like:
+ *
+ * Main Thread1
+ * . .
+ * . .
+ * +-----+ .
+ * | AM | .
+ * +--+--+ .
+ * +-------+ | .
+ * | Main | +--+--+ .
+ * | | | SRE |---. .
+ * | Stats | +-----+ \ .
+ * | | | \ (uuid) +-----+
+ * | Coll. | +--+--+ `-------->| SR |
+ * +-------+ | MSC | +--+--+
+ * | ^ +-----+ |
+ * | | (uuid) / . +-----+ (uuid)
+ * | `--------' . | MSC |---------.
+ * | . +-----+ |
+ * | +-----+ . v
+ * | | TE | . +-------+
+ * | +--+--+ . | Thd1 |
+ * | | . | |
+ * | +-----+ . | Stats |
+ * `--------->| RSC | . | |
+ * +--+--+ . | Coll. |
+ * | . +-------+
+ * +--+--+ . |
+ * | SME |---. . |
+ * +-----+ \ . |
+ * . \ (clone) +-----+ |
+ * . `-------->| SM | |
+ * . +--+--+ |
+ * . | |
+ * . +-----+ |
+ * . | RSC |<--------'
+ * . +-----+
+ * . |
+ * . +-----+
+ * . | CP |--> HTTP POST
+ * . +-----+
+ * . .
+ * . .
+ *
+ *
+ * Key:
+ *
+ * SRE - Set Region Enqueued. Enqueue a 'Set Region' command in
+ * the other thread providing the new UUID of the region.
+ * TFReqSetRegion carries the data.
+ * SR - Set Region. New region UUID is sent to the thread-local
+ * collector.
+ * SME - Send Metrics Enqueued. Enqueue a 'Send Metrics' command
+ * including an ownership transfer of a cloned LLViewerAssetStats.
+ * TFReqSendMetrics carries the data.
+ * SM - Send Metrics. Global metrics reporting operation. Takes
+ * the cloned stats from the command, merges it with the
+ * thread's local stats, converts to LLSD and sends it on
+ * to the grid.
+ * AM - Agent Moved. Agent has completed some sort of move to a
+ * new region.
+ * TE - Timer Expired. Metrics timer has expired (on the order
+ * of 10 minutes).
+ * CP - CURL Post
+ * MSC - Modify Stats Collector. State change in the thread-local
+ * collector. Typically a region change which affects the
+ * global pointers used to find the 'current stats'.
+ * RSC - Read Stats Collector. Extract collector data cloning it
+ * (i.e. deep copy) when necessary.
+ *
+ */
+class LLTextureFetch::TFRequest // : public LLQueuedThread::QueuedRequest
+{
+public:
+ // Default ctors and assignment operator are correct.
+
+ virtual ~TFRequest()
+ {}
+
+ // Patterned after QueuedRequest's method but expected behavior
+ // is different. Always expected to complete on the first call
+ // and work dispatcher will assume the same and delete the
+ // request after invocation.
+ virtual bool doWork(LLTextureFetch * fetcher) = 0;
+};
+
+namespace
+{
+
+/**
+ * @brief Implements a 'Set Region' cross-thread command.
+ *
+ * When an agent moves to a new region, subsequent metrics need
+ * to be binned into a new or existing stats collection in 1:1
+ * relationship with the region. We communicate this region
+ * change across the threads involved in the communication with
+ * this message.
+ *
+ * Corresponds to LLTextureFetch::commandSetRegion()
+ */
+class TFReqSetRegion : public LLTextureFetch::TFRequest
+{
+public:
+ TFReqSetRegion(U64 region_handle)
+ : LLTextureFetch::TFRequest(),
+ mRegionHandle(region_handle)
+ {}
+ TFReqSetRegion & operator=(const TFReqSetRegion &); // Not defined
+
+ virtual ~TFReqSetRegion()
+ {}
+
+ virtual bool doWork(LLTextureFetch * fetcher);
+
+public:
+ const U64 mRegionHandle;
+};
+
+
+/**
+ * @brief Implements a 'Send Metrics' cross-thread command.
+ *
+ * This is the big operation. The main thread gathers metrics
+ * for a period of minutes into LLViewerAssetStats and other
+ * objects then makes a snapshot of the data by cloning the
+ * collector. This command transfers the clone, along with a few
+ * additional arguments (UUIDs), handing ownership to the
+ * TextureFetch thread. It then merges its own data into the
+ * cloned copy, converts to LLSD and kicks off an HTTP POST of
+ * the resulting data to the currently active metrics collector.
+ *
+ * Corresponds to LLTextureFetch::commandSendMetrics()
+ */
+class TFReqSendMetrics : public LLTextureFetch::TFRequest
+{
+public:
+ /**
+ * Construct the 'Send Metrics' command to have the TextureFetch
+ * thread add and log metrics data.
+ *
+ * @param caps_url URL of a "ViewerMetrics" Caps target
+ * to receive the data. Does not have to
+ * be associated with a particular region.
+ *
+ * @param session_id UUID of the agent's session.
+ *
+ * @param agent_id UUID of the agent. (Being pure here...)
+ *
+ * @param main_stats Pointer to a clone of the main thread's
+ * LLViewerAssetStats data. Thread1 takes
+ * ownership of the copy and disposes of it
+ * when done.
+ */
+ TFReqSendMetrics(const std::string & caps_url,
+ const LLUUID & session_id,
+ const LLUUID & agent_id,
+ LLViewerAssetStats * main_stats)
+ : LLTextureFetch::TFRequest(),
+ mCapsURL(caps_url),
+ mSessionID(session_id),
+ mAgentID(agent_id),
+ mMainStats(main_stats)
+ {}
+ TFReqSendMetrics & operator=(const TFReqSendMetrics &); // Not defined
+
+ virtual ~TFReqSendMetrics();
+
+ virtual bool doWork(LLTextureFetch * fetcher);
+
+public:
+ const std::string mCapsURL;
+ const LLUUID mSessionID;
+ const LLUUID mAgentID;
+ LLViewerAssetStats * mMainStats;
+};
+
+/*
+ * Examines the merged viewer metrics report and if found to be too long,
+ * will attempt to truncate it in some reasonable fashion.
+ *
+ * @param max_regions Limit of regions allowed in report.
+ *
+ * @param metrics Full, merged viewer metrics report.
+ *
+ * @returns If data was truncated, returns true.
+ */
+bool truncate_viewer_metrics(int max_regions, LLSD & metrics);
+
+} // end of anonymous namespace
+
+
+//////////////////////////////////////////////////////////////////////////////
+
//static
const char* LLTextureFetchWorker::sStateDescs[] = {
"INVALID",
@@ -374,6 +626,9 @@ const char* LLTextureFetchWorker::sStateDescs[] = {
"DONE",
};
+// static
+volatile bool LLTextureFetch::svMetricsDataBreak(true); // Start with a data break
+
// called from MAIN THREAD
LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,
@@ -423,7 +678,8 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,
mFirstPacket(0),
mLastPacket(-1),
mTotalPackets(0),
- mImageCodec(IMG_CODEC_INVALID)
+ mImageCodec(IMG_CODEC_INVALID),
+ mMetricsStartTime(0)
{
mCanUseNET = mUrl.empty() ;
@@ -591,6 +847,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
return true; // abort
}
}
+
if(mImagePriority < F_ALMOST_ZERO)
{
if (mState == INIT || mState == LOAD_FROM_NETWORK || mState == LOAD_FROM_SIMULATOR)
@@ -800,7 +1057,15 @@ bool LLTextureFetchWorker::doWork(S32 param)
mRequestedDiscard = mDesiredDiscard;
mSentRequest = QUEUED;
mFetcher->addToNetworkQueue(this);
+ if (! mMetricsStartTime)
+ {
+ mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp();
+ }
+ LLViewerAssetStatsFF::record_enqueue_thread1(LLViewerAssetType::AT_TEXTURE,
+ false,
+ LLImageBase::TYPE_AVATAR_BAKE == mType);
setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
+
return false;
}
else
@@ -809,6 +1074,12 @@ bool LLTextureFetchWorker::doWork(S32 param)
//llassert_always(mFetcher->mNetworkQueue.find(mID) != mFetcher->mNetworkQueue.end());
// Make certain this is in the network queue
//mFetcher->addToNetworkQueue(this);
+ //if (! mMetricsStartTime)
+ //{
+ // mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp();
+ //}
+ //LLViewerAssetStatsFF::record_enqueue_thread1(LLViewerAssetType::AT_TEXTURE, false,
+ // LLImageBase::TYPE_AVATAR_BAKE == mType);
//setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
return false;
}
@@ -832,11 +1103,30 @@ bool LLTextureFetchWorker::doWork(S32 param)
}
setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
mState = DECODE_IMAGE;
- mWriteToCacheState = SHOULD_WRITE ;
+ mWriteToCacheState = SHOULD_WRITE;
+
+ if (mMetricsStartTime)
+ {
+ LLViewerAssetStatsFF::record_response_thread1(LLViewerAssetType::AT_TEXTURE,
+ false,
+ LLImageBase::TYPE_AVATAR_BAKE == mType,
+ LLViewerAssetStatsFF::get_timestamp() - mMetricsStartTime);
+ mMetricsStartTime = 0;
+ }
+ LLViewerAssetStatsFF::record_dequeue_thread1(LLViewerAssetType::AT_TEXTURE,
+ false,
+ LLImageBase::TYPE_AVATAR_BAKE == mType);
}
else
{
mFetcher->addToNetworkQueue(this); // failsafe
+ if (! mMetricsStartTime)
+ {
+ mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp();
+ }
+ LLViewerAssetStatsFF::record_enqueue_thread1(LLViewerAssetType::AT_TEXTURE,
+ false,
+ LLImageBase::TYPE_AVATAR_BAKE == mType);
setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
}
return false;
@@ -851,7 +1141,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
//1, not openning too many file descriptors at the same time;
//2, control the traffic of http so udp gets bandwidth.
//
- static const S32 MAX_NUM_OF_HTTP_REQUESTS_IN_QUEUE = 32 ;
+ static const S32 MAX_NUM_OF_HTTP_REQUESTS_IN_QUEUE = 8 ;
if(mFetcher->getNumHTTPRequests() > MAX_NUM_OF_HTTP_REQUESTS_IN_QUEUE)
{
return false ; //wait.
@@ -898,6 +1188,14 @@ bool LLTextureFetchWorker::doWork(S32 param)
mState = WAIT_HTTP_REQ;
mFetcher->addToHTTPQueue(mID);
+ if (! mMetricsStartTime)
+ {
+ mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp();
+ }
+ LLViewerAssetStatsFF::record_enqueue_thread1(LLViewerAssetType::AT_TEXTURE,
+ true,
+ LLImageBase::TYPE_AVATAR_BAKE == mType);
+
// Will call callbackHttpGet when curl request completes
std::vector<std::string> headers;
headers.push_back("Accept: image/x-j2c");
@@ -1512,7 +1810,7 @@ bool LLTextureFetchWorker::writeToCacheComplete()
//////////////////////////////////////////////////////////////////////////////
// public
-LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* imagedecodethread, bool threaded)
+LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* imagedecodethread, bool threaded, bool qa_mode)
: LLWorkerThread("TextureFetch", threaded),
mDebugCount(0),
mDebugPause(FALSE),
@@ -1524,8 +1822,11 @@ LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* image
mImageDecodeThread(imagedecodethread),
mTextureBandwidth(0),
mHTTPTextureBits(0),
- mCurlGetRequest(NULL)
+ mTotalHTTPRequests(0),
+ mCurlGetRequest(NULL),
+ mQAMode(qa_mode)
{
+ mCurlPOSTRequestCount = 0;
mMaxBandwidth = gSavedSettings.getF32("ThrottleBandwidthKBPS");
mTextureInfo.setUpLogging(gSavedSettings.getBOOL("LogTextureDownloadsToViewerLog"), gSavedSettings.getBOOL("LogTextureDownloadsToSimulator"), gSavedSettings.getU32("TextureLoggingThreshold"));
}
@@ -1534,6 +1835,13 @@ LLTextureFetch::~LLTextureFetch()
{
clearDeleteList() ;
+ while (! mCommands.empty())
+ {
+ TFRequest * req(mCommands.front());
+ mCommands.erase(mCommands.begin());
+ delete req;
+ }
+
// ~LLQueuedThread() called here
}
@@ -1563,7 +1871,6 @@ bool LLTextureFetch::createRequest(const std::string& url, const LLUUID& id, con
if (!url.empty() && (!exten.empty() && LLImageBase::getCodecFromExtension(exten) != IMG_CODEC_J2C))
{
// Only do partial requests for J2C at the moment
- //llinfos << "Merov : LLTextureFetch::createRequest(), blocking fetch on " << url << llendl;
desired_size = MAX_IMAGE_DATA_SIZE;
desired_discard = 0;
}
@@ -1667,6 +1974,7 @@ void LLTextureFetch::addToHTTPQueue(const LLUUID& id)
{
LLMutexLock lock(&mNetworkQueueMutex);
mHTTPTextureQueue.insert(id);
+ mTotalHTTPRequests++;
}
void LLTextureFetch::removeFromHTTPQueue(const LLUUID& id, S32 received_size)
@@ -1729,6 +2037,15 @@ S32 LLTextureFetch::getNumHTTPRequests()
return size ;
}
+U32 LLTextureFetch::getTotalNumHTTPRequests()
+{
+ mNetworkQueueMutex.lock() ;
+ U32 size = mTotalHTTPRequests ;
+ mNetworkQueueMutex.unlock() ;
+
+ return size ;
+}
+
// call lockQueue() first!
LLTextureFetchWorker* LLTextureFetch::getWorkerAfterLock(const LLUUID& id)
{
@@ -1815,8 +2132,76 @@ bool LLTextureFetch::updateRequestPriority(const LLUUID& id, F32 priority)
return res;
}
+// Replicates and expands upon the base class's
+// getPending() implementation. getPending() and
+// runCondition() replicate one another's logic to
+// an extent and are sometimes used for the same
+// function (deciding whether or not to sleep/pause
+// a thread). So the implementations need to stay
+// in step, at least until this can be refactored and
+// the redundancy eliminated.
+//
+// May be called from any thread
+
+//virtual
+S32 LLTextureFetch::getPending()
+{
+ S32 res;
+ lockData();
+ {
+ LLMutexLock lock(&mQueueMutex);
+
+ res = mRequestQueue.size();
+ res += mCurlPOSTRequestCount;
+ res += mCommands.size();
+ }
+ unlockData();
+ return res;
+}
+
+// virtual
+bool LLTextureFetch::runCondition()
+{
+ // Caller is holding the lock on LLThread's condition variable.
+
+ // LLQueuedThread, unlike its base class LLThread, makes this a
+ // private method which is unfortunate. I want to use it directly
+ // but I'm going to have to re-implement the logic here (or change
+ // declarations, which I don't want to do right now).
+ //
+ // Changes here may need to be reflected in getPending().
+
+ bool have_no_commands(false);
+ {
+ LLMutexLock lock(&mQueueMutex);
+
+ have_no_commands = mCommands.empty();
+ }
+
+ bool have_no_curl_requests(0 == mCurlPOSTRequestCount);
+
+ return ! (have_no_commands
+ && have_no_curl_requests
+ && (mRequestQueue.empty() && mIdleThread)); // From base class
+}
+
//////////////////////////////////////////////////////////////////////////////
+// MAIN THREAD (unthreaded envs), WORKER THREAD (threaded envs)
+void LLTextureFetch::commonUpdate()
+{
+ // Run a cross-thread command, if any.
+ cmdDoWork();
+
+ // Update Curl on same thread as mCurlGetRequest was constructed
+ S32 processed = mCurlGetRequest->process();
+ if (processed > 0)
+ {
+ lldebugs << "processed: " << processed << " messages." << llendl;
+ }
+}
+
+
// MAIN THREAD
//virtual
S32 LLTextureFetch::update(U32 max_time_ms)
@@ -1842,12 +2227,7 @@ S32 LLTextureFetch::update(U32 max_time_ms)
if (!mThreaded)
{
- // Update Curl on same thread as mCurlGetRequest was constructed
- S32 processed = mCurlGetRequest->process();
- if (processed > 0)
- {
- lldebugs << "processed: " << processed << " messages." << llendl;
- }
+ commonUpdate();
}
return res;
@@ -1902,12 +2282,7 @@ void LLTextureFetch::threadedUpdate()
}
process_timer.reset();
- // Update Curl on same thread as mCurlGetRequest was constructed
- S32 processed = mCurlGetRequest->process();
- if (processed > 0)
- {
- lldebugs << "processed: " << processed << " messages." << llendl;
- }
+ commonUpdate();
#if 0
const F32 INFO_TIME = 1.0f;
@@ -2357,3 +2732,280 @@ void LLTextureFetch::dump()
}
}
+//////////////////////////////////////////////////////////////////////////////
+
+// cross-thread command methods
+
+void LLTextureFetch::commandSetRegion(U64 region_handle)
+{
+ TFReqSetRegion * req = new TFReqSetRegion(region_handle);
+
+ cmdEnqueue(req);
+}
+
+void LLTextureFetch::commandSendMetrics(const std::string & caps_url,
+ const LLUUID & session_id,
+ const LLUUID & agent_id,
+ LLViewerAssetStats * main_stats)
+{
+ TFReqSendMetrics * req = new TFReqSendMetrics(caps_url, session_id, agent_id, main_stats);
+
+ cmdEnqueue(req);
+}
+
+void LLTextureFetch::commandDataBreak()
+{
+ // The pedantically correct way to implement this is to create a command
+ // request object in the above fashion and enqueue it. However, this is
+ // simple data of an advisorial not operational nature and this case
+ // of shared-write access is tolerable.
+
+ LLTextureFetch::svMetricsDataBreak = true;
+}
+
+void LLTextureFetch::cmdEnqueue(TFRequest * req)
+{
+ lockQueue();
+ mCommands.push_back(req);
+ unlockQueue();
+
+ unpause();
+}
+
+LLTextureFetch::TFRequest * LLTextureFetch::cmdDequeue()
+{
+ TFRequest * ret = 0;
+
+ lockQueue();
+ if (! mCommands.empty())
+ {
+ ret = mCommands.front();
+ mCommands.erase(mCommands.begin());
+ }
+ unlockQueue();
+
+ return ret;
+}
+
+void LLTextureFetch::cmdDoWork()
+{
+ if (mDebugPause)
+ {
+ return; // debug: don't do any work
+ }
+
+ TFRequest * req = cmdDequeue();
+ if (req)
+ {
+ // One request per pass should really be enough for this.
+ req->doWork(this);
+ delete req;
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+
+// Private (anonymous) class methods implementing the command scheme.
+
+namespace
+{
+
+/**
+ * Implements the 'Set Region' command.
+ *
+ * Thread: Thread1 (TextureFetch)
+ */
+bool
+TFReqSetRegion::doWork(LLTextureFetch *)
+{
+ LLViewerAssetStatsFF::set_region_thread1(mRegionHandle);
+
+ return true;
+}
+
+
+TFReqSendMetrics::~TFReqSendMetrics()
+{
+ delete mMainStats;
+ mMainStats = 0;
+}
+
+
+/**
+ * Implements the 'Send Metrics' command. Takes over
+ * ownership of the passed LLViewerAssetStats pointer.
+ *
+ * Thread: Thread1 (TextureFetch)
+ */
+bool
+TFReqSendMetrics::doWork(LLTextureFetch * fetcher)
+{
+ /*
+ * HTTP POST responder. Doesn't do much but tries to
+ * detect simple breaks in recording the metrics stream.
+ *
+ * The 'volatile' modifiers don't indicate signals,
+ * mmap'd memory or threads, really. They indicate that
+ * the referenced data is part of a pseudo-closure for
+ * this responder rather than being required for correct
+ * operation.
+ *
+ * We don't try very hard with the POST request. We give
+ * it one shot and that's more-or-less it. With a proper
+ * refactoring of the LLQueuedThread usage, these POSTs
+ * could be put in a request object and made more reliable.
+ */
+ class lcl_responder : public LLCurl::Responder
+ {
+ public:
+ lcl_responder(LLTextureFetch * fetcher,
+ S32 expected_sequence,
+ volatile const S32 & live_sequence,
+ volatile bool & reporting_break,
+ volatile bool & reporting_started)
+ : LLCurl::Responder(),
+ mFetcher(fetcher),
+ mExpectedSequence(expected_sequence),
+ mLiveSequence(live_sequence),
+ mReportingBreak(reporting_break),
+ mReportingStarted(reporting_started)
+ {
+ mFetcher->incrCurlPOSTCount();
+ }
+
+ ~lcl_responder()
+ {
+ mFetcher->decrCurlPOSTCount();
+ }
+
+ // virtual
+ void error(U32 status_num, const std::string & reason)
+ {
+ if (mLiveSequence == mExpectedSequence)
+ {
+ mReportingBreak = true;
+ }
+ LL_WARNS("Texture") << "Break in metrics stream due to POST failure to metrics collection service. Reason: "
+ << reason << LL_ENDL;
+ }
+
+ // virtual
+ void result(const LLSD & content)
+ {
+ if (mLiveSequence == mExpectedSequence)
+ {
+ mReportingBreak = false;
+ mReportingStarted = true;
+ }
+ }
+
+ private:
+ LLTextureFetch * mFetcher;
+ S32 mExpectedSequence;
+ volatile const S32 & mLiveSequence;
+ volatile bool & mReportingBreak;
+ volatile bool & mReportingStarted;
+
+ }; // class lcl_responder
+
+ if (! gViewerAssetStatsThread1)
+ return true;
+
+ static volatile bool reporting_started(false);
+ static volatile S32 report_sequence(0);
+
+ // We've taken over ownership of the stats copy at this
+ // point. Get a working reference to it for merging here
+ // but leave it in 'this'. Destructor will rid us of it.
+ LLViewerAssetStats & main_stats = *mMainStats;
+
+ // Merge existing stats into those from main, convert to LLSD
+ main_stats.merge(*gViewerAssetStatsThread1);
+ LLSD merged_llsd = main_stats.asLLSD(true);
+
+ // Add some additional meta fields to the content
+ merged_llsd["session_id"] = mSessionID;
+ merged_llsd["agent_id"] = mAgentID;
+ merged_llsd["message"] = "ViewerAssetMetrics"; // Identifies the type of metrics
+ merged_llsd["sequence"] = report_sequence; // Sequence number
+ merged_llsd["initial"] = ! reporting_started; // Initial data from viewer
+ merged_llsd["break"] = LLTextureFetch::svMetricsDataBreak; // Break in data prior to this report
+
+ // Update sequence number
+ if (S32_MAX == ++report_sequence)
+ report_sequence = 0;
+
+ // Limit the size of the stats report if necessary.
+ merged_llsd["truncated"] = truncate_viewer_metrics(10, merged_llsd);
+
+ if (! mCapsURL.empty())
+ {
+ LLCurlRequest::headers_t headers;
+ fetcher->getCurlRequest().post(mCapsURL,
+ headers,
+ merged_llsd,
+ new lcl_responder(fetcher,
+ report_sequence,
+ report_sequence,
+ LLTextureFetch::svMetricsDataBreak,
+ reporting_started));
+ }
+ else
+ {
+ LLTextureFetch::svMetricsDataBreak = true;
+ }
+
+ // In QA mode, Metrics submode, log the result for ease of testing
+ if (fetcher->isQAMode())
+ {
+ LL_INFOS("Textures") << merged_llsd << LL_ENDL;
+ }
+
+ gViewerAssetStatsThread1->reset();
+
+ return true;
+}
+
+
+bool
+truncate_viewer_metrics(int max_regions, LLSD & metrics)
+{
+ static const LLSD::String reg_tag("regions");
+ static const LLSD::String duration_tag("duration");
+
+ LLSD & reg_map(metrics[reg_tag]);
+ if (reg_map.size() <= max_regions)
+ {
+ return false;
+ }
+
+ // Build map of region hashes ordered by duration
+ typedef std::multimap<LLSD::Real, int> reg_ordered_list_t;
+ reg_ordered_list_t regions_by_duration;
+
+ int ind(0);
+ LLSD::array_const_iterator it_end(reg_map.endArray());
+ for (LLSD::array_const_iterator it(reg_map.beginArray()); it_end != it; ++it, ++ind)
+ {
+ LLSD::Real duration = (*it)[duration_tag].asReal();
+ regions_by_duration.insert(reg_ordered_list_t::value_type(duration, ind));
+ }
+
+ // Build a replacement regions array with the longest-persistence regions
+ LLSD new_region(LLSD::emptyArray());
+ reg_ordered_list_t::const_reverse_iterator it2_end(regions_by_duration.rend());
+ reg_ordered_list_t::const_reverse_iterator it2(regions_by_duration.rbegin());
+ for (int i(0); i < max_regions && it2_end != it2; ++i, ++it2)
+ {
+ new_region.append(reg_map[it2->second]);
+ }
+ reg_map = new_region;
+
+ return true;
+}
+
+} // end of anonymous namespace
+
+
+
diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h
index 796109df06..d101da1f4b 100644
--- a/indra/newview/lltexturefetch.h
+++ b/indra/newview/lltexturefetch.h
@@ -33,6 +33,7 @@
#include "llworkerthread.h"
#include "llcurl.h"
#include "lltextureinfo.h"
+#include "llapr.h"
class LLViewerTexture;
class LLTextureFetchWorker;
@@ -40,6 +41,7 @@ class HTTPGetResponder;
class LLTextureCache;
class LLImageDecodeThread;
class LLHost;
+class LLViewerAssetStats;
// Interface class
class LLTextureFetch : public LLWorkerThread
@@ -48,9 +50,11 @@ class LLTextureFetch : public LLWorkerThread
friend class HTTPGetResponder;
public:
- LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* imagedecodethread, bool threaded);
+ LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* imagedecodethread, bool threaded, bool qa_mode);
~LLTextureFetch();
+ class TFRequest;
+
/*virtual*/ S32 update(U32 max_time_ms);
void shutDownTextureCacheThread() ; //called in the main thread after the TextureCacheThread shuts down.
void shutDownImageDecodeThread() ; //called in the main thread after the ImageDecodeThread shuts down.
@@ -75,30 +79,80 @@ public:
void dump();
S32 getNumRequests() ;
S32 getNumHTTPRequests() ;
+ U32 getTotalNumHTTPRequests() ;
// Public for access by callbacks
+ S32 getPending();
void lockQueue() { mQueueMutex.lock(); }
void unlockQueue() { mQueueMutex.unlock(); }
LLTextureFetchWorker* getWorker(const LLUUID& id);
LLTextureFetchWorker* getWorkerAfterLock(const LLUUID& id);
LLTextureInfo* getTextureInfo() { return &mTextureInfo; }
-
+
+ // Commands available to other threads to control metrics gathering operations.
+ void commandSetRegion(U64 region_handle);
+ void commandSendMetrics(const std::string & caps_url,
+ const LLUUID & session_id,
+ const LLUUID & agent_id,
+ LLViewerAssetStats * main_stats);
+ void commandDataBreak();
+
+ LLCurlRequest & getCurlRequest() { return *mCurlGetRequest; }
+
+ bool isQAMode() const { return mQAMode; }
+
+ // Curl POST counter maintenance
+ inline void incrCurlPOSTCount() { mCurlPOSTRequestCount++; }
+ inline void decrCurlPOSTCount() { mCurlPOSTRequestCount--; }
+
protected:
void addToNetworkQueue(LLTextureFetchWorker* worker);
void removeFromNetworkQueue(LLTextureFetchWorker* worker, bool cancel);
void addToHTTPQueue(const LLUUID& id);
void removeFromHTTPQueue(const LLUUID& id, S32 received_size = 0);
void removeRequest(LLTextureFetchWorker* worker, bool cancel);
- // Called from worker thread (during doWork)
- void processCurlRequests();
+
+ // Overrides from the LLThread tree
+ bool runCondition();
private:
void sendRequestListToSimulators();
/*virtual*/ void startThread(void);
/*virtual*/ void endThread(void);
/*virtual*/ void threadedUpdate(void);
-
+ void commonUpdate();
+
+ // Metrics command helpers
+ /**
+ * Enqueues a command request at the end of the command queue
+ * and wakes up the thread as needed.
+ *
+ * Takes ownership of the TFRequest object.
+ *
+ * Method locks the command queue.
+ */
+ void cmdEnqueue(TFRequest *);
+
+ /**
+ * Returns the first TFRequest object in the command queue or
+ * NULL if none is present.
+ *
+ * Caller acquires ownership of the object and must dispose of it.
+ *
+ * Method locks the command queue.
+ */
+ TFRequest * cmdDequeue();
+
+ /**
+ * Processes the first command in the queue disposing of the
+ * request on completion. Successive calls are needed to perform
+ * additional commands.
+ *
+ * Method locks the command queue.
+ */
+ void cmdDoWork();
+
public:
LLUUID mDebugID;
S32 mDebugCount;
@@ -107,7 +161,7 @@ public:
S32 mBadPacketCount;
private:
- LLMutex mQueueMutex; //to protect mRequestMap only
+ LLMutex mQueueMutex; //to protect mRequestMap and mCommands only
LLMutex mNetworkQueueMutex; //to protect mNetworkQueue, mHTTPTextureQueue and mCancelQueue.
LLTextureCache* mTextureCache;
@@ -129,6 +183,32 @@ private:
LLTextureInfo mTextureInfo;
U32 mHTTPTextureBits;
+
+ //debug use
+ U32 mTotalHTTPRequests ;
+
+ // Out-of-band cross-thread command queue. This command queue
+ // is logically tied to LLQueuedThread's list of
+ // QueuedRequest instances and so must be covered by the
+ // same locks.
+ typedef std::vector<TFRequest *> command_queue_t;
+ command_queue_t mCommands;
+
+ // If true, modifies some behaviors that help with QA tasks.
+ const bool mQAMode;
+
+ // Count of POST requests outstanding. We maintain the count
+ // indirectly in the CURL request responder's ctor and dtor and
+ // use it when determining whether or not to sleep the thread. Can't
+ // use the LLCurl module's request counter as it isn't thread compatible.
+ // *NOTE: Don't mix Atomic and static, apr_initialize must be called first.
+ LLAtomic32<S32> mCurlPOSTRequestCount;
+
+public:
+ // A probabilistically-correct indicator that the current
+ // attempt to log metrics follows a break in the metrics stream
+ // reporting due to either startup or a problem POSTing data.
+ static volatile bool svMetricsDataBreak;
};
#endif // LL_LLTEXTUREFETCH_H
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/lltextureview.cpp b/indra/newview/lltextureview.cpp
index c87aff022f..0115115a23 100644
--- a/indra/newview/lltextureview.cpp
+++ b/indra/newview/lltextureview.cpp
@@ -514,7 +514,9 @@ void LLGLTexMemBar::draw()
F32 cache_max_usage = (F32)BYTES_TO_MEGA_BYTES(LLAppViewer::getTextureCache()->getMaxUsage()) ;
S32 line_height = (S32)(LLFontGL::getFontMonospace()->getLineHeight() + .5f);
S32 v_offset = (S32)((texture_bar_height + 2.2f) * mTextureView->mNumTextureBars + 2.0f);
- S32 total_downloaded = BYTES_TO_MEGA_BYTES(gTotalTextureBytes);
+ F32 total_texture_downloaded = (F32)gTotalTextureBytes / (1024 * 1024);
+ F32 total_object_downloaded = (F32)gTotalObjectBytes / (1024 * 1024);
+ U32 total_http_requests = LLAppViewer::getTextureFetch()->getTotalNumHTTPRequests() ;
//----------------------------------------------------------------------------
LLGLSUIDefault gls_ui;
LLColor4 text_color(1.f, 1.f, 1.f, 0.75f);
@@ -525,13 +527,13 @@ void LLGLTexMemBar::draw()
LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, v_offset + line_height*6,
text_color, LLFontGL::LEFT, LLFontGL::TOP);
- text = llformat("GL Tot: %d/%d MB Bound: %d/%d MB Raw Tot: %d MB Bias: %.2f Cache: %.1f/%.1f MB Net Tot: %d MB",
+ text = llformat("GL Tot: %d/%d MB Bound: %d/%d MB Raw Tot: %d MB Bias: %.2f Cache: %.1f/%.1f MB Net Tot Tex: %.1f MB Tot Obj: %.1f MB Tot Htp: %d",
total_mem,
max_total_mem,
bound_mem,
max_bound_mem,
LLImageRaw::sGlobalRawMemory >> 20, discard_bias,
- cache_usage, cache_max_usage, total_downloaded);
+ cache_usage, cache_max_usage, total_texture_downloaded, total_object_downloaded, total_http_requests);
//, cache_entries, cache_max_entries
LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, v_offset + line_height*3,
diff --git a/indra/newview/lltoast.cpp b/indra/newview/lltoast.cpp
index c3090cb1fc..e0b07ed408 100644
--- a/indra/newview/lltoast.cpp
+++ b/indra/newview/lltoast.cpp
@@ -35,6 +35,13 @@
using namespace LLNotificationsUI;
+//--------------------------------------------------------------------------
+LLToastLifeTimer::LLToastLifeTimer(LLToast* toast, F32 period)
+ : mToast(toast),
+ LLEventTimer(period)
+{
+}
+
/*virtual*/
BOOL LLToastLifeTimer::tick()
{
@@ -45,6 +52,38 @@ BOOL LLToastLifeTimer::tick()
return FALSE;
}
+void LLToastLifeTimer::stop()
+{
+ mEventTimer.stop();
+}
+
+void LLToastLifeTimer::start()
+{
+ mEventTimer.start();
+}
+
+void LLToastLifeTimer::restart()
+{
+ mEventTimer.reset();
+}
+
+BOOL LLToastLifeTimer::getStarted()
+{
+ return mEventTimer.getStarted();
+}
+
+void LLToastLifeTimer::setPeriod(F32 period)
+{
+ mPeriod = period;
+}
+
+F32 LLToastLifeTimer::getRemainingTimeF32()
+{
+ F32 et = mEventTimer.getElapsedTimeF32();
+ if (!getStarted() || et > mPeriod) return 0.0f;
+ return mPeriod - et;
+}
+
//--------------------------------------------------------------------------
LLToast::Params::Params()
: can_fade("can_fade", true),
@@ -60,7 +99,6 @@ LLToast::Params::Params()
LLToast::LLToast(const LLToast::Params& p)
: LLModalDialog(LLSD(), p.is_modal),
- mPanel(p.panel),
mToastLifetime(p.lifetime_secs),
mToastFadingTime(p.fading_time_secs),
mNotificationID(p.notif_id),
@@ -69,11 +107,13 @@ LLToast::LLToast(const LLToast::Params& p)
mCanBeStored(p.can_be_stored),
mHideBtnEnabled(p.enable_hide_btn),
mHideBtn(NULL),
+ mPanel(NULL),
mNotification(p.notification),
mIsHidden(false),
mHideBtnPressed(false),
mIsTip(p.is_tip),
- mWrapperPanel(NULL)
+ mWrapperPanel(NULL),
+ mIsFading(false)
{
mTimer.reset(new LLToastLifeTimer(this, p.lifetime_secs));
@@ -85,9 +125,12 @@ LLToast::LLToast(const LLToast::Params& p)
mWrapperPanel->setMouseEnterCallback(boost::bind(&LLToast::onToastMouseEnter, this));
mWrapperPanel->setMouseLeaveCallback(boost::bind(&LLToast::onToastMouseLeave, this));
- if(mPanel)
+ setBackgroundOpaque(TRUE); // *TODO: obsolete
+ updateTransparency();
+
+ if(p.panel())
{
- insertPanel(mPanel);
+ insertPanel(p.panel);
}
if(mHideBtnEnabled)
@@ -101,10 +144,6 @@ LLToast::LLToast(const LLToast::Params& p)
// init callbacks if present
if(!p.on_delete_toast().empty())
mOnDeleteToastSignal.connect(p.on_delete_toast());
-
- // *TODO: This signal doesn't seem to be used at all.
- if(!p.on_mouse_enter().empty())
- mOnMouseEnterSignal.connect(p.on_mouse_enter());
}
void LLToast::reshape(S32 width, S32 height, BOOL called_from_parent)
@@ -143,6 +182,7 @@ LLToast::~LLToast()
void LLToast::hide()
{
setVisible(FALSE);
+ setFading(false);
mTimer->stop();
mIsHidden = true;
mOnFadeSignal(this);
@@ -153,7 +193,7 @@ void LLToast::onFocusLost()
if(mWrapperPanel && !isBackgroundVisible())
{
// Lets make wrapper panel behave like a floater
- setBackgroundOpaque(FALSE);
+ updateTransparency();
}
}
@@ -162,10 +202,20 @@ void LLToast::onFocusReceived()
if(mWrapperPanel && !isBackgroundVisible())
{
// Lets make wrapper panel behave like a floater
- setBackgroundOpaque(TRUE);
+ updateTransparency();
}
}
+void LLToast::setLifetime(S32 seconds)
+{
+ mToastLifetime = seconds;
+}
+
+void LLToast::setFadingTime(S32 seconds)
+{
+ mToastFadingTime = seconds;
+}
+
S32 LLToast::getTopPad()
{
if(mWrapperPanel)
@@ -195,13 +245,48 @@ void LLToast::setCanFade(bool can_fade)
//--------------------------------------------------------------------------
void LLToast::expire()
{
- // if toast has fade property - hide it
- if(mCanFade)
+ if (mCanFade)
{
- hide();
+ if (mIsFading)
+ {
+ // Fade timer expired. Time to hide.
+ hide();
+ }
+ else
+ {
+ // "Life" time has ended. Time to fade.
+ setFading(true);
+ mTimer->restart();
+ }
}
}
+void LLToast::setFading(bool transparent)
+{
+ mIsFading = transparent;
+ updateTransparency();
+
+ if (transparent)
+ {
+ mTimer->setPeriod(mToastFadingTime);
+ }
+ else
+ {
+ mTimer->setPeriod(mToastLifetime);
+ }
+}
+
+F32 LLToast::getTimeLeftToLive()
+{
+ F32 time_to_live = mTimer->getRemainingTimeF32();
+
+ if (!mIsFading)
+ {
+ time_to_live += mToastFadingTime;
+ }
+
+ return time_to_live;
+}
//--------------------------------------------------------------------------
void LLToast::reshapeToPanel()
@@ -224,6 +309,7 @@ void LLToast::reshapeToPanel()
void LLToast::insertPanel(LLPanel* panel)
{
+ mPanel = panel;
mWrapperPanel->addChild(panel);
reshapeToPanel();
}
@@ -245,13 +331,6 @@ void LLToast::draw()
drawChild(mHideBtn);
}
}
-
- // if timer started and remaining time <= fading time
- if (mTimer->getStarted() && (mToastLifetime
- - mTimer->getEventTimer().getElapsedTimeF32()) <= mToastFadingTime)
- {
- setBackgroundOpaque(FALSE);
- }
}
//--------------------------------------------------------------------------
@@ -267,9 +346,13 @@ void LLToast::setVisible(BOOL show)
return;
}
+ if (show && getVisible())
+ {
+ return;
+ }
+
if(show)
{
- setBackgroundOpaque(TRUE);
if(!mTimer->getStarted() && mCanFade)
{
mTimer->start();
@@ -311,7 +394,7 @@ void LLToast::onToastMouseEnter()
{
mOnToastHoverSignal(this, MOUSE_ENTER);
- setBackgroundOpaque(TRUE);
+ updateTransparency();
//toasts fading is management by Screen Channel
@@ -320,7 +403,6 @@ void LLToast::onToastMouseEnter()
{
mHideBtn->setVisible(TRUE);
}
- mOnMouseEnterSignal(this);
mToastMouseEnterSignal(this, getValue());
}
}
@@ -341,6 +423,8 @@ void LLToast::onToastMouseLeave()
{
mOnToastHoverSignal(this, MOUSE_LEAVE);
+ updateTransparency();
+
//toasts fading is management by Screen Channel
if(mHideBtn && mHideBtn->getEnabled())
@@ -368,19 +452,46 @@ void LLToast::setBackgroundOpaque(BOOL b)
}
}
-void LLNotificationsUI::LLToast::stopFading()
+void LLToast::updateTransparency()
+{
+ ETypeTransparency transparency_type;
+
+ if (mCanFade)
+ {
+ // Notification toasts (including IM/chat toasts) change their transparency on hover.
+ if (isHovered())
+ {
+ transparency_type = TT_ACTIVE;
+ }
+ else
+ {
+ transparency_type = mIsFading ? TT_FADING : TT_INACTIVE;
+ }
+ }
+ else
+ {
+ // Transparency of alert toasts depends on focus.
+ transparency_type = hasFocus() ? TT_ACTIVE : TT_INACTIVE;
+ }
+
+ LLFloater::updateTransparency(transparency_type);
+}
+
+void LLNotificationsUI::LLToast::stopTimer()
{
if(mCanFade)
{
- stopTimer();
+ setFading(false);
+ mTimer->stop();
}
}
-void LLNotificationsUI::LLToast::startFading()
+void LLNotificationsUI::LLToast::startTimer()
{
if(mCanFade)
{
- resetTimer();
+ setFading(false);
+ mTimer->start();
}
}
diff --git a/indra/newview/lltoast.h b/indra/newview/lltoast.h
index 0a96c092a0..242f786bf2 100644
--- a/indra/newview/lltoast.h
+++ b/indra/newview/lltoast.h
@@ -49,14 +49,16 @@ class LLToast;
class LLToastLifeTimer: public LLEventTimer
{
public:
- LLToastLifeTimer(LLToast* toast, F32 period) : mToast(toast), LLEventTimer(period){}
+ LLToastLifeTimer(LLToast* toast, F32 period);
/*virtual*/
BOOL tick();
- void stop() { mEventTimer.stop(); }
- void start() { mEventTimer.start(); }
- void restart() {mEventTimer.reset(); }
- BOOL getStarted() { return mEventTimer.getStarted(); }
+ void stop();
+ void start();
+ void restart();
+ BOOL getStarted();
+ void setPeriod(F32 period);
+ F32 getRemainingTimeF32();
LLTimer& getEventTimer() { return mEventTimer;}
private :
@@ -80,10 +82,15 @@ public:
Optional<LLUUID> notif_id, //notification ID
session_id; //im session ID
Optional<LLNotificationPtr> notification;
- Optional<F32> lifetime_secs,
- fading_time_secs; // Number of seconds while a toast is fading
- Optional<toast_callback_t> on_delete_toast,
- on_mouse_enter;
+
+ //NOTE: Life time of a toast (i.e. period of time from the moment toast was shown
+ //till the moment when toast was hidden) is the sum of lifetime_secs and fading_time_secs.
+
+ Optional<F32> lifetime_secs, // Number of seconds while a toast is non-transparent
+ fading_time_secs; // Number of seconds while a toast is transparent
+
+
+ Optional<toast_callback_t> on_delete_toast;
Optional<bool> can_fade,
can_be_stored,
enable_hide_btn,
@@ -107,11 +114,11 @@ public:
//Fading
- /** Stop fading timer */
- virtual void stopFading();
+ /** Stop lifetime/fading timer */
+ virtual void stopTimer();
- /** Start fading timer */
- virtual void startFading();
+ /** Start lifetime/fading timer */
+ virtual void startTimer();
bool isHovered();
@@ -125,10 +132,8 @@ public:
LLPanel* getPanel() { return mPanel; }
// enable/disable Toast's Hide button
void setHideButtonEnabled(bool enabled);
- //
- void resetTimer() { mTimer->start(); }
//
- void stopTimer() { mTimer->stop(); }
+ F32 getTimeLeftToLive();
//
LLToastLifeTimer* getTimer() { return mTimer.get();}
//
@@ -144,6 +149,10 @@ public:
/*virtual*/ void onFocusReceived();
+ void setLifetime(S32 seconds);
+
+ void setFadingTime(S32 seconds);
+
/**
* Returns padding between floater top and wrapper_panel top.
* This padding should be taken into account when positioning or reshaping toasts
@@ -172,7 +181,6 @@ public:
// Registers signals/callbacks for events
toast_signal_t mOnFadeSignal;
- toast_signal_t mOnMouseEnterSignal;
toast_signal_t mOnDeleteToastSignal;
toast_signal_t mOnToastDestroyedSignal;
boost::signals2::connection setOnFadeCallback(toast_callback_t cb) { return mOnFadeSignal.connect(cb); }
@@ -190,13 +198,18 @@ public:
LLHandle<LLToast> getHandle() { mHandle.bind(this); return mHandle; }
+protected:
+ void updateTransparency();
+
private:
void onToastMouseEnter();
void onToastMouseLeave();
- void expire();
+ void expire();
+
+ void setFading(bool fading);
LLUUID mNotificationID;
LLUUID mSessionID;
@@ -222,6 +235,7 @@ private:
bool mHideBtnPressed;
bool mIsHidden; // this flag is TRUE when a toast has faded or was hidden with (x) button (EXT-1849)
bool mIsTip;
+ bool mIsFading;
commit_signal_t mToastMouseEnterSignal;
commit_signal_t mToastMouseLeaveSignal;
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/lltoastgroupnotifypanel.cpp b/indra/newview/lltoastgroupnotifypanel.cpp
index 371aad64bb..75178a6ef8 100644
--- a/indra/newview/lltoastgroupnotifypanel.cpp
+++ b/indra/newview/lltoastgroupnotifypanel.cpp
@@ -60,7 +60,7 @@ LLToastGroupNotifyPanel::LLToastGroupNotifyPanel(LLNotificationPtr& notification
LLGroupData groupData;
if (!gAgent.getGroupData(payload["group_id"].asUUID(),groupData))
{
- llwarns << "Group notice for unkown group: " << payload["group_id"].asUUID() << llendl;
+ llwarns << "Group notice for unknown group: " << payload["group_id"].asUUID() << llendl;
}
//group icon
@@ -77,6 +77,7 @@ LLToastGroupNotifyPanel::LLToastGroupNotifyPanel(LLNotificationPtr& notification
from << from_name << "/" << groupData.mName;
LLTextBox* pTitleText = getChild<LLTextBox>("title");
pTitleText->setValue(from.str());
+ pTitleText->setToolTip(from.str());
//message subject
const std::string& subject = payload["subject"].asString();
diff --git a/indra/newview/lltoastnotifypanel.cpp b/indra/newview/lltoastnotifypanel.cpp
index 9017f5ec55..fa91f129b8 100644
--- a/indra/newview/lltoastnotifypanel.cpp
+++ b/indra/newview/lltoastnotifypanel.cpp
@@ -33,6 +33,7 @@
// library includes
#include "lldbstrings.h"
+#include "lllslconstants.h"
#include "llnotifications.h"
#include "lluiconstants.h"
#include "llrect.h"
@@ -70,11 +71,11 @@ mCloseNotificationOnDestroy(true)
mControlPanel = getChild<LLPanel>("control_panel");
BUTTON_WIDTH = gSavedSettings.getS32("ToastButtonWidth");
// customize panel's attributes
- // is it intended for displaying a tip
+ // is it intended for displaying a tip?
mIsTip = notification->getType() == "notifytip";
- // is it a script dialog
+ // is it a script dialog?
mIsScriptDialog = (notification->getName() == "ScriptDialog" || notification->getName() == "ScriptDialogGroup");
- // is it a caution
+ // is it a caution?
//
// caution flag can be set explicitly by specifying it in the notification payload, or it can be set implicitly if the
// notify xml template specifies that it is a caution
@@ -139,6 +140,12 @@ mCloseNotificationOnDestroy(true)
LLSD form_element = form->getElement(i);
if (form_element["type"].asString() != "button")
{
+ // not a button.
+ continue;
+ }
+ if (form_element["name"].asString() == TEXTBOX_MAGIC_TOKEN)
+ {
+ // a textbox pretending to be a button.
continue;
}
LLButton* new_button = createButton(form_element, TRUE);
@@ -159,7 +166,7 @@ mCloseNotificationOnDestroy(true)
if(h_pad < 2*HPAD)
{
/*
- * Probably it is a scriptdialog toast
+ * Probably it is a scriptdialog toast
* for a scriptdialog toast h_pad can be < 2*HPAD if we have a lot of buttons.
* In last case set default h_pad to avoid heaping of buttons
*/
@@ -261,7 +268,7 @@ LLButton* LLToastNotifyPanel::createButton(const LLSD& form_element, BOOL is_opt
}
else if (mIsScriptDialog && is_ignore_btn)
{
- // this is ignore button,make it smaller
+ // this is ignore button, make it smaller
p.rect.height = BTN_HEIGHT_SMALL;
p.rect.width = 1;
p.auto_resize = true;
@@ -556,7 +563,17 @@ void LLIMToastNotifyPanel::reshape(S32 width, S32 height, BOOL called_from_paren
height = rc.getHeight();
width = rc.getWidth();
+ bool is_width_changed = width != getRect().getWidth();
+
LLToastPanel::reshape(width, height, called_from_parent);
+
+ // Notification height required to display the text message depends on
+ // the width of the text box thus if panel width is changed the text box
+ // width is also changed then reshape() is called to adjust proper height.
+ if (is_width_changed)
+ {
+ reshape(width, height, called_from_parent);
+ }
}
// EOF
diff --git a/indra/newview/lltoastscripttextbox.cpp b/indra/newview/lltoastscripttextbox.cpp
new file mode 100644
index 0000000000..2529ec865a
--- /dev/null
+++ b/indra/newview/lltoastscripttextbox.cpp
@@ -0,0 +1,121 @@
+/**
+ * @file lltoastscripttextbox.cpp
+ * @brief Panel for script llTextBox dialogs
+ *
+ * $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 "lltoastscripttextbox.h"
+
+#include "llfocusmgr.h"
+
+#include "llbutton.h"
+#include "llnotifications.h"
+#include "llviewertexteditor.h"
+
+#include "llavatarnamecache.h"
+#include "lluiconstants.h"
+#include "llui.h"
+#include "llviewercontrol.h"
+#include "lltrans.h"
+#include "llstyle.h"
+
+#include "llglheaders.h"
+#include "llagent.h"
+
+const S32 LLToastScriptTextbox::DEFAULT_MESSAGE_MAX_LINE_COUNT= 7;
+
+LLToastScriptTextbox::LLToastScriptTextbox(const LLNotificationPtr& notification)
+: LLToastPanel(notification)
+{
+ buildFromFile( "panel_notify_textbox.xml");
+
+ LLTextEditor* text_editorp = getChild<LLTextEditor>("text_editor_box");
+ text_editorp->setValue(notification->getMessage());
+
+ getChild<LLButton>("ignore_btn")->setClickedCallback(boost::bind(&LLToastScriptTextbox::onClickIgnore, this));
+
+ const LLSD& payload = notification->getPayload();
+
+ //message body
+ const std::string& message = payload["message"].asString();
+
+ LLViewerTextEditor* pMessageText = getChild<LLViewerTextEditor>("message");
+ pMessageText->clear();
+
+ LLStyle::Params style;
+ style.font = pMessageText->getDefaultFont();
+ pMessageText->appendText(message, TRUE, style);
+
+ //submit button
+ LLButton* pSubmitBtn = getChild<LLButton>("btn_submit");
+ pSubmitBtn->setClickedCallback((boost::bind(&LLToastScriptTextbox::onClickSubmit, this)));
+ setDefaultBtn(pSubmitBtn);
+
+ S32 maxLinesCount;
+ std::istringstream ss( getString("message_max_lines_count") );
+ if (!(ss >> maxLinesCount))
+ {
+ maxLinesCount = DEFAULT_MESSAGE_MAX_LINE_COUNT;
+ }
+ //snapToMessageHeight(pMessageText, maxLinesCount);
+}
+
+// virtual
+LLToastScriptTextbox::~LLToastScriptTextbox()
+{
+}
+
+void LLToastScriptTextbox::close()
+{
+ die();
+}
+
+#include "lllslconstants.h"
+void LLToastScriptTextbox::onClickSubmit()
+{
+ LLViewerTextEditor* pMessageText = getChild<LLViewerTextEditor>("message");
+
+ if (pMessageText)
+ {
+ LLSD response = mNotification->getResponseTemplate();
+ response[TEXTBOX_MAGIC_TOKEN] = pMessageText->getText();
+ if (response[TEXTBOX_MAGIC_TOKEN].asString().empty())
+ {
+ // so we can distinguish between a successfully
+ // submitted blank textbox, and an ignored toast
+ response[TEXTBOX_MAGIC_TOKEN] = true;
+ }
+ mNotification->respond(response);
+ close();
+ llwarns << response << llendl;
+ }
+}
+
+void LLToastScriptTextbox::onClickIgnore()
+{
+ LLSD response = mNotification->getResponseTemplate();
+ mNotification->respond(response);
+ close();
+}
diff --git a/indra/newview/lltoastscripttextbox.h b/indra/newview/lltoastscripttextbox.h
new file mode 100644
index 0000000000..8e69d8834d
--- /dev/null
+++ b/indra/newview/lltoastscripttextbox.h
@@ -0,0 +1,59 @@
+/**
+ * @file lltoastscripttextbox.h
+ * @brief Panel for script llTextBox dialogs
+ *
+ * $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_LLTOASTSCRIPTTEXTBOX_H
+#define LL_LLTOASTSCRIPTTEXTBOX_H
+
+#include "lltoastnotifypanel.h"
+#include "llnotificationptr.h"
+
+/**
+ * Toast panel for scripted llTextbox notifications.
+ */
+class LLToastScriptTextbox
+: public LLToastPanel
+{
+public:
+ void close();
+
+ static bool onNewNotification(const LLSD& notification);
+
+ // Non-transient messages. You can specify non-default button
+ // layouts (like one for script dialogs) by passing various
+ // numbers in for "layout".
+ LLToastScriptTextbox(const LLNotificationPtr& notification);
+
+ /*virtual*/ ~LLToastScriptTextbox();
+
+private:
+
+ void onClickSubmit();
+ void onClickIgnore();
+
+ static const S32 DEFAULT_MESSAGE_MAX_LINE_COUNT;
+};
+
+#endif
diff --git a/indra/newview/lltool.cpp b/indra/newview/lltool.cpp
index 282d4e19c6..2d8ce95347 100644
--- a/indra/newview/lltool.cpp
+++ b/indra/newview/lltool.cpp
@@ -33,6 +33,7 @@
#include "llview.h"
#include "llviewerwindow.h"
+#include "llviewercontrol.h"
#include "lltoolcomp.h"
#include "lltoolfocus.h"
#include "llfocusmgr.h"
@@ -190,9 +191,12 @@ LLTool* LLTool::getOverrideTool(MASK mask)
{
return NULL;
}
- if (mask & MASK_ALT)
+ if (gSavedSettings.getBOOL("EnableAltZoom"))
{
- return LLToolCamera::getInstance();
+ if (mask & MASK_ALT)
+ {
+ return LLToolCamera::getInstance();
+ }
}
return NULL;
}
diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp
index 1c745906aa..d23d2b3abd 100644
--- a/indra/newview/lltooldraganddrop.cpp
+++ b/indra/newview/lltooldraganddrop.cpp
@@ -35,7 +35,6 @@
#include "llagentwearables.h"
#include "llappearancemgr.h"
#include "lldictionary.h"
-//#include "llfirstuse.h"
#include "llfloaterreg.h"
#include "llfloatertools.h"
#include "llgesturemgr.h"
@@ -308,23 +307,24 @@ LLToolDragAndDrop::dragOrDrop3dImpl LLToolDragAndDrop::LLDragAndDropDictionary::
LLToolDragAndDrop::LLDragAndDropDictionary::LLDragAndDropDictionary()
{
- // DT_NONE DT_SELF DT_AVATAR DT_OBJECT DT_LAND
- // |--------------|---------------------------|---------------------------|-------------------------------|--------------|
+ // DT_NONE DT_SELF DT_AVATAR DT_OBJECT DT_LAND
+ // |-------------------------------|----------------------------------------------|-----------------------------------------------|---------------------------------------------------|--------------------------------|
addEntry(DAD_NONE, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL));
- addEntry(DAD_TEXTURE, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dTextureObject, &LLToolDragAndDrop::dad3dNULL));
- addEntry(DAD_SOUND, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL));
+ addEntry(DAD_TEXTURE, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dTextureObject, &LLToolDragAndDrop::dad3dNULL));
+ addEntry(DAD_SOUND, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL));
addEntry(DAD_CALLINGCARD, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL));
- addEntry(DAD_LANDMARK, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL));
- addEntry(DAD_SCRIPT, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dRezScript, &LLToolDragAndDrop::dad3dNULL));
- addEntry(DAD_CLOTHING, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dWearItem, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL));
- addEntry(DAD_OBJECT, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dRezAttachmentFromInv, &LLToolDragAndDrop::dad3dGiveInventoryObject, &LLToolDragAndDrop::dad3dRezObjectOnObject, &LLToolDragAndDrop::dad3dRezObjectOnLand));
- addEntry(DAD_NOTECARD, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL));
- addEntry(DAD_CATEGORY, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dWearCategory, &LLToolDragAndDrop::dad3dGiveInventoryCategory,&LLToolDragAndDrop::dad3dUpdateInventoryCategory, &LLToolDragAndDrop::dad3dNULL));
+ addEntry(DAD_LANDMARK, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL));
+ addEntry(DAD_SCRIPT, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dRezScript, &LLToolDragAndDrop::dad3dNULL));
+ addEntry(DAD_CLOTHING, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dWearItem, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL));
+ addEntry(DAD_OBJECT, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dRezAttachmentFromInv, &LLToolDragAndDrop::dad3dGiveInventoryObject, &LLToolDragAndDrop::dad3dRezObjectOnObject, &LLToolDragAndDrop::dad3dRezObjectOnLand));
+ addEntry(DAD_NOTECARD, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL));
+ addEntry(DAD_CATEGORY, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dWearCategory, &LLToolDragAndDrop::dad3dGiveInventoryCategory, &LLToolDragAndDrop::dad3dUpdateInventoryCategory, &LLToolDragAndDrop::dad3dNULL));
addEntry(DAD_ROOT_CATEGORY, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL));
- addEntry(DAD_BODYPART, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dWearItem, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL));
- addEntry(DAD_ANIMATION, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL));
- addEntry(DAD_GESTURE, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dActivateGesture, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL));
+ addEntry(DAD_BODYPART, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dWearItem, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL));
+ addEntry(DAD_ANIMATION, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL));
+ addEntry(DAD_GESTURE, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dActivateGesture, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL));
addEntry(DAD_LINK, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL));
+ addEntry(DAD_MESH, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dMeshObject, &LLToolDragAndDrop::dad3dNULL));
// TODO: animation on self could play it? edit it?
// TODO: gesture on self could play it? edit it?
};
@@ -397,7 +397,7 @@ void LLToolDragAndDrop::beginDrag(EDragAndDropType type,
{
folder_ids.push_back(cargo_id);
}
- gInventory.collectDescendentsIf (
+ gInventory.collectDescendentsIf(
cargo_id,
cats,
items,
@@ -468,7 +468,7 @@ void LLToolDragAndDrop::beginMultiDrag(
{
cat_ids.insert(cat->getUUID());
}
- gInventory.collectDescendentsIf (
+ gInventory.collectDescendentsIf(
cat->getUUID(),
cats,
items,
@@ -1028,6 +1028,31 @@ void LLToolDragAndDrop::dropTextureAllFaces(LLViewerObject* hit_obj,
hit_obj->sendTEUpdate();
}
+void LLToolDragAndDrop::dropMesh(LLViewerObject* hit_obj,
+ LLInventoryItem* item,
+ LLToolDragAndDrop::ESource source,
+ const LLUUID& src_id)
+{
+ if (!item)
+ {
+ llwarns << "no inventory item." << llendl;
+ return;
+ }
+ LLUUID asset_id = item->getAssetUUID();
+ BOOL success = handleDropTextureProtections(hit_obj, item, source, src_id);
+ if(!success)
+ {
+ return;
+ }
+
+ LLSculptParams sculpt_params;
+ sculpt_params.setSculptTexture(asset_id);
+ sculpt_params.setSculptType(LL_SCULPT_TYPE_MESH);
+ hit_obj->setParameterEntry(LLNetworkData::PARAMS_SCULPT, sculpt_params, TRUE);
+
+ dialog_refresh_all();
+}
+
/*
void LLToolDragAndDrop::dropTextureOneFaceAvatar(LLVOAvatar* avatar, S32 hit_face, LLInventoryItem* item)
{
@@ -1124,9 +1149,9 @@ void LLToolDragAndDrop::dropScript(LLViewerObject* hit_obj,
}
void LLToolDragAndDrop::dropObject(LLViewerObject* raycast_target,
- BOOL bypass_sim_raycast,
- BOOL from_task_inventory,
- BOOL remove_from_inventory)
+ BOOL bypass_sim_raycast,
+ BOOL from_task_inventory,
+ BOOL remove_from_inventory)
{
LLViewerRegion* regionp = LLWorld::getInstance()->getRegionFromPosGlobal(mLastHitPos);
if (!regionp)
@@ -1362,7 +1387,7 @@ EAcceptance LLToolDragAndDrop::willObjectAcceptInventory(LLViewerObject* obj, LL
// help make sure that drops that are from an object to an object
// don't have to worry about order of evaluation. Think of this
// like check for self in assignment.
- if (obj->getID() == item->getParentUUID())
+ if(obj->getID() == item->getParentUUID())
{
return ACCEPT_NO;
}
@@ -1371,28 +1396,34 @@ EAcceptance LLToolDragAndDrop::willObjectAcceptInventory(LLViewerObject* obj, LL
// gAgent.getGroupID())
// && (obj->mPermModify || obj->mFlagAllowInventoryAdd));
BOOL worn = FALSE;
+ LLVOAvatarSelf* my_avatar = NULL;
switch(item->getType())
{
case LLAssetType::AT_OBJECT:
- if (isAgentAvatarValid() && gAgentAvatarp->isWearingAttachment(item->getUUID()))
+ my_avatar = gAgentAvatarp;
+ if(my_avatar && my_avatar->isWearingAttachment(item->getUUID()))
{
worn = TRUE;
}
break;
case LLAssetType::AT_BODYPART:
case LLAssetType::AT_CLOTHING:
- if (gAgentWearables.isWearingItem(item->getUUID()))
+ if(gAgentWearables.isWearingItem(item->getUUID()))
{
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;
}
const LLPermissions& perm = item->getPermissions();
BOOL modify = (obj->permModify() || obj->flagAllowInventoryAdd());
BOOL transfer = FALSE;
- if ((obj->permYouOwner() && (perm.getOwner() == gAgent.getID()))
+ if((obj->permYouOwner() && (perm.getOwner() == gAgent.getID()))
|| perm.allowOperationBy(PERM_TRANSFER, gAgent.getID()))
{
transfer = TRUE;
@@ -1400,15 +1431,15 @@ EAcceptance LLToolDragAndDrop::willObjectAcceptInventory(LLViewerObject* obj, LL
BOOL volume = (LL_PCODE_VOLUME == obj->getPCode());
BOOL attached = obj->isAttachment();
BOOL unrestricted = ((perm.getMaskBase() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED) ? TRUE : FALSE;
- if (attached && !unrestricted)
+ if(attached && !unrestricted)
{
return ACCEPT_NO_LOCKED;
}
- else if (modify && transfer && volume && !worn)
+ else if(modify && transfer && volume && !worn)
{
return ACCEPT_YES_MULTI;
}
- else if (!modify)
+ else if(!modify)
{
return ACCEPT_NO_LOCKED;
}
@@ -1503,14 +1534,15 @@ bool LLToolDragAndDrop::handleGiveDragAndDrop(LLUUID dest_agent, LLUUID session_
case DAD_ANIMATION:
case DAD_GESTURE:
case DAD_CALLINGCARD:
+ case DAD_MESH:
{
LLViewerInventoryItem* inv_item = (LLViewerInventoryItem*)cargo_data;
- if (gInventory.getItem(inv_item->getUUID())
+ if(gInventory.getItem(inv_item->getUUID())
&& LLGiveInventory::isInventoryGiveAcceptable(inv_item))
{
// *TODO: get multiple object transfers working
*accept = ACCEPT_YES_COPY_SINGLE;
- if (drop)
+ if(drop)
{
LLIMModel::LLIMSession * session = LLIMModel::instance().findIMSession(session_id);
@@ -1550,11 +1582,11 @@ bool LLToolDragAndDrop::handleGiveDragAndDrop(LLUUID dest_agent, LLUUID session_
case DAD_CATEGORY:
{
LLViewerInventoryCategory* inv_cat = (LLViewerInventoryCategory*)cargo_data;
- if (gInventory.getCategory(inv_cat->getUUID()))
+ if( gInventory.getCategory( inv_cat->getUUID() ) )
{
// *TODO: get multiple object transfers working
*accept = ACCEPT_YES_COPY_SINGLE;
- if (drop)
+ if(drop)
{
LLGiveInventory::doGiveInventoryCategory(dest_agent, inv_cat, session_id);
}
@@ -1595,7 +1627,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezAttachmentFromInv(
{
lldebugs << "LLToolDragAndDrop::dad3dRezAttachmentFromInv()" << llendl;
// must be in the user's inventory
- if (mSource != SOURCE_AGENT && mSource != SOURCE_LIBRARY)
+ if(mSource != SOURCE_AGENT && mSource != SOURCE_LIBRARY)
{
return ACCEPT_NO;
}
@@ -1607,20 +1639,21 @@ EAcceptance LLToolDragAndDrop::dad3dRezAttachmentFromInv(
// must not be in the trash
const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
- if (gInventory.isObjectDescendentOf(item->getUUID(), trash_id))
+ if( gInventory.isObjectDescendentOf( item->getUUID(), trash_id ) )
{
return ACCEPT_NO;
}
// must not be already wearing it
- if (!isAgentAvatarValid() || gAgentAvatarp->isWearingAttachment(item->getUUID()))
+ LLVOAvatarSelf* avatar = gAgentAvatarp;
+ if( !avatar || avatar->isWearingAttachment(item->getUUID()) )
{
return ACCEPT_NO;
}
- if (drop)
+ if( drop )
{
- if (mSource == SOURCE_LIBRARY)
+ if(mSource == SOURCE_LIBRARY)
{
LLPointer<LLInventoryCallback> cb = new RezAttachmentCallback(0);
copy_inventory_item(
@@ -1654,7 +1687,8 @@ EAcceptance LLToolDragAndDrop::dad3dRezObjectOnLand(
locateInventory(item, cat);
if (!item || !item->isFinished()) return ACCEPT_NO;
- if (!isAgentAvatarValid() || gAgentAvatarp->isWearingAttachment(item->getUUID()))
+ LLVOAvatarSelf* my_avatar = gAgentAvatarp;
+ if( !my_avatar || my_avatar->isWearingAttachment( item->getUUID() ) )
{
return ACCEPT_NO;
}
@@ -1679,7 +1713,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezObjectOnLand(
// check if the item can be copied. If not, send that to the sim
// which will remove the inventory item.
- if (!item->getPermissions().allowCopyBy(gAgent.getID()))
+ if(!item->getPermissions().allowCopyBy(gAgent.getID()))
{
accept = ACCEPT_YES_SINGLE;
remove_inventory = TRUE;
@@ -1687,13 +1721,13 @@ EAcceptance LLToolDragAndDrop::dad3dRezObjectOnLand(
// Check if it's in the trash.
const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
- if (gInventory.isObjectDescendentOf(item->getUUID(), trash_id))
+ if(gInventory.isObjectDescendentOf(item->getUUID(), trash_id))
{
accept = ACCEPT_YES_SINGLE;
remove_inventory = TRUE;
}
- if (drop)
+ if(drop)
{
dropObject(obj, TRUE, FALSE, remove_inventory);
}
@@ -1715,22 +1749,23 @@ EAcceptance LLToolDragAndDrop::dad3dRezObjectOnObject(
LLViewerInventoryCategory* cat;
locateInventory(item, cat);
if (!item || !item->isFinished()) return ACCEPT_NO;
- if (!isAgentAvatarValid() || gAgentAvatarp->isWearingAttachment(item->getUUID()))
+ LLVOAvatarSelf* my_avatar = gAgentAvatarp;
+ if( !my_avatar || my_avatar->isWearingAttachment( item->getUUID() ) )
{
return ACCEPT_NO;
}
- if ((mask & MASK_CONTROL))
+ if((mask & MASK_CONTROL))
{
// *HACK: In order to resolve SL-22177, we need to block drags
// from notecards and objects onto other objects.
- if (mSource == SOURCE_NOTECARD)
+ if(mSource == SOURCE_NOTECARD)
{
return ACCEPT_NO;
}
EAcceptance rv = willObjectAcceptInventory(obj, item);
- if (drop && (ACCEPT_YES_SINGLE <= rv))
+ if(drop && (ACCEPT_YES_SINGLE <= rv))
{
dropInventory(obj, item, mSource, mSourceID);
}
@@ -1756,7 +1791,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezObjectOnObject(
// check if the item can be copied. If not, send that to the sim
// which will remove the inventory item.
- if (!item->getPermissions().allowCopyBy(gAgent.getID()))
+ if(!item->getPermissions().allowCopyBy(gAgent.getID()))
{
accept = ACCEPT_YES_SINGLE;
remove_inventory = TRUE;
@@ -1764,13 +1799,13 @@ EAcceptance LLToolDragAndDrop::dad3dRezObjectOnObject(
// Check if it's in the trash.
const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
- if (gInventory.isObjectDescendentOf(item->getUUID(), trash_id))
+ if(gInventory.isObjectDescendentOf(item->getUUID(), trash_id))
{
accept = ACCEPT_YES_SINGLE;
remove_inventory = TRUE;
}
- if (drop)
+ if(drop)
{
dropObject(obj, FALSE, FALSE, remove_inventory);
}
@@ -1785,7 +1820,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezScript(
// *HACK: In order to resolve SL-22177, we need to block drags
// from notecards and objects onto other objects.
- if ((SOURCE_WORLD == mSource) || (SOURCE_NOTECARD == mSource))
+ if((SOURCE_WORLD == mSource) || (SOURCE_NOTECARD == mSource))
{
return ACCEPT_NO;
}
@@ -1795,7 +1830,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezScript(
locateInventory(item, cat);
if (!item || !item->isFinished()) return ACCEPT_NO;
EAcceptance rv = willObjectAcceptInventory(obj, item);
- if (drop && (ACCEPT_YES_SINGLE <= rv))
+ if(drop && (ACCEPT_YES_SINGLE <= rv))
{
// rez in the script active by default, rez in inactive if the
// control key is being held down.
@@ -1816,14 +1851,14 @@ EAcceptance LLToolDragAndDrop::dad3dRezScript(
return rv;
}
-EAcceptance LLToolDragAndDrop::dad3dTextureObject(
- LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
+EAcceptance LLToolDragAndDrop::dad3dApplyToObject(
+ LLViewerObject* obj, S32 face, MASK mask, BOOL drop, EDragAndDropType cargo_type)
{
- lldebugs << "LLToolDragAndDrop::dad3dTextureObject()" << llendl;
+ lldebugs << "LLToolDragAndDrop::dad3dApplyToObject()" << llendl;
// *HACK: In order to resolve SL-22177, we need to block drags
// from notecards and objects onto other objects.
- if ((SOURCE_WORLD == mSource) || (SOURCE_NOTECARD == mSource))
+ if((SOURCE_WORLD == mSource) || (SOURCE_NOTECARD == mSource))
{
return ACCEPT_NO;
}
@@ -1833,33 +1868,44 @@ EAcceptance LLToolDragAndDrop::dad3dTextureObject(
locateInventory(item, cat);
if (!item || !item->isFinished()) return ACCEPT_NO;
EAcceptance rv = willObjectAcceptInventory(obj, item);
- if ((mask & MASK_CONTROL))
+ if((mask & MASK_CONTROL))
{
- if ((ACCEPT_YES_SINGLE <= rv) && drop)
+ if((ACCEPT_YES_SINGLE <= rv) && drop)
{
dropInventory(obj, item, mSource, mSourceID);
}
return rv;
}
- if (!obj->permModify())
+ if(!obj->permModify())
{
return ACCEPT_NO_LOCKED;
}
//If texture !copyable don't texture or you'll never get it back.
- if (!item->getPermissions().allowCopyBy(gAgent.getID()))
+ if(!item->getPermissions().allowCopyBy(gAgent.getID()))
{
return ACCEPT_NO;
}
- if (drop && (ACCEPT_YES_SINGLE <= rv))
+ if(drop && (ACCEPT_YES_SINGLE <= rv))
{
- if ((mask & MASK_SHIFT))
+ if (cargo_type == DAD_TEXTURE)
{
- dropTextureAllFaces(obj, item, mSource, mSourceID);
+ if((mask & MASK_SHIFT))
+ {
+ dropTextureAllFaces(obj, item, mSource, mSourceID);
+ }
+ else
+ {
+ dropTextureOneFace(obj, face, item, mSource, mSourceID);
+ }
+ }
+ else if (cargo_type == DAD_MESH)
+ {
+ dropMesh(obj, item, mSource, mSourceID);
}
else
{
- dropTextureOneFace(obj, face, item, mSource, mSourceID);
+ llwarns << "unsupported asset type" << llendl;
}
// VEFFECT: SetTexture
@@ -1873,14 +1919,29 @@ EAcceptance LLToolDragAndDrop::dad3dTextureObject(
// enable multi-drop, although last texture will win
return ACCEPT_YES_MULTI;
}
+
+
+EAcceptance LLToolDragAndDrop::dad3dTextureObject(
+ LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
+{
+ return dad3dApplyToObject(obj, face, mask, drop, DAD_TEXTURE);
+}
+
+EAcceptance LLToolDragAndDrop::dad3dMeshObject(
+ LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
+{
+ return dad3dApplyToObject(obj, face, mask, drop, DAD_MESH);
+}
+
+
/*
EAcceptance LLToolDragAndDrop::dad3dTextureSelf(
LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
{
lldebugs << "LLToolDragAndDrop::dad3dTextureAvatar()" << llendl;
- if (drop)
+ if(drop)
{
- if (!(mask & MASK_SHIFT))
+ if( !(mask & MASK_SHIFT) )
{
dropTextureOneFaceAvatar( (LLVOAvatar*)obj, face, (LLInventoryItem*)mCargoData);
}
@@ -1898,16 +1959,16 @@ EAcceptance LLToolDragAndDrop::dad3dWearItem(
locateInventory(item, cat);
if (!item || !item->isFinished()) return ACCEPT_NO;
- if (mSource == SOURCE_AGENT || mSource == SOURCE_LIBRARY)
+ if(mSource == SOURCE_AGENT || mSource == SOURCE_LIBRARY)
{
// it's in the agent inventory
const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
- if (gInventory.isObjectDescendentOf(item->getUUID(), trash_id))
+ if( gInventory.isObjectDescendentOf( item->getUUID(), trash_id ) )
{
return ACCEPT_NO;
}
- if (drop)
+ if( drop )
{
// TODO: investigate wearables may not be loaded at this point EXT-8231
@@ -1931,19 +1992,19 @@ EAcceptance LLToolDragAndDrop::dad3dActivateGesture(
locateInventory(item, cat);
if (!item || !item->isFinished()) return ACCEPT_NO;
- if (mSource == SOURCE_AGENT || mSource == SOURCE_LIBRARY)
+ if(mSource == SOURCE_AGENT || mSource == SOURCE_LIBRARY)
{
// it's in the agent inventory
const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
- if (gInventory.isObjectDescendentOf(item->getUUID(), trash_id))
+ if( gInventory.isObjectDescendentOf( item->getUUID(), trash_id ) )
{
return ACCEPT_NO;
}
- if (drop)
+ if( drop )
{
LLUUID item_id;
- if (mSource == SOURCE_LIBRARY)
+ if(mSource == SOURCE_LIBRARY)
{
// create item based on that one, and put it on if that
// was a success.
@@ -1978,31 +2039,31 @@ EAcceptance LLToolDragAndDrop::dad3dWearCategory(
LLViewerInventoryItem* item;
LLViewerInventoryCategory* category;
locateInventory(item, category);
- if (!category) return ACCEPT_NO;
+ if(!category) return ACCEPT_NO;
if (drop)
{
// TODO: investigate wearables may not be loaded at this point EXT-8231
}
- if (mSource == SOURCE_AGENT)
+ if(mSource == SOURCE_AGENT)
{
const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
- if (gInventory.isObjectDescendentOf(category->getUUID(), trash_id))
+ if( gInventory.isObjectDescendentOf( category->getUUID(), trash_id ) )
{
return ACCEPT_NO;
}
- if (drop)
+ if(drop)
{
- BOOL append = ( (mask & MASK_SHIFT) ? TRUE : FALSE );
+ BOOL append = ( (mask & MASK_SHIFT) ? TRUE : FALSE );
LLAppearanceMgr::instance().wearInventoryCategory(category, false, append);
}
return ACCEPT_YES_MULTI;
}
- else if (mSource == SOURCE_LIBRARY)
+ else if(mSource == SOURCE_LIBRARY)
{
- if (drop)
+ if(drop)
{
LLAppearanceMgr::instance().wearInventoryCategory(category, true, false);
}
@@ -2023,7 +2084,7 @@ EAcceptance LLToolDragAndDrop::dad3dUpdateInventory(
// *HACK: In order to resolve SL-22177, we need to block drags
// from notecards and objects onto other objects.
- if ((SOURCE_WORLD == mSource) || (SOURCE_NOTECARD == mSource))
+ if((SOURCE_WORLD == mSource) || (SOURCE_NOTECARD == mSource))
{
return ACCEPT_NO;
}
@@ -2043,7 +2104,7 @@ EAcceptance LLToolDragAndDrop::dad3dUpdateInventory(
}
EAcceptance rv = willObjectAcceptInventory(root_object, item);
- if (root_object && drop && (ACCEPT_YES_COPY_SINGLE <= rv))
+ if(root_object && drop && (ACCEPT_YES_COPY_SINGLE <= rv))
{
dropInventory(root_object, item, mSource, mSourceID);
}
@@ -2087,7 +2148,7 @@ EAcceptance LLToolDragAndDrop::dad3dUpdateInventoryCategory(
LLDroppableItem droppable(!obj->permYouOwner());
LLInventoryModel::cat_array_t cats;
LLInventoryModel::item_array_t items;
- gInventory.collectDescendentsIf (cat->getUUID(),
+ gInventory.collectDescendentsIf(cat->getUUID(),
cats,
items,
LLInventoryModel::EXCLUDE_TRASH,
@@ -2116,7 +2177,7 @@ EAcceptance LLToolDragAndDrop::dad3dUpdateInventoryCategory(
{
const LLViewerInventoryCategory *cat = (*cat_iter);
rv = gInventory.isCategoryComplete(cat->getUUID()) ? ACCEPT_YES_MULTI : ACCEPT_NO;
- if (rv < ACCEPT_YES_SINGLE)
+ if(rv < ACCEPT_YES_SINGLE)
{
lldebugs << "Category " << cat->getUUID() << "is not complete." << llendl;
break;
@@ -2184,26 +2245,27 @@ EAcceptance LLToolDragAndDrop::dad3dGiveInventoryObject(
lldebugs << "LLToolDragAndDrop::dad3dGiveInventoryObject()" << llendl;
// item has to be in agent inventory.
- if (mSource != SOURCE_AGENT) return ACCEPT_NO;
+ if(mSource != SOURCE_AGENT) return ACCEPT_NO;
// find the item now.
LLViewerInventoryItem* item;
LLViewerInventoryCategory* cat;
locateInventory(item, cat);
if (!item || !item->isFinished()) return ACCEPT_NO;
- if (!item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID()))
+ if(!item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID()))
{
// cannot give away no-transfer objects
return ACCEPT_NO;
}
- if (isAgentAvatarValid() && gAgentAvatarp->isWearingAttachment(item->getUUID()))
+ LLVOAvatarSelf* avatar = gAgentAvatarp;
+ if(avatar && avatar->isWearingAttachment( item->getUUID() ) )
{
// You can't give objects that are attached to you
return ACCEPT_NO;
}
- if (obj && isAgentAvatarValid())
+ if( obj && avatar )
{
- if (drop)
+ if(drop)
{
LLGiveInventory::doGiveInventoryItem(obj->getID(), item );
}
@@ -2220,7 +2282,7 @@ EAcceptance LLToolDragAndDrop::dad3dGiveInventory(
{
lldebugs << "LLToolDragAndDrop::dad3dGiveInventory()" << llendl;
// item has to be in agent inventory.
- if (mSource != SOURCE_AGENT) return ACCEPT_NO;
+ if(mSource != SOURCE_AGENT) return ACCEPT_NO;
LLViewerInventoryItem* item;
LLViewerInventoryCategory* cat;
locateInventory(item, cat);
@@ -2242,12 +2304,12 @@ EAcceptance LLToolDragAndDrop::dad3dGiveInventoryCategory(
LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
{
lldebugs << "LLToolDragAndDrop::dad3dGiveInventoryCategory()" << llendl;
- if (drop && obj)
+ if(drop && obj)
{
LLViewerInventoryItem* item;
LLViewerInventoryCategory* cat;
locateInventory(item, cat);
- if (!cat) return ACCEPT_NO;
+ if(!cat) return ACCEPT_NO;
LLGiveInventory::doGiveInventoryCategory(obj->getID(), cat);
}
// *TODO: deal with all the issues surrounding multi-object
@@ -2265,12 +2327,12 @@ EAcceptance LLToolDragAndDrop::dad3dRezFromObjectOnLand(
locateInventory(item, cat);
if (!item || !item->isFinished()) return ACCEPT_NO;
- if (!gAgent.allowOperation(PERM_COPY, item->getPermissions())
+ if(!gAgent.allowOperation(PERM_COPY, item->getPermissions())
|| !item->getPermissions().allowTransferTo(LLUUID::null))
{
return ACCEPT_NO_LOCKED;
}
- if (drop)
+ if(drop)
{
dropObject(obj, TRUE, TRUE, FALSE);
}
@@ -2285,7 +2347,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezFromObjectOnObject(
LLViewerInventoryCategory* cat;
locateInventory(item, cat);
if (!item || !item->isFinished()) return ACCEPT_NO;
- if ((mask & MASK_CONTROL))
+ if((mask & MASK_CONTROL))
{
// *HACK: In order to resolve SL-22177, we need to block drags
// from notecards and objects onto other objects.
@@ -2293,19 +2355,19 @@ EAcceptance LLToolDragAndDrop::dad3dRezFromObjectOnObject(
// *HACK: uncomment this when appropriate
//EAcceptance rv = willObjectAcceptInventory(obj, item);
- //if (drop && (ACCEPT_YES_SINGLE <= rv))
+ //if(drop && (ACCEPT_YES_SINGLE <= rv))
//{
// dropInventory(obj, item, mSource, mSourceID);
//}
//return rv;
}
- if (!item->getPermissions().allowCopyBy(gAgent.getID(),
+ if(!item->getPermissions().allowCopyBy(gAgent.getID(),
gAgent.getGroupID())
|| !item->getPermissions().allowTransferTo(LLUUID::null))
{
return ACCEPT_NO_LOCKED;
}
- if (drop)
+ if(drop)
{
dropObject(obj, FALSE, TRUE, FALSE);
}
@@ -2321,23 +2383,23 @@ EAcceptance LLToolDragAndDrop::dad3dCategoryOnLand(
LLInventoryItem* item;
LLInventoryCategory* cat;
locateInventory(item, cat);
- if (!cat) return ACCEPT_NO;
+ if(!cat) return ACCEPT_NO;
EAcceptance rv = ACCEPT_NO;
// find all the items in the category
LLViewerInventoryCategory::cat_array_t cats;
LLViewerInventoryItem::item_array_t items;
LLDropCopyableItems droppable;
- gInventory.collectDescendentsIf (cat->getUUID(),
+ gInventory.collectDescendentsIf(cat->getUUID(),
cats,
items,
LLInventoryModel::EXCLUDE_TRASH,
droppable);
- if (items.count() > 0)
+ if(items.count() > 0)
{
rv = ACCEPT_YES_SINGLE;
}
- if ((rv >= ACCEPT_YES_COPY_SINGLE) && drop)
+ if((rv >= ACCEPT_YES_COPY_SINGLE) && drop)
{
createContainer(items, cat->getName());
return ACCEPT_NO;
@@ -2360,19 +2422,19 @@ EAcceptance LLToolDragAndDrop::dad3dAssetOnLand(
LLViewerInventoryItem::item_array_t items;
LLViewerInventoryItem::item_array_t copyable_items;
locateMultipleInventory(items, cats);
- if (!items.count()) return ACCEPT_NO;
+ if(!items.count()) return ACCEPT_NO;
EAcceptance rv = ACCEPT_NO;
for (S32 i = 0; i < items.count(); i++)
{
LLInventoryItem* item = items[i];
- if (item->getPermissions().allowCopyBy(gAgent.getID()))
+ if(item->getPermissions().allowCopyBy(gAgent.getID()))
{
copyable_items.put(item);
rv = ACCEPT_YES_SINGLE;
}
}
- if ((rv >= ACCEPT_YES_COPY_SINGLE) && drop)
+ if((rv >= ACCEPT_YES_COPY_SINGLE) && drop)
{
createContainer(copyable_items, NULL);
}
@@ -2387,20 +2449,20 @@ LLInventoryObject* LLToolDragAndDrop::locateInventory(
{
item = NULL;
cat = NULL;
- if (mCargoIDs.empty()) return NULL;
- if ((mSource == SOURCE_AGENT) || (mSource == SOURCE_LIBRARY))
+ if(mCargoIDs.empty()) return NULL;
+ if((mSource == SOURCE_AGENT) || (mSource == SOURCE_LIBRARY))
{
// The object should be in user inventory.
item = (LLViewerInventoryItem*)gInventory.getItem(mCargoIDs[mCurItemIndex]);
cat = (LLViewerInventoryCategory*)gInventory.getCategory(mCargoIDs[mCurItemIndex]);
}
- else if (mSource == SOURCE_WORLD)
+ else if(mSource == SOURCE_WORLD)
{
// This object is in some task inventory somewhere.
LLViewerObject* obj = gObjectList.findObject(mSourceID);
- if (obj)
+ if(obj)
{
- if ((mCargoTypes[mCurItemIndex] == DAD_CATEGORY)
+ if((mCargoTypes[mCurItemIndex] == DAD_CATEGORY)
|| (mCargoTypes[mCurItemIndex] == DAD_ROOT_CATEGORY))
{
cat = (LLViewerInventoryCategory*)obj->getInventoryObject(mCargoIDs[mCurItemIndex]);
@@ -2411,16 +2473,16 @@ LLInventoryObject* LLToolDragAndDrop::locateInventory(
}
}
}
- else if (mSource == SOURCE_NOTECARD)
+ else if(mSource == SOURCE_NOTECARD)
{
LLPreviewNotecard* preview = LLFloaterReg::findTypedInstance<LLPreviewNotecard>("preview_notecard", mSourceID);
- if (preview)
+ if(preview)
{
item = (LLViewerInventoryItem*)preview->getDragItem();
}
}
- if (item) return item;
- if (cat) return cat;
+ if(item) return item;
+ if(cat) return cat;
return NULL;
}
@@ -2428,8 +2490,8 @@ LLInventoryObject* LLToolDragAndDrop::locateInventory(
LLInventoryObject* LLToolDragAndDrop::locateMultipleInventory(LLViewerInventoryCategory::cat_array_t& cats,
LLViewerInventoryItem::item_array_t& items)
{
- if (mCargoIDs.count() == 0) return NULL;
- if ((mSource == SOURCE_AGENT) || (mSource == SOURCE_LIBRARY))
+ if(mCargoIDs.count() == 0) return NULL;
+ if((mSource == SOURCE_AGENT) || (mSource == SOURCE_LIBRARY))
{
// The object should be in user inventory.
for (S32 i = 0; i < mCargoIDs.count(); i++)
@@ -2446,13 +2508,13 @@ LLInventoryObject* LLToolDragAndDrop::locateMultipleInventory(LLViewerInventoryC
}
}
}
- else if (mSource == SOURCE_WORLD)
+ else if(mSource == SOURCE_WORLD)
{
// This object is in some task inventory somewhere.
LLViewerObject* obj = gObjectList.findObject(mSourceID);
- if (obj)
+ if(obj)
{
- if ((mCargoType == DAD_CATEGORY)
+ if((mCargoType == DAD_CATEGORY)
|| (mCargoType == DAD_ROOT_CATEGORY))
{
// The object should be in user inventory.
@@ -2478,17 +2540,17 @@ LLInventoryObject* LLToolDragAndDrop::locateMultipleInventory(LLViewerInventoryC
}
}
}
- else if (mSource == SOURCE_NOTECARD)
+ else if(mSource == SOURCE_NOTECARD)
{
LLPreviewNotecard* card;
card = (LLPreviewNotecard*)LLPreview::find(mSourceID);
- if (card)
+ if(card)
{
items.put((LLInventoryItem*)card->getDragItem());
}
}
- if (items.count()) return items[0];
- if (cats.count()) return cats[0];
+ if(items.count()) return items[0];
+ if(cats.count()) return cats[0];
return NULL;
}
*/
diff --git a/indra/newview/lltooldraganddrop.h b/indra/newview/lltooldraganddrop.h
index a13b775699..7b8cce3dc7 100644
--- a/indra/newview/lltooldraganddrop.h
+++ b/indra/newview/lltooldraganddrop.h
@@ -148,6 +148,8 @@ protected:
MASK mask, BOOL drop);
EAcceptance dad3dTextureObject(LLViewerObject* obj, S32 face,
MASK mask, BOOL drop);
+ EAcceptance dad3dMeshObject(LLViewerObject* obj, S32 face,
+ MASK mask, BOOL drop);
// EAcceptance dad3dTextureSelf(LLViewerObject* obj, S32 face,
// MASK mask, BOOL drop);
EAcceptance dad3dWearItem(LLViewerObject* obj, S32 face,
@@ -179,6 +181,11 @@ protected:
EAcceptance dad3dActivateGesture(LLViewerObject *obj, S32 face,
MASK mask, BOOL drop);
+ // helper called by methods above to handle "application" of an item
+ // to an object (texture applied to face, mesh applied to shape, etc.)
+ EAcceptance dad3dApplyToObject(LLViewerObject* obj, S32 face, MASK mask, BOOL drop, EDragAndDropType cargo_type);
+
+
// set the LLToolDragAndDrop's cursor based on the given acceptance
ECursorType acceptanceToCursor( EAcceptance acceptance );
@@ -229,6 +236,11 @@ public:
LLInventoryItem* item,
ESource source,
const LLUUID& src_id);
+ static void dropMesh(LLViewerObject* hit_obj,
+ LLInventoryItem* item,
+ ESource source,
+ const LLUUID& src_id);
+
//static void dropTextureOneFaceAvatar(LLVOAvatar* avatar,S32 hit_face,
// LLInventoryItem* item)
diff --git a/indra/newview/lltoolmorph.cpp b/indra/newview/lltoolmorph.cpp
index ca80a1db79..964b17d3a6 100644
--- a/indra/newview/lltoolmorph.cpp
+++ b/indra/newview/lltoolmorph.cpp
@@ -244,13 +244,13 @@ BOOL LLVisualParamHint::render()
//-----------------------------------------------------------------------------
// draw()
//-----------------------------------------------------------------------------
-void LLVisualParamHint::draw()
+void LLVisualParamHint::draw(F32 alpha)
{
if (!mIsVisible) return;
gGL.getTexUnit(0)->bind(this);
- gGL.color4f(1.f, 1.f, 1.f, 1.f);
+ gGL.color4f(1.f, 1.f, 1.f, alpha);
LLGLSUIDefault gls_ui;
gGL.begin(LLRender::QUADS);
diff --git a/indra/newview/lltoolmorph.h b/indra/newview/lltoolmorph.h
index 59201233ae..a6889be151 100644
--- a/indra/newview/lltoolmorph.h
+++ b/indra/newview/lltoolmorph.h
@@ -68,7 +68,7 @@ public:
BOOL render();
void requestUpdate( S32 delay_frames ) {mNeedsUpdate = TRUE; mDelayFrames = delay_frames; }
void setUpdateDelayFrames( S32 delay_frames ) { mDelayFrames = delay_frames; }
- void draw();
+ void draw(F32 alpha);
LLViewerVisualParam* getVisualParam() { return mVisualParam; }
F32 getVisualParamWeight() { return mVisualParamWeight; }
diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp
index d992d808c7..9ec4d33036 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"
@@ -79,11 +79,16 @@ static ECursorType cursor_from_parcel_media(U8 click_action);
LLToolPie::LLToolPie()
: LLTool(std::string("Pie")),
- mGrabMouseButtonDown( FALSE ),
- mMouseOutsideSlop( FALSE ),
- mClickAction(0)
-{ }
-
+ mMouseButtonDown( false ),
+ mMouseOutsideSlop( false ),
+ mMouseSteerX(-1),
+ mMouseSteerY(-1),
+ mBlockClickToWalk(false),
+ mClickAction(0),
+ mClickActionBuyEnabled( gSavedSettings.getBOOL("ClickActionBuyEnabled") ),
+ mClickActionPayEnabled( gSavedSettings.getBOOL("ClickActionPayEnabled") )
+{
+}
BOOL LLToolPie::handleAnyMouseClick(S32 x, S32 y, MASK mask, EClickType clicktype, BOOL down)
{
@@ -97,12 +102,17 @@ BOOL LLToolPie::handleAnyMouseClick(S32 x, S32 y, MASK mask, EClickType clicktyp
BOOL LLToolPie::handleMouseDown(S32 x, S32 y, MASK mask)
{
+ mMouseOutsideSlop = FALSE;
+ mMouseDownX = x;
+ mMouseDownY = y;
+
//left mouse down always picks transparent
mPick = gViewerWindow->pickImmediate(x, y, TRUE);
mPick.mKeyMask = mask;
- mGrabMouseButtonDown = TRUE;
+
+ mMouseButtonDown = true;
- pickLeftMouseDownCallback();
+ handleLeftClickPick();
return TRUE;
}
@@ -117,7 +127,7 @@ BOOL LLToolPie::handleRightMouseDown(S32 x, S32 y, MASK mask)
// claim not handled so UI focus stays same
- pickRightMouseDownCallback();
+ handleRightClickPick();
return FALSE;
}
@@ -134,7 +144,7 @@ BOOL LLToolPie::handleScrollWheel(S32 x, S32 y, S32 clicks)
}
// True if you selected an object.
-BOOL LLToolPie::pickLeftMouseDownCallback()
+BOOL LLToolPie::handleLeftClickPick()
{
S32 x = mPick.mMousePt.mX;
S32 y = mPick.mMousePt.mY;
@@ -211,12 +221,28 @@ BOOL LLToolPie::pickLeftMouseDownCallback()
} // else nothing (fall through to touch)
}
case CLICK_ACTION_PAY:
- if ((object && object->flagTakesMoney())
- || (parent && parent->flagTakesMoney()))
+ if ( mClickActionPayEnabled )
+ {
+ if ((object && object->flagTakesMoney())
+ || (parent && parent->flagTakesMoney()))
+ {
+ // pay event goes to object actually clicked on
+ mClickActionObject = object;
+ mLeftClickSelection = LLToolSelect::handleObjectSelection(mPick, FALSE, TRUE);
+ if (LLSelectMgr::getInstance()->selectGetAllValid())
+ {
+ // call this right away, since we have all the info we need to continue the action
+ selectionPropertiesReceived();
+ }
+ return TRUE;
+ }
+ }
+ break;
+ case CLICK_ACTION_BUY:
+ if ( mClickActionBuyEnabled )
{
- // pay event goes to object actually clicked on
- mClickActionObject = object;
- mLeftClickSelection = LLToolSelect::handleObjectSelection(mPick, FALSE, TRUE);
+ mClickActionObject = parent;
+ mLeftClickSelection = LLToolSelect::handleObjectSelection(mPick, FALSE, TRUE, TRUE);
if (LLSelectMgr::getInstance()->selectGetAllValid())
{
// call this right away, since we have all the info we need to continue the action
@@ -225,15 +251,6 @@ BOOL LLToolPie::pickLeftMouseDownCallback()
return TRUE;
}
break;
- case CLICK_ACTION_BUY:
- mClickActionObject = parent;
- mLeftClickSelection = LLToolSelect::handleObjectSelection(mPick, FALSE, TRUE, TRUE);
- if (LLSelectMgr::getInstance()->selectGetAllValid())
- {
- // call this right away, since we have all the info we need to continue the action
- selectionPropertiesReceived();
- }
- return TRUE;
case CLICK_ACTION_OPEN:
if (parent && parent->allowOpen())
{
@@ -283,7 +300,12 @@ BOOL LLToolPie::pickLeftMouseDownCallback()
}
// put focus back "in world"
- gFocusMgr.setKeyboardFocus(NULL);
+ if (gFocusMgr.getKeyboardFocus())
+ {
+ // don't click to walk on attempt to give focus to world
+ mBlockClickToWalk = true;
+ gFocusMgr.setKeyboardFocus(NULL);
+ }
BOOL touchable = (object && object->flagHandleTouch())
|| (parent && parent->flagHandleTouch());
@@ -295,6 +317,7 @@ BOOL LLToolPie::pickLeftMouseDownCallback()
)
{
gGrabTransientTool = this;
+ mMouseButtonDown = false;
LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolGrab::getInstance() );
return LLToolGrab::getInstance()->handleObjectHit( mPick );
}
@@ -310,9 +333,9 @@ BOOL LLToolPie::pickLeftMouseDownCallback()
if (!gSavedSettings.getBOOL("LeftClickShowMenu"))
{
// mouse already released
- if (!mGrabMouseButtonDown)
+ if (!mMouseButtonDown)
{
- return TRUE;
+ return true;
}
while( object && object->isAttachment() && !object->flagHandleTouch())
@@ -324,9 +347,10 @@ BOOL LLToolPie::pickLeftMouseDownCallback()
}
object = (LLViewerObject*)object->getParent();
}
- if (object && object == gAgentAvatarp)
+ if (object && object == gAgentAvatarp && !gSavedSettings.getBOOL("ClickToWalk"))
{
// we left clicked on avatar, switch to focus mode
+ mMouseButtonDown = false;
LLToolMgr::getInstance()->setTransientTool(LLToolCamera::getInstance());
gViewerWindow->hideCursor();
LLToolCamera::getInstance()->setMouseCapture(TRUE);
@@ -393,7 +417,7 @@ U8 final_click_action(LLViewerObject* obj)
return click_action;
}
-ECursorType cursor_from_object(LLViewerObject* object)
+ECursorType LLToolPie::cursorFromObject(LLViewerObject* object)
{
LLViewerObject* parent = NULL;
if (object)
@@ -413,7 +437,10 @@ ECursorType cursor_from_object(LLViewerObject* object)
}
break;
case CLICK_ACTION_BUY:
- cursor = UI_CURSOR_TOOLBUY;
+ if ( mClickActionBuyEnabled )
+ {
+ cursor = UI_CURSOR_TOOLBUY;
+ }
break;
case CLICK_ACTION_OPEN:
// Open always opens the parent.
@@ -423,10 +450,13 @@ ECursorType cursor_from_object(LLViewerObject* object)
}
break;
case CLICK_ACTION_PAY:
- if ((object && object->flagTakesMoney())
- || (parent && parent->flagTakesMoney()))
+ if ( mClickActionPayEnabled )
{
- cursor = UI_CURSOR_TOOLBUY;
+ if ((object && object->flagTakesMoney())
+ || (parent && parent->flagTakesMoney()))
+ {
+ cursor = UI_CURSOR_TOOLBUY;
+ }
}
break;
case CLICK_ACTION_ZOOM:
@@ -474,10 +504,16 @@ void LLToolPie::selectionPropertiesReceived()
switch (click_action)
{
case CLICK_ACTION_BUY:
- handle_buy();
+ if ( LLToolPie::getInstance()->mClickActionBuyEnabled )
+ {
+ handle_buy();
+ }
break;
case CLICK_ACTION_PAY:
- handle_give_money_dialog();
+ if ( LLToolPie::getInstance()->mClickActionPayEnabled )
+ {
+ handle_give_money_dialog();
+ }
break;
case CLICK_ACTION_OPEN:
LLFloaterReg::showInstance("openobject");
@@ -493,20 +529,16 @@ void LLToolPie::selectionPropertiesReceived()
BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask)
{
mHoverPick = gViewerWindow->pickImmediate(x, y, FALSE);
- // 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
@@ -515,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 = cursor_from_object(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;
@@ -563,40 +626,77 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask)
BOOL LLToolPie::handleMouseUp(S32 x, S32 y, MASK mask)
{
LLViewerObject* obj = mPick.getObject();
-
- handleMediaMouseUp();
-
U8 click_action = final_click_action(obj);
- if (click_action != CLICK_ACTION_NONE)
+
+ // let media have first pass at click
+ if (handleMediaMouseUp() || LLViewerMediaFocus::getInstance()->getFocus())
{
- switch(click_action)
+ mBlockClickToWalk = true;
+ }
+ stopCameraSteering();
+ mMouseButtonDown = false;
+
+ if (click_action == CLICK_ACTION_NONE // not doing 1-click action
+ && gSavedSettings.getBOOL("ClickToWalk") // click to walk enabled
+ && !gAgent.getFlying() // don't auto-navigate while flying until that works
+ && !gAgentAvatarp->isSitting()
+ && !mBlockClickToWalk // another behavior hasn't cancelled click to walk
+ && !mPick.mPosGlobal.isExactlyZero() // valid coordinates for pick
+ && (mPick.mPickType == LLPickInfo::PICK_LAND // we clicked on land
+ || mPick.mObjectID.notNull())) // or on an object
+ {
+ // handle special cases of steering picks
+ LLViewerObject* avatar_object = mPick.getObject();
+
+ // get pointer to avatar
+ while (avatar_object && !avatar_object->isAvatar())
{
- case CLICK_ACTION_BUY:
- case CLICK_ACTION_PAY:
- case CLICK_ACTION_OPEN:
- case CLICK_ACTION_ZOOM:
- case CLICK_ACTION_PLAY:
- case CLICK_ACTION_OPEN_MEDIA:
- // Because these actions open UI dialogs, we won't change
- // the cursor again until the next hover and GL pick over
- // the world. Keep the cursor an arrow, assuming that
- // after the user moves off the UI, they won't be on the
- // same object anymore.
- gViewerWindow->setCursor(UI_CURSOR_ARROW);
- // Make sure the hover-picked object is ignored.
- //gToolTipView->resetLastHoverObject();
- break;
- default:
- break;
+ avatar_object = (LLViewerObject*)avatar_object->getParent();
+ }
+
+ if (avatar_object && ((LLVOAvatar*)avatar_object)->isSelf())
+ {
+ const F64 SELF_CLICK_WALK_DISTANCE = 3.0;
+ // pretend we picked some point a bit in front of avatar
+ mPick.mPosGlobal = gAgent.getPositionGlobal() + LLVector3d(LLViewerCamera::instance().getAtAxis()) * SELF_CLICK_WALK_DISTANCE;
}
+ gAgentCamera.setFocusOnAvatar(TRUE, TRUE);
+ if(mAutoPilotDestination) { mAutoPilotDestination->markDead(); }
+ mAutoPilotDestination = (LLHUDEffectBlob *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BLOB, FALSE);
+ mAutoPilotDestination->setPositionGlobal(mPick.mPosGlobal);
+ mAutoPilotDestination->setPixelSize(5);
+ mAutoPilotDestination->setColor(LLColor4U(170, 210, 190));
+ mAutoPilotDestination->setDuration(3.f);
+
+ handle_go_to();
+ LLFirstUse::notMoving(false);
+
+ mBlockClickToWalk = false;
+
+ return TRUE;
+ }
+ gViewerWindow->setCursor(UI_CURSOR_ARROW);
+ if (hasMouseCapture())
+ {
+ setMouseCapture(FALSE);
}
- mGrabMouseButtonDown = FALSE;
LLToolMgr::getInstance()->clearTransientTool();
gAgentCamera.setLookAt(LOOKAT_TARGET_CONVERSATION, obj); // maybe look at object/person clicked on
+
+ mBlockClickToWalk = false;
return LLTool::handleMouseUp(x, y, mask);
}
+void LLToolPie::stopClickToWalk()
+{
+ mPick.mPosGlobal = gAgent.getPositionGlobal();
+ handle_go_to();
+ if(mAutoPilotDestination)
+ {
+ mAutoPilotDestination->markDead();
+ }
+}
BOOL LLToolPie::handleDoubleClick(S32 x, S32 y, MASK mask)
{
@@ -913,7 +1013,7 @@ BOOL LLToolPie::handleTooltipObject( LLViewerObject* hover_object, std::string l
p.click_callback(boost::bind(showAvatarInspector, hover_object->getID()));
p.visible_time_near(6.f);
p.visible_time_far(3.f);
- p.delay_time(0.35f);
+ p.delay_time(gSavedSettings.getF32("AvatarInspectorTooltipDelay"));
p.wrap(false);
LLToolTipMgr::instance().show(p);
@@ -1031,7 +1131,7 @@ BOOL LLToolPie::handleTooltipObject( LLViewerObject* hover_object, std::string l
p.click_homepage_callback(boost::bind(VisitHomePage, mHoverPick));
p.visible_time_near(6.f);
p.visible_time_far(3.f);
- p.delay_time(0.35f);
+ p.delay_time(gSavedSettings.getF32("ObjectInspectorTooltipDelay"));
p.wrap(false);
LLToolTipMgr::instance().show(p);
@@ -1214,6 +1314,11 @@ void LLToolPie::VisitHomePage(const LLPickInfo& info)
}
}
+void LLToolPie::handleSelect()
+{
+ // tool is reselected when app gets focus, etc.
+ mBlockClickToWalk = true;
+}
void LLToolPie::handleDeselect()
{
@@ -1228,15 +1333,17 @@ void LLToolPie::handleDeselect()
LLTool* LLToolPie::getOverrideTool(MASK mask)
{
- if (mask == MASK_CONTROL)
- {
- return LLToolGrab::getInstance();
- }
- else if (mask == (MASK_CONTROL | MASK_SHIFT))
+ if (gSavedSettings.getBOOL("EnableGrab"))
{
- return LLToolGrab::getInstance();
+ if (mask == MASK_CONTROL)
+ {
+ return LLToolGrab::getInstance();
+ }
+ else if (mask == (MASK_CONTROL | MASK_SHIFT))
+ {
+ return LLToolGrab::getInstance();
+ }
}
-
return LLTool::getOverrideTool(mask);
}
@@ -1250,10 +1357,20 @@ void LLToolPie::stopEditing()
void LLToolPie::onMouseCaptureLost()
{
- mMouseOutsideSlop = FALSE;
+ stopCameraSteering();
+ mMouseButtonDown = false;
handleMediaMouseUp();
}
+void LLToolPie::stopCameraSteering()
+{
+ mMouseOutsideSlop = false;
+}
+
+bool LLToolPie::inCameraSteerMode()
+{
+ return mMouseButtonDown && mMouseOutsideSlop && gSavedSettings.getBOOL("ClickToWalk");
+}
// true if x,y outside small box around start_x,start_y
BOOL LLToolPie::outsideSlop(S32 x, S32 y, S32 start_x, S32 start_y)
@@ -1331,6 +1448,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();
@@ -1419,8 +1537,6 @@ bool LLToolPie::handleMediaMouseUp()
mMediaMouseCaptureID.setNull();
- setMouseCapture(FALSE);
-
result = true;
}
@@ -1483,7 +1599,7 @@ static ECursorType cursor_from_parcel_media(U8 click_action)
// True if we handled the event.
-BOOL LLToolPie::pickRightMouseDownCallback()
+BOOL LLToolPie::handleRightClickPick()
{
S32 x = mPick.mMousePt.mX;
S32 y = mPick.mMousePt.mY;
@@ -1605,10 +1721,173 @@ BOOL LLToolPie::pickRightMouseDownCallback()
void LLToolPie::showVisualContextMenuEffect()
{
- // VEFFECT: ShowPie
- LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_SPHERE, TRUE);
- effectp->setPositionGlobal(mPick.mPosGlobal);
- effectp->setColor(LLColor4U(gAgent.getEffectColor()));
- effectp->setDuration(0.25f);
+ // VEFFECT: ShowPie
+ LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_SPHERE, TRUE);
+ effectp->setPositionGlobal(mPick.mPosGlobal);
+ effectp->setColor(LLColor4U(gAgent.getEffectColor()));
+ 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, 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;
+ F32 B = 2.f * ray_dir * sphere_to_ray_start_vec;
+ F32 C = sphere_to_ray_start_vec.lengthSquared() - (sphere_radius * sphere_radius);
+
+ F32 discriminant = B*B - 4.f*C;
+ if (discriminant >= 0.f)
+ { // intersection detected, now find closest one
+ F32 t0 = (-B - sqrtf(discriminant)) / 2.f;
+
+ if (t0 > 0.f && near_far == NEAR_INTERSECTION)
+ {
+ intersection_pt = ray_pt + ray_dir * t0;
+ }
+ else
+ {
+ F32 t1 = (-B + sqrtf(discriminant)) / 2.f;
+ intersection_pt = ray_pt + ray_dir * t1;
+ }
+ return true;
+ }
+ else
+ { // no intersection
+ return false;
+ }
+}
+
+void LLToolPie::startCameraSteering()
+{
+ LLFirstUse::notMoving(false);
+ mMouseOutsideSlop = true;
+ mBlockClickToWalk = true;
+
+ if (gAgentCamera.getFocusOnAvatar())
+ {
+ mSteerPick = mPick;
+
+ // handle special cases of steering picks
+ LLViewerObject* avatar_object = mSteerPick.getObject();
+
+ // get pointer to avatar
+ while (avatar_object && !avatar_object->isAvatar())
+ {
+ avatar_object = (LLViewerObject*)avatar_object->getParent();
+ }
+
+ // if clicking on own avatar...
+ if (avatar_object && ((LLVOAvatar*)avatar_object)->isSelf())
+ {
+ // ...project pick point a few meters in front of avatar
+ mSteerPick.mPosGlobal = gAgent.getPositionGlobal() + LLVector3d(LLViewerCamera::instance().getAtAxis()) * 3.0;
+ }
+
+ if (!mSteerPick.isValid())
+ {
+ mSteerPick.mPosGlobal = gAgent.getPosGlobalFromAgent(
+ LLViewerCamera::instance().getOrigin() + gViewerWindow->mouseDirectionGlobal(mSteerPick.mMousePt.mX, mSteerPick.mMousePt.mY) * 100.f);
+ }
+
+ setMouseCapture(TRUE);
+
+ mMouseSteerX = mMouseDownX;
+ mMouseSteerY = mMouseDownY;
+ const LLVector3 camera_to_rotation_center = gAgent.getFrameAgent().getOrigin() - LLViewerCamera::instance().getOrigin();
+ const LLVector3 rotation_center_to_pick = gAgent.getPosAgentFromGlobal(mSteerPick.mPosGlobal) - gAgent.getFrameAgent().getOrigin();
+
+ mClockwise = camera_to_rotation_center * rotation_center_to_pick < 0.f;
+ if (mMouseSteerGrabPoint) { mMouseSteerGrabPoint->markDead(); }
+ mMouseSteerGrabPoint = (LLHUDEffectBlob *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BLOB, FALSE);
+ mMouseSteerGrabPoint->setPositionGlobal(mSteerPick.mPosGlobal);
+ mMouseSteerGrabPoint->setColor(LLColor4U(170, 210, 190));
+ mMouseSteerGrabPoint->setPixelSize(5);
+ mMouseSteerGrabPoint->setDuration(2.f);
+ }
+}
+
+void LLToolPie::steerCameraWithMouse(S32 x, S32 y)
+{
+ const LLViewerCamera& camera = LLViewerCamera::instance();
+ const LLCoordFrame& rotation_frame = gAgent.getFrameAgent();
+ const LLVector3 pick_pos = gAgent.getPosAgentFromGlobal(mSteerPick.mPosGlobal);
+ 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_frame.getUpAxis());
+ mouse_ray.normalize();
+
+ LLVector3 old_mouse_ray = orthogonal_component(gViewerWindow->mouseDirectionGlobal(mMouseSteerX, mMouseSteerY), rotation_frame.getUpAxis());
+ old_mouse_ray.normalize();
+
+ F32 yaw_angle;
+ F32 old_yaw_angle;
+ LLVector3 mouse_on_sphere;
+ LLVector3 old_mouse_on_sphere;
+
+ if (intersect_ray_with_sphere(
+ adjusted_camera_pos,
+ mouse_ray,
+ pick_rotation_center,
+ pick_distance_from_rotation_center,
+ FAR_INTERSECTION,
+ mouse_on_sphere))
+ {
+ 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;
+ }
+ }
+
+ 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);
+
+ if (mouse_ray * rotation_frame.getLeftAxis() < 0.f)
+ {
+ old_yaw_angle *= -1.f;
+ }
+ }
+
+ const F32 delta_angle = yaw_angle - old_yaw_angle;
+
+ if (mClockwise)
+ {
+ gAgent.yaw(delta_angle);
+ }
+ else
+ {
+ gAgent.yaw(-delta_angle);
+ }
+ mMouseSteerX = x;
+ mMouseSteerY = y;
}
diff --git a/indra/newview/lltoolpie.h b/indra/newview/lltoolpie.h
index 65cb3e36a7..d7c79ee223 100644
--- a/indra/newview/lltoolpie.h
+++ b/indra/newview/lltoolpie.h
@@ -30,6 +30,7 @@
#include "lltool.h"
#include "lluuid.h"
#include "llviewerwindow.h" // for LLPickInfo
+#include "llhudeffectblob.h" // for LLPointer<LLHudEffectBlob>, apparently
class LLViewerObject;
class LLObjectSelection;
@@ -56,6 +57,7 @@ public:
virtual void stopEditing();
virtual void onMouseCaptureLost();
+ virtual void handleSelect();
virtual void handleDeselect();
virtual LLTool* getOverrideTool(MASK mask);
@@ -64,6 +66,8 @@ public:
LLViewerObject* getClickActionObject() { return mClickActionObject; }
LLObjectSelection* getLeftClickSelection() { return (LLObjectSelection*)mLeftClickSelection; }
void resetSelection();
+ void blockClickToWalk() { mBlockClickToWalk = true; }
+ void stopClickToWalk();
static void selectionPropertiesReceived();
@@ -75,11 +79,12 @@ public:
private:
BOOL outsideSlop (S32 x, S32 y, S32 start_x, S32 start_y);
- BOOL pickLeftMouseDownCallback();
- BOOL pickRightMouseDownCallback();
+ BOOL handleLeftClickPick();
+ BOOL handleRightClickPick();
BOOL useClickAction (MASK mask, LLViewerObject* object,LLViewerObject* parent);
void showVisualContextMenuEffect();
+ ECursorType cursorFromObject(LLViewerObject* object);
bool handleMediaClick(const LLPickInfo& info);
bool handleMediaHover(const LLPickInfo& info);
@@ -87,17 +92,31 @@ private:
BOOL handleTooltipLand(std::string line, std::string tooltip_msg);
BOOL handleTooltipObject( LLViewerObject* hover_object, std::string line, std::string tooltip_msg);
+ void steerCameraWithMouse(S32 x, S32 y);
+ void startCameraSteering();
+ void stopCameraSteering();
+ bool inCameraSteerMode();
+
private:
- BOOL mGrabMouseButtonDown;
- BOOL mMouseOutsideSlop; // for this drag, has mouse moved outside slop region
+ bool mMouseButtonDown;
+ bool mMouseOutsideSlop; // for this drag, has mouse moved outside slop region
+ S32 mMouseDownX;
+ S32 mMouseDownY;
+ S32 mMouseSteerX;
+ S32 mMouseSteerY;
+ LLPointer<LLHUDEffectBlob> mAutoPilotDestination;
+ LLPointer<LLHUDEffectBlob> mMouseSteerGrabPoint;
+ bool mClockwise;
+ bool mBlockClickToWalk;
LLUUID mMediaMouseCaptureID;
LLPickInfo mPick;
LLPickInfo mHoverPick;
+ LLPickInfo mSteerPick;
LLPointer<LLViewerObject> mClickActionObject;
U8 mClickAction;
LLSafeHandle<LLObjectSelection> mLeftClickSelection;
-
+ BOOL mClickActionBuyEnabled;
+ BOOL mClickActionPayEnabled;
};
-
#endif
diff --git a/indra/newview/lltracker.cpp b/indra/newview/lltracker.cpp
index c3dd17def9..983108391f 100644
--- a/indra/newview/lltracker.cpp
+++ b/indra/newview/lltracker.cpp
@@ -109,6 +109,8 @@ void LLTracker::stopTracking(void* userdata)
// static virtual
void LLTracker::drawHUDArrow()
{
+ if (!gSavedSettings.getBOOL("RenderTrackerBeacon")) return;
+
static LLUIColor map_track_color = LLUIColorTable::instance().getColor("MapTrackColor", LLColor4::white);
/* tracking autopilot destination has been disabled
@@ -155,7 +157,7 @@ void LLTracker::drawHUDArrow()
// static
void LLTracker::render3D()
{
- if (!gFloaterWorldMap)
+ if (!gFloaterWorldMap || !gSavedSettings.getBOOL("RenderTrackerBeacon"))
{
return;
}
diff --git a/indra/newview/lltracker.h b/indra/newview/lltracker.h
index c0c154abe8..8e916af315 100644
--- a/indra/newview/lltracker.h
+++ b/indra/newview/lltracker.h
@@ -75,7 +75,7 @@ public:
// these are static so that they can be used a callbacks
static ETrackingStatus getTrackingStatus() { return instance()->mTrackingStatus; }
static ETrackingLocationType getTrackedLocationType() { return instance()->mTrackingLocationType; }
- static BOOL isTracking(void*) { return (BOOL) instance()->mTrackingStatus; }
+ static BOOL isTracking(void*) { return instance()->mTrackingStatus != TRACKING_NOTHING; }
static void stopTracking(void*);
static void clearFocus();
diff --git a/indra/newview/lltransientfloatermgr.cpp b/indra/newview/lltransientfloatermgr.cpp
index 78dd602f39..c648a6a28a 100644
--- a/indra/newview/lltransientfloatermgr.cpp
+++ b/indra/newview/lltransientfloatermgr.cpp
@@ -36,8 +36,11 @@
LLTransientFloaterMgr::LLTransientFloaterMgr()
{
- gViewerWindow->getRootView()->addMouseDownCallback(boost::bind(
- &LLTransientFloaterMgr::leftMouseClickCallback, this, _1, _2, _3));
+ if(gViewerWindow)
+ {
+ gViewerWindow->getRootView()->getChild<LLUICtrl>("popup_holder")->setMouseDownCallback(boost::bind(
+ &LLTransientFloaterMgr::leftMouseClickCallback, this, _2, _3, _4));
+ }
mGroupControls.insert(std::pair<ETransientGroup, std::set<LLView*> >(GLOBAL, std::set<LLView*>()));
mGroupControls.insert(std::pair<ETransientGroup, std::set<LLView*> >(DOCKED, std::set<LLView*>()));
diff --git a/indra/newview/lltranslate.cpp b/indra/newview/lltranslate.cpp
index 050e34ade9..2de7db38ed 100644
--- a/indra/newview/lltranslate.cpp
+++ b/indra/newview/lltranslate.cpp
@@ -2,33 +2,27 @@
* @file lltranslate.cpp
* @brief Functions for translating text via Google Translate.
*
-* $LicenseInfo:firstyear=2009&license=viewergpl$
-*
-* Copyright (c) 2009-2010, 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$
-*/
+ * $LicenseInfo:firstyear=2009&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"
@@ -36,10 +30,10 @@
#include "llbufferstream.h"
#include "llui.h"
-#include "llversionviewer.h"
+#include "llversioninfo.h"
#include "llviewercontrol.h"
-#include "jsoncpp/reader.h"
+#include "reader.h"
// These two are concatenated with the language specifiers to form a complete Google Translate URL
const char* LLTranslate::m_GoogleURL = "http://ajax.googleapis.com/ajax/services/language/translate?v=1.0&q=";
@@ -64,11 +58,11 @@ void LLTranslate::translateMessage(LLHTTPClient::ResponderPtr &result, const std
getTranslateUrl(url, from_lang, to_lang, mesg);
std::string user_agent = llformat("%s %d.%d.%d (%d)",
- LL_CHANNEL,
- LL_VERSION_MAJOR,
- LL_VERSION_MINOR,
- LL_VERSION_PATCH,
- LL_VERSION_BUILD );
+ LLVersionInfo::getChannel().c_str(),
+ LLVersionInfo::getMajor(),
+ LLVersionInfo::getMinor(),
+ LLVersionInfo::getPatch(),
+ LLVersionInfo::getBuild());
if (!m_Header.size())
{
diff --git a/indra/newview/lltranslate.h b/indra/newview/lltranslate.h
index 0786dc0ca3..e85a42e878 100644
--- a/indra/newview/lltranslate.h
+++ b/indra/newview/lltranslate.h
@@ -2,33 +2,27 @@
* @file lltranslate.h
* @brief Human language translation class and JSON response receiver.
*
-* $LicenseInfo:firstyear=2009&license=viewergpl$
-*
-* Copyright (c) 2009-2010, 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$
-*/
+ * $LicenseInfo:firstyear=2009&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_LLTRANSLATE_H
#define LL_LLTRANSLATE_H
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 bd4d3c2b78..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)
{
@@ -180,7 +186,7 @@ bool LLURLDispatcherImpl::dispatchRegion(const LLSLURL& slurl, bool right_mouse)
LLWorldMapMessage::getInstance()->sendNamedRegionRequest(slurl.getRegion(),
LLURLDispatcherImpl::regionNameCallback,
slurl.getSLURLString(),
- false); // don't teleport
+ LLUI::sSettingGroups["config"]->getBOOL("SLURLTeleportDirectly")); // don't teleport
return true;
}
@@ -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/llversioninfo.cpp b/indra/newview/llversioninfo.cpp
index 733d05834a..673d0c24cf 100644
--- a/indra/newview/llversioninfo.cpp
+++ b/indra/newview/llversioninfo.cpp
@@ -95,9 +95,42 @@ const std::string &LLVersionInfo::getShortVersion()
return version;
}
+namespace
+{
+ /// Storage of the channel name the viewer is using.
+ // The channel name is set by hardcoded constant,
+ // or by calling LLVersionInfo::resetChannel()
+ std::string sWorkingChannelName(LL_CHANNEL);
+
+ // Storage for the "version and channel" string.
+ // This will get reset too.
+ std::string sVersionChannel("");
+}
+
+//static
+const std::string &LLVersionInfo::getChannelAndVersion()
+{
+ if (sVersionChannel.empty())
+ {
+ // cache the version string
+ std::ostringstream stream;
+ stream << LLVersionInfo::getChannel()
+ << " "
+ << LLVersionInfo::getVersion();
+ sVersionChannel = stream.str();
+ }
+
+ return sVersionChannel;
+}
+
//static
const std::string &LLVersionInfo::getChannel()
{
- static std::string name(LL_CHANNEL);
- return name;
+ return sWorkingChannelName;
+}
+
+void LLVersionInfo::resetChannel(const std::string& channel)
+{
+ sWorkingChannelName = channel;
+ sVersionChannel.clear(); // Reset version and channel string til next use.
}
diff --git a/indra/newview/llversioninfo.h b/indra/newview/llversioninfo.h
index e468b6ae4e..6f64544f3b 100644
--- a/indra/newview/llversioninfo.h
+++ b/indra/newview/llversioninfo.h
@@ -58,8 +58,15 @@ public:
/// return the viewer version as a string like "2.0.0"
static const std::string &getShortVersion();
+ /// return the viewer version and channel as a string
+ /// like "Second Life Release 2.0.0.200030"
+ static const std::string &getChannelAndVersion();
+
/// return the channel name, e.g. "Second Life"
static const std::string &getChannel();
+
+ /// reset the channel name used by the viewer.
+ static void resetChannel(const std::string& channel);
};
#endif
diff --git a/indra/newview/llviewerassetstats.cpp b/indra/newview/llviewerassetstats.cpp
new file mode 100644
index 0000000000..e621cf647e
--- /dev/null
+++ b/indra/newview/llviewerassetstats.cpp
@@ -0,0 +1,612 @@
+/**
+ * @file llviewerassetstats.cpp
+ * @brief
+ *
+ * $LicenseInfo:firstyear=2010&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 "llviewerassetstats.h"
+#include "llregionhandle.h"
+
+#include "stdtypes.h"
+
+/*
+ * Classes and utility functions for per-thread and per-region
+ * asset and experiential metrics to be aggregated grid-wide.
+ *
+ * The basic metrics grouping is LLViewerAssetStats::PerRegionStats.
+ * This provides various counters and simple statistics for asset
+ * fetches binned into a few categories. One of these is maintained
+ * for each region encountered and the 'current' region is available
+ * as a simple reference. Each thread (presently two) interested
+ * in participating in these stats gets an instance of the
+ * LLViewerAssetStats class so that threads are completely
+ * independent.
+ *
+ * The idea of a current region is used for simplicity and speed
+ * of categorization. Each metrics event could have taken a
+ * region uuid argument resulting in a suitable lookup. Arguments
+ * against this design include:
+ *
+ * - Region uuid not trivially available to caller.
+ * - Cost (cpu, disruption in real work flow) too high.
+ * - Additional precision not really meaningful.
+ *
+ * By itself, the LLViewerAssetStats class is thread- and
+ * viewer-agnostic and can be used anywhere without assumptions
+ * of global pointers and other context. For the viewer,
+ * a set of free functions are provided in the namespace
+ * LLViewerAssetStatsFF which *do* implement viewer-native
+ * policies about per-thread globals and will do correct
+ * defensive tests of same.
+ *
+ * References
+ *
+ * Project:
+ * <TBD>
+ *
+ * Test Plan:
+ * <TBD>
+ *
+ * Jiras:
+ * <TBD>
+ *
+ * Unit Tests:
+ * indra/newview/tests/llviewerassetstats_test.cpp
+ *
+ */
+
+
+// ------------------------------------------------------
+// Global data definitions
+// ------------------------------------------------------
+LLViewerAssetStats * gViewerAssetStatsMain(0);
+LLViewerAssetStats * gViewerAssetStatsThread1(0);
+
+
+// ------------------------------------------------------
+// Local declarations
+// ------------------------------------------------------
+namespace
+{
+
+static LLViewerAssetStats::EViewerAssetCategories
+asset_type_to_category(const LLViewerAssetType::EType at, bool with_http, bool is_temp);
+
+}
+
+// ------------------------------------------------------
+// LLViewerAssetStats::PerRegionStats struct definition
+// ------------------------------------------------------
+void
+LLViewerAssetStats::PerRegionStats::reset()
+{
+ for (int i(0); i < LL_ARRAY_SIZE(mRequests); ++i)
+ {
+ mRequests[i].mEnqueued.reset();
+ mRequests[i].mDequeued.reset();
+ mRequests[i].mResponse.reset();
+ }
+ mFPS.reset();
+
+ mTotalTime = 0;
+ mStartTimestamp = LLViewerAssetStatsFF::get_timestamp();
+}
+
+
+void
+LLViewerAssetStats::PerRegionStats::merge(const LLViewerAssetStats::PerRegionStats & src)
+{
+ // mRegionHandle, mTotalTime, mStartTimestamp are left alone.
+
+ // mFPS
+ if (src.mFPS.getCount() && mFPS.getCount())
+ {
+ mFPS.merge(src.mFPS);
+ }
+
+ // Requests
+ for (int i = 0; i < LL_ARRAY_SIZE(mRequests); ++i)
+ {
+ mRequests[i].mEnqueued.merge(src.mRequests[i].mEnqueued);
+ mRequests[i].mDequeued.merge(src.mRequests[i].mDequeued);
+ mRequests[i].mResponse.merge(src.mRequests[i].mResponse);
+ }
+}
+
+
+void
+LLViewerAssetStats::PerRegionStats::accumulateTime(duration_t now)
+{
+ mTotalTime += (now - mStartTimestamp);
+ mStartTimestamp = now;
+}
+
+
+// ------------------------------------------------------
+// LLViewerAssetStats class definition
+// ------------------------------------------------------
+LLViewerAssetStats::LLViewerAssetStats()
+ : mRegionHandle(U64(0))
+{
+ reset();
+}
+
+
+LLViewerAssetStats::LLViewerAssetStats(const LLViewerAssetStats & src)
+ : mRegionHandle(src.mRegionHandle),
+ mResetTimestamp(src.mResetTimestamp)
+{
+ const PerRegionContainer::const_iterator it_end(src.mRegionStats.end());
+ for (PerRegionContainer::const_iterator it(src.mRegionStats.begin()); it_end != it; ++it)
+ {
+ mRegionStats[it->first] = new PerRegionStats(*it->second);
+ }
+ mCurRegionStats = mRegionStats[mRegionHandle];
+}
+
+
+void
+LLViewerAssetStats::reset()
+{
+ // Empty the map of all region stats
+ mRegionStats.clear();
+
+ // If we have a current stats, reset it, otherwise, as at construction,
+ // create a new one as we must always have a current stats block.
+ if (mCurRegionStats)
+ {
+ mCurRegionStats->reset();
+ }
+ else
+ {
+ mCurRegionStats = new PerRegionStats(mRegionHandle);
+ }
+
+ // And add reference to map
+ mRegionStats[mRegionHandle] = mCurRegionStats;
+
+ // Start timestamp consistent with per-region collector
+ mResetTimestamp = mCurRegionStats->mStartTimestamp;
+}
+
+
+void
+LLViewerAssetStats::setRegion(region_handle_t region_handle)
+{
+ if (region_handle == mRegionHandle)
+ {
+ // Already active, ignore.
+ return;
+ }
+
+ // Get duration for current set
+ const duration_t now = LLViewerAssetStatsFF::get_timestamp();
+ mCurRegionStats->accumulateTime(now);
+
+ // Prepare new set
+ PerRegionContainer::iterator new_stats = mRegionStats.find(region_handle);
+ if (mRegionStats.end() == new_stats)
+ {
+ // Haven't seen this region_id before, create a new block and make it current.
+ mCurRegionStats = new PerRegionStats(region_handle);
+ mRegionStats[region_handle] = mCurRegionStats;
+ }
+ else
+ {
+ mCurRegionStats = new_stats->second;
+ }
+ mCurRegionStats->mStartTimestamp = now;
+ mRegionHandle = region_handle;
+}
+
+
+void
+LLViewerAssetStats::recordGetEnqueued(LLViewerAssetType::EType at, bool with_http, bool is_temp)
+{
+ const EViewerAssetCategories eac(asset_type_to_category(at, with_http, is_temp));
+
+ ++(mCurRegionStats->mRequests[int(eac)].mEnqueued);
+}
+
+void
+LLViewerAssetStats::recordGetDequeued(LLViewerAssetType::EType at, bool with_http, bool is_temp)
+{
+ const EViewerAssetCategories eac(asset_type_to_category(at, with_http, is_temp));
+
+ ++(mCurRegionStats->mRequests[int(eac)].mDequeued);
+}
+
+void
+LLViewerAssetStats::recordGetServiced(LLViewerAssetType::EType at, bool with_http, bool is_temp, duration_t duration)
+{
+ const EViewerAssetCategories eac(asset_type_to_category(at, with_http, is_temp));
+
+ mCurRegionStats->mRequests[int(eac)].mResponse.record(duration);
+}
+
+void
+LLViewerAssetStats::recordFPS(F32 fps)
+{
+ mCurRegionStats->mFPS.record(fps);
+}
+
+LLSD
+LLViewerAssetStats::asLLSD(bool compact_output)
+{
+ // Top-level tags
+ static const LLSD::String tags[EVACCount] =
+ {
+ LLSD::String("get_texture_temp_http"),
+ LLSD::String("get_texture_temp_udp"),
+ LLSD::String("get_texture_non_temp_http"),
+ LLSD::String("get_texture_non_temp_udp"),
+ LLSD::String("get_wearable_udp"),
+ LLSD::String("get_sound_udp"),
+ LLSD::String("get_gesture_udp"),
+ LLSD::String("get_other")
+ };
+
+ // Stats Group Sub-tags.
+ static const LLSD::String enq_tag("enqueued");
+ static const LLSD::String deq_tag("dequeued");
+ static const LLSD::String rcnt_tag("resp_count");
+ static const LLSD::String rmin_tag("resp_min");
+ static const LLSD::String rmax_tag("resp_max");
+ static const LLSD::String rmean_tag("resp_mean");
+
+ // MMM Group Sub-tags.
+ static const LLSD::String cnt_tag("count");
+ static const LLSD::String min_tag("min");
+ static const LLSD::String max_tag("max");
+ static const LLSD::String mean_tag("mean");
+
+ const duration_t now = LLViewerAssetStatsFF::get_timestamp();
+ mCurRegionStats->accumulateTime(now);
+
+ LLSD regions = LLSD::emptyArray();
+ for (PerRegionContainer::iterator it = mRegionStats.begin();
+ mRegionStats.end() != it;
+ ++it)
+ {
+ if (0 == it->first)
+ {
+ // Never emit NULL UUID/handle in results.
+ continue;
+ }
+
+ PerRegionStats & stats = *it->second;
+
+ LLSD reg_stat = LLSD::emptyMap();
+
+ for (int i = 0; i < LL_ARRAY_SIZE(tags); ++i)
+ {
+ PerRegionStats::prs_group & group(stats.mRequests[i]);
+
+ if ((! compact_output) ||
+ group.mEnqueued.getCount() ||
+ group.mDequeued.getCount() ||
+ group.mResponse.getCount())
+ {
+ LLSD & slot = reg_stat[tags[i]];
+ slot = LLSD::emptyMap();
+ slot[enq_tag] = LLSD(S32(stats.mRequests[i].mEnqueued.getCount()));
+ slot[deq_tag] = LLSD(S32(stats.mRequests[i].mDequeued.getCount()));
+ slot[rcnt_tag] = LLSD(S32(stats.mRequests[i].mResponse.getCount()));
+ slot[rmin_tag] = LLSD(F64(stats.mRequests[i].mResponse.getMin() * 1.0e-6));
+ slot[rmax_tag] = LLSD(F64(stats.mRequests[i].mResponse.getMax() * 1.0e-6));
+ slot[rmean_tag] = LLSD(F64(stats.mRequests[i].mResponse.getMean() * 1.0e-6));
+ }
+ }
+
+ if ((! compact_output) || stats.mFPS.getCount())
+ {
+ LLSD & slot = reg_stat["fps"];
+ slot = LLSD::emptyMap();
+ slot[cnt_tag] = LLSD(S32(stats.mFPS.getCount()));
+ slot[min_tag] = LLSD(F64(stats.mFPS.getMin()));
+ slot[max_tag] = LLSD(F64(stats.mFPS.getMax()));
+ slot[mean_tag] = LLSD(F64(stats.mFPS.getMean()));
+ }
+
+ U32 grid_x(0), grid_y(0);
+ grid_from_region_handle(it->first, &grid_x, &grid_y);
+ reg_stat["grid_x"] = LLSD::Integer(grid_x);
+ reg_stat["grid_y"] = LLSD::Integer(grid_y);
+ reg_stat["duration"] = LLSD::Real(stats.mTotalTime * 1.0e-6);
+ regions.append(reg_stat);
+ }
+
+ LLSD ret = LLSD::emptyMap();
+ ret["regions"] = regions;
+ ret["duration"] = LLSD::Real((now - mResetTimestamp) * 1.0e-6);
+
+ return ret;
+}
+
+void
+LLViewerAssetStats::merge(const LLViewerAssetStats & src)
+{
+ // mRegionHandle, mCurRegionStats and mResetTimestamp are left untouched.
+ // Just merge the stats bodies
+
+ const PerRegionContainer::const_iterator it_end(src.mRegionStats.end());
+ for (PerRegionContainer::const_iterator it(src.mRegionStats.begin()); it_end != it; ++it)
+ {
+ PerRegionContainer::iterator dst(mRegionStats.find(it->first));
+ if (mRegionStats.end() == dst)
+ {
+ // Destination is missing data, just make a private copy
+ mRegionStats[it->first] = new PerRegionStats(*it->second);
+ }
+ else
+ {
+ dst->second->merge(*it->second);
+ }
+ }
+}
+
+
+// ------------------------------------------------------
+// Global free-function definitions (LLViewerAssetStatsFF namespace)
+// ------------------------------------------------------
+
+namespace LLViewerAssetStatsFF
+{
+
+//
+// Target thread is elaborated in the function name. This could
+// have been something 'templatey' like specializations iterated
+// over a set of constants but with so few, this is clearer I think.
+//
+// As for the threads themselves... rather than do fine-grained
+// locking as we gather statistics, this code creates a collector
+// for each thread, allocated and run independently. Logging
+// happens at relatively infrequent intervals and at that time
+// the data is sent to a single thread to be aggregated into
+// a single entity with locks, thread safety and other niceties.
+//
+// A particularly fussy implementation would distribute the
+// per-thread pointers across separate cache lines. But that should
+// be beyond current requirements.
+//
+
+// 'main' thread - initial program thread
+
+void
+set_region_main(LLViewerAssetStats::region_handle_t region_handle)
+{
+ if (! gViewerAssetStatsMain)
+ return;
+
+ gViewerAssetStatsMain->setRegion(region_handle);
+}
+
+void
+record_enqueue_main(LLViewerAssetType::EType at, bool with_http, bool is_temp)
+{
+ if (! gViewerAssetStatsMain)
+ return;
+
+ gViewerAssetStatsMain->recordGetEnqueued(at, with_http, is_temp);
+}
+
+void
+record_dequeue_main(LLViewerAssetType::EType at, bool with_http, bool is_temp)
+{
+ if (! gViewerAssetStatsMain)
+ return;
+
+ gViewerAssetStatsMain->recordGetDequeued(at, with_http, is_temp);
+}
+
+void
+record_response_main(LLViewerAssetType::EType at, bool with_http, bool is_temp, LLViewerAssetStats::duration_t duration)
+{
+ if (! gViewerAssetStatsMain)
+ return;
+
+ gViewerAssetStatsMain->recordGetServiced(at, with_http, is_temp, duration);
+}
+
+void
+record_fps_main(F32 fps)
+{
+ if (! gViewerAssetStatsMain)
+ return;
+
+ gViewerAssetStatsMain->recordFPS(fps);
+}
+
+
+// 'thread1' - should be for TextureFetch thread
+
+void
+set_region_thread1(LLViewerAssetStats::region_handle_t region_handle)
+{
+ if (! gViewerAssetStatsThread1)
+ return;
+
+ gViewerAssetStatsThread1->setRegion(region_handle);
+}
+
+void
+record_enqueue_thread1(LLViewerAssetType::EType at, bool with_http, bool is_temp)
+{
+ if (! gViewerAssetStatsThread1)
+ return;
+
+ gViewerAssetStatsThread1->recordGetEnqueued(at, with_http, is_temp);
+}
+
+void
+record_dequeue_thread1(LLViewerAssetType::EType at, bool with_http, bool is_temp)
+{
+ if (! gViewerAssetStatsThread1)
+ return;
+
+ gViewerAssetStatsThread1->recordGetDequeued(at, with_http, is_temp);
+}
+
+void
+record_response_thread1(LLViewerAssetType::EType at, bool with_http, bool is_temp, LLViewerAssetStats::duration_t duration)
+{
+ if (! gViewerAssetStatsThread1)
+ return;
+
+ gViewerAssetStatsThread1->recordGetServiced(at, with_http, is_temp, duration);
+}
+
+
+void
+init()
+{
+ if (! gViewerAssetStatsMain)
+ {
+ gViewerAssetStatsMain = new LLViewerAssetStats();
+ }
+ if (! gViewerAssetStatsThread1)
+ {
+ gViewerAssetStatsThread1 = new LLViewerAssetStats();
+ }
+}
+
+void
+cleanup()
+{
+ delete gViewerAssetStatsMain;
+ gViewerAssetStatsMain = 0;
+
+ delete gViewerAssetStatsThread1;
+ gViewerAssetStatsThread1 = 0;
+}
+
+
+} // namespace LLViewerAssetStatsFF
+
+
+// ------------------------------------------------------
+// Local function definitions
+// ------------------------------------------------------
+
+namespace
+{
+
+LLViewerAssetStats::EViewerAssetCategories
+asset_type_to_category(const LLViewerAssetType::EType at, bool with_http, bool is_temp)
+{
+ // For statistical purposes, we divide GETs into several
+ // populations of asset fetches:
+ // - textures which are de-prioritized in the asset system
+ // - wearables (clothing, bodyparts) which directly affect
+ // user experiences when they log in
+ // - sounds
+ // - gestures
+ // - everything else.
+ //
+ llassert_always(50 == LLViewerAssetType::AT_COUNT);
+
+ // Multiple asset definitions are floating around so this requires some
+ // maintenance and attention.
+ static const LLViewerAssetStats::EViewerAssetCategories asset_to_bin_map[LLViewerAssetType::AT_COUNT] =
+ {
+ LLViewerAssetStats::EVACTextureTempHTTPGet, // (0) AT_TEXTURE
+ LLViewerAssetStats::EVACSoundUDPGet, // AT_SOUND
+ LLViewerAssetStats::EVACOtherGet, // AT_CALLINGCARD
+ LLViewerAssetStats::EVACOtherGet, // AT_LANDMARK
+ LLViewerAssetStats::EVACOtherGet, // AT_SCRIPT
+ LLViewerAssetStats::EVACWearableUDPGet, // AT_CLOTHING
+ LLViewerAssetStats::EVACOtherGet, // AT_OBJECT
+ LLViewerAssetStats::EVACOtherGet, // AT_NOTECARD
+ LLViewerAssetStats::EVACOtherGet, // AT_CATEGORY
+ LLViewerAssetStats::EVACOtherGet, // AT_ROOT_CATEGORY
+ LLViewerAssetStats::EVACOtherGet, // (10) AT_LSL_TEXT
+ LLViewerAssetStats::EVACOtherGet, // AT_LSL_BYTECODE
+ LLViewerAssetStats::EVACOtherGet, // AT_TEXTURE_TGA
+ LLViewerAssetStats::EVACWearableUDPGet, // AT_BODYPART
+ LLViewerAssetStats::EVACOtherGet, // AT_TRASH
+ LLViewerAssetStats::EVACOtherGet, // AT_SNAPSHOT_CATEGORY
+ LLViewerAssetStats::EVACOtherGet, // AT_LOST_AND_FOUND
+ LLViewerAssetStats::EVACSoundUDPGet, // AT_SOUND_WAV
+ LLViewerAssetStats::EVACOtherGet, // AT_IMAGE_TGA
+ LLViewerAssetStats::EVACOtherGet, // AT_IMAGE_JPEG
+ LLViewerAssetStats::EVACGestureUDPGet, // (20) AT_ANIMATION
+ LLViewerAssetStats::EVACGestureUDPGet, // AT_GESTURE
+ LLViewerAssetStats::EVACOtherGet, // AT_SIMSTATE
+ LLViewerAssetStats::EVACOtherGet, // AT_FAVORITE
+ LLViewerAssetStats::EVACOtherGet, // AT_LINK
+ LLViewerAssetStats::EVACOtherGet, // AT_LINK_FOLDER
+ LLViewerAssetStats::EVACOtherGet, //
+ LLViewerAssetStats::EVACOtherGet, //
+ LLViewerAssetStats::EVACOtherGet, //
+ LLViewerAssetStats::EVACOtherGet, //
+ LLViewerAssetStats::EVACOtherGet, // (30)
+ LLViewerAssetStats::EVACOtherGet, //
+ LLViewerAssetStats::EVACOtherGet, //
+ LLViewerAssetStats::EVACOtherGet, //
+ LLViewerAssetStats::EVACOtherGet, //
+ LLViewerAssetStats::EVACOtherGet, //
+ LLViewerAssetStats::EVACOtherGet, //
+ LLViewerAssetStats::EVACOtherGet, //
+ LLViewerAssetStats::EVACOtherGet, //
+ LLViewerAssetStats::EVACOtherGet, //
+ LLViewerAssetStats::EVACOtherGet, // (40)
+ LLViewerAssetStats::EVACOtherGet, //
+ LLViewerAssetStats::EVACOtherGet, //
+ LLViewerAssetStats::EVACOtherGet, //
+ LLViewerAssetStats::EVACOtherGet, //
+ LLViewerAssetStats::EVACOtherGet, //
+ LLViewerAssetStats::EVACOtherGet, //
+ LLViewerAssetStats::EVACOtherGet, //
+ LLViewerAssetStats::EVACOtherGet, //
+ LLViewerAssetStats::EVACOtherGet, // AT_MESH
+ // (50)
+ };
+
+ if (at < 0 || at >= LLViewerAssetType::AT_COUNT)
+ {
+ return LLViewerAssetStats::EVACOtherGet;
+ }
+ LLViewerAssetStats::EViewerAssetCategories ret(asset_to_bin_map[at]);
+ if (LLViewerAssetStats::EVACTextureTempHTTPGet == ret)
+ {
+ // Indexed with [is_temp][with_http]
+ static const LLViewerAssetStats::EViewerAssetCategories texture_bin_map[2][2] =
+ {
+ {
+ LLViewerAssetStats::EVACTextureNonTempUDPGet,
+ LLViewerAssetStats::EVACTextureNonTempHTTPGet,
+ },
+ {
+ LLViewerAssetStats::EVACTextureTempUDPGet,
+ LLViewerAssetStats::EVACTextureTempHTTPGet,
+ }
+ };
+
+ ret = texture_bin_map[is_temp][with_http];
+ }
+ return ret;
+}
+
+} // anonymous namespace
diff --git a/indra/newview/llviewerassetstats.h b/indra/newview/llviewerassetstats.h
new file mode 100644
index 0000000000..73ec5974b2
--- /dev/null
+++ b/indra/newview/llviewerassetstats.h
@@ -0,0 +1,328 @@
+/**
+ * @file llviewerassetstats.h
+ * @brief Client-side collection of asset request statistics
+ *
+ * $LicenseInfo:firstyear=2010&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_LLVIEWERASSETSTATUS_H
+#define LL_LLVIEWERASSETSTATUS_H
+
+
+#include "linden_common.h"
+
+#include "llpointer.h"
+#include "llrefcount.h"
+#include "llviewerassettype.h"
+#include "llviewerassetstorage.h"
+#include "llsimplestat.h"
+#include "llsd.h"
+
+/**
+ * @class LLViewerAssetStats
+ * @brief Records performance aspects of asset access operations.
+ *
+ * This facility is derived from a very similar simulator-based
+ * one, LLSimAssetStats. It's function is to count asset access
+ * operations and characterize response times. Collected data
+ * are binned in several dimensions:
+ *
+ * - Asset types collapsed into a few aggregated categories
+ * - By simulator UUID
+ * - By transport mechanism (HTTP vs MessageSystem)
+ * - By persistence (temp vs non-temp)
+ *
+ * Statistics collected are fairly basic at this point:
+ *
+ * - Counts of enqueue and dequeue operations
+ * - Min/Max/Mean of asset transfer operations
+ *
+ * This collector differs from the simulator-based on in a
+ * number of ways:
+ *
+ * - The front-end/back-end distinction doesn't exist in viewer
+ * code
+ * - Multiple threads must be safely accomodated in the viewer
+ *
+ * Access to results is by conversion to an LLSD with some standardized
+ * key names. The intent of this structure is that it be emitted as
+ * standard syslog-based metrics formatting where it can be picked
+ * up by interested parties.
+ *
+ * For convenience, a set of free functions in namespace
+ * LLViewerAssetStatsFF is provided for conditional test-and-call
+ * operations.
+ */
+class LLViewerAssetStats
+{
+public:
+ enum EViewerAssetCategories
+ {
+ EVACTextureTempHTTPGet, //< Texture GETs - temp/baked, HTTP
+ EVACTextureTempUDPGet, //< Texture GETs - temp/baked, UDP
+ EVACTextureNonTempHTTPGet, //< Texture GETs - perm, HTTP
+ EVACTextureNonTempUDPGet, //< Texture GETs - perm, UDP
+ EVACWearableUDPGet, //< Wearable GETs
+ EVACSoundUDPGet, //< Sound GETs
+ EVACGestureUDPGet, //< Gesture GETs
+ EVACOtherGet, //< Other GETs
+
+ EVACCount // Must be last
+ };
+
+ /**
+ * Type for duration and other time values in the metrics. Selected
+ * for compatibility with the pre-existing timestamp on the texture
+ * fetcher class, LLTextureFetch.
+ */
+ typedef U64 duration_t;
+
+ /**
+ * Type for the region identifier used in stats. Currently uses
+ * the region handle's type (a U64) rather than the regions's LLUUID
+ * as the latter isn't available immediately.
+ */
+ typedef U64 region_handle_t;
+
+ /**
+ * @brief Collected data for a single region visited by the avatar.
+ *
+ * Fairly simple, for each asset bin enumerated above a count
+ * of enqueue and dequeue operations and simple stats on response
+ * times for completed requests.
+ */
+ class PerRegionStats : public LLRefCount
+ {
+ public:
+ PerRegionStats(const region_handle_t region_handle)
+ : LLRefCount(),
+ mRegionHandle(region_handle)
+ {
+ reset();
+ }
+
+ PerRegionStats(const PerRegionStats & src)
+ : LLRefCount(),
+ mRegionHandle(src.mRegionHandle),
+ mTotalTime(src.mTotalTime),
+ mStartTimestamp(src.mStartTimestamp),
+ mFPS(src.mFPS)
+ {
+ for (int i = 0; i < LL_ARRAY_SIZE(mRequests); ++i)
+ {
+ mRequests[i] = src.mRequests[i];
+ }
+ }
+
+ // Default assignment and destructor are correct.
+
+ void reset();
+
+ void merge(const PerRegionStats & src);
+
+ // Apply current running time to total and reset start point.
+ // Return current timestamp as a convenience.
+ void accumulateTime(duration_t now);
+
+ public:
+ region_handle_t mRegionHandle;
+ duration_t mTotalTime;
+ duration_t mStartTimestamp;
+ LLSimpleStatMMM<> mFPS;
+
+ struct prs_group
+ {
+ LLSimpleStatCounter mEnqueued;
+ LLSimpleStatCounter mDequeued;
+ LLSimpleStatMMM<duration_t> mResponse;
+ }
+ mRequests [EVACCount];
+ };
+
+public:
+ LLViewerAssetStats();
+ LLViewerAssetStats(const LLViewerAssetStats &);
+ // Default destructor is correct.
+ LLViewerAssetStats & operator=(const LLViewerAssetStats &); // Not defined
+
+ // Clear all metrics data. This leaves the currently-active region
+ // in place but with zero'd data for all metrics. All other regions
+ // are removed from the collection map.
+ void reset();
+
+ // Set hidden region argument and establish context for subsequent
+ // collection calls.
+ void setRegion(region_handle_t region_handle);
+
+ // Asset GET Requests
+ void recordGetEnqueued(LLViewerAssetType::EType at, bool with_http, bool is_temp);
+ void recordGetDequeued(LLViewerAssetType::EType at, bool with_http, bool is_temp);
+ void recordGetServiced(LLViewerAssetType::EType at, bool with_http, bool is_temp, duration_t duration);
+
+ // Frames-Per-Second Samples
+ void recordFPS(F32 fps);
+
+ // Merge a source instance into a destination instance. This is
+ // conceptually an 'operator+=()' method:
+ // - counts are added
+ // - minimums are min'd
+ // - maximums are max'd
+ // - other scalars are ignored ('this' wins)
+ //
+ void merge(const LLViewerAssetStats & src);
+
+ // Retrieve current metrics for all visited regions (NULL region UUID/handle excluded)
+ // Returned LLSD is structured as follows:
+ //
+ // &stats_group = {
+ // enqueued : int,
+ // dequeued : int,
+ // resp_count : int,
+ // resp_min : float,
+ // resp_max : float,
+ // resp_mean : float
+ // }
+ //
+ // &mmm_group = {
+ // count : int,
+ // min : float,
+ // max : float,
+ // mean : float
+ // }
+ //
+ // {
+ // duration: int
+ // regions: {
+ // $: { // Keys are strings of the region's handle in hex
+ // duration: : int,
+ // fps: : &mmm_group,
+ // get_texture_temp_http : &stats_group,
+ // get_texture_temp_udp : &stats_group,
+ // get_texture_non_temp_http : &stats_group,
+ // get_texture_non_temp_udp : &stats_group,
+ // get_wearable_udp : &stats_group,
+ // get_sound_udp : &stats_group,
+ // get_gesture_udp : &stats_group,
+ // get_other : &stats_group
+ // }
+ // }
+ // }
+ //
+ // @param compact_output If true, omits from conversion any mmm_block
+ // or stats_block that would contain all zero data.
+ // Useful for transmission when the receiver knows
+ // what is expected and will assume zero for missing
+ // blocks.
+ LLSD asLLSD(bool compact_output);
+
+protected:
+ typedef std::map<region_handle_t, LLPointer<PerRegionStats> > PerRegionContainer;
+
+ // Region of the currently-active region. Always valid but may
+ // be zero after construction or when explicitly set. Unchanged
+ // by a reset() call.
+ region_handle_t mRegionHandle;
+
+ // Pointer to metrics collection for currently-active region. Always
+ // valid and unchanged after reset() though contents will be changed.
+ // Always points to a collection contained in mRegionStats.
+ LLPointer<PerRegionStats> mCurRegionStats;
+
+ // Metrics data for all regions during one collection cycle
+ PerRegionContainer mRegionStats;
+
+ // Time of last reset
+ duration_t mResetTimestamp;
+};
+
+
+/**
+ * Global stats collectors one for each independent thread where
+ * assets and other statistics are gathered. The globals are
+ * expected to be created at startup time and then picked up by
+ * their respective threads afterwards. A set of free functions
+ * are provided to access methods behind the globals while both
+ * minimally disrupting visual flow and supplying a description
+ * of intent.
+ *
+ * Expected thread assignments:
+ *
+ * - Main: main() program execution thread
+ * - Thread1: TextureFetch worker thread
+ */
+extern LLViewerAssetStats * gViewerAssetStatsMain;
+
+extern LLViewerAssetStats * gViewerAssetStatsThread1;
+
+namespace LLViewerAssetStatsFF
+{
+/**
+ * @brief Allocation and deallocation of globals.
+ *
+ * init() should be called before threads are started that will access it though
+ * you'll likely get away with calling it afterwards. cleanup() should only be
+ * called after threads are shutdown to prevent races on the global pointers.
+ */
+void init();
+
+void cleanup();
+
+/**
+ * We have many timers, clocks etc. in the runtime. This is the
+ * canonical timestamp for these metrics which is compatible with
+ * the pre-existing timestamping in the texture fetcher.
+ */
+inline LLViewerAssetStats::duration_t get_timestamp()
+{
+ return LLTimer::getTotalTime();
+}
+
+/**
+ * Region context, event and duration loggers for the Main thread.
+ */
+void set_region_main(LLViewerAssetStats::region_handle_t region_handle);
+
+void record_enqueue_main(LLViewerAssetType::EType at, bool with_http, bool is_temp);
+
+void record_dequeue_main(LLViewerAssetType::EType at, bool with_http, bool is_temp);
+
+void record_response_main(LLViewerAssetType::EType at, bool with_http, bool is_temp,
+ LLViewerAssetStats::duration_t duration);
+
+void record_fps_main(F32 fps);
+
+
+/**
+ * Region context, event and duration loggers for Thread 1.
+ */
+void set_region_thread1(LLViewerAssetStats::region_handle_t region_handle);
+
+void record_enqueue_thread1(LLViewerAssetType::EType at, bool with_http, bool is_temp);
+
+void record_dequeue_thread1(LLViewerAssetType::EType at, bool with_http, bool is_temp);
+
+void record_response_thread1(LLViewerAssetType::EType at, bool with_http, bool is_temp,
+ LLViewerAssetStats::duration_t duration);
+
+} // namespace LLViewerAssetStatsFF
+
+#endif // LL_LLVIEWERASSETSTATUS_H
diff --git a/indra/newview/llviewerassetstorage.cpp b/indra/newview/llviewerassetstorage.cpp
index 2e7ef0fec3..36c8b42a52 100644
--- a/indra/newview/llviewerassetstorage.cpp
+++ b/indra/newview/llviewerassetstorage.cpp
@@ -33,6 +33,61 @@
#include "message.h"
#include "llagent.h"
+#include "lltransfersourceasset.h"
+#include "lltransfertargetvfile.h"
+#include "llviewerassetstats.h"
+
+///----------------------------------------------------------------------------
+/// LLViewerAssetRequest
+///----------------------------------------------------------------------------
+
+/**
+ * @brief Local class to encapsulate asset fetch requests with a timestamp.
+ *
+ * Derived from the common LLAssetRequest class, this is currently used
+ * only for fetch/get operations and its only function is to wrap remote
+ * asset fetch requests so that they can be timed.
+ */
+class LLViewerAssetRequest : public LLAssetRequest
+{
+public:
+ LLViewerAssetRequest(const LLUUID &uuid, const LLAssetType::EType type)
+ : LLAssetRequest(uuid, type),
+ mMetricsStartTime(0)
+ {
+ }
+
+ LLViewerAssetRequest & operator=(const LLViewerAssetRequest &); // Not defined
+ // Default assignment operator valid
+
+ // virtual
+ ~LLViewerAssetRequest()
+ {
+ recordMetrics();
+ }
+
+protected:
+ void recordMetrics()
+ {
+ if (mMetricsStartTime)
+ {
+ // Okay, it appears this request was used for useful things. Record
+ // the expected dequeue and duration of request processing.
+ LLViewerAssetStatsFF::record_dequeue_main(mType, false, false);
+ LLViewerAssetStatsFF::record_response_main(mType, false, false,
+ (LLViewerAssetStatsFF::get_timestamp()
+ - mMetricsStartTime));
+ mMetricsStartTime = 0;
+ }
+ }
+
+public:
+ LLViewerAssetStats::duration_t mMetricsStartTime;
+};
+
+///----------------------------------------------------------------------------
+/// LLViewerAssetStorage
+///----------------------------------------------------------------------------
LLViewerAssetStorage::LLViewerAssetStorage(LLMessageSystem *msg, LLXferManager *xfer,
LLVFS *vfs, LLVFS *static_vfs,
@@ -258,3 +313,77 @@ void LLViewerAssetStorage::storeAssetData(
}
}
}
+
+
+/**
+ * @brief Allocate and queue an asset fetch request for the viewer
+ *
+ * This is a nearly-verbatim copy of the base class's implementation
+ * with the following changes:
+ * - Use a locally-derived request class
+ * - Start timing for metrics when request is queued
+ *
+ * This is an unfortunate implementation choice but it's forced by
+ * current conditions. A refactoring that might clean up the layers
+ * of responsibility or introduce factories or more virtualization
+ * of methods would enable a more attractive solution.
+ *
+ * If LLAssetStorage::_queueDataRequest changes, this must change
+ * as well.
+ */
+
+// virtual
+void LLViewerAssetStorage::_queueDataRequest(
+ const LLUUID& uuid,
+ LLAssetType::EType atype,
+ LLGetAssetCallback callback,
+ void *user_data,
+ BOOL duplicate,
+ BOOL is_priority)
+{
+ if (mUpstreamHost.isOk())
+ {
+ // stash the callback info so we can find it after we get the response message
+ LLViewerAssetRequest *req = new LLViewerAssetRequest(uuid, atype);
+ req->mDownCallback = callback;
+ req->mUserData = user_data;
+ req->mIsPriority = is_priority;
+ if (!duplicate)
+ {
+ // Only collect metrics for non-duplicate requests. Others
+ // are piggy-backing and will artificially lower averages.
+ req->mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp();
+ }
+
+ mPendingDownloads.push_back(req);
+
+ if (!duplicate)
+ {
+ // send request message to our upstream data provider
+ // Create a new asset transfer.
+ LLTransferSourceParamsAsset spa;
+ spa.setAsset(uuid, atype);
+
+ // Set our destination file, and the completion callback.
+ LLTransferTargetParamsVFile tpvf;
+ tpvf.setAsset(uuid, atype);
+ tpvf.setCallback(downloadCompleteCallback, req);
+
+ llinfos << "Starting transfer for " << uuid << llendl;
+ LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(mUpstreamHost, LLTCT_ASSET);
+ ttcp->requestTransfer(spa, tpvf, 100.f + (is_priority ? 1.f : 0.f));
+
+ LLViewerAssetStatsFF::record_enqueue_main(atype, false, false);
+ }
+ }
+ else
+ {
+ // uh-oh, we shouldn't have gotten here
+ llwarns << "Attempt to move asset data request upstream w/o valid upstream provider" << llendl;
+ if (callback)
+ {
+ callback(mVFS, uuid, atype, user_data, LL_ERR_CIRCUIT_GONE, LL_EXSTAT_NO_UPSTREAM);
+ }
+ }
+}
+
diff --git a/indra/newview/llviewerassetstorage.h b/indra/newview/llviewerassetstorage.h
index 6346b79f03..ca9b9943fa 100644
--- a/indra/newview/llviewerassetstorage.h
+++ b/indra/newview/llviewerassetstorage.h
@@ -63,6 +63,17 @@ public:
bool is_priority = false,
bool user_waiting=FALSE,
F64 timeout=LL_ASSET_STORAGE_TIMEOUT);
+
+protected:
+ using LLAssetStorage::_queueDataRequest;
+
+ // virtual
+ void _queueDataRequest(const LLUUID& uuid,
+ LLAssetType::EType type,
+ void (*callback) (LLVFS *vfs, const LLUUID&, LLAssetType::EType, void *, S32, LLExtStat),
+ void *user_data,
+ BOOL duplicate,
+ BOOL is_priority);
};
#endif
diff --git a/indra/newview/llviewerassettype.cpp b/indra/newview/llviewerassettype.cpp
index 9a52422641..b103f11597 100644
--- a/indra/newview/llviewerassettype.cpp
+++ b/indra/newview/llviewerassettype.cpp
@@ -79,6 +79,8 @@ LLViewerAssetDictionary::LLViewerAssetDictionary()
addEntry(LLViewerAssetType::AT_LINK, new ViewerAssetEntry(DAD_LINK));
addEntry(LLViewerAssetType::AT_LINK_FOLDER, new ViewerAssetEntry(DAD_LINK));
+ addEntry(LLViewerAssetType::AT_MESH, new ViewerAssetEntry(DAD_MESH));
+
addEntry(LLViewerAssetType::AT_NONE, new ViewerAssetEntry(DAD_NONE));
};
diff --git a/indra/newview/llviewercamera.cpp b/indra/newview/llviewercamera.cpp
index cbb1d25f78..7f7366dd3d 100644
--- a/indra/newview/llviewercamera.cpp
+++ b/indra/newview/llviewercamera.cpp
@@ -32,6 +32,7 @@
// Viewer includes
#include "llagent.h"
#include "llagentcamera.h"
+#include "llmatrix4a.h"
#include "llviewercontrol.h"
#include "llviewerobjectlist.h"
#include "llviewerregion.h"
@@ -755,6 +756,10 @@ LLVector3 LLViewerCamera::roundToPixel(const LLVector3 &pos_agent)
BOOL LLViewerCamera::cameraUnderWater() const
{
+ if(!gAgent.getRegion())
+ {
+ return FALSE ;
+ }
return getOrigin().mV[VZ] < gAgent.getRegion()->getWaterHeight();
}
@@ -781,21 +786,29 @@ BOOL LLViewerCamera::areVertsVisible(LLViewerObject* volumep, BOOL all_verts)
LLMatrix4 render_mat(vo_volume->getRenderRotation(), LLVector4(vo_volume->getRenderPosition()));
+ LLMatrix4a render_mata;
+ render_mata.loadu(render_mat);
+ LLMatrix4a mata;
+ mata.loadu(mat);
+
num_faces = volume->getNumVolumeFaces();
for (i = 0; i < num_faces; i++)
{
const LLVolumeFace& face = volume->getVolumeFace(i);
- for (U32 v = 0; v < face.mVertices.size(); v++)
+ for (U32 v = 0; v < face.mNumVertices; v++)
{
- LLVector4 vec = LLVector4(face.mVertices[v].mPosition) * mat;
+ const LLVector4a& src_vec = face.mPositions[v];
+ LLVector4a vec;
+ mata.affineTransform(src_vec, vec);
if (drawablep->isActive())
{
- vec = vec * render_mat;
+ LLVector4a t = vec;
+ render_mata.affineTransform(t, vec);
}
- BOOL in_frustum = pointInFrustum(LLVector3(vec)) > 0;
+ BOOL in_frustum = pointInFrustum(LLVector3(vec.getF32ptr())) > 0;
if (( !in_frustum && all_verts) ||
(in_frustum && !all_verts))
diff --git a/indra/newview/llviewerchat.cpp b/indra/newview/llviewerchat.cpp
index 0af850a46b..e06fe7bda0 100644
--- a/indra/newview/llviewerchat.cpp
+++ b/indra/newview/llviewerchat.cpp
@@ -29,11 +29,16 @@
// newview includes
#include "llagent.h" // gAgent
+#include "llslurl.h"
+#include "lluicolor.h"
#include "lluicolortable.h"
#include "llviewercontrol.h" // gSavedSettings
+#include "llviewerregion.h"
+#include "llworld.h"
#include "llinstantmessage.h" //SYSTEM_FROM
// LLViewerChat
+LLViewerChat::font_change_signal_t LLViewerChat::sChatFontChangedSignal;
//static
void LLViewerChat::getChatColor(const LLChat& chat, LLColor4& r_color)
@@ -87,8 +92,9 @@ void LLViewerChat::getChatColor(const LLChat& chat, LLColor4& r_color)
if (!chat.mPosAgent.isExactlyZero())
{
LLVector3 pos_agent = gAgent.getPositionAgent();
- F32 distance = dist_vec(pos_agent, chat.mPosAgent);
- if (distance > gAgent.getNearChatRadius())
+ F32 distance_squared = dist_vec_squared(pos_agent, chat.mPosAgent);
+ F32 dist_near_chat = gAgent.getNearChatRadius();
+ if (distance_squared > dist_near_chat * dist_near_chat)
{
// diminish far-off chat
r_color.mV[VALPHA] = 0.8f;
@@ -152,8 +158,9 @@ void LLViewerChat::getChatColor(const LLChat& chat, std::string& r_color_name, F
if (!chat.mPosAgent.isExactlyZero())
{
LLVector3 pos_agent = gAgent.getPositionAgent();
- F32 distance = dist_vec(pos_agent, chat.mPosAgent);
- if (distance > gAgent.getNearChatRadius())
+ F32 distance_squared = dist_vec_squared(pos_agent, chat.mPosAgent);
+ F32 dist_near_chat = gAgent.getNearChatRadius();
+ if (distance_squared > dist_near_chat * dist_near_chat)
{
// diminish far-off chat
r_color_alpha = 0.8f;
@@ -214,3 +221,56 @@ void LLViewerChat::formatChatMsg(const LLChat& chat, std::string& formated_msg)
}
+//static
+std::string LLViewerChat::getSenderSLURL(const LLChat& chat, const LLSD& args)
+{
+ switch (chat.mSourceType)
+ {
+ case CHAT_SOURCE_AGENT:
+ return LLSLURL("agent", chat.mFromID, "about").getSLURLString();
+
+ case CHAT_SOURCE_OBJECT:
+ return getObjectImSLURL(chat, args);
+
+ default:
+ llwarns << "Getting SLURL for an unsupported sender type: " << chat.mSourceType << llendl;
+ }
+
+ return LLStringUtil::null;
+}
+
+//static
+std::string LLViewerChat::getObjectImSLURL(const LLChat& chat, const LLSD& args)
+{
+ std::string url = LLSLURL("objectim", chat.mFromID, "").getSLURLString();
+ url += "?name=" + chat.mFromName;
+ url += "&owner=" + chat.mOwnerID.asString();
+
+ std::string slurl = args["slurl"].asString();
+ if (slurl.empty())
+ {
+ LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosAgent(chat.mPosAgent);
+ if(region)
+ {
+ LLSLURL region_slurl(region->getName(), chat.mPosAgent);
+ slurl = region_slurl.getLocationString();
+ }
+ }
+
+ url += "&slurl=" + LLURI::escape(slurl);
+
+ return url;
+}
+
+//static
+boost::signals2::connection LLViewerChat::setFontChangedCallback(const font_change_signal_t::slot_type& cb)
+{
+ return sChatFontChangedSignal.connect(cb);
+}
+
+//static
+void LLViewerChat::signalChatFontChanged()
+{
+ // Notify all observers that our font has changed
+ sChatFontChangedSignal(getChatFont());
+}
diff --git a/indra/newview/llviewerchat.h b/indra/newview/llviewerchat.h
index a9f9a98960..c05caf0a95 100644
--- a/indra/newview/llviewerchat.h
+++ b/indra/newview/llviewerchat.h
@@ -35,11 +35,21 @@
class LLViewerChat
{
public:
+ typedef boost::signals2::signal<void (LLFontGL*)> font_change_signal_t;
+
static void getChatColor(const LLChat& chat, LLColor4& r_color);
static void getChatColor(const LLChat& chat, std::string& r_color_name, F32& r_color_alpha);
static LLFontGL* getChatFont();
static S32 getChatFontSize();
static void formatChatMsg(const LLChat& chat, std::string& formated_msg);
+ static std::string getSenderSLURL(const LLChat& chat, const LLSD& args);
+
+ static boost::signals2::connection setFontChangedCallback(const font_change_signal_t::slot_type& cb);
+ static void signalChatFontChanged();
+
+private:
+ static std::string getObjectImSLURL(const LLChat& chat, const LLSD& args);
+ static font_change_signal_t sChatFontChangedSignal;
};
diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index fbec2a7b9e..379bbe614d 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -70,6 +70,7 @@
#include "llpaneloutfitsinventory.h"
#include "llpanellogin.h"
#include "llpaneltopinfobar.h"
+#include "llupdaterservice.h"
#ifdef TOGGLE_HACKED_GODLIKE_VIEWER
BOOL gHackGodmode = FALSE;
@@ -82,7 +83,6 @@ LLControlGroup gCrashSettings("CrashSettings"); // saved at end of session
LLControlGroup gWarningSettings("Warnings"); // persists ignored dialogs/warnings
std::string gLastRunVersion;
-std::string gCurrentVersion;
extern BOOL gResizeScreenTexture;
extern BOOL gDebugGL;
@@ -117,10 +117,62 @@ static bool handleSetShaderChanged(const LLSD& newvalue)
gBumpImageList.destroyGL();
gBumpImageList.restoreGL();
+ // Changing shader also changes the terrain detail to high, reflect that change here
+ if (newvalue.asBoolean())
+ {
+ // shaders enabled, set terrain detail to high
+ gSavedSettings.setS32("RenderTerrainDetail", 1);
+ }
+ // else, leave terrain detail as is
LLViewerShaderMgr::instance()->setShaders();
return true;
}
+static bool handleRenderPerfTestChanged(const LLSD& newvalue)
+{
+ bool status = !newvalue.asBoolean();
+ if (!status)
+ {
+ gPipeline.clearRenderTypeMask(LLPipeline::RENDER_TYPE_WL_SKY,
+ LLPipeline::RENDER_TYPE_GROUND,
+ LLPipeline::RENDER_TYPE_TERRAIN,
+ LLPipeline::RENDER_TYPE_GRASS,
+ LLPipeline::RENDER_TYPE_TREE,
+ LLPipeline::RENDER_TYPE_WATER,
+ LLPipeline::RENDER_TYPE_PASS_GRASS,
+ LLPipeline::RENDER_TYPE_HUD,
+ LLPipeline::RENDER_TYPE_PARTICLES,
+ LLPipeline::RENDER_TYPE_CLOUDS,
+ LLPipeline::RENDER_TYPE_HUD_PARTICLES,
+ LLPipeline::END_RENDER_TYPES);
+ gPipeline.setRenderDebugFeatureControl(LLPipeline::RENDER_DEBUG_FEATURE_UI, false);
+ }
+ else
+ {
+ gPipeline.setRenderTypeMask(LLPipeline::RENDER_TYPE_WL_SKY,
+ LLPipeline::RENDER_TYPE_GROUND,
+ LLPipeline::RENDER_TYPE_TERRAIN,
+ LLPipeline::RENDER_TYPE_GRASS,
+ LLPipeline::RENDER_TYPE_TREE,
+ LLPipeline::RENDER_TYPE_WATER,
+ LLPipeline::RENDER_TYPE_PASS_GRASS,
+ LLPipeline::RENDER_TYPE_HUD,
+ LLPipeline::RENDER_TYPE_PARTICLES,
+ LLPipeline::RENDER_TYPE_CLOUDS,
+ LLPipeline::RENDER_TYPE_HUD_PARTICLES,
+ LLPipeline::END_RENDER_TYPES);
+ gPipeline.setRenderDebugFeatureControl(LLPipeline::RENDER_DEBUG_FEATURE_UI, true);
+ }
+
+ return true;
+}
+
+bool handleRenderTransparentWaterChanged(const LLSD& newvalue)
+{
+ LLWorld::getInstance()->updateWaterObjects();
+ return true;
+}
+
static bool handleReleaseGLBufferChanged(const LLSD& newvalue)
{
if (gPipeline.isInit())
@@ -151,6 +203,12 @@ static bool handleAvatarLODChanged(const LLSD& newvalue)
return true;
}
+static bool handleAvatarPhysicsLODChanged(const LLSD& newvalue)
+{
+ LLVOAvatar::sPhysicsLODFactor = (F32) newvalue.asReal();
+ return true;
+}
+
static bool handleAvatarMaxVisibleChanged(const LLSD& newvalue)
{
LLVOAvatar::sMaxVisible = (U32) newvalue.asInteger();
@@ -220,12 +278,6 @@ static bool handleVideoMemoryChanged(const LLSD& newvalue)
return true;
}
-static bool handleBandwidthChanged(const LLSD& newvalue)
-{
- gViewerThrottle.setMaxBandwidth((F32) newvalue.asReal());
- return true;
-}
-
static bool handleChatFontSizeChanged(const LLSD& newvalue)
{
if(gConsole)
@@ -287,15 +339,6 @@ static bool handleNumpadControlChanged(const LLSD& newvalue)
return true;
}
-static bool handleRenderUseVBOChanged(const LLSD& newvalue)
-{
- if (gPipeline.isInit())
- {
- gPipeline.setUseVBO(newvalue.asBoolean());
- }
- return true;
-}
-
static bool handleWLSkyDetailChanged(const LLSD&)
{
if (gSky.mVOWLSkyp.notNull())
@@ -320,13 +363,21 @@ static bool handleRenderDynamicLODChanged(const LLSD& newvalue)
return true;
}
-static bool handleRenderUseFBOChanged(const LLSD& newvalue)
+static bool handleRenderLocalLightsChanged(const LLSD& newvalue)
+{
+ gPipeline.setLightingDetail(-1);
+ return true;
+}
+
+static bool handleRenderDeferredChanged(const LLSD& newvalue)
{
LLRenderTarget::sUseFBO = newvalue.asBoolean();
if (gPipeline.isInit())
{
+ gPipeline.updateRenderDeferred();
gPipeline.releaseGLBuffers();
gPipeline.createGLBuffers();
+ gPipeline.resetVertexBuffers();
if (LLPipeline::sRenderDeferred && LLRenderTarget::sUseFBO)
{
LLViewerShaderMgr::instance()->setShaders();
@@ -489,6 +540,19 @@ bool toggle_show_object_render_cost(const LLSD& newvalue)
return true;
}
+void toggle_updater_service_active(LLControlVariable* control, const LLSD& new_value)
+{
+ if(new_value.asInteger())
+ {
+ LLUpdaterService update_service;
+ if(!update_service.isChecking()) update_service.startChecking();
+ }
+ else
+ {
+ LLUpdaterService().stopChecking();
+ }
+}
+
////////////////////////////////////////////////////////////////////////////
void settings_setup_listeners()
@@ -517,29 +581,30 @@ void settings_setup_listeners()
gSavedSettings.getControl("RenderAvatarMaxVisible")->getSignal()->connect(boost::bind(&handleAvatarMaxVisibleChanged, _2));
gSavedSettings.getControl("RenderVolumeLODFactor")->getSignal()->connect(boost::bind(&handleVolumeLODChanged, _2));
gSavedSettings.getControl("RenderAvatarLODFactor")->getSignal()->connect(boost::bind(&handleAvatarLODChanged, _2));
+ gSavedSettings.getControl("RenderAvatarPhysicsLODFactor")->getSignal()->connect(boost::bind(&handleAvatarPhysicsLODChanged, _2));
gSavedSettings.getControl("RenderTerrainLODFactor")->getSignal()->connect(boost::bind(&handleTerrainLODChanged, _2));
gSavedSettings.getControl("RenderTreeLODFactor")->getSignal()->connect(boost::bind(&handleTreeLODChanged, _2));
gSavedSettings.getControl("RenderFlexTimeFactor")->getSignal()->connect(boost::bind(&handleFlexLODChanged, _2));
- gSavedSettings.getControl("ThrottleBandwidthKBPS")->getSignal()->connect(boost::bind(&handleBandwidthChanged, _2));
gSavedSettings.getControl("RenderGamma")->getSignal()->connect(boost::bind(&handleGammaChanged, _2));
gSavedSettings.getControl("RenderFogRatio")->getSignal()->connect(boost::bind(&handleFogRatioChanged, _2));
gSavedSettings.getControl("RenderMaxPartCount")->getSignal()->connect(boost::bind(&handleMaxPartCountChanged, _2));
gSavedSettings.getControl("RenderDynamicLOD")->getSignal()->connect(boost::bind(&handleRenderDynamicLODChanged, _2));
+ gSavedSettings.getControl("RenderLocalLights")->getSignal()->connect(boost::bind(&handleRenderLocalLightsChanged, _2));
gSavedSettings.getControl("RenderDebugTextureBind")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
gSavedSettings.getControl("RenderAutoMaskAlphaDeferred")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
gSavedSettings.getControl("RenderAutoMaskAlphaNonDeferred")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
gSavedSettings.getControl("RenderObjectBump")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
gSavedSettings.getControl("RenderMaxVBOSize")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
- gSavedSettings.getControl("RenderUseFBO")->getSignal()->connect(boost::bind(&handleRenderUseFBOChanged, _2));
gSavedSettings.getControl("RenderDeferredNoise")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2));
gSavedSettings.getControl("RenderUseImpostors")->getSignal()->connect(boost::bind(&handleRenderUseImpostorsChanged, _2));
gSavedSettings.getControl("RenderDebugGL")->getSignal()->connect(boost::bind(&handleRenderDebugGLChanged, _2));
gSavedSettings.getControl("RenderDebugPipeline")->getSignal()->connect(boost::bind(&handleRenderDebugPipelineChanged, _2));
gSavedSettings.getControl("RenderResolutionDivisor")->getSignal()->connect(boost::bind(&handleRenderResolutionDivisorChanged, _2));
- gSavedSettings.getControl("RenderDeferred")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2));
+ gSavedSettings.getControl("RenderDeferred")->getSignal()->connect(boost::bind(&handleRenderDeferredChanged, _2));
gSavedSettings.getControl("RenderShadowDetail")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2));
gSavedSettings.getControl("RenderDeferredSSAO")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2));
gSavedSettings.getControl("RenderDeferredGI")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2));
+ gSavedSettings.getControl("RenderPerformanceTest")->getSignal()->connect(boost::bind(&handleRenderPerfTestChanged, _2));
gSavedSettings.getControl("TextureMemory")->getSignal()->connect(boost::bind(&handleVideoMemoryChanged, _2));
gSavedSettings.getControl("AuditTexture")->getSignal()->connect(boost::bind(&handleAuditTextureChanged, _2));
gSavedSettings.getControl("ChatFontSize")->getSignal()->connect(boost::bind(&handleChatFontSizeChanged, _2));
@@ -562,8 +627,10 @@ void settings_setup_listeners()
gSavedSettings.getControl("MuteVoice")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2));
gSavedSettings.getControl("MuteAmbient")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2));
gSavedSettings.getControl("MuteUI")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2));
- gSavedSettings.getControl("RenderVBOEnable")->getSignal()->connect(boost::bind(&handleRenderUseVBOChanged, _2));
+ gSavedSettings.getControl("RenderVBOEnable")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
+ gSavedSettings.getControl("RenderVBOMappingDisable")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
gSavedSettings.getControl("RenderUseStreamVBO")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
+ gSavedSettings.getControl("RenderPreferStreamDraw")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
gSavedSettings.getControl("WLSkyDetail")->getSignal()->connect(boost::bind(&handleWLSkyDetailChanged, _2));
gSavedSettings.getControl("NumpadControl")->getSignal()->connect(boost::bind(&handleNumpadControlChanged, _2));
gSavedSettings.getControl("JoystickAxis0")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
@@ -636,7 +703,9 @@ void settings_setup_listeners()
gSavedSettings.getControl("ShowNavbarFavoritesPanel")->getSignal()->connect(boost::bind(&toggle_show_favorites_panel, _2));
gSavedSettings.getControl("ShowMiniLocationPanel")->getSignal()->connect(boost::bind(&toggle_show_mini_location_panel, _2));
gSavedSettings.getControl("ShowObjectRenderingCost")->getSignal()->connect(boost::bind(&toggle_show_object_render_cost, _2));
+ gSavedSettings.getControl("UpdaterServiceSetting")->getSignal()->connect(&toggle_updater_service_active);
gSavedSettings.getControl("ForceShowGrid")->getSignal()->connect(boost::bind(&handleForceShowGrid, _2));
+ gSavedSettings.getControl("RenderTransparentWater")->getSignal()->connect(boost::bind(&handleRenderTransparentWaterChanged, _2));
}
#if TEST_CACHED_CONTROL
diff --git a/indra/newview/llviewercontrol.h b/indra/newview/llviewercontrol.h
index 22b48f8906..d7191f5c8d 100644
--- a/indra/newview/llviewercontrol.h
+++ b/indra/newview/llviewercontrol.h
@@ -57,7 +57,5 @@ extern LLControlGroup gCrashSettings;
// Set after settings loaded
extern std::string gLastRunVersion;
-extern std::string gCurrentVersion;
-
#endif // LL_LLVIEWERCONTROL_H
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index 40583f05bf..e41773d273 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -95,6 +95,7 @@ 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
@@ -114,8 +115,7 @@ void display_startup()
{
if ( !gViewerWindow->getActive()
|| !gViewerWindow->mWindow->getVisible()
- || gViewerWindow->mWindow->getMinimized()
- || gNoRender )
+ || gViewerWindow->mWindow->getMinimized() )
{
return;
}
@@ -218,22 +218,15 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
LLMemType mt_render(LLMemType::MTYPE_RENDER);
LLFastTimer t(FTM_RENDER);
- if (gResizeScreenTexture)
- { //skip render on frames where screen texture is resizing
+ if (gWindowResized)
+ { //skip render on frames where window has been resized
gGL.flush();
- if (!for_snapshot)
- {
- glClear(GL_COLOR_BUFFER_BIT);
- gViewerWindow->mWindow->swapBuffers();
- }
-
- gResizeScreenTexture = FALSE;
+ glClear(GL_COLOR_BUFFER_BIT);
+ gViewerWindow->mWindow->swapBuffers();
gPipeline.resizeScreenTexture();
-
- if (!for_snapshot)
- {
- return;
- }
+ gResizeScreenTexture = FALSE;
+ gWindowResized = FALSE;
+ return;
}
if (LLPipeline::sRenderDeferred)
@@ -300,7 +293,8 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
// Logic for forcing window updates if we're in drone mode.
//
- if (gNoRender)
+ // *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;
@@ -597,7 +591,8 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
S32 water_clip = 0;
if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_ENVIRONMENT) > 1) &&
- gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_WATER))
+ (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_WATER) ||
+ gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_VOIDWATER)))
{
if (LLViewerCamera::getInstance()->cameraUnderWater())
{
@@ -621,10 +616,10 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
&& gSavedSettings.getBOOL("UseOcclusion")
&& gGLManager.mHasOcclusionQuery) ? 2 : 0;
- if (LLPipeline::sUseOcclusion && LLPipeline::sRenderDeferred)
- { //force occlusion on for all render types if doing deferred render
+ /*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");
@@ -652,8 +647,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
LLGLState::checkTextureChannels();
LLGLState::checkClientArrays();
- BOOL to_texture = !for_snapshot &&
- gPipeline.canUseVertexShaders() &&
+ BOOL to_texture = gPipeline.canUseVertexShaders() &&
LLPipeline::sRenderGlow;
LLAppViewer::instance()->pingMainloopTimeout("Display:Swap");
@@ -665,11 +659,11 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
LLVertexBuffer::clientCopy(0.016);
}
- //if (gResizeScreenTexture)
- //{
- // gResizeScreenTexture = FALSE;
- // gPipeline.resizeScreenTexture();
- //}
+ if (gResizeScreenTexture)
+ {
+ gResizeScreenTexture = FALSE;
+ gPipeline.resizeScreenTexture();
+ }
gGL.setColorMask(true, true);
glClearColor(0,0,0,0);
@@ -714,7 +708,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
}
- if (!for_snapshot)
+ //if (!for_snapshot)
{
LLMemType mt_gw(LLMemType::MTYPE_DISPLAY_GEN_REFLECTION);
LLAppViewer::instance()->pingMainloopTimeout("Display:Imagery");
@@ -730,7 +724,6 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
//
// Doing this here gives hardware occlusion queries extra time to complete
LLAppViewer::instance()->pingMainloopTimeout("Display:UpdateImages");
- LLError::LLCallStacks::clear() ;
{
LLMemType mt_iu(LLMemType::MTYPE_DISPLAY_IMAGE_UPDATE);
@@ -761,7 +754,6 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
{
LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
LLMemType mt_ss(LLMemType::MTYPE_DISPLAY_STATE_SORT);
- gPipeline.sAllowRebuildPriorityGroup = TRUE ;
gPipeline.stateSort(*LLViewerCamera::getInstance(), result);
stop_glerror();
@@ -833,13 +825,14 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
//}
LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater() ? TRUE : FALSE;
- LLPipeline::updateRenderDeferred();
+ LLPipeline::refreshRenderDeferred();
stop_glerror();
if (to_texture)
{
gGL.setColorMask(true, true);
+
if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender)
{
gPipeline.mDeferredScreen.bindTarget();
@@ -892,10 +885,26 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
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);
+ }
}
}
@@ -913,9 +922,11 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
render_ui();
}
- gPipeline.rebuildGroups();
-
+
LLSpatialGroup::sNoDelete = FALSE;
+ gPipeline.clearReferences();
+
+ gPipeline.rebuildGroups();
}
LLAppViewer::instance()->pingMainloopTimeout("Display:FrameStats");
@@ -1013,6 +1024,7 @@ void render_hud_attachments()
gPipeline.renderGeom(hud_cam);
LLSpatialGroup::sNoDelete = FALSE;
+ //gPipeline.clearReferences();
render_hud_elements();
@@ -1049,8 +1061,7 @@ LLRect get_whole_screen_region()
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);
- glh::matrix4f mat;
-
+
whole_screen.setLeftTopAndSize(tile_x * tile_width, gViewerWindow->getWorldViewHeightScaled() - (tile_y * tile_height), tile_width, tile_height);
}
return whole_screen;
@@ -1074,8 +1085,8 @@ bool get_hud_matrices(const LLRect& screen_region, glh::matrix4f &proj, glh::mat
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),
+ 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;
@@ -1130,10 +1141,14 @@ void render_ui(F32 zoom_factor, int subfield)
LLMemType mt_ru(LLMemType::MTYPE_DISPLAY_RENDER_UI);
LLGLState::checkStates();
- glPushMatrix();
- glLoadMatrixd(gGLLastModelView);
glh::matrix4f saved_view = glh_get_current_modelview();
- glh_set_current_modelview(glh_copy_matrix(gGLLastModelView));
+
+ if (!gSnapshot)
+ {
+ glPushMatrix();
+ glLoadMatrixd(gGLLastModelView);
+ glh_set_current_modelview(glh_copy_matrix(gGLLastModelView));
+ }
{
BOOL to_texture = gPipeline.canUseVertexShaders() &&
@@ -1184,8 +1199,11 @@ void render_ui(F32 zoom_factor, int subfield)
LLVertexBuffer::unbind();
}
- glh_set_current_modelview(saved_view);
- glPopMatrix();
+ if (!gSnapshot)
+ {
+ glh_set_current_modelview(saved_view);
+ glPopMatrix();
+ }
if (gDisplaySwapBuffers)
{
@@ -1327,7 +1345,7 @@ void render_ui_2d()
// render outline for HUD
if (isAgentAvatarValid() && gAgentCamera.mHUDCurZoom < 0.98f)
{
- glPushMatrix();
+ 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);
@@ -1336,7 +1354,7 @@ void render_ui_2d()
glScalef(zoom,zoom,1.f);
gGL.color4fv(LLColor4::white.mV);
gl_rect_2d(-half_width, half_height, half_width, -half_height, FALSE);
- glPopMatrix();
+ gGL.popMatrix();
stop_glerror();
}
@@ -1384,8 +1402,7 @@ void render_ui_2d()
gGL.setColorMask(true, false);
LLUI::sDirtyRect = t_rect;
-
- }
+ }
LLGLDisable cull(GL_CULL_FACE);
LLGLDisable blend(GL_BLEND);
diff --git a/indra/newview/llviewerdisplay.h b/indra/newview/llviewerdisplay.h
index c6e86751e8..f6467d7f93 100644
--- a/indra/newview/llviewerdisplay.h
+++ b/indra/newview/llviewerdisplay.h
@@ -40,5 +40,6 @@ extern BOOL gTeleportDisplay;
extern LLFrameTimer gTeleportDisplayTimer;
extern BOOL gForceRenderLandFence;
extern BOOL gResizeScreenTexture;
+extern BOOL gWindowResized;
#endif // LL_LLVIEWERDISPLAY_H
diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp
index b3f14b441d..a1c2c926af 100644
--- a/indra/newview/llviewerfloaterreg.cpp
+++ b/indra/newview/llviewerfloaterreg.cpp
@@ -60,6 +60,7 @@
#include "llfloaterhardwaresettings.h"
#include "llfloaterhelpbrowser.h"
#include "llfloatermediabrowser.h"
+#include "llfloaterwebcontent.h"
#include "llfloatermediasettings.h"
#include "llfloaterhud.h"
#include "llfloaterimagepreview.h"
@@ -72,6 +73,7 @@
#include "llfloaterlandholdings.h"
#include "llfloatermap.h"
#include "llfloatermemleak.h"
+#include "llfloatermodelwizard.h"
#include "llfloaternamedesc.h"
#include "llfloaternotificationsconsole.h"
#include "llfloateropenobject.h"
@@ -81,6 +83,7 @@
#include "llfloaterpostprocess.h"
#include "llfloaterpreference.h"
#include "llfloaterproperties.h"
+#include "llfloaterregiondebugconsole.h"
#include "llfloaterregioninfo.h"
#include "llfloaterreporter.h"
#include "llfloaterscriptdebug.h"
@@ -89,6 +92,7 @@
#include "llfloatersettingsdebug.h"
#include "llfloatersidetraytab.h"
#include "llfloatersnapshot.h"
+#include "llfloatersounddevices.h"
#include "llfloatertelehub.h"
#include "llfloatertestinspectors.h"
#include "llfloatertestlistview.h"
@@ -120,8 +124,34 @@
#include "llpreviewtexture.h"
#include "llsyswellwindow.h"
#include "llscriptfloater.h"
+#include "llfloatermodelpreview.h"
+#include "llcommandhandler.h"
+
// *NOTE: Please add files in alphabetical order to keep merges easy.
+// handle secondlife:///app/floater/{NAME} URLs
+class LLFloaterOpenHandler : public LLCommandHandler
+{
+public:
+ // requires trusted browser to trigger
+ LLFloaterOpenHandler() : LLCommandHandler("floater", UNTRUSTED_THROTTLE) { }
+
+ bool handle(const LLSD& params, const LLSD& query_map,
+ LLMediaCtrl* web)
+ {
+ if (params.size() != 1)
+ {
+ return false;
+ }
+
+ const std::string floater_name = LLURI::unescape(params[0].asString());
+ LLFloaterReg::showInstance(floater_name);
+
+ return true;
+ }
+};
+
+LLFloaterOpenHandler gFloaterOpenHandler;
void LLViewerFloaterReg::registerFloaters()
{
@@ -227,6 +257,7 @@ void LLViewerFloaterReg::registerFloaters()
LLFloaterReg::add("reporter", "floater_report_abuse.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterReporter>);
LLFloaterReg::add("reset_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterResetQueue>);
+ LLFloaterReg::add("region_debug_console", "floater_region_debug_console.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterRegionDebugConsole>);
LLFloaterReg::add("region_info", "floater_region_info.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterRegionInfo>);
LLFloaterReg::add("script_debug", "floater_script_debug.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterScriptDebug>);
@@ -236,6 +267,7 @@ void LLViewerFloaterReg::registerFloaters()
LLFloaterReg::add("sell_land", "floater_sell_land.xml", &LLFloaterSellLand::buildFloater);
LLFloaterReg::add("settings_debug", "floater_settings_debug.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSettingsDebug>);
LLFloaterReg::add("side_bar_tab", "floater_side_bar_tab.xml", &LLFloaterReg::build<LLFloaterSideTrayTab>);
+ LLFloaterReg::add("sound_devices", "floater_sound_devices.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSoundDevices>);
LLFloaterReg::add("stats", "floater_stats.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloater>);
LLFloaterReg::add("start_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterRunQueue>);
LLFloaterReg::add("stop_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterNotRunQueue>);
@@ -246,10 +278,13 @@ void LLViewerFloaterReg::registerFloaters()
LLFloaterReg::add("upload_anim", "floater_animation_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAnimPreview>, "upload");
LLFloaterReg::add("upload_image", "floater_image_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterImagePreview>, "upload");
LLFloaterReg::add("upload_sound", "floater_sound_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSoundPreview>, "upload");
-
+ LLFloaterReg::add("upload_model", "floater_model_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterModelPreview>, "upload");
+ LLFloaterReg::add("upload_model_wizard", "floater_model_wizard.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterModelWizard>);
+
LLFloaterReg::add("voice_controls", "floater_voice_controls.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLCallFloater>);
LLFloaterReg::add("voice_effect", "floater_voice_effect.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterVoiceEffect>);
+ LLFloaterReg::add("web_content", "floater_web_content.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterWebContent>);
LLFloaterReg::add("whitelist_entry", "floater_whitelist_entry.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterWhiteListEntry>);
LLFloaterWindowSizeUtil::registerFloater();
LLFloaterReg::add("world_map", "floater_world_map.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterWorldMap>);
diff --git a/indra/newview/llviewerfoldertype.cpp b/indra/newview/llviewerfoldertype.cpp
index de1c8d14a8..42f780a8a3 100644
--- a/indra/newview/llviewerfoldertype.cpp
+++ b/indra/newview/llviewerfoldertype.cpp
@@ -126,6 +126,9 @@ LLViewerFolderDictionary::LLViewerFolderDictionary()
addEntry(LLFolderType::FT_CURRENT_OUTFIT, new ViewerFolderEntry("Current Outfit", "Inv_SysOpen", "Inv_SysClosed", TRUE));
addEntry(LLFolderType::FT_OUTFIT, new ViewerFolderEntry("New Outfit", "Inv_LookFolderOpen", "Inv_LookFolderClosed", TRUE));
addEntry(LLFolderType::FT_MY_OUTFITS, new ViewerFolderEntry("My Outfits", "Inv_SysOpen", "Inv_SysClosed", TRUE));
+ addEntry(LLFolderType::FT_MESH, new ViewerFolderEntry("Meshes", "Inv_SysOpen", "Inv_SysClosed", FALSE));
+
+
addEntry(LLFolderType::FT_INBOX, new ViewerFolderEntry("Inbox", "Inv_SysOpen", "Inv_SysClosed", FALSE));
addEntry(LLFolderType::FT_NONE, new ViewerFolderEntry("New Folder", "Inv_FolderOpen", "Inv_FolderClosed", FALSE, "default"));
diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp
index 7dbaa4cf92..9e58acdcd3 100644
--- a/indra/newview/llviewerinventory.cpp
+++ b/indra/newview/llviewerinventory.cpp
@@ -48,6 +48,7 @@
#include "llinventorybridge.h"
#include "llinventorypanel.h"
#include "llfloaterinventory.h"
+#include "lllandmarkactions.h"
#include "llviewerassettype.h"
#include "llviewerregion.h"
@@ -59,6 +60,9 @@
#include "llcommandhandler.h"
#include "llviewermessage.h"
#include "llsidepanelappearance.h"
+#include "llavatarnamecache.h"
+#include "llavataractions.h"
+#include "lllogininstance.h"
///----------------------------------------------------------------------------
/// Helper class to store special inventory item names and their localized values.
@@ -85,6 +89,7 @@ public:
mInventoryItemsDict["New Skirt"] = LLTrans::getString("New Skirt");
mInventoryItemsDict["New Alpha"] = LLTrans::getString("New Alpha");
mInventoryItemsDict["New Tattoo"] = LLTrans::getString("New Tattoo");
+ mInventoryItemsDict["New Physics"] = LLTrans::getString("New Physics");
mInventoryItemsDict["Invalid Wearable"] = LLTrans::getString("Invalid Wearable");
mInventoryItemsDict["New Gesture"] = LLTrans::getString("New Gesture");
@@ -178,6 +183,12 @@ public:
return false;
}
+ if (!LLUI::sSettingGroups["config"]->getBOOL("EnableInventory"))
+ {
+ LLNotificationsUtil::add("NoInventory", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit"));
+ return true;
+ }
+
// support secondlife:///app/inventory/show
if (params[0].asString() == "show")
{
@@ -211,6 +222,7 @@ public:
};
LLInventoryHandler gInventoryHandler;
+
///----------------------------------------------------------------------------
/// Class LLViewerInventoryItem
///----------------------------------------------------------------------------
@@ -361,11 +373,11 @@ void LLViewerInventoryItem::fetchFromServer(void) const
{
if(gAgent.getID() != mPermissions.getOwner())
{
- url = region->getCapability("FetchLib");
+ url = region->getCapability("FetchLib2");
}
else
{
- url = region->getCapability("FetchInventory");
+ url = region->getCapability("FetchInventory2");
}
}
else
@@ -643,7 +655,7 @@ bool LLViewerInventoryCategory::fetch()
std::string url;
if (gAgent.getRegion())
{
- url = gAgent.getRegion()->getCapability("WebFetchInventoryDescendents");
+ url = gAgent.getRegion()->getCapability("FetchInventoryDescendents2");
}
else
{
@@ -655,7 +667,7 @@ bool LLViewerInventoryCategory::fetch()
}
else
{ //Deprecated, but if we don't have a capability, use the old system.
- llinfos << "WebFetchInventoryDescendents capability not found. Using deprecated UDP message." << llendl;
+ llinfos << "FetchInventoryDescendents2 capability not found. Using deprecated UDP message." << llendl;
LLMessageSystem* msg = gMessageSystem;
msg->newMessage("FetchInventoryDescendents");
msg->nextBlock("AgentData");
@@ -1414,6 +1426,8 @@ public:
S32 getSortIndex(const LLUUID& inv_item_id);
void removeSortIndex(const LLUUID& inv_item_id);
+ void getSLURL(const LLUUID& asset_id);
+
/**
* Implementation of LLDestroyClass. Calls cleanup() instance method.
*
@@ -1440,9 +1454,20 @@ private:
void load();
void save();
+ void saveFavoritesSLURLs();
+
+ // Remove record of current user's favorites from file on disk.
+ void removeFavoritesRecordOfUser();
+
+ void onLandmarkLoaded(const LLUUID& asset_id, LLLandmark* landmark);
+ void storeFavoriteSLURL(const LLUUID& asset_id, std::string& slurl);
+
typedef std::map<LLUUID, S32> sort_index_map_t;
sort_index_map_t mSortIndexes;
+ typedef std::map<LLUUID, std::string> slurls_map_t;
+ slurls_map_t mSLURLs;
+
bool mIsDirty;
struct IsNotInFavorites
@@ -1497,10 +1522,31 @@ void LLFavoritesOrderStorage::removeSortIndex(const LLUUID& inv_item_id)
mIsDirty = true;
}
+void LLFavoritesOrderStorage::getSLURL(const LLUUID& asset_id)
+{
+ slurls_map_t::iterator slurl_iter = mSLURLs.find(asset_id);
+ if (slurl_iter != mSLURLs.end()) return; // SLURL for current landmark is already cached
+
+ LLLandmark* lm = gLandmarkList.getAsset(asset_id,
+ boost::bind(&LLFavoritesOrderStorage::onLandmarkLoaded, this, asset_id, _1));
+ if (lm)
+ {
+ onLandmarkLoaded(asset_id, lm);
+ }
+}
+
// static
void LLFavoritesOrderStorage::destroyClass()
{
LLFavoritesOrderStorage::instance().cleanup();
+ if (gSavedPerAccountSettings.getBOOL("ShowFavoritesOnLogin"))
+ {
+ LLFavoritesOrderStorage::instance().saveFavoritesSLURLs();
+ }
+ else
+ {
+ LLFavoritesOrderStorage::instance().removeFavoritesRecordOfUser();
+ }
}
void LLFavoritesOrderStorage::load()
@@ -1523,6 +1569,98 @@ void LLFavoritesOrderStorage::load()
}
}
+void LLFavoritesOrderStorage::saveFavoritesSLURLs()
+{
+ // Do not change the file if we are not logged in yet.
+ if (!LLLoginInstance::getInstance()->authSuccess()) return;
+
+ std::string user_dir = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "");
+ if (user_dir.empty()) return;
+
+ std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "stored_favorites.xml");
+ llifstream in_file;
+ in_file.open(filename);
+ LLSD fav_llsd;
+ if (in_file.is_open())
+ {
+ LLSDSerialize::fromXML(fav_llsd, in_file);
+ }
+
+ const LLUUID fav_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE);
+ LLInventoryModel::cat_array_t cats;
+ LLInventoryModel::item_array_t items;
+ gInventory.collectDescendents(fav_id, cats, items, LLInventoryModel::EXCLUDE_TRASH);
+
+ LLSD user_llsd;
+ for (LLInventoryModel::item_array_t::iterator it = items.begin(); it != items.end(); it++)
+ {
+ LLSD value;
+ value["name"] = (*it)->getName();
+ value["asset_id"] = (*it)->getAssetUUID();
+
+ slurls_map_t::iterator slurl_iter = mSLURLs.find(value["asset_id"]);
+ if (slurl_iter != mSLURLs.end())
+ {
+ value["slurl"] = slurl_iter->second;
+ user_llsd[(*it)->getSortField()] = value;
+ }
+ }
+
+ LLAvatarName av_name;
+ LLAvatarNameCache::get( gAgentID, &av_name );
+ fav_llsd[av_name.getLegacyName()] = user_llsd;
+
+ llofstream file;
+ file.open(filename);
+ LLSDSerialize::toPrettyXML(fav_llsd, file);
+}
+
+void LLFavoritesOrderStorage::removeFavoritesRecordOfUser()
+{
+ std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "stored_favorites.xml");
+ LLSD fav_llsd;
+ llifstream file;
+ file.open(filename);
+ if (!file.is_open()) return;
+ LLSDSerialize::fromXML(fav_llsd, file);
+
+ LLAvatarName av_name;
+ LLAvatarNameCache::get( gAgentID, &av_name );
+ if (fav_llsd.has(av_name.getLegacyName()))
+ {
+ fav_llsd.erase(av_name.getLegacyName());
+ }
+
+ llofstream out_file;
+ out_file.open(filename);
+ LLSDSerialize::toPrettyXML(fav_llsd, out_file);
+
+}
+
+void LLFavoritesOrderStorage::onLandmarkLoaded(const LLUUID& asset_id, LLLandmark* landmark)
+{
+ if (!landmark) return;
+
+ LLVector3d pos_global;
+ if (!landmark->getGlobalPos(pos_global))
+ {
+ // If global position was unknown on first getGlobalPos() call
+ // it should be set for the subsequent calls.
+ landmark->getGlobalPos(pos_global);
+ }
+
+ if (!pos_global.isExactlyZero())
+ {
+ LLLandmarkActions::getSLURLfromPosGlobal(pos_global,
+ boost::bind(&LLFavoritesOrderStorage::storeFavoriteSLURL, this, asset_id, _1));
+ }
+}
+
+void LLFavoritesOrderStorage::storeFavoriteSLURL(const LLUUID& asset_id, std::string& slurl)
+{
+ mSLURLs[asset_id] = slurl;
+}
+
void LLFavoritesOrderStorage::save()
{
// nothing to save if clean
@@ -1579,6 +1717,12 @@ S32 LLViewerInventoryItem::getSortField() const
void LLViewerInventoryItem::setSortField(S32 sortField)
{
LLFavoritesOrderStorage::instance().setSortIndex(mUUID, sortField);
+ getSLURL();
+}
+
+void LLViewerInventoryItem::getSLURL()
+{
+ LLFavoritesOrderStorage::instance().getSLURL(mAssetUUID);
}
const LLPermissions& LLViewerInventoryItem::getPermissions() const
diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h
index 1af06a1be8..41542a4e0f 100644
--- a/indra/newview/llviewerinventory.h
+++ b/indra/newview/llviewerinventory.h
@@ -62,6 +62,7 @@ public:
virtual const std::string& getName() const;
virtual S32 getSortField() const;
virtual void setSortField(S32 sortField);
+ virtual void getSLURL(); //Caches SLURL for landmark. //*TODO: Find a better way to do it and remove this method from here.
virtual const LLPermissions& getPermissions() const;
virtual const bool getIsFullPerm() const; // 'fullperm' in the popular sense: modify-ok & copy-ok & transfer-ok, no special god rules applied
virtual const LLUUID& getCreatorUUID() const;
diff --git a/indra/newview/llviewerjoint.cpp b/indra/newview/llviewerjoint.cpp
index 0cf5fe0ada..baf85d6884 100644
--- a/indra/newview/llviewerjoint.cpp
+++ b/indra/newview/llviewerjoint.cpp
@@ -257,7 +257,7 @@ U32 LLViewerJoint::render( F32 pixelArea, BOOL first_pass, BOOL is_dummy )
// if object is transparent, defer it, otherwise
// give the joint subclass a chance to draw itself
//----------------------------------------------------------------
- if ( gRenderForSelect || is_dummy )
+ if ( is_dummy )
{
triangle_count += drawShape( pixelArea, first_pass, is_dummy );
}
diff --git a/indra/newview/llviewerjointmesh.cpp b/indra/newview/llviewerjointmesh.cpp
index ae2aa41b3a..77c8bb0329 100644
--- a/indra/newview/llviewerjointmesh.cpp
+++ b/indra/newview/llviewerjointmesh.cpp
@@ -55,13 +55,13 @@
#include "v4math.h"
#include "m3math.h"
#include "m4math.h"
+#include "llmatrix4a.h"
#if !LL_DARWIN && !LL_LINUX && !LL_SOLARIS
extern PFNGLWEIGHTPOINTERARBPROC glWeightPointerARB;
extern PFNGLWEIGHTFVARBPROC glWeightfvARB;
extern PFNGLVERTEXBLENDARBPROC glVertexBlendARB;
#endif
-extern BOOL gRenderForSelect;
static LLPointer<LLVertexBuffer> sRenderBuffer = NULL;
static const U32 sRenderMask = LLVertexBuffer::MAP_VERTEX |
@@ -376,6 +376,7 @@ const S32 NUM_AXES = 3;
// pivot parent 0-n -- child = n+1
static LLMatrix4 gJointMatUnaligned[32];
+static LLMatrix4a gJointMatAligned[32];
static LLMatrix3 gJointRotUnaligned[32];
static LLVector4 gJointPivot[32];
@@ -461,6 +462,14 @@ void LLViewerJointMesh::uploadJointMatrices()
glUniform4fvARB(gAvatarMatrixParam, 45, mat);
stop_glerror();
}
+ else
+ {
+ //load gJointMatUnaligned into gJointMatAligned
+ for (joint_num = 0; joint_num < reference_mesh->mJointRenderData.count(); ++joint_num)
+ {
+ gJointMatAligned[joint_num].loadu(gJointMatUnaligned[joint_num]);
+ }
+ }
}
//--------------------------------------------------------------------
@@ -502,7 +511,7 @@ int compare_int(const void *a, const void *b)
U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy)
{
if (!mValid || !mMesh || !mFace || !mVisible ||
- mFace->mVertexBuffer.isNull() ||
+ !mFace->getVertexBuffer() ||
mMesh->getNumFaces() == 0)
{
return 0;
@@ -510,22 +519,21 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy)
U32 triangle_count = 0;
+ S32 diffuse_channel = LLDrawPoolAvatar::sDiffuseChannel;
+
stop_glerror();
//----------------------------------------------------------------
// setup current color
//----------------------------------------------------------------
- if (!gRenderForSelect)
- {
- if (is_dummy)
- glColor4fv(LLVOAvatar::getDummyColor().mV);
- else
- glColor4fv(mColor.mV);
- }
+ if (is_dummy)
+ glColor4fv(LLVOAvatar::getDummyColor().mV);
+ else
+ glColor4fv(mColor.mV);
stop_glerror();
- LLGLSSpecular specular(LLColor4(1.f,1.f,1.f,1.f), gRenderForSelect ? 0.0f : mShiny && !(mFace->getPool()->getVertexShaderLevel() > 0));
+ LLGLSSpecular specular(LLColor4(1.f,1.f,1.f,1.f), mFace->getPool()->getVertexShaderLevel() > 0 ? 0.f : mShiny);
//----------------------------------------------------------------
// setup current texture
@@ -535,7 +543,7 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy)
LLTexUnit::eTextureAddressMode old_mode = LLTexUnit::TAM_WRAP;
if (mTestImageName)
{
- gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mTestImageName);
+ gGL.getTexUnit(diffuse_channel)->bindManual(LLTexUnit::TT_TEXTURE, mTestImageName);
if (mIsTransparent)
{
@@ -544,24 +552,18 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy)
else
{
glColor4f(0.7f, 0.6f, 0.3f, 1.f);
- gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_LERP_TEX_ALPHA, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_PREV_COLOR);
+ gGL.getTexUnit(diffuse_channel)->setTextureColorBlend(LLTexUnit::TBO_LERP_TEX_ALPHA, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_PREV_COLOR);
}
}
else if( !is_dummy && mLayerSet )
{
if( mLayerSet->hasComposite() )
{
- gGL.getTexUnit(0)->bind(mLayerSet->getComposite());
+ gGL.getTexUnit(diffuse_channel)->bind(mLayerSet->getComposite());
}
else
{
- // This warning will always trigger if you've hacked the avatar to show as incomplete.
- // Ignore the warning if that's the case.
- if (!gSavedSettings.getBOOL("RenderUnloadedAvatar"))
- {
- //llwarns << "Layerset without composite" << llendl;
- }
- gGL.getTexUnit(0)->bind(LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT));
+ gGL.getTexUnit(diffuse_channel)->bind(LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT));
}
}
else
@@ -571,29 +573,16 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy)
{
old_mode = mTexture->getAddressMode();
}
- gGL.getTexUnit(0)->bind(mTexture.get());
- gGL.getTexUnit(0)->bind(mTexture);
- gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
+ gGL.getTexUnit(diffuse_channel)->bind(mTexture.get());
+ gGL.getTexUnit(diffuse_channel)->bind(mTexture);
+ gGL.getTexUnit(diffuse_channel)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
}
else
{
- gGL.getTexUnit(0)->bind(LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT));
- }
-
- if (gRenderForSelect)
- {
- if (isTransparent())
- {
- gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_COLOR);
- gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_ALPHA, LLTexUnit::TBS_CONST_ALPHA);
- }
- else
- {
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- }
+ gGL.getTexUnit(diffuse_channel)->bind(LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT));
}
- mFace->mVertexBuffer->setBuffer(sRenderMask);
+ mFace->getVertexBuffer()->setBuffer(sRenderMask);
U32 start = mMesh->mFaceVertexOffset;
U32 end = start + mMesh->mFaceVertexCount - 1;
@@ -610,14 +599,14 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy)
}
}
- mFace->mVertexBuffer->drawRange(LLRender::TRIANGLES, start, end, count, offset);
+ mFace->getVertexBuffer()->drawRange(LLRender::TRIANGLES, start, end, count, offset);
}
else
{
glPushMatrix();
LLMatrix4 jointToWorld = getWorldMatrix();
glMultMatrixf((GLfloat*)jointToWorld.mMatrix);
- mFace->mVertexBuffer->drawRange(LLRender::TRIANGLES, start, end, count, offset);
+ mFace->getVertexBuffer()->drawRange(LLRender::TRIANGLES, start, end, count, offset);
glPopMatrix();
}
gPipeline.addTrianglesDrawn(count);
@@ -626,13 +615,13 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy)
if (mTestImageName)
{
- gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
+ gGL.getTexUnit(diffuse_channel)->setTextureBlendType(LLTexUnit::TB_MULT);
}
if (mTexture.notNull() && !is_dummy)
{
- gGL.getTexUnit(0)->bind(mTexture);
- gGL.getTexUnit(0)->setTextureAddressMode(old_mode);
+ gGL.getTexUnit(diffuse_channel)->bind(mTexture);
+ gGL.getTexUnit(diffuse_channel)->setTextureAddressMode(old_mode);
}
return triangle_count;
@@ -643,6 +632,9 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy)
//-----------------------------------------------------------------------------
void LLViewerJointMesh::updateFaceSizes(U32 &num_vertices, U32& num_indices, F32 pixel_area)
{
+ //bump num_vertices to next multiple of 4
+ num_vertices = (num_vertices + 0x3) & ~0x3;
+
// Do a pre-alloc pass to determine sizes of data.
if (mMesh && mValid)
{
@@ -665,13 +657,25 @@ static LLFastTimer::DeclareTimer FTM_AVATAR_FACE("Avatar Face");
void LLViewerJointMesh::updateFaceData(LLFace *face, F32 pixel_area, BOOL damp_wind, bool terse_update)
{
+ //IF THIS FUNCTION BREAKS, SEE LLPOLYMESH CONSTRUCTOR AND CHECK ALIGNMENT OF INPUT ARRAYS
+
mFace = face;
- if (mFace->mVertexBuffer.isNull())
+ if (!mFace->getVertexBuffer())
{
return;
}
+ LLDrawPool *poolp = mFace->getPool();
+ BOOL hardware_skinning = (poolp && poolp->getVertexShaderLevel() > 0) ? TRUE : FALSE;
+
+ if (!hardware_skinning && terse_update)
+ { //no need to do terse updates if we're doing software vertex skinning
+ // since mMesh is being copied into mVertexBuffer every frame
+ return;
+ }
+
+
LLFastTimer t(FTM_AVATAR_FACE);
LLStrider<LLVector3> verticesp;
@@ -684,111 +688,59 @@ void LLViewerJointMesh::updateFaceData(LLFace *face, F32 pixel_area, BOOL damp_w
// Copy data into the faces from the polymesh data.
if (mMesh && mValid)
{
- if (mMesh->getNumVertices())
+ const U32 num_verts = mMesh->getNumVertices();
+
+ if (num_verts)
{
- stop_glerror();
face->getGeometryAvatar(verticesp, normalsp, tex_coordsp, vertex_weightsp, clothing_weightsp);
- stop_glerror();
- face->mVertexBuffer->getIndexStrider(indicesp);
- stop_glerror();
+ face->getVertexBuffer()->getIndexStrider(indicesp);
verticesp += mMesh->mFaceVertexOffset;
- tex_coordsp += mMesh->mFaceVertexOffset;
normalsp += mMesh->mFaceVertexOffset;
- vertex_weightsp += mMesh->mFaceVertexOffset;
- clothing_weightsp += mMesh->mFaceVertexOffset;
-
- const U32* __restrict coords = (U32*) mMesh->getCoords();
- const U32* __restrict tex_coords = (U32*) mMesh->getTexCoords();
- const U32* __restrict normals = (U32*) mMesh->getNormals();
- const U32* __restrict weights = (U32*) mMesh->getWeights();
- const U32* __restrict cloth_weights = (U32*) mMesh->getClothingWeights();
-
- const U32 num_verts = mMesh->getNumVertices();
-
- U32 i = 0;
-
- const U32 skip = verticesp.getSkip()/sizeof(U32);
+
+ F32* v = (F32*) verticesp.get();
+ F32* n = (F32*) normalsp.get();
+
+ U32 words = num_verts*4;
- U32* __restrict v = (U32*) verticesp.get();
- U32* __restrict n = (U32*) normalsp.get();
+ LLVector4a::memcpyNonAliased16(v, (F32*) mMesh->getCoords(), words*sizeof(F32));
+ LLVector4a::memcpyNonAliased16(n, (F32*) mMesh->getNormals(), words*sizeof(F32));
+
- if (terse_update)
+ if (!terse_update)
{
- for (S32 i = num_verts; i > 0; --i)
- {
- //morph target application only, only update positions and normals
- v[0] = coords[0];
- v[1] = coords[1];
- v[2] = coords[2];
- coords += 3;
- v += skip;
- }
+ vertex_weightsp += mMesh->mFaceVertexOffset;
+ clothing_weightsp += mMesh->mFaceVertexOffset;
+ tex_coordsp += mMesh->mFaceVertexOffset;
+
+ F32* tc = (F32*) tex_coordsp.get();
+ F32* vw = (F32*) vertex_weightsp.get();
+ F32* cw = (F32*) clothing_weightsp.get();
- for (S32 i = num_verts; i > 0; --i)
- {
- n[0] = normals[0];
- n[1] = normals[1];
- n[2] = normals[2];
- normals += 3;
- n += skip;
- }
+ LLVector4a::memcpyNonAliased16(tc, (F32*) mMesh->getTexCoords(), num_verts*2*sizeof(F32));
+ LLVector4a::memcpyNonAliased16(vw, (F32*) mMesh->getWeights(), num_verts*sizeof(F32));
+ LLVector4a::memcpyNonAliased16(cw, (F32*) mMesh->getClothingWeights(), num_verts*4*sizeof(F32));
}
- else
- {
-
- U32* __restrict tc = (U32*) tex_coordsp.get();
- U32* __restrict vw = (U32*) vertex_weightsp.get();
- U32* __restrict cw = (U32*) clothing_weightsp.get();
-
- do
- {
- v[0] = *(coords++);
- v[1] = *(coords++);
- v[2] = *(coords++);
- v += skip;
-
- tc[0] = *(tex_coords++);
- tc[1] = *(tex_coords++);
- tc += skip;
-
- n[0] = *(normals++);
- n[1] = *(normals++);
- n[2] = *(normals++);
- n += skip;
-
- vw[0] = *(weights++);
- vw += skip;
-
- cw[0] = *(cloth_weights++);
- cw[1] = *(cloth_weights++);
- cw[2] = *(cloth_weights++);
- cw[3] = *(cloth_weights++);
- cw += skip;
- }
- while (++i < num_verts);
-
- const U32 idx_count = mMesh->getNumFaces()*3;
- indicesp += mMesh->mFaceIndexOffset;
+ const U32 idx_count = mMesh->getNumFaces()*3;
- U16* __restrict idx = indicesp.get();
- S32* __restrict src_idx = (S32*) mMesh->getFaces();
+ indicesp += mMesh->mFaceIndexOffset;
- i = 0;
+ U16* __restrict idx = indicesp.get();
+ S32* __restrict src_idx = (S32*) mMesh->getFaces();
- const S32 offset = (S32) mMesh->mFaceVertexOffset;
+ const S32 offset = (S32) mMesh->mFaceVertexOffset;
- do
- {
- *(idx++) = *(src_idx++)+offset;
- }
- while (++i < idx_count);
+ for (S32 i = 0; i < idx_count; ++i)
+ {
+ *(idx++) = *(src_idx++)+offset;
}
}
}
}
+
+
//-----------------------------------------------------------------------------
// updateLOD()
//-----------------------------------------------------------------------------
@@ -806,89 +758,49 @@ void LLViewerJointMesh::updateGeometryOriginal(LLFace *mFace, LLPolyMesh *mMesh)
LLStrider<LLVector3> o_normals;
//get vertex and normal striders
- LLVertexBuffer *buffer = mFace->mVertexBuffer;
+ LLVertexBuffer* buffer = mFace->getVertexBuffer();
buffer->getVertexStrider(o_vertices, 0);
buffer->getNormalStrider(o_normals, 0);
- F32 last_weight = F32_MAX;
- LLMatrix4 gBlendMat;
- LLMatrix3 gBlendRotMat;
+ F32* __restrict vert = o_vertices[0].mV;
+ F32* __restrict norm = o_normals[0].mV;
+
+ const F32* __restrict weights = mMesh->getWeights();
+ const LLVector4a* __restrict coords = (LLVector4a*) mMesh->getCoords();
+ const LLVector4a* __restrict normals = (LLVector4a*) mMesh->getNormals();
+
+ U32 offset = mMesh->mFaceVertexOffset*4;
+ vert += offset;
+ norm += offset;
- const F32* weights = mMesh->getWeights();
- const LLVector3* coords = mMesh->getCoords();
- const LLVector3* normals = mMesh->getNormals();
for (U32 index = 0; index < mMesh->getNumVertices(); index++)
{
- U32 bidx = index + mMesh->mFaceVertexOffset;
-
- // blend by first matrix
- F32 w = weights[index];
-
- // Maybe we don't have to change gBlendMat.
- // Profiles of a single-avatar scene on a Mac show this to be a very
- // common case. JC
- if (w == last_weight)
- {
- o_vertices[bidx] = coords[index] * gBlendMat;
- o_normals[bidx] = normals[index] * gBlendRotMat;
- continue;
- }
-
- last_weight = w;
+ // equivalent to joint = floorf(weights[index]);
+ S32 joint = _mm_cvtt_ss2si(_mm_load_ss(weights+index));
+ F32 w = weights[index] - joint;
- S32 joint = llfloor(w);
- w -= joint;
-
- // No lerp required in this case.
- if (w == 1.0f)
+ LLMatrix4a gBlendMat;
+
+ if (w != 0.f)
{
- gBlendMat = gJointMatUnaligned[joint+1];
- o_vertices[bidx] = coords[index] * gBlendMat;
- gBlendRotMat = gJointRotUnaligned[joint+1];
- o_normals[bidx] = normals[index] * gBlendRotMat;
- continue;
+ // blend between matrices and apply
+ gBlendMat.setLerp(gJointMatAligned[joint+0],
+ gJointMatAligned[joint+1], w);
+
+ LLVector4a res;
+ gBlendMat.affineTransform(coords[index], res);
+ res.store4a(vert+index*4);
+ gBlendMat.rotate(normals[index], res);
+ res.store4a(norm+index*4);
+ }
+ else
+ { // No lerp required in this case.
+ LLVector4a res;
+ gJointMatAligned[joint].affineTransform(coords[index], res);
+ res.store4a(vert+index*4);
+ gJointMatAligned[joint].rotate(normals[index], res);
+ res.store4a(norm+index*4);
}
-
- // Try to keep all the accesses to the matrix data as close
- // together as possible. This function is a hot spot on the
- // Mac. JC
- LLMatrix4 &m0 = gJointMatUnaligned[joint+1];
- LLMatrix4 &m1 = gJointMatUnaligned[joint+0];
-
- gBlendMat.mMatrix[VX][VX] = lerp(m1.mMatrix[VX][VX], m0.mMatrix[VX][VX], w);
- gBlendMat.mMatrix[VX][VY] = lerp(m1.mMatrix[VX][VY], m0.mMatrix[VX][VY], w);
- gBlendMat.mMatrix[VX][VZ] = lerp(m1.mMatrix[VX][VZ], m0.mMatrix[VX][VZ], w);
-
- gBlendMat.mMatrix[VY][VX] = lerp(m1.mMatrix[VY][VX], m0.mMatrix[VY][VX], w);
- gBlendMat.mMatrix[VY][VY] = lerp(m1.mMatrix[VY][VY], m0.mMatrix[VY][VY], w);
- gBlendMat.mMatrix[VY][VZ] = lerp(m1.mMatrix[VY][VZ], m0.mMatrix[VY][VZ], w);
-
- gBlendMat.mMatrix[VZ][VX] = lerp(m1.mMatrix[VZ][VX], m0.mMatrix[VZ][VX], w);
- gBlendMat.mMatrix[VZ][VY] = lerp(m1.mMatrix[VZ][VY], m0.mMatrix[VZ][VY], w);
- gBlendMat.mMatrix[VZ][VZ] = lerp(m1.mMatrix[VZ][VZ], m0.mMatrix[VZ][VZ], w);
-
- gBlendMat.mMatrix[VW][VX] = lerp(m1.mMatrix[VW][VX], m0.mMatrix[VW][VX], w);
- gBlendMat.mMatrix[VW][VY] = lerp(m1.mMatrix[VW][VY], m0.mMatrix[VW][VY], w);
- gBlendMat.mMatrix[VW][VZ] = lerp(m1.mMatrix[VW][VZ], m0.mMatrix[VW][VZ], w);
-
- o_vertices[bidx] = coords[index] * gBlendMat;
-
- LLMatrix3 &n0 = gJointRotUnaligned[joint+1];
- LLMatrix3 &n1 = gJointRotUnaligned[joint+0];
-
- gBlendRotMat.mMatrix[VX][VX] = lerp(n1.mMatrix[VX][VX], n0.mMatrix[VX][VX], w);
- gBlendRotMat.mMatrix[VX][VY] = lerp(n1.mMatrix[VX][VY], n0.mMatrix[VX][VY], w);
- gBlendRotMat.mMatrix[VX][VZ] = lerp(n1.mMatrix[VX][VZ], n0.mMatrix[VX][VZ], w);
-
- gBlendRotMat.mMatrix[VY][VX] = lerp(n1.mMatrix[VY][VX], n0.mMatrix[VY][VX], w);
- gBlendRotMat.mMatrix[VY][VY] = lerp(n1.mMatrix[VY][VY], n0.mMatrix[VY][VY], w);
- gBlendRotMat.mMatrix[VY][VZ] = lerp(n1.mMatrix[VY][VZ], n0.mMatrix[VY][VZ], w);
-
- gBlendRotMat.mMatrix[VZ][VX] = lerp(n1.mMatrix[VZ][VX], n0.mMatrix[VZ][VX], w);
- gBlendRotMat.mMatrix[VZ][VY] = lerp(n1.mMatrix[VZ][VY], n0.mMatrix[VZ][VY], w);
- gBlendRotMat.mMatrix[VZ][VZ] = lerp(n1.mMatrix[VZ][VZ], n0.mMatrix[VZ][VZ], w);
-
- o_normals[bidx] = normals[index] * gBlendRotMat;
}
buffer->setBuffer(0);
@@ -957,7 +869,7 @@ void LLViewerJointMesh::updateJointGeometry()
&& mMesh
&& mFace
&& mMesh->hasWeights()
- && mFace->mVertexBuffer.notNull()
+ && mFace->getVertexBuffer()
&& LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_AVATAR) == 0))
{
return;
diff --git a/indra/newview/llviewerjointmesh_sse.cpp b/indra/newview/llviewerjointmesh_sse.cpp
index 174b6eae29..400b49d046 100644
--- a/indra/newview/llviewerjointmesh_sse.cpp
+++ b/indra/newview/llviewerjointmesh_sse.cpp
@@ -83,13 +83,13 @@ void LLViewerJointMesh::updateGeometrySSE(LLFace *face, LLPolyMesh *mesh)
LLStrider<LLVector3> o_vertices;
LLStrider<LLVector3> o_normals;
- LLVertexBuffer *buffer = face->mVertexBuffer;
+ LLVertexBuffer *buffer = face->getVertexBuffer();
buffer->getVertexStrider(o_vertices, mesh->mFaceVertexOffset);
buffer->getNormalStrider(o_normals, mesh->mFaceVertexOffset);
const F32* weights = mesh->getWeights();
- const LLVector3* coords = mesh->getCoords();
- const LLVector3* normals = mesh->getNormals();
+ const LLVector3* coords = (const LLVector3*)mesh->getCoords();
+ const LLVector3* normals = (const LLVector3*)mesh->getNormals();
for (U32 index = 0, index_end = mesh->getNumVertices(); index < index_end; ++index)
{
if( weight != weights[index])
diff --git a/indra/newview/llviewerjointmesh_sse2.cpp b/indra/newview/llviewerjointmesh_sse2.cpp
index a374ba2471..c2296dd569 100644
--- a/indra/newview/llviewerjointmesh_sse2.cpp
+++ b/indra/newview/llviewerjointmesh_sse2.cpp
@@ -90,13 +90,13 @@ void LLViewerJointMesh::updateGeometrySSE2(LLFace *face, LLPolyMesh *mesh)
LLStrider<LLVector3> o_vertices;
LLStrider<LLVector3> o_normals;
- LLVertexBuffer *buffer = face->mVertexBuffer;
+ LLVertexBuffer *buffer = face->getVertexBuffer();
buffer->getVertexStrider(o_vertices, mesh->mFaceVertexOffset);
buffer->getNormalStrider(o_normals, mesh->mFaceVertexOffset);
const F32* weights = mesh->getWeights();
- const LLVector3* coords = mesh->getCoords();
- const LLVector3* normals = mesh->getNormals();
+ const LLVector3* coords = (const LLVector3*)mesh->getCoords();
+ const LLVector3* normals = (const LLVector3*)mesh->getNormals();
for (U32 index = 0, index_end = mesh->getNumVertices(); index < index_end; ++index)
{
if( weight != weights[index])
diff --git a/indra/newview/llviewerjointmesh_vec.cpp b/indra/newview/llviewerjointmesh_vec.cpp
index c9371030ad..6600d01d17 100644
--- a/indra/newview/llviewerjointmesh_vec.cpp
+++ b/indra/newview/llviewerjointmesh_vec.cpp
@@ -46,6 +46,7 @@
// static
void LLViewerJointMesh::updateGeometryVectorized(LLFace *face, LLPolyMesh *mesh)
{
+#if 0
static LLV4Matrix4 sJointMat[32];
LLDynamicArray<LLJointRenderData*>& joint_data = mesh->getReferenceMesh()->mJointRenderData;
S32 j, joint_num, joint_end = joint_data.count();
@@ -92,4 +93,5 @@ void LLViewerJointMesh::updateGeometryVectorized(LLFace *face, LLPolyMesh *mesh)
}
buffer->setBuffer(0);
+#endif
}
diff --git a/indra/newview/llviewerjoystick.cpp b/indra/newview/llviewerjoystick.cpp
index e1dd72dddc..fbf11f20db 100644
--- a/indra/newview/llviewerjoystick.cpp
+++ b/indra/newview/llviewerjoystick.cpp
@@ -758,7 +758,7 @@ void LLViewerJoystick::moveAvatar(bool reset)
sDelta[RX_I] += (cur_delta[RX_I] - sDelta[RX_I]) * time * feather;
sDelta[RY_I] += (cur_delta[RY_I] - sDelta[RY_I]) * time * feather;
- handleRun(fsqrtf(sDelta[Z_I]*sDelta[Z_I] + sDelta[X_I]*sDelta[X_I]));
+ handleRun((F32) sqrt(sDelta[Z_I]*sDelta[Z_I] + sDelta[X_I]*sDelta[X_I]));
// Allow forward/backward movement some priority
if (dom_axis == Z_I)
diff --git a/indra/newview/llviewerkeyboard.cpp b/indra/newview/llviewerkeyboard.cpp
index d7e15e7d6c..1aa9fd8a45 100644
--- a/indra/newview/llviewerkeyboard.cpp
+++ b/indra/newview/llviewerkeyboard.cpp
@@ -40,6 +40,7 @@
#include "llviewerwindow.h"
#include "llvoavatarself.h"
#include "llfloatercamera.h"
+#include "llinitparam.h"
//
// Constants
@@ -53,6 +54,11 @@ const S32 NUDGE_FRAMES = 2;
const F32 ORBIT_NUDGE_RATE = 0.05f; // fraction of normal speed
const F32 YAW_NUDGE_RATE = 0.05f; // fraction of normal speed
+struct LLKeyboardActionRegistry
+: public LLRegistrySingleton<std::string, boost::function<void (EKeystate keystate)>, LLKeyboardActionRegistry>
+{
+};
+
LLViewerKeyboard gViewerKeyboard;
void agent_jump( EKeystate s )
@@ -550,52 +556,50 @@ void start_gesture( EKeystate s )
}
}
-void bind_keyboard_functions()
-{
- gViewerKeyboard.bindNamedFunction("jump", agent_jump);
- gViewerKeyboard.bindNamedFunction("push_down", agent_push_down);
- gViewerKeyboard.bindNamedFunction("push_forward", agent_push_forward);
- gViewerKeyboard.bindNamedFunction("push_backward", agent_push_backward);
- gViewerKeyboard.bindNamedFunction("look_up", agent_look_up);
- gViewerKeyboard.bindNamedFunction("look_down", agent_look_down);
- gViewerKeyboard.bindNamedFunction("toggle_fly", agent_toggle_fly);
- gViewerKeyboard.bindNamedFunction("turn_left", agent_turn_left);
- gViewerKeyboard.bindNamedFunction("turn_right", agent_turn_right);
- gViewerKeyboard.bindNamedFunction("slide_left", agent_slide_left);
- gViewerKeyboard.bindNamedFunction("slide_right", agent_slide_right);
- gViewerKeyboard.bindNamedFunction("spin_around_ccw", camera_spin_around_ccw);
- gViewerKeyboard.bindNamedFunction("spin_around_cw", camera_spin_around_cw);
- gViewerKeyboard.bindNamedFunction("spin_around_ccw_sitting", camera_spin_around_ccw_sitting);
- gViewerKeyboard.bindNamedFunction("spin_around_cw_sitting", camera_spin_around_cw_sitting);
- gViewerKeyboard.bindNamedFunction("spin_over", camera_spin_over);
- gViewerKeyboard.bindNamedFunction("spin_under", camera_spin_under);
- gViewerKeyboard.bindNamedFunction("spin_over_sitting", camera_spin_over_sitting);
- gViewerKeyboard.bindNamedFunction("spin_under_sitting", camera_spin_under_sitting);
- gViewerKeyboard.bindNamedFunction("move_forward", camera_move_forward);
- gViewerKeyboard.bindNamedFunction("move_backward", camera_move_backward);
- gViewerKeyboard.bindNamedFunction("move_forward_sitting", camera_move_forward_sitting);
- gViewerKeyboard.bindNamedFunction("move_backward_sitting", camera_move_backward_sitting);
- gViewerKeyboard.bindNamedFunction("pan_up", camera_pan_up);
- gViewerKeyboard.bindNamedFunction("pan_down", camera_pan_down);
- gViewerKeyboard.bindNamedFunction("pan_left", camera_pan_left);
- gViewerKeyboard.bindNamedFunction("pan_right", camera_pan_right);
- gViewerKeyboard.bindNamedFunction("pan_in", camera_pan_in);
- gViewerKeyboard.bindNamedFunction("pan_out", camera_pan_out);
- gViewerKeyboard.bindNamedFunction("move_forward_fast", camera_move_forward_fast);
- gViewerKeyboard.bindNamedFunction("move_backward_fast", camera_move_backward_fast);
- gViewerKeyboard.bindNamedFunction("edit_avatar_spin_ccw", edit_avatar_spin_ccw);
- gViewerKeyboard.bindNamedFunction("edit_avatar_spin_cw", edit_avatar_spin_cw);
- gViewerKeyboard.bindNamedFunction("edit_avatar_spin_over", edit_avatar_spin_over);
- gViewerKeyboard.bindNamedFunction("edit_avatar_spin_under", edit_avatar_spin_under);
- gViewerKeyboard.bindNamedFunction("edit_avatar_move_forward", edit_avatar_move_forward);
- gViewerKeyboard.bindNamedFunction("edit_avatar_move_backward", edit_avatar_move_backward);
- gViewerKeyboard.bindNamedFunction("stop_moving", stop_moving);
- gViewerKeyboard.bindNamedFunction("start_chat", start_chat);
- gViewerKeyboard.bindNamedFunction("start_gesture", start_gesture);
-}
-
-LLViewerKeyboard::LLViewerKeyboard() :
- mNamedFunctionCount(0)
+#define REGISTER_KEYBOARD_ACTION(KEY, ACTION) LLREGISTER_STATIC(LLKeyboardActionRegistry, KEY, ACTION);
+REGISTER_KEYBOARD_ACTION("jump", agent_jump);
+REGISTER_KEYBOARD_ACTION("push_down", agent_push_down);
+REGISTER_KEYBOARD_ACTION("push_forward", agent_push_forward);
+REGISTER_KEYBOARD_ACTION("push_backward", agent_push_backward);
+REGISTER_KEYBOARD_ACTION("look_up", agent_look_up);
+REGISTER_KEYBOARD_ACTION("look_down", agent_look_down);
+REGISTER_KEYBOARD_ACTION("toggle_fly", agent_toggle_fly);
+REGISTER_KEYBOARD_ACTION("turn_left", agent_turn_left);
+REGISTER_KEYBOARD_ACTION("turn_right", agent_turn_right);
+REGISTER_KEYBOARD_ACTION("slide_left", agent_slide_left);
+REGISTER_KEYBOARD_ACTION("slide_right", agent_slide_right);
+REGISTER_KEYBOARD_ACTION("spin_around_ccw", camera_spin_around_ccw);
+REGISTER_KEYBOARD_ACTION("spin_around_cw", camera_spin_around_cw);
+REGISTER_KEYBOARD_ACTION("spin_around_ccw_sitting", camera_spin_around_ccw_sitting);
+REGISTER_KEYBOARD_ACTION("spin_around_cw_sitting", camera_spin_around_cw_sitting);
+REGISTER_KEYBOARD_ACTION("spin_over", camera_spin_over);
+REGISTER_KEYBOARD_ACTION("spin_under", camera_spin_under);
+REGISTER_KEYBOARD_ACTION("spin_over_sitting", camera_spin_over_sitting);
+REGISTER_KEYBOARD_ACTION("spin_under_sitting", camera_spin_under_sitting);
+REGISTER_KEYBOARD_ACTION("move_forward", camera_move_forward);
+REGISTER_KEYBOARD_ACTION("move_backward", camera_move_backward);
+REGISTER_KEYBOARD_ACTION("move_forward_sitting", camera_move_forward_sitting);
+REGISTER_KEYBOARD_ACTION("move_backward_sitting", camera_move_backward_sitting);
+REGISTER_KEYBOARD_ACTION("pan_up", camera_pan_up);
+REGISTER_KEYBOARD_ACTION("pan_down", camera_pan_down);
+REGISTER_KEYBOARD_ACTION("pan_left", camera_pan_left);
+REGISTER_KEYBOARD_ACTION("pan_right", camera_pan_right);
+REGISTER_KEYBOARD_ACTION("pan_in", camera_pan_in);
+REGISTER_KEYBOARD_ACTION("pan_out", camera_pan_out);
+REGISTER_KEYBOARD_ACTION("move_forward_fast", camera_move_forward_fast);
+REGISTER_KEYBOARD_ACTION("move_backward_fast", camera_move_backward_fast);
+REGISTER_KEYBOARD_ACTION("edit_avatar_spin_ccw", edit_avatar_spin_ccw);
+REGISTER_KEYBOARD_ACTION("edit_avatar_spin_cw", edit_avatar_spin_cw);
+REGISTER_KEYBOARD_ACTION("edit_avatar_spin_over", edit_avatar_spin_over);
+REGISTER_KEYBOARD_ACTION("edit_avatar_spin_under", edit_avatar_spin_under);
+REGISTER_KEYBOARD_ACTION("edit_avatar_move_forward", edit_avatar_move_forward);
+REGISTER_KEYBOARD_ACTION("edit_avatar_move_backward", edit_avatar_move_backward);
+REGISTER_KEYBOARD_ACTION("stop_moving", stop_moving);
+REGISTER_KEYBOARD_ACTION("start_chat", start_chat);
+REGISTER_KEYBOARD_ACTION("start_gesture", start_gesture);
+#undef REGISTER_KEYBOARD_ACTION
+
+LLViewerKeyboard::LLViewerKeyboard()
{
for (S32 i = 0; i < MODE_COUNT; i++)
{
@@ -613,16 +617,6 @@ LLViewerKeyboard::LLViewerKeyboard() :
}
}
-
-void LLViewerKeyboard::bindNamedFunction(const std::string& name, LLKeyFunc func)
-{
- S32 i = mNamedFunctionCount;
- mNamedFunctions[i].mName = name;
- mNamedFunctions[i].mFunction = func;
- mNamedFunctionCount++;
-}
-
-
BOOL LLViewerKeyboard::modeFromString(const std::string& string, S32 *mode)
{
if (string == "FIRST_PERSON")
@@ -695,8 +689,9 @@ BOOL LLViewerKeyboard::handleKey(KEY translated_key, MASK translated_mask, BOOL
BOOL LLViewerKeyboard::bindKey(const S32 mode, const KEY key, const MASK mask, const std::string& function_name)
{
- S32 i,index;
- void (*function)(EKeystate keystate) = NULL;
+ S32 index;
+ typedef boost::function<void(EKeystate)> function_t;
+ function_t function = NULL;
std::string name;
// Allow remapping of F2-F12
@@ -719,13 +714,11 @@ BOOL LLViewerKeyboard::bindKey(const S32 mode, const KEY key, const MASK mask, c
}
// Not remapped, look for a function
- for (i = 0; i < mNamedFunctionCount; i++)
+
+ function_t* result = LLKeyboardActionRegistry::getValue(function_name);
+ if (result)
{
- if (function_name == mNamedFunctions[i].mName)
- {
- function = mNamedFunctions[i].mFunction;
- name = mNamedFunctions[i].mName;
- }
+ function = *result;
}
if (!function)
@@ -755,7 +748,6 @@ BOOL LLViewerKeyboard::bindKey(const S32 mode, const KEY key, const MASK mask, c
mBindings[mode][index].mKey = key;
mBindings[mode][index].mMask = mask;
-// mBindings[mode][index].mName = name;
mBindings[mode][index].mFunction = function;
if (index == mBindingCount[mode])
@@ -764,6 +756,61 @@ BOOL LLViewerKeyboard::bindKey(const S32 mode, const KEY key, const MASK mask, c
return TRUE;
}
+LLViewerKeyboard::KeyBinding::KeyBinding()
+: key("key"),
+ mask("mask"),
+ command("command")
+{}
+
+LLViewerKeyboard::KeyMode::KeyMode(EKeyboardMode _mode)
+: bindings("binding"),
+ mode(_mode)
+{}
+
+LLViewerKeyboard::Keys::Keys()
+: first_person("first_person", KeyMode(MODE_FIRST_PERSON)),
+ third_person("third_person", KeyMode(MODE_THIRD_PERSON)),
+ edit("edit", KeyMode(MODE_EDIT)),
+ sitting("sitting", KeyMode(MODE_SITTING)),
+ edit_avatar("edit_avatar", KeyMode(MODE_EDIT_AVATAR))
+{}
+
+S32 LLViewerKeyboard::loadBindingsXML(const std::string& filename)
+{
+ S32 binding_count = 0;
+ Keys keys;
+ LLSimpleXUIParser parser;
+
+ if (parser.readXUI(filename, keys)
+ && keys.validateBlock())
+ {
+ binding_count += loadBindingMode(keys.first_person);
+ binding_count += loadBindingMode(keys.third_person);
+ binding_count += loadBindingMode(keys.edit);
+ binding_count += loadBindingMode(keys.sitting);
+ binding_count += loadBindingMode(keys.edit_avatar);
+ }
+ return binding_count;
+}
+
+S32 LLViewerKeyboard::loadBindingMode(const LLViewerKeyboard::KeyMode& keymode)
+{
+ S32 binding_count = 0;
+ for (LLInitParam::ParamIterator<KeyBinding>::const_iterator it = keymode.bindings.begin(),
+ end_it = keymode.bindings.end();
+ it != end_it;
+ ++it)
+ {
+ KEY key;
+ MASK mask;
+ LLKeyboard::keyFromString(it->key, &key);
+ LLKeyboard::maskFromString(it->mask, &mask);
+ bindKey(keymode.mode, key, mask, it->command);
+ binding_count++;
+ }
+
+ return binding_count;
+}
S32 LLViewerKeyboard::loadBindings(const std::string& filename)
{
@@ -912,18 +959,18 @@ void LLViewerKeyboard::scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_lev
if (key_down && !repeat)
{
// ...key went down this frame, call function
- (*binding[i].mFunction)( KEYSTATE_DOWN );
+ binding[i].mFunction( KEYSTATE_DOWN );
}
else if (key_up)
{
// ...key went down this frame, call function
- (*binding[i].mFunction)( KEYSTATE_UP );
+ binding[i].mFunction( KEYSTATE_UP );
}
else if (key_level)
{
// ...key held down from previous frame
// Not windows, just call the function.
- (*binding[i].mFunction)( KEYSTATE_LEVEL );
+ binding[i].mFunction( KEYSTATE_LEVEL );
}//if
}//if
}//for
diff --git a/indra/newview/llviewerkeyboard.h b/indra/newview/llviewerkeyboard.h
index 2fa5d5dfa6..ca73212ed1 100644
--- a/indra/newview/llviewerkeyboard.h
+++ b/indra/newview/llviewerkeyboard.h
@@ -28,6 +28,7 @@
#define LL_LLVIEWERKEYBOARD_H
#include "llkeyboard.h" // For EKeystate
+#include "llinitparam.h"
const S32 MAX_NAMED_FUNCTIONS = 100;
const S32 MAX_KEY_BINDINGS = 128; // was 60
@@ -55,26 +56,51 @@ typedef enum e_keyboard_mode
void bind_keyboard_functions();
-
class LLViewerKeyboard
{
public:
+ struct KeyBinding : public LLInitParam::Block<KeyBinding>
+ {
+ Mandatory<std::string> key,
+ mask,
+ command;
+
+ KeyBinding();
+ };
+
+ struct KeyMode : public LLInitParam::Block<KeyMode>
+ {
+ Multiple<KeyBinding> bindings;
+ EKeyboardMode mode;
+ KeyMode(EKeyboardMode mode);
+ };
+
+ struct Keys : public LLInitParam::Block<Keys>
+ {
+ Optional<KeyMode> first_person,
+ third_person,
+ edit,
+ sitting,
+ edit_avatar;
+
+ Keys();
+ };
+
LLViewerKeyboard();
BOOL handleKey(KEY key, MASK mask, BOOL repeated);
- void bindNamedFunction(const std::string& name, LLKeyFunc func);
-
S32 loadBindings(const std::string& filename); // returns number bound, 0 on error
+ S32 loadBindingsXML(const std::string& filename); // returns number bound, 0 on error
EKeyboardMode getMode();
BOOL modeFromString(const std::string& string, S32 *mode); // False on failure
void scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level);
-protected:
+
+private:
+ S32 loadBindingMode(const LLViewerKeyboard::KeyMode& keymode);
BOOL bindKey(const S32 mode, const KEY key, const MASK mask, const std::string& function_name);
- S32 mNamedFunctionCount;
- LLNamedFunction mNamedFunctions[MAX_NAMED_FUNCTIONS];
// Hold all the ugly stuff torn out to make LLKeyboard non-viewer-specific here
S32 mBindingCount[MODE_COUNT];
diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index 48ab122edf..79c6c8db75 100644
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -52,16 +52,21 @@
#include "llviewerregion.h"
#include "llwebsharing.h" // For LLWebSharing::setOpenIDCookie(), *TODO: find a better way to do this!
#include "llfilepicker.h"
-
+#include "llnotifications.h"
+#include "lldir.h"
+#include "lldiriterator.h"
#include "llevent.h" // LLSimpleListener
#include "llnotificationsutil.h"
#include "lluuid.h"
#include "llkeyboard.h"
#include "llmutelist.h"
+#include "llpanelprofile.h"
+#include "llappviewer.h"
//#include "llfirstuse.h"
#include "llwindow.h"
#include "llfloatermediabrowser.h" // for handling window close requests and geometry change requests in media browser windows.
+#include "llfloaterwebcontent.h" // for handling window close requests and geometry change requests in media browser windows.
#include <boost/bind.hpp> // for SkinFolder listener
#include <boost/signals2.hpp>
@@ -290,9 +295,47 @@ public:
};
+class LLViewerMediaWebProfileResponder : public LLHTTPClient::Responder
+{
+LOG_CLASS(LLViewerMediaWebProfileResponder);
+public:
+ LLViewerMediaWebProfileResponder(std::string host)
+ {
+ mHost = host;
+ }
+
+ ~LLViewerMediaWebProfileResponder()
+ {
+ }
+
+ /* virtual */ void completedHeader(U32 status, const std::string& reason, const LLSD& content)
+ {
+ LL_WARNS("MediaAuth") << "status = " << status << ", reason = " << reason << LL_ENDL;
+ LL_WARNS("MediaAuth") << content << LL_ENDL;
+
+ std::string cookie = content["set-cookie"].asString();
+
+ LLViewerMedia::getCookieStore()->setCookiesFromHost(cookie, mHost);
+ }
+
+ void completedRaw(
+ U32 status,
+ const std::string& reason,
+ const LLChannelDescriptors& channels,
+ const LLIOPipe::buffer_ptr_t& buffer)
+ {
+ // This is just here to disable the default behavior (attempting to parse the response as llsd).
+ // We don't care about the content of the response, only the set-cookie header.
+ }
+
+ std::string mHost;
+};
+
+
LLPluginCookieStore *LLViewerMedia::sCookieStore = NULL;
LLURL LLViewerMedia::sOpenIDURL;
std::string LLViewerMedia::sOpenIDCookie;
+LLPluginClassMedia* LLViewerMedia::sSpareBrowserMediaSource = NULL;
static LLViewerMedia::impl_list sViewerMediaImplList;
static LLViewerMedia::impl_id_map sViewerMediaTextureIDMap;
static LLTimer sMediaCreateTimer;
@@ -492,7 +535,7 @@ std::string LLViewerMedia::getCurrentUserAgent()
// Just in case we need to check browser differences in A/B test
// builds.
- std::string channel = gSavedSettings.getString("VersionChannelName");
+ std::string channel = LLVersionInfo::getChannel();
// append our magic version number string to the browser user agent id
// See the HTTP 1.0 and 1.1 specifications for allowed formats:
@@ -742,6 +785,9 @@ void LLViewerMedia::updateMedia(void *dummy_arg)
// Enable/disable the plugin read thread
LLPluginProcessParent::setUseReadThread(gSavedSettings.getBOOL("PluginUseReadThread"));
+ // HACK: we always try to keep a spare running webkit plugin around to improve launch times.
+ createSpareBrowserMediaSource();
+
sAnyMediaShowing = false;
sUpdatedCookies = getCookieStore()->getChangedCookies();
if(!sUpdatedCookies.empty())
@@ -759,6 +805,12 @@ void LLViewerMedia::updateMedia(void *dummy_arg)
pimpl->update();
pimpl->calculateInterest();
}
+
+ // Let the spare media source actually launch
+ if(sSpareBrowserMediaSource)
+ {
+ sSpareBrowserMediaSource->idle();
+ }
// Sort the static instance list using our interest criteria
sViewerMediaImplList.sort(priorityComparitor);
@@ -862,7 +914,7 @@ void LLViewerMedia::updateMedia(void *dummy_arg)
// Set the low priority size for downsampling to approximately the size the texture is displayed at.
{
- F32 approximate_interest_dimension = fsqrtf(pimpl->getInterest());
+ F32 approximate_interest_dimension = (F32) sqrt(pimpl->getInterest());
pimpl->setLowPrioritySizeLimit(llround(approximate_interest_dimension));
}
@@ -1034,6 +1086,26 @@ bool LLViewerMedia::isParcelAudioPlaying()
return (LLViewerMedia::hasParcelAudio() && gAudiop && LLAudioEngine::AUDIO_PLAYING == gAudiop->isInternetStreamPlaying());
}
+void LLViewerMedia::onAuthSubmit(const LLSD& notification, const LLSD& response)
+{
+ LLViewerMediaImpl *impl = LLViewerMedia::getMediaImplFromTextureID(notification["payload"]["media_id"]);
+ if(impl)
+ {
+ LLPluginClassMedia* media = impl->getMediaPlugin();
+ if(media)
+ {
+ if (response["ok"])
+ {
+ media->sendAuthResponse(true, response["username"], response["password"]);
+ }
+ else
+ {
+ media->sendAuthResponse(false, "", "");
+ }
+ }
+ }
+}
+
/////////////////////////////////////////////////////////////////////////////////////////
// static
void LLViewerMedia::clearAllCookies()
@@ -1083,7 +1155,8 @@ void LLViewerMedia::clearAllCookies()
}
// the hard part: iterate over all user directories and delete the cookie file from each one
- while(gDirUtilp->getNextFileInDir(base_dir, "*_*", filename, false))
+ LLDirIterator dir_iter(base_dir, "*_*");
+ while (dir_iter.next(filename))
{
target = base_dir;
target += filename;
@@ -1319,6 +1392,19 @@ void LLViewerMedia::setOpenIDCookie()
// *HACK: Doing this here is nasty, find a better way.
LLWebSharing::instance().setOpenIDCookie(sOpenIDCookie);
+
+ // Do a web profile get so we can store the cookie
+ LLSD headers = LLSD::emptyMap();
+ headers["Accept"] = "*/*";
+ headers["Cookie"] = sOpenIDCookie;
+ headers["User-Agent"] = getCurrentUserAgent();
+
+ std::string profile_url = getProfileURL("");
+ LLURL raw_profile_url( profile_url.c_str() );
+
+ LLHTTPClient::get(profile_url,
+ new LLViewerMediaWebProfileResponder(raw_profile_url.getAuthority()),
+ headers);
}
}
@@ -1400,6 +1486,32 @@ void LLViewerMedia::proxyWindowClosed(const std::string &uuid)
}
}
+/////////////////////////////////////////////////////////////////////////////////////////
+// static
+void LLViewerMedia::createSpareBrowserMediaSource()
+{
+ // If we don't have a spare browser media source, create one.
+ // However, if PluginAttachDebuggerToPlugins is set then don't spawn a spare
+ // SLPlugin process in order to not be confused by an unrelated gdb terminal
+ // popping up at the moment we start a media plugin.
+ if (!sSpareBrowserMediaSource && !gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins"))
+ {
+ // The null owner will keep the browser plugin from fully initializing
+ // (specifically, it keeps LLPluginClassMedia from negotiating a size change,
+ // which keeps MediaPluginWebkit::initBrowserWindow from doing anything until we have some necessary data, like the background color)
+ sSpareBrowserMediaSource = LLViewerMediaImpl::newSourceFromMediaType("text/html", NULL, 0, 0);
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// static
+LLPluginClassMedia* LLViewerMedia::getSpareBrowserMediaSource()
+{
+ LLPluginClassMedia* result = sSpareBrowserMediaSource;
+ sSpareBrowserMediaSource = NULL;
+ return result;
+};
+
bool LLViewerMedia::hasInWorldMedia()
{
if (sInWorldMediaDisabled) return false;
@@ -1636,6 +1748,22 @@ void LLViewerMediaImpl::setMediaType(const std::string& media_type)
LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_type, LLPluginClassMediaOwner *owner /* may be NULL */, S32 default_width, S32 default_height, const std::string target)
{
std::string plugin_basename = LLMIMETypes::implType(media_type);
+ LLPluginClassMedia* media_source = NULL;
+
+ // HACK: we always try to keep a spare running webkit plugin around to improve launch times.
+ // If a spare was already created before PluginAttachDebuggerToPlugins was set, don't use it.
+ if(plugin_basename == "media_plugin_webkit" && !gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins"))
+ {
+ media_source = LLViewerMedia::getSpareBrowserMediaSource();
+ if(media_source)
+ {
+ media_source->setOwner(owner);
+ media_source->setTarget(target);
+ media_source->setSize(default_width, default_height);
+
+ return media_source;
+ }
+ }
if(plugin_basename.empty())
{
@@ -1673,7 +1801,7 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_
}
else
{
- LLPluginClassMedia* media_source = new LLPluginClassMedia(owner);
+ media_source = new LLPluginClassMedia(owner);
media_source->setSize(default_width, default_height);
media_source->setUserDataPath(user_data_path);
media_source->setLanguageCode(LLUI::getLanguage());
@@ -1692,7 +1820,8 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_
media_source->setTarget(target);
- if (media_source->init(launcher_name, plugin_name, gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins")))
+ const std::string plugin_dir = gDirUtilp->getLLPluginDir();
+ if (media_source->init(launcher_name, plugin_dir, plugin_name, gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins")))
{
return media_source;
}
@@ -1753,6 +1882,18 @@ bool LLViewerMediaImpl::initializePlugin(const std::string& media_type)
media_source->focus(mHasFocus);
media_source->setBackgroundColor(mBackgroundColor);
+ if(gSavedSettings.getBOOL("BrowserIgnoreSSLCertErrors"))
+ {
+ media_source->ignore_ssl_cert_errors(true);
+ }
+
+ // the correct way to deal with certs it to load ours from CA.pem and append them to the ones
+ // Qt/WebKit loads from your system location.
+ // Note: This needs the new CA.pem file with the Equifax Secure Certificate Authority
+ // cert at the bottom: (MIIDIDCCAomgAwIBAgIENd70zzANBg)
+ std::string ca_path = gDirUtilp->getExpandedFilename( LL_PATH_APP_SETTINGS, "CA.pem" );
+ media_source->addCertificateFilePath( ca_path );
+
media_source->proxy_setup(gSavedSettings.getBOOL("BrowserProxyEnabled"), gSavedSettings.getString("BrowserProxyAddress"), gSavedSettings.getS32("BrowserProxyPort"));
if(mClearCache)
@@ -1849,6 +1990,18 @@ void LLViewerMediaImpl::setSize(int width, int height)
}
//////////////////////////////////////////////////////////////////////////////////////////
+void LLViewerMediaImpl::showNotification(LLNotificationPtr notify)
+{
+ mNotification = notify;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+void LLViewerMediaImpl::hideNotification()
+{
+ mNotification.reset();
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
void LLViewerMediaImpl::play()
{
// If the media source isn't there, try to initialize it and load an URL.
@@ -2392,23 +2545,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)
@@ -2849,8 +2986,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:
@@ -2913,6 +3050,7 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla
case LLViewerMediaObserver::MEDIA_EVENT_NAVIGATE_BEGIN:
{
LL_DEBUGS("Media") << "MEDIA_EVENT_NAVIGATE_BEGIN, uri is: " << plugin->getNavigateURI() << LL_ENDL;
+ hideNotification();
if(getNavState() == MEDIANAVSTATE_SERVER_SENT)
{
@@ -3003,7 +3141,26 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla
plugin->sendPickFileResponse(response);
}
break;
-
+
+
+ case LLViewerMediaObserver::MEDIA_EVENT_AUTH_REQUEST:
+ {
+ LLNotification::Params auth_request_params;
+ auth_request_params.name = "AuthRequest";
+
+ // pass in host name and realm for site (may be zero length but will always exist)
+ LLSD args;
+ LLURL raw_url( plugin->getAuthURL().c_str() );
+ args["HOST_NAME"] = raw_url.getAuthority();
+ args["REALM"] = plugin->getAuthRealm();
+ auth_request_params.substitutions = args;
+
+ auth_request_params.payload = LLSD().with("media_id", mTextureId);
+ auth_request_params.functor.function = boost::bind(&LLViewerMedia::onAuthSubmit, _1, _2);
+ LLNotifications::instance().add(auth_request_params);
+ };
+ break;
+
case LLViewerMediaObserver::MEDIA_EVENT_CLOSE_REQUEST:
{
std::string uuid = plugin->getClickUUID();
@@ -3019,6 +3176,7 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla
// This close request is directed at another instance
pass_through = false;
LLFloaterMediaBrowser::closeRequest(uuid);
+ LLFloaterWebContent::closeRequest(uuid);
}
}
break;
@@ -3038,6 +3196,7 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla
// This request is directed at another instance
pass_through = false;
LLFloaterMediaBrowser::geometryChanged(uuid, plugin->getGeometryX(), plugin->getGeometryY(), plugin->getGeometryWidth(), plugin->getGeometryHeight());
+ LLFloaterWebContent::geometryChanged(uuid, plugin->getGeometryX(), plugin->getGeometryY(), plugin->getGeometryWidth(), plugin->getGeometryHeight());
}
}
break;
@@ -3521,6 +3680,11 @@ bool LLViewerMediaImpl::isInAgentParcel() const
return result;
}
+LLNotificationPtr LLViewerMediaImpl::getCurrentNotification() const
+{
+ return mNotification;
+}
+
//////////////////////////////////////////////////////////////////////////////////////////
//
// static
diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h
index 4025a4484f..e2e342cc45 100644
--- a/indra/newview/llviewermedia.h
+++ b/indra/newview/llviewermedia.h
@@ -37,6 +37,7 @@
#include "llpluginclassmedia.h"
#include "v4color.h"
+#include "llnotificationptr.h"
#include "llurl.h"
@@ -130,6 +131,8 @@ public:
static bool isParcelMediaPlaying();
static bool isParcelAudioPlaying();
+ static void onAuthSubmit(const LLSD& notification, const LLSD& response);
+
// Clear all cookies for all plugins
static void clearAllCookies();
@@ -155,6 +158,9 @@ public:
static void proxyWindowOpened(const std::string &target, const std::string &uuid);
static void proxyWindowClosed(const std::string &uuid);
+ static void createSpareBrowserMediaSource();
+ static LLPluginClassMedia* getSpareBrowserMediaSource();
+
private:
static void setOpenIDCookie();
static void onTeleportFinished();
@@ -162,6 +168,7 @@ private:
static LLPluginCookieStore *sCookieStore;
static LLURL sOpenIDURL;
static std::string sOpenIDCookie;
+ static LLPluginClassMedia* sSpareBrowserMediaSource;
};
// Implementation functions not exported into header file
@@ -195,6 +202,9 @@ public:
LLPluginClassMedia* getMediaPlugin() { return mMediaSource; }
void setSize(int width, int height);
+ void showNotification(LLNotificationPtr notify);
+ void hideNotification();
+
void play();
void stop();
void pause();
@@ -387,6 +397,9 @@ public:
// Is this media in the agent's parcel?
bool isInAgentParcel() const;
+ // get currently active notification associated with this media instance
+ LLNotificationPtr getCurrentNotification() const;
+
private:
bool isAutoPlayable() const;
bool shouldShowBasedOnClass() const;
@@ -444,7 +457,8 @@ private:
bool mNavigateSuspendedDeferred;
bool mTrustedBrowser;
std::string mTarget;
-
+ LLNotificationPtr mNotification;
+
private:
BOOL mIsUpdated ;
std::list< LLVOVolume* > mObjectList ;
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 ccf3df827d..2ed208bad1 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -37,6 +37,7 @@
// newview includes
#include "llagent.h"
+#include "llagentaccess.h"
#include "llagentcamera.h"
#include "llagentwearables.h"
#include "llagentpilot.h"
@@ -45,7 +46,7 @@
#include "llconsole.h"
#include "lldebugview.h"
#include "llfilepicker.h"
-//#include "llfirstuse.h"
+#include "llfirstuse.h"
#include "llfloaterbuy.h"
#include "llfloaterbuycontents.h"
#include "llbuycurrencyhtml.h"
@@ -76,6 +77,7 @@
#include "llmoveview.h"
#include "llparcel.h"
#include "llrootview.h"
+#include "llsceneview.h"
#include "llselectmgr.h"
#include "llsidetray.h"
#include "llstatusbar.h"
@@ -167,7 +169,6 @@ LLMenuItemCallGL* gBusyMenu = NULL;
// Local prototypes
// File Menu
-const char* upload_pick(void* data);
void handle_compress_image(void*);
@@ -191,6 +192,8 @@ BOOL is_selection_buy_not_take();
S32 selection_price();
BOOL enable_take();
void handle_take();
+void handle_object_show_inspector();
+void handle_avatar_show_inspector();
bool confirm_take(const LLSD& notification, const LLSD& response);
void handle_buy_object(LLSaleInfo sale_info);
@@ -221,8 +224,6 @@ BOOL check_show_xui_names(void *);
// Debug UI
void handle_buy_currency_test(void*);
-void handle_save_to_xml(void*);
-void handle_load_from_xml(void*);
void handle_god_mode(void*);
@@ -454,7 +455,7 @@ void init_menus()
gMenuHolder->childSetLabelArg("Upload Sound", "[COST]", upload_cost);
gMenuHolder->childSetLabelArg("Upload Animation", "[COST]", upload_cost);
gMenuHolder->childSetLabelArg("Bulk Upload", "[COST]", upload_cost);
-
+
gAFKMenu = gMenuBarView->getChild<LLMenuItemCallGL>("Set Away", TRUE);
gBusyMenu = gMenuBarView->getChild<LLMenuItemCallGL>("Set Busy", TRUE);
gAttachSubMenu = gMenuBarView->findChildMenuByName("Attach Object", TRUE);
@@ -516,6 +517,11 @@ class LLAdvancedToggleConsole : public view_listener_t
{
toggle_visibility( (void*)gDebugView->mFastTimerView );
}
+ else if ("scene view" == console_type)
+ {
+ toggle_visibility( (void*)gSceneView);
+ }
+
#if MEM_TRACK_MEM
else if ("memory view" == console_type)
{
@@ -551,13 +557,17 @@ class LLAdvancedCheckConsole : public view_listener_t
{
new_value = get_visibility( (void*)gDebugView->mFastTimerView );
}
+ else if ("scene view" == console_type)
+ {
+ new_value = get_visibility( (void*) gSceneView);
+ }
#if MEM_TRACK_MEM
else if ("memory view" == console_type)
{
new_value = get_visibility( (void*)gDebugView->mMemoryView );
}
#endif
-
+
return new_value;
}
};
@@ -698,7 +708,7 @@ U32 render_type_from_string(std::string render_type)
{
return LLPipeline::RENDER_TYPE_AVATAR;
}
- else if ("surfacePath" == render_type)
+ else if ("surfacePatch" == render_type)
{
return LLPipeline::RENDER_TYPE_TERRAIN;
}
@@ -843,6 +853,51 @@ class LLAdvancedCheckFeature : public view_listener_t
}
};
+void toggle_destination_and_avatar_picker(const LLSD& show)
+{
+ S32 panel_idx = show.isDefined() ? show.asInteger() : -1;
+ LLView* container = gViewerWindow->getRootView()->findChildView("avatar_picker_and_destination_guide_container");
+ if (!container) return;
+
+ LLMediaCtrl* destinations = container->findChild<LLMediaCtrl>("destination_guide_contents");
+ LLMediaCtrl* avatar_picker = container->findChild<LLMediaCtrl>("avatar_picker_contents");
+ if (!destinations || !avatar_picker) return;
+
+ LLButton* avatar_btn = gViewerWindow->getRootView()->getChildView("bottom_tray")->getChild<LLButton>("avatar_btn");
+ LLButton* destination_btn = gViewerWindow->getRootView()->getChildView("bottom_tray")->getChild<LLButton>("destination_btn");
+
+ 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);
+ }
+};
+
//////////////////
// INFO DISPLAY //
@@ -857,6 +912,10 @@ U32 info_display_from_string(std::string info_display)
{
return LLPipeline::RENDER_DEBUG_BBOXES;
}
+ else if ("normals" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_NORMALS;
+ }
else if ("points" == info_display)
{
return LLPipeline::RENDER_DEBUG_POINTS;
@@ -869,6 +928,10 @@ U32 info_display_from_string(std::string info_display)
{
return LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA;
}
+ else if ("physics shapes" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_PHYSICS_SHAPES;
+ }
else if ("occlusion" == info_display)
{
return LLPipeline::RENDER_DEBUG_OCCLUSION;
@@ -877,6 +940,10 @@ U32 info_display_from_string(std::string info_display)
{
return LLPipeline::RENDER_DEBUG_BATCH_SIZE;
}
+ else if ("update type" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_UPDATE_TYPE;
+ }
else if ("texture anim" == info_display)
{
return LLPipeline::RENDER_DEBUG_TEXTURE_ANIM;
@@ -897,6 +964,14 @@ U32 info_display_from_string(std::string info_display)
{
return LLPipeline::RENDER_DEBUG_FACE_AREA;
}
+ else if ("lod info" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_LOD_INFO;
+ }
+ else if ("build queue" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_BUILD_QUEUE;
+ }
else if ("lights" == info_display)
{
return LLPipeline::RENDER_DEBUG_LIGHTS;
@@ -925,6 +1000,10 @@ U32 info_display_from_string(std::string info_display)
{
return LLPipeline::RENDER_DEBUG_AGENT_TARGET;
}
+ else if ("sculpt" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_SCULPTED;
+ }
else
{
return 0;
@@ -1384,37 +1463,6 @@ class LLAdvancedCheckDebugWindowProc : public view_listener_t
// ------------------------------XUI MENU ---------------------------
-//////////////////////
-// LOAD UI FROM XML //
-//////////////////////
-
-
-class LLAdvancedLoadUIFromXML : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- handle_load_from_xml(NULL);
- return true;
-}
-};
-
-
-
-////////////////////
-// SAVE UI TO XML //
-////////////////////
-
-
-class LLAdvancedSaveUIToXML : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- handle_save_to_xml(NULL);
- return true;
-}
-};
-
-
class LLAdvancedSendTestIms : public view_listener_t
{
bool handleEvent(const LLSD& userdata)
@@ -1888,19 +1936,20 @@ class LLAdvancedAgentPilot : public view_listener_t
std::string command = userdata.asString();
if ("start playback" == command)
{
- LLAgentPilot::startPlayback(NULL);
+ gAgentPilot.setNumRuns(-1);
+ gAgentPilot.startPlayback();
}
else if ("stop playback" == command)
{
- LLAgentPilot::stopPlayback(NULL);
+ gAgentPilot.stopPlayback();
}
else if ("start record" == command)
{
- LLAgentPilot::startRecord(NULL);
+ gAgentPilot.startRecord();
}
else if ("stop record" == command)
{
- LLAgentPilot::saveRecord(NULL);
+ gAgentPilot.stopRecord();
}
return true;
@@ -1918,7 +1967,7 @@ class LLAdvancedToggleAgentPilotLoop : public view_listener_t
{
bool handleEvent(const LLSD& userdata)
{
- LLAgentPilot::sLoop = !(LLAgentPilot::sLoop);
+ gAgentPilot.setLoop(!gAgentPilot.getLoop());
return true;
}
};
@@ -1927,7 +1976,7 @@ class LLAdvancedCheckAgentPilotLoop : public view_listener_t
{
bool handleEvent(const LLSD& userdata)
{
- bool new_value = LLAgentPilot::sLoop;
+ bool new_value = gAgentPilot.getLoop();
return new_value;
}
};
@@ -1994,6 +2043,16 @@ class LLAdvancedShowDebugSettings : public view_listener_t
// VIEW ADMIN OPTIONS //
////////////////////////
+class LLAdvancedEnableViewAdminOptions : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ // Don't enable in god mode since the admin menu is shown anyway.
+ // Only enable if the user has set the appropriate debug setting.
+ bool new_value = !gAgent.getAgentAccess().isGodlikeWithoutAdminMenuFakery() && gSavedSettings.getBOOL("AdminMenu");
+ return new_value;
+ }
+};
class LLAdvancedToggleViewAdminOptions : public view_listener_t
{
@@ -2008,7 +2067,7 @@ class LLAdvancedCheckViewAdminOptions : public view_listener_t
{
bool handleEvent(const LLSD& userdata)
{
- bool new_value = check_admin_override(NULL);
+ bool new_value = check_admin_override(NULL) || gAgent.isGodlike();
return new_value;
}
};
@@ -2045,7 +2104,7 @@ class LLAdvancedEnableRenderDeferred: public view_listener_t
{
bool handleEvent(const LLSD& userdata)
{
- bool new_value = gSavedSettings.getBOOL("RenderUseFBO") && LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_WINDLIGHT > 0) &&
+ bool new_value = gGLManager.mHasFramebufferObject && LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_WINDLIGHT) > 1 &&
LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_AVATAR) > 0;
return new_value;
}
@@ -2058,7 +2117,8 @@ class LLAdvancedEnableRenderDeferredOptions: public view_listener_t
{
bool handleEvent(const LLSD& userdata)
{
- bool new_value = gSavedSettings.getBOOL("RenderUseFBO") && gSavedSettings.getBOOL("RenderDeferred");
+ bool new_value = gGLManager.mHasFramebufferObject && LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_WINDLIGHT) > 1 &&
+ LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_AVATAR) > 0 && gSavedSettings.getBOOL("RenderDeferred");
return new_value;
}
};
@@ -2823,7 +2883,7 @@ class LLObjectMute : public view_listener_t
}
LLMute mute(id, name, type);
- if (LLMuteList::getInstance()->isMuted(mute.mID, mute.mName))
+ if (LLMuteList::getInstance()->isMuted(mute.mID))
{
LLMuteList::getInstance()->remove(mute);
}
@@ -3608,6 +3668,15 @@ class LLEnableEditShape : public view_listener_t
}
};
+class LLEnableEditPhysics : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ //return gAgentWearables.isWearableModifiable(LLWearableType::WT_SHAPE, 0);
+ return TRUE;
+ }
+};
+
bool is_object_sittable()
{
LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
@@ -4160,6 +4229,11 @@ class LLObjectEnableReturn : public view_listener_t
{
bool handleEvent(const LLSD& userdata)
{
+ if (LLSelectMgr::getInstance()->getSelection()->isEmpty())
+ {
+ // Do not enable if nothing selected
+ return false;
+ }
#ifdef HACKED_GODLIKE_VIEWER
bool new_value = true;
#else
@@ -4184,9 +4258,9 @@ class LLObjectEnableReturn : public view_listener_t
{
virtual bool apply(LLViewerObject* obj)
{
- return (obj->isOverAgentOwnedLand() ||
- obj->isOverGroupOwnedLand() ||
- obj->permModify());
+ return
+ obj->permModify() ||
+ obj->isReturnable();
}
} func;
const bool firstonly = true;
@@ -4312,6 +4386,33 @@ void handle_take()
}
}
+void handle_object_show_inspector()
+{
+ LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
+ LLViewerObject* objectp = selection->getFirstRootObject(TRUE);
+ if (!objectp)
+ {
+ return;
+ }
+
+ LLSD params;
+ params["object_id"] = objectp->getID();
+ LLFloaterReg::showInstance("inspect_object", params);
+}
+
+void handle_avatar_show_inspector()
+{
+ LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() );
+ if(avatar)
+ {
+ LLSD params;
+ params["avatar_id"] = avatar->getID();
+ LLFloaterReg::showInstance("inspect_avatar", params);
+ }
+}
+
+
+
bool confirm_take(const LLSD& notification, const LLSD& response)
{
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
@@ -4737,110 +4838,6 @@ class LLToolsSelectNextPart : public view_listener_t
}
};
-// in order to link, all objects must have the same owner, and the
-// agent must have the ability to modify all of the objects. However,
-// we're not answering that question with this method. The question
-// we're answering is: does the user have a reasonable expectation
-// that a link operation should work? If so, return true, false
-// otherwise. this allows the handle_link method to more finely check
-// the selection and give an error message when the uer has a
-// reasonable expectation for the link to work, but it will fail.
-class LLToolsEnableLink : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = false;
- // check if there are at least 2 objects selected, and that the
- // user can modify at least one of the selected objects.
-
- // in component mode, can't link
- if (!gSavedSettings.getBOOL("EditLinkedParts"))
- {
- if(LLSelectMgr::getInstance()->selectGetAllRootsValid() && LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() >= 2)
- {
- struct f : public LLSelectedObjectFunctor
- {
- virtual bool apply(LLViewerObject* object)
- {
- return object->permModify();
- }
- } func;
- const bool firstonly = true;
- new_value = LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, firstonly);
- }
- }
- return new_value;
- }
-};
-
-class LLToolsLink : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- if(!LLSelectMgr::getInstance()->selectGetAllRootsValid())
- {
- LLNotificationsUtil::add("UnableToLinkWhileDownloading");
- return true;
- }
-
- S32 object_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount();
- if (object_count > MAX_CHILDREN_PER_TASK + 1)
- {
- LLSD args;
- args["COUNT"] = llformat("%d", object_count);
- int max = MAX_CHILDREN_PER_TASK+1;
- args["MAX"] = llformat("%d", max);
- LLNotificationsUtil::add("UnableToLinkObjects", args);
- return true;
- }
-
- if(LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() < 2)
- {
- LLNotificationsUtil::add("CannotLinkIncompleteSet");
- return true;
- }
- if(!LLSelectMgr::getInstance()->selectGetRootsModify())
- {
- LLNotificationsUtil::add("CannotLinkModify");
- return true;
- }
- LLUUID owner_id;
- std::string owner_name;
- if(!LLSelectMgr::getInstance()->selectGetOwner(owner_id, owner_name))
- {
- // we don't actually care if you're the owner, but novices are
- // the most likely to be stumped by this one, so offer the
- // easiest and most likely solution.
- LLNotificationsUtil::add("CannotLinkDifferentOwners");
- return true;
- }
- LLSelectMgr::getInstance()->sendLink();
- return true;
- }
-};
-
-class LLToolsEnableUnlink : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLViewerObject* first_editable_object = LLSelectMgr::getInstance()->getSelection()->getFirstEditableObject();
- bool new_value = LLSelectMgr::getInstance()->selectGetAllRootsValid() &&
- first_editable_object &&
- !first_editable_object->isAttachment();
- return new_value;
- }
-};
-
-class LLToolsUnlink : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLSelectMgr::getInstance()->sendDelink();
- return true;
- }
-};
-
-
class LLToolsStopAllAnimations : public view_listener_t
{
bool handleEvent(const LLSD& userdata)
@@ -5566,6 +5563,11 @@ void handle_edit_shape()
LLSideTray::getInstance()->showPanel("sidepanel_appearance", LLSD().with("type", "edit_shape"));
}
+void handle_edit_physics()
+{
+ LLSideTray::getInstance()->showPanel("sidepanel_appearance", LLSD().with("type", "edit_physics"));
+}
+
void handle_report_abuse()
{
// Prevent menu from appearing in screen shot.
@@ -5602,20 +5604,50 @@ class LLShowHelp : public view_listener_t
}
};
-class LLShowSidetrayPanel : public view_listener_t
+class LLToggleHelp : public view_listener_t
{
bool handleEvent(const LLSD& userdata)
{
- std::string panel_name = userdata.asString();
- // Toggle the panel
- if (!LLSideTray::getInstance()->isPanelActive(panel_name))
+ LLFloater* help_browser = (LLFloaterReg::findInstance("help_browser"));
+ if (help_browser && help_browser->isInVisibleChain())
{
- // LLFloaterInventory::showAgentInventory();
- LLSideTray::getInstance()->showPanel(panel_name, LLSD());
+ help_browser->closeFloater();
}
else
{
- LLSideTray::getInstance()->collapseSideBar();
+ std::string help_topic = userdata.asString();
+ LLViewerHelp* vhelp = LLViewerHelp::getInstance();
+ vhelp->showTopic(help_topic);
+ }
+ return true;
+ }
+};
+
+class LLToggleSpeak : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLVoiceClient::getInstance()->toggleUserPTTState();
+ return true;
+ }
+};
+class LLShowSidetrayPanel : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string panel_name = userdata.asString();
+
+ LLPanel* panel = LLSideTray::getInstance()->getPanel(panel_name);
+ if (panel)
+ {
+ if (panel->isInVisibleChain())
+ {
+ LLSideTray::getInstance()->hidePanel(panel_name);
+ }
+ else
+ {
+ LLSideTray::getInstance()->showPanel(panel_name);
+ }
}
return true;
}
@@ -5744,6 +5776,44 @@ class LLShowAgentProfile : public view_listener_t
}
};
+class LLToggleAgentProfile : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLUUID agent_id;
+ if (userdata.asString() == "agent")
+ {
+ agent_id = gAgent.getID();
+ }
+ else if (userdata.asString() == "hit object")
+ {
+ LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+ if (objectp)
+ {
+ agent_id = objectp->getID();
+ }
+ }
+ else
+ {
+ agent_id = userdata.asUUID();
+ }
+
+ LLVOAvatar* avatar = find_avatar_from_object(agent_id);
+ if (avatar)
+ {
+ if (!LLAvatarActions::profileVisible(avatar->getID()))
+ {
+ LLAvatarActions::showProfile(avatar->getID());
+ }
+ else
+ {
+ LLAvatarActions::hideProfile(avatar->getID());
+ }
+ }
+ return true;
+ }
+};
+
class LLLandEdit : public view_listener_t
{
bool handleEvent(const LLSD& userdata)
@@ -6382,12 +6452,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();
@@ -6518,16 +6588,6 @@ class LLToggleControl : public view_listener_t
std::string control_name = userdata.asString();
BOOL checked = gSavedSettings.getBOOL( control_name );
gSavedSettings.setBOOL( control_name, !checked );
-
- // Doubleclick actions - there can be only one
- if ((control_name == "DoubleClickAutoPilot") && !checked)
- {
- gSavedSettings.setBOOL( "DoubleClickTeleport", FALSE );
- }
- else if ((control_name == "DoubleClickTeleport") && !checked)
- {
- gSavedSettings.setBOOL( "DoubleClickAutoPilot", FALSE );
- }
return true;
}
};
@@ -7152,7 +7212,13 @@ LLViewerMenuHolderGL::LLViewerMenuHolderGL(const LLViewerMenuHolderGL::Params& p
BOOL LLViewerMenuHolderGL::hideMenus()
{
- BOOL handled = LLMenuHolderGL::hideMenus();
+ BOOL handled = FALSE;
+
+ if (LLMenuHolderGL::hideMenus())
+ {
+ LLToolPie::instance().blockClickToWalk();
+ handled = TRUE;
+ }
// drop pie menu selection
mParcelSelection = NULL;
@@ -7183,44 +7249,6 @@ const LLRect LLViewerMenuHolderGL::getMenuRect() const
return LLRect(0, getRect().getHeight() - MENU_BAR_HEIGHT, getRect().getWidth(), STATUS_BAR_HEIGHT);
}
-void handle_save_to_xml(void*)
-{
- LLFloater* frontmost = gFloaterView->getFrontmost();
- if (!frontmost)
- {
- LLNotificationsUtil::add("NoFrontmostFloater");
- return;
- }
-
- std::string default_name = "floater_";
- default_name += frontmost->getTitle();
- default_name += ".xml";
-
- LLStringUtil::toLower(default_name);
- LLStringUtil::replaceChar(default_name, ' ', '_');
- LLStringUtil::replaceChar(default_name, '/', '_');
- LLStringUtil::replaceChar(default_name, ':', '_');
- LLStringUtil::replaceChar(default_name, '"', '_');
-
- LLFilePicker& picker = LLFilePicker::instance();
- if (picker.getSaveFile(LLFilePicker::FFSAVE_XML, default_name))
- {
- std::string filename = picker.getFirstFile();
- LLUICtrlFactory::getInstance()->saveToXML(frontmost, filename);
- }
-}
-
-void handle_load_from_xml(void*)
-{
- LLFilePicker& picker = LLFilePicker::instance();
- if (picker.getOpenFile(LLFilePicker::FFLOAD_XML))
- {
- std::string filename = picker.getFirstFile();
- LLFloater* floater = new LLFloater(LLSD());
- floater->buildFromFile(filename);
- }
-}
-
void handle_web_browser_test(const LLSD& param)
{
std::string url = param.asString();
@@ -7231,6 +7259,12 @@ void handle_web_browser_test(const LLSD& param)
LLWeb::loadURLInternal(url);
}
+void handle_web_content_test(const LLSD& param)
+{
+ std::string url = param.asString();
+ LLWeb::loadWebURLInternal(url);
+}
+
void handle_buy_currency_test(void*)
{
std::string url =
@@ -7354,6 +7388,11 @@ class LLViewToggleBeacon : public view_listener_t
LLPipeline::toggleRenderPhysicalBeacons(NULL);
gSavedSettings.setBOOL( "physicalbeacon", LLPipeline::getRenderPhysicalBeacons(NULL) );
}
+ else if (beacon == "moapbeacon")
+ {
+ LLPipeline::toggleRenderMOAPBeacons(NULL);
+ gSavedSettings.setBOOL( "moapbeacon", LLPipeline::getRenderMOAPBeacons(NULL) );
+ }
else if (beacon == "soundsbeacon")
{
LLPipeline::toggleRenderSoundBeacons(NULL);
@@ -7413,6 +7452,11 @@ class LLViewCheckBeaconEnabled : public view_listener_t
new_value = gSavedSettings.getBOOL( "scriptsbeacon");
LLPipeline::setRenderScriptedBeacons(new_value);
}
+ else if (beacon == "moapbeacon")
+ {
+ new_value = gSavedSettings.getBOOL( "moapbeacon");
+ LLPipeline::setRenderMOAPBeacons(new_value);
+ }
else if (beacon == "physicalbeacon")
{
new_value = gSavedSettings.getBOOL( "physicalbeacon");
@@ -7833,9 +7877,11 @@ void initialize_menus()
view_listener_t::addMenu(new LLEditEnableTakeOff(), "Edit.EnableTakeOff");
view_listener_t::addMenu(new LLEditEnableCustomizeAvatar(), "Edit.EnableCustomizeAvatar");
view_listener_t::addMenu(new LLEnableEditShape(), "Edit.EnableEditShape");
+ view_listener_t::addMenu(new LLEnableEditPhysics(), "Edit.EnableEditPhysics");
commit.add("CustomizeAvatar", boost::bind(&handle_customize_avatar));
commit.add("EditOutfit", boost::bind(&handle_edit_outfit));
commit.add("EditShape", boost::bind(&handle_edit_shape));
+ commit.add("EditPhysics", boost::bind(&handle_edit_physics));
// View menu
view_listener_t::addMenu(new LLViewMouselook(), "View.Mouselook");
@@ -7861,6 +7907,9 @@ void initialize_menus()
view_listener_t::addMenu(new LLViewCheckRenderType(), "View.CheckRenderType");
view_listener_t::addMenu(new LLViewCheckHUDAttachments(), "View.CheckHUDAttachments");
+ // Me > Movement
+ view_listener_t::addMenu(new LLAdvancedAgentFlyingInfo(), "Agent.getFlying");
+
// World menu
commit.add("World.Chat", boost::bind(&handle_chat, (void*)NULL));
view_listener_t::addMenu(new LLWorldAlwaysRun(), "World.AlwaysRun");
@@ -7897,8 +7946,8 @@ void initialize_menus()
view_listener_t::addMenu(new LLToolsSnapObjectXY(), "Tools.SnapObjectXY");
view_listener_t::addMenu(new LLToolsUseSelectionForGrid(), "Tools.UseSelectionForGrid");
view_listener_t::addMenu(new LLToolsSelectNextPart(), "Tools.SelectNextPart");
- view_listener_t::addMenu(new LLToolsLink(), "Tools.Link");
- view_listener_t::addMenu(new LLToolsUnlink(), "Tools.Unlink");
+ commit.add("Tools.Link", boost::bind(&LLSelectMgr::linkObjects, LLSelectMgr::getInstance()));
+ commit.add("Tools.Unlink", boost::bind(&LLSelectMgr::unlinkObjects, LLSelectMgr::getInstance()));
view_listener_t::addMenu(new LLToolsStopAllAnimations(), "Tools.StopAllAnimations");
view_listener_t::addMenu(new LLToolsReleaseKeys(), "Tools.ReleaseKeys");
view_listener_t::addMenu(new LLToolsEnableReleaseKeys(), "Tools.EnableReleaseKeys");
@@ -7911,8 +7960,8 @@ void initialize_menus()
view_listener_t::addMenu(new LLToolsEnableToolNotPie(), "Tools.EnableToolNotPie");
view_listener_t::addMenu(new LLToolsEnableSelectNextPart(), "Tools.EnableSelectNextPart");
- view_listener_t::addMenu(new LLToolsEnableLink(), "Tools.EnableLink");
- view_listener_t::addMenu(new LLToolsEnableUnlink(), "Tools.EnableUnlink");
+ enable.add("Tools.EnableLink", boost::bind(&LLSelectMgr::enableLinkObjects, LLSelectMgr::getInstance()));
+ enable.add("Tools.EnableUnlink", boost::bind(&LLSelectMgr::enableUnlinkObjects, LLSelectMgr::getInstance()));
view_listener_t::addMenu(new LLToolsEnableBuyOrTake(), "Tools.EnableBuyOrTake");
enable.add("Tools.EnableTakeCopy", boost::bind(&enable_object_take_copy));
enable.add("Tools.VisibleBuyObject", boost::bind(&tools_visible_buy_object));
@@ -7934,9 +7983,6 @@ void initialize_menus()
// Advanced Other Settings
view_listener_t::addMenu(new LLAdvancedClearGroupCache(), "Advanced.ClearGroupCache");
-
- // Advanced > Shortcuts
- view_listener_t::addMenu(new LLAdvancedAgentFlyingInfo(), "Agent.getFlying");
// Advanced > Render > Types
view_listener_t::addMenu(new LLAdvancedToggleRenderType(), "Advanced.ToggleRenderType");
@@ -7981,7 +8027,8 @@ void initialize_menus()
view_listener_t::addMenu(new LLAdvancedDumpRegionObjectCache(), "Advanced.DumpRegionObjectCache");
// Advanced > UI
- commit.add("Advanced.WebBrowserTest", boost::bind(&handle_web_browser_test, _2));
+ commit.add("Advanced.WebBrowserTest", boost::bind(&handle_web_browser_test, _2)); // sigh! this one opens the MEDIA browser
+ commit.add("Advanced.WebContentTest", boost::bind(&handle_web_content_test, _2)); // this one opens the Web Content floater
view_listener_t::addMenu(new LLAdvancedBuyCurrencyTest(), "Advanced.BuyCurrencyTest");
view_listener_t::addMenu(new LLAdvancedDumpSelectMgr(), "Advanced.DumpSelectMgr");
view_listener_t::addMenu(new LLAdvancedDumpInventory(), "Advanced.DumpInventory");
@@ -8006,8 +8053,6 @@ void initialize_menus()
// Advanced > XUI
commit.add("Advanced.ReloadColorSettings", boost::bind(&LLUIColorTable::loadFromSettings, LLUIColorTable::getInstance()));
- view_listener_t::addMenu(new LLAdvancedLoadUIFromXML(), "Advanced.LoadUIFromXML");
- view_listener_t::addMenu(new LLAdvancedSaveUIToXML(), "Advanced.SaveUIToXML");
view_listener_t::addMenu(new LLAdvancedToggleXUINames(), "Advanced.ToggleXUINames");
view_listener_t::addMenu(new LLAdvancedCheckXUINames(), "Advanced.CheckXUINames");
view_listener_t::addMenu(new LLAdvancedSendTestIms(), "Advanced.SendTestIMs");
@@ -8068,6 +8113,7 @@ void initialize_menus()
view_listener_t::addMenu(new LLAdvancedCheckShowObjectUpdates(), "Advanced.CheckShowObjectUpdates");
view_listener_t::addMenu(new LLAdvancedCompressImage(), "Advanced.CompressImage");
view_listener_t::addMenu(new LLAdvancedShowDebugSettings(), "Advanced.ShowDebugSettings");
+ view_listener_t::addMenu(new LLAdvancedEnableViewAdminOptions(), "Advanced.EnableViewAdminOptions");
view_listener_t::addMenu(new LLAdvancedToggleViewAdminOptions(), "Advanced.ToggleViewAdminOptions");
view_listener_t::addMenu(new LLAdvancedCheckViewAdminOptions(), "Advanced.CheckViewAdminOptions");
view_listener_t::addMenu(new LLAdvancedRequestAdminStatus(), "Advanced.RequestAdminStatus");
@@ -8113,6 +8159,7 @@ void initialize_menus()
view_listener_t::addMenu(new LLAvatarVisibleDebug(), "Avatar.VisibleDebug");
view_listener_t::addMenu(new LLAvatarInviteToGroup(), "Avatar.InviteToGroup");
commit.add("Avatar.Eject", boost::bind(&handle_avatar_eject, LLSD()));
+ commit.add("Avatar.ShowInspector", boost::bind(&handle_avatar_show_inspector));
view_listener_t::addMenu(new LLAvatarSendIM(), "Avatar.SendIM");
view_listener_t::addMenu(new LLAvatarCall(), "Avatar.Call");
enable.add("Avatar.EnableCall", boost::bind(&LLAvatarActions::canCall));
@@ -8140,6 +8187,7 @@ void initialize_menus()
commit.add("Object.Inspect", boost::bind(&handle_object_inspect));
commit.add("Object.Open", boost::bind(&handle_object_open));
commit.add("Object.Take", boost::bind(&handle_take));
+ commit.add("Object.ShowInspector", boost::bind(&handle_object_show_inspector));
enable.add("Object.EnableOpen", boost::bind(&enable_object_open));
enable.add("Object.EnableTouch", boost::bind(&enable_object_touch, _1));
enable.add("Object.EnableDelete", boost::bind(&enable_object_delete));
@@ -8178,8 +8226,11 @@ void initialize_menus()
commit.add("ReportAbuse", boost::bind(&handle_report_abuse));
commit.add("BuyCurrency", boost::bind(&handle_buy_currency));
view_listener_t::addMenu(new LLShowHelp(), "ShowHelp");
+ view_listener_t::addMenu(new LLToggleHelp(), "ToggleHelp");
+ view_listener_t::addMenu(new LLToggleSpeak(), "ToggleSpeak");
view_listener_t::addMenu(new LLPromptShowURL(), "PromptShowURL");
view_listener_t::addMenu(new LLShowAgentProfile(), "ShowAgentProfile");
+ view_listener_t::addMenu(new LLToggleAgentProfile(), "ToggleAgentProfile");
view_listener_t::addMenu(new LLToggleControl(), "ToggleControl");
view_listener_t::addMenu(new LLCheckControl(), "CheckControl");
view_listener_t::addMenu(new LLGoToObject(), "GoToObject");
@@ -8199,4 +8250,7 @@ void initialize_menus()
view_listener_t::addMenu(new LLEditableSelectedMono(), "EditableSelectedMono");
view_listener_t::addMenu(new LLToggleUIHints(), "ToggleUIHints");
+
+ commit.add("Destination.show", boost::bind(&toggle_destination_and_avatar_picker, 0));
+ commit.add("Avatar.show", boost::bind(&toggle_destination_and_avatar_picker, 1));
}
diff --git a/indra/newview/llviewermenu.h b/indra/newview/llviewermenu.h
index 87cb4efbc4..b4e239b0cd 100644
--- a/indra/newview/llviewermenu.h
+++ b/indra/newview/llviewermenu.h
@@ -126,6 +126,8 @@ bool enable_pay_object();
bool enable_buy_object();
bool handle_go_to();
+void toggle_destination_and_avatar_picker(const LLSD& show);
+
// Export to XML or Collada
void handle_export_selected( void * );
diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp
index 237aa39e6e..37640ad0d4 100644
--- a/indra/newview/llviewermenufile.cpp
+++ b/indra/newview/llviewermenufile.cpp
@@ -34,6 +34,7 @@
#include "llfilepicker.h"
#include "llfloaterreg.h"
#include "llbuycurrencyhtml.h"
+#include "llfloatermodelpreview.h"
#include "llfloatersnapshot.h"
#include "llimage.h"
#include "llimagebmp.h"
@@ -52,13 +53,14 @@
#include "llvfs.h"
#include "llviewerinventory.h"
#include "llviewermenu.h" // gMenuHolder
+#include "llviewerparcelmgr.h"
#include "llviewerregion.h"
#include "llviewerstats.h"
#include "llviewerwindow.h"
#include "llappviewer.h"
#include "lluploaddialog.h"
#include "lltrans.h"
-
+#include "llfloaterbuycurrency.h"
// linden libraries
#include "llassetuploadresponders.h"
@@ -66,6 +68,7 @@
#include "llhttpclient.h"
#include "llnotificationsutil.h"
#include "llsdserialize.h"
+#include "llsdutil.h"
#include "llstring.h"
#include "lltransactiontypes.h"
#include "lluuid.h"
@@ -84,6 +87,99 @@ class LLFileEnableUpload : public view_listener_t
}
};
+class LLFileEnableUploadModel : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ return true;
+ }
+};
+
+class LLMeshEnabled : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ return gSavedSettings.getBOOL("MeshEnabled");
+ }
+};
+
+class LLMeshUploadVisible : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ return gSavedSettings.getBOOL("MeshEnabled") &&
+ LLViewerParcelMgr::getInstance()->allowAgentBuild() &&
+ !gAgent.getRegion()->getCapability("ObjectAdd").empty();
+ }
+};
+
+LLMutex* LLFilePickerThread::sMutex = NULL;
+std::queue<LLFilePickerThread*> LLFilePickerThread::sDeadQ;
+
+void LLFilePickerThread::getFile()
+{
+#if LL_WINDOWS
+ start();
+#else
+ run();
+#endif
+}
+
+//virtual
+void LLFilePickerThread::run()
+{
+ LLFilePicker picker;
+#if LL_WINDOWS
+ if (picker.getOpenFile(mFilter, false))
+ {
+ mFile = picker.getFirstFile();
+ }
+#else
+ if (picker.getOpenFile(mFilter, true))
+ {
+ mFile = picker.getFirstFile();
+ }
+#endif
+
+ {
+ LLMutexLock lock(sMutex);
+ sDeadQ.push(this);
+ }
+
+}
+
+//static
+void LLFilePickerThread::initClass()
+{
+ sMutex = new LLMutex(NULL);
+}
+
+//static
+void LLFilePickerThread::cleanupClass()
+{
+ clearDead();
+
+ delete sMutex;
+ sMutex = NULL;
+}
+
+//static
+void LLFilePickerThread::clearDead()
+{
+ if (!sDeadQ.empty())
+ {
+ LLMutexLock lock(sMutex);
+ while (!sDeadQ.empty())
+ {
+ LLFilePickerThread* thread = sDeadQ.front();
+ thread->notify(thread->mFile);
+ delete thread;
+ sDeadQ.pop();
+ }
+ }
+}
+
+
//============================================================================
#if LL_WINDOWS
@@ -97,6 +193,7 @@ static std::string XML_EXTENSIONS = "xml";
static std::string SLOBJECT_EXTENSIONS = "slobject";
#endif
static std::string ALL_FILE_EXTENSIONS = "*.*";
+static std::string MODEL_EXTENSIONS = "dae";
std::string build_extensions_string(LLFilePicker::ELoadFilter filter)
{
@@ -111,6 +208,8 @@ std::string build_extensions_string(LLFilePicker::ELoadFilter filter)
return ANIM_EXTENSIONS;
case LLFilePicker::FFLOAD_SLOBJECT:
return SLOBJECT_EXTENSIONS;
+ case LLFilePicker::FFLOAD_MODEL:
+ return MODEL_EXTENSIONS;
#ifdef _CORY_TESTING
case LLFilePicker::FFLOAD_GEOMETRY:
return GEOMETRY_EXTENSIONS;
@@ -254,6 +353,20 @@ class LLFileUploadImage : public view_listener_t
}
};
+class LLFileUploadModel : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) LLFloaterReg::getInstance("upload_model");
+ if (fmp)
+ {
+ fmp->loadModel(3);
+ }
+
+ return TRUE;
+ }
+};
+
class LLFileUploadSound : public view_listener_t
{
bool handleEvent(const LLSD& userdata)
@@ -315,10 +428,21 @@ class LLFileUploadBulk : public view_listener_t
LLAssetStorage::LLStoreAssetCallback callback = NULL;
S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload();
void *userdata = NULL;
- upload_new_resource(filename, asset_name, asset_name, 0, LLFolderType::FT_NONE, LLInventoryType::IT_NONE,
- LLFloaterPerms::getNextOwnerPerms(), LLFloaterPerms::getGroupPerms(), LLFloaterPerms::getEveryonePerms(),
- display_name,
- callback, expected_upload_cost, userdata);
+
+ upload_new_resource(
+ filename,
+ asset_name,
+ asset_name,
+ 0,
+ LLFolderType::FT_NONE,
+ LLInventoryType::IT_NONE,
+ LLFloaterPerms::getNextOwnerPerms(),
+ LLFloaterPerms::getGroupPerms(),
+ LLFloaterPerms::getEveryonePerms(),
+ display_name,
+ callback,
+ expected_upload_cost,
+ userdata);
// *NOTE: Ew, we don't iterate over the file list here,
// we handle the next files in upload_done_callback()
@@ -473,17 +597,20 @@ void handle_compress_image(void*)
}
}
-void upload_new_resource(const std::string& src_filename, std::string name,
- std::string desc, S32 compression_info,
- LLFolderType::EType destination_folder_type,
- LLInventoryType::EType inv_type,
- U32 next_owner_perms,
- U32 group_perms,
- U32 everyone_perms,
- const std::string& display_name,
- LLAssetStorage::LLStoreAssetCallback callback,
- S32 expected_upload_cost,
- void *userdata)
+LLUUID upload_new_resource(
+ const std::string& src_filename,
+ std::string name,
+ std::string desc,
+ S32 compression_info,
+ LLFolderType::EType destination_folder_type,
+ LLInventoryType::EType inv_type,
+ U32 next_owner_perms,
+ U32 group_perms,
+ U32 everyone_perms,
+ const std::string& display_name,
+ LLAssetStorage::LLStoreAssetCallback callback,
+ S32 expected_upload_cost,
+ void *userdata)
{
// Generate the temporary UUID.
std::string filename = gDirUtilp->getTempFilename();
@@ -493,6 +620,7 @@ void upload_new_resource(const std::string& src_filename, std::string name,
LLSD args;
std::string exten = gDirUtilp->getExtension(src_filename);
+ U32 codec = LLImageBase::getCodecFromExtension(exten);
LLAssetType::EType asset_type = LLAssetType::AT_NONE;
std::string error_message;
@@ -507,69 +635,23 @@ void upload_new_resource(const std::string& src_filename, std::string name,
"No file extension for the file: '%s'\nPlease make sure the file has a correct file extension",
short_name.c_str());
args["FILE"] = short_name;
- upload_error(error_message, "NofileExtension", filename, args);
- return;
+ upload_error(error_message, "NoFileExtension", filename, args);
+ return LLUUID();
}
- else if( exten == "bmp")
+ else if (codec != IMG_CODEC_INVALID)
{
+ // It's an image file, the upload procedure is the same for all
asset_type = LLAssetType::AT_TEXTURE;
- if (!LLViewerTextureList::createUploadFile(src_filename,
- filename,
- IMG_CODEC_BMP ))
+ if (!LLViewerTextureList::createUploadFile(src_filename, filename, codec ))
{
error_message = llformat( "Problem with file %s:\n\n%s\n",
- src_filename.c_str(), LLImage::getLastError().c_str());
- args["FILE"] = src_filename;
- args["ERROR"] = LLImage::getLastError();
- upload_error(error_message, "ProblemWithFile", filename, args);
- return;
- }
- }
- else if( exten == "tga")
- {
- asset_type = LLAssetType::AT_TEXTURE;
- if (!LLViewerTextureList::createUploadFile(src_filename,
- filename,
- IMG_CODEC_TGA ))
- {
- error_message = llformat("Problem with file %s:\n\n%s\n",
- src_filename.c_str(), LLImage::getLastError().c_str());
- args["FILE"] = src_filename;
- args["ERROR"] = LLImage::getLastError();
- upload_error(error_message, "ProblemWithFile", filename, args);
- return;
- }
- }
- else if( exten == "jpg" || exten == "jpeg")
- {
- asset_type = LLAssetType::AT_TEXTURE;
- if (!LLViewerTextureList::createUploadFile(src_filename,
- filename,
- IMG_CODEC_JPEG ))
- {
- error_message = llformat("Problem with file %s:\n\n%s\n",
- src_filename.c_str(), LLImage::getLastError().c_str());
+ src_filename.c_str(), LLImage::getLastError().c_str());
args["FILE"] = src_filename;
args["ERROR"] = LLImage::getLastError();
upload_error(error_message, "ProblemWithFile", filename, args);
- return;
+ return LLUUID();
}
}
- else if( exten == "png")
- {
- asset_type = LLAssetType::AT_TEXTURE;
- if (!LLViewerTextureList::createUploadFile(src_filename,
- filename,
- IMG_CODEC_PNG ))
- {
- error_message = llformat("Problem with file %s:\n\n%s\n",
- src_filename.c_str(), LLImage::getLastError().c_str());
- args["FILE"] = src_filename;
- args["ERROR"] = LLImage::getLastError();
- upload_error(error_message, "ProblemWithFile", filename, args);
- return;
- }
- }
else if(exten == "wav")
{
asset_type = LLAssetType::AT_SOUND; // tag it as audio
@@ -595,7 +677,7 @@ void upload_new_resource(const std::string& src_filename, std::string name,
upload_error(error_message, "UnknownVorbisEncodeFailure", filename, args);
break;
}
- return;
+ return LLUUID();
}
}
else if(exten == "tmp")
@@ -635,7 +717,7 @@ void upload_new_resource(const std::string& src_filename, std::string name,
error_message = llformat("corrupt resource file: %s", src_filename.c_str());
args["FILE"] = src_filename;
upload_error(error_message, "CorruptResourceFile", filename, args);
- return;
+ return LLUUID();
}
if (2 == tokens_read)
@@ -663,7 +745,7 @@ void upload_new_resource(const std::string& src_filename, std::string name,
error_message = llformat("unknown linden resource file version in file: %s", src_filename.c_str());
args["FILE"] = src_filename;
upload_error(error_message, "UnknownResourceFileVersion", filename, args);
- return;
+ return LLUUID();
}
}
else
@@ -705,7 +787,7 @@ void upload_new_resource(const std::string& src_filename, std::string name,
error_message = llformat( "Unable to create output file: %s", filename.c_str());
args["FILE"] = filename;
upload_error(error_message, "UnableToCreateOutputFile", filename, args);
- return;
+ return LLUUID();
}
fclose(in);
@@ -719,7 +801,7 @@ void upload_new_resource(const std::string& src_filename, std::string name,
{
error_message = llformat("We do not currently support bulk upload of animation files\n");
upload_error(error_message, "DoNotSupportBulkAnimationUpload", filename, args);
- return;
+ return LLUUID();
}
else
{
@@ -765,9 +847,21 @@ void upload_new_resource(const std::string& src_filename, std::string name,
{
t_disp_name = src_filename;
}
- upload_new_resource(tid, asset_type, name, desc, compression_info, // tid
- destination_folder_type, inv_type, next_owner_perms, group_perms, everyone_perms,
- display_name, callback, expected_upload_cost, userdata);
+ upload_new_resource(
+ tid,
+ asset_type,
+ name,
+ desc,
+ compression_info, // tid
+ destination_folder_type,
+ inv_type,
+ next_owner_perms,
+ group_perms,
+ everyone_perms,
+ display_name,
+ callback,
+ expected_upload_cost,
+ userdata);
}
else
{
@@ -781,9 +875,15 @@ void upload_new_resource(const std::string& src_filename, std::string name,
}
LLFilePicker::instance().reset();
}
+
+ return uuid;
}
-void upload_done_callback(const LLUUID& uuid, void* user_data, S32 result, LLExtStat ext_status) // StoreAssetData callback (fixed)
+void upload_done_callback(
+ const LLUUID& uuid,
+ void* user_data,
+ S32 result,
+ LLExtStat ext_status) // StoreAssetData callback (fixed)
{
LLResourceData* data = (LLResourceData*)user_data;
S32 expected_upload_cost = data ? data->mExpectedUploadCost : 0;
@@ -888,35 +988,102 @@ void upload_done_callback(const LLUUID& uuid, void* user_data, S32 result, LLExt
std::string display_name = LLStringUtil::null;
LLAssetStorage::LLStoreAssetCallback callback = NULL;
void *userdata = NULL;
- upload_new_resource(next_file, asset_name, asset_name, // file
- 0, LLFolderType::FT_NONE, LLInventoryType::IT_NONE,
- PERM_NONE, PERM_NONE, PERM_NONE,
- display_name,
- callback,
- expected_upload_cost, // assuming next in a group of uploads is of roughly the same type, i.e. same upload cost
- userdata);
+ upload_new_resource(
+ next_file,
+ asset_name,
+ asset_name, // file
+ 0,
+ LLFolderType::FT_NONE,
+ LLInventoryType::IT_NONE,
+ PERM_NONE,
+ PERM_NONE,
+ PERM_NONE,
+ display_name,
+ callback,
+ expected_upload_cost, // assuming next in a group of uploads is of roughly the same type, i.e. same upload cost
+ userdata);
}
}
-void upload_new_resource(const LLTransactionID &tid, LLAssetType::EType asset_type,
- std::string name,
- std::string desc, S32 compression_info,
- LLFolderType::EType destination_folder_type,
- LLInventoryType::EType inv_type,
- U32 next_owner_perms,
- U32 group_perms,
- U32 everyone_perms,
- const std::string& display_name,
- LLAssetStorage::LLStoreAssetCallback callback,
- S32 expected_upload_cost,
- void *userdata)
+static LLAssetID upload_new_resource_prep(
+ const LLTransactionID& tid,
+ LLAssetType::EType asset_type,
+ LLInventoryType::EType& inventory_type,
+ std::string& name,
+ const std::string& display_name,
+ std::string& description)
+{
+ LLAssetID uuid = generate_asset_id_for_new_upload(tid);
+
+ increase_new_upload_stats(asset_type);
+
+ assign_defaults_and_show_upload_message(
+ asset_type,
+ inventory_type,
+ name,
+ display_name,
+ description);
+
+ return uuid;
+}
+
+LLSD generate_new_resource_upload_capability_body(
+ LLAssetType::EType asset_type,
+ const std::string& name,
+ const std::string& desc,
+ LLFolderType::EType destination_folder_type,
+ LLInventoryType::EType inv_type,
+ U32 next_owner_perms,
+ U32 group_perms,
+ U32 everyone_perms)
+{
+ LLSD body;
+
+ body["folder_id"] = gInventory.findCategoryUUIDForType(
+ (destination_folder_type == LLFolderType::FT_NONE) ?
+ (LLFolderType::EType) asset_type :
+ destination_folder_type);
+
+ body["asset_type"] = LLAssetType::lookup(asset_type);
+ body["inventory_type"] = LLInventoryType::lookup(inv_type);
+ body["name"] = name;
+ body["description"] = desc;
+ body["next_owner_mask"] = LLSD::Integer(next_owner_perms);
+ body["group_mask"] = LLSD::Integer(group_perms);
+ body["everyone_mask"] = LLSD::Integer(everyone_perms);
+
+ return body;
+}
+
+void upload_new_resource(
+ const LLTransactionID &tid,
+ LLAssetType::EType asset_type,
+ std::string name,
+ std::string desc,
+ S32 compression_info,
+ LLFolderType::EType destination_folder_type,
+ LLInventoryType::EType inv_type,
+ U32 next_owner_perms,
+ U32 group_perms,
+ U32 everyone_perms,
+ const std::string& display_name,
+ LLAssetStorage::LLStoreAssetCallback callback,
+ S32 expected_upload_cost,
+ void *userdata)
{
if(gDisconnected)
{
return ;
}
-
- LLAssetID uuid = tid.makeAssetID(gAgent.getSecureSessionID());
+
+ LLAssetID uuid =
+ upload_new_resource_prep(
+ tid,
+ asset_type,
+ inv_type,
+ name,
+ display_name,
+ desc);
if( LLAssetType::AT_SOUND == asset_type )
{
@@ -961,26 +1128,32 @@ void upload_new_resource(const LLTransactionID &tid, LLAssetType::EType asset_ty
llinfos << "Expected Upload Cost: " << expected_upload_cost << llendl;
lldebugs << "Folder: " << gInventory.findCategoryUUIDForType((destination_folder_type == LLFolderType::FT_NONE) ? LLFolderType::assetTypeToFolderType(asset_type) : destination_folder_type) << llendl;
lldebugs << "Asset Type: " << LLAssetType::lookup(asset_type) << llendl;
- std::string url = gAgent.getRegion()->getCapability("NewFileAgentInventory");
- if (!url.empty())
+
+ std::string url = gAgent.getRegion()->getCapability(
+ "NewFileAgentInventory");
+
+ if ( !url.empty() )
{
llinfos << "New Agent Inventory via capability" << llendl;
- LLSD body;
- body["folder_id"] = gInventory.findCategoryUUIDForType((destination_folder_type == LLFolderType::FT_NONE) ? LLFolderType::assetTypeToFolderType(asset_type) : destination_folder_type);
- body["asset_type"] = LLAssetType::lookup(asset_type);
- body["inventory_type"] = LLInventoryType::lookup(inv_type);
- body["name"] = name;
- body["description"] = desc;
- body["next_owner_mask"] = LLSD::Integer(next_owner_perms);
- body["group_mask"] = LLSD::Integer(group_perms);
- body["everyone_mask"] = LLSD::Integer(everyone_perms);
- body["expected_upload_cost"] = LLSD::Integer(expected_upload_cost);
-
- //std::ostringstream llsdxml;
- //LLSDSerialize::toPrettyXML(body, llsdxml);
- //llinfos << "posting body to capability: " << llsdxml.str() << llendl;
- LLHTTPClient::post(url, body, new LLNewAgentInventoryResponder(body, uuid, asset_type));
+ LLSD body;
+ body = generate_new_resource_upload_capability_body(
+ asset_type,
+ name,
+ desc,
+ destination_folder_type,
+ inv_type,
+ next_owner_perms,
+ group_perms,
+ everyone_perms);
+
+ LLHTTPClient::post(
+ url,
+ body,
+ new LLNewAgentInventoryResponder(
+ body,
+ uuid,
+ asset_type));
}
else
{
@@ -994,10 +1167,10 @@ void upload_new_resource(const LLTransactionID &tid, LLAssetType::EType asset_ty
S32 balance = gStatusBar->getBalance();
if (balance < expected_upload_cost)
{
+ // insufficient funds, bail on this upload
LLStringUtil::format_map_t args;
args["NAME"] = name;
args["AMOUNT"] = llformat("%d", expected_upload_cost);
- // insufficient funds, bail on this upload
LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString("UploadingCosts", args), expected_upload_cost );
return;
}
@@ -1021,18 +1194,157 @@ void upload_new_resource(const LLTransactionID &tid, LLAssetType::EType asset_ty
{
asset_callback = callback;
}
- gAssetStorage->storeAssetData(data->mAssetInfo.mTransactionID, data->mAssetInfo.mType,
- asset_callback,
- (void*)data,
- FALSE);
+ gAssetStorage->storeAssetData(
+ data->mAssetInfo.mTransactionID,
+ data->mAssetInfo.mType,
+ asset_callback,
+ (void*)data,
+ FALSE);
+ }
+}
+
+BOOL upload_new_variable_price_resource(
+ const LLTransactionID &tid,
+ LLAssetType::EType asset_type,
+ std::string name,
+ std::string desc,
+ LLFolderType::EType destination_folder_type,
+ LLInventoryType::EType inv_type,
+ U32 next_owner_perms,
+ U32 group_perms,
+ U32 everyone_perms,
+ const std::string& display_name,
+ const LLSD& asset_resources)
+{
+ LLAssetID uuid =
+ upload_new_resource_prep(
+ tid,
+ asset_type,
+ inv_type,
+ name,
+ display_name,
+ desc);
+
+ llinfos << "*** Uploading: " << llendl;
+ llinfos << "Type: " << LLAssetType::lookup(asset_type) << llendl;
+ llinfos << "UUID: " << uuid << llendl;
+ llinfos << "Name: " << name << llendl;
+ llinfos << "Desc: " << desc << llendl;
+ lldebugs << "Folder: "
+ << gInventory.findCategoryUUIDForType((destination_folder_type == LLFolderType::FT_NONE) ? (LLFolderType::EType)asset_type : destination_folder_type) << llendl;
+ lldebugs << "Asset Type: " << LLAssetType::lookup(asset_type) << llendl;
+
+ std::string url = gAgent.getRegion()->getCapability(
+ "NewFileAgentInventoryVariablePrice");
+
+ if ( !url.empty() )
+ {
+ lldebugs
+ << "New Agent Inventory variable price upload" << llendl;
+
+ // Each of the two capabilities has similar data, so
+ // let's reuse that code
+
+ LLSD body;
+
+ body = generate_new_resource_upload_capability_body(
+ asset_type,
+ name,
+ desc,
+ destination_folder_type,
+ inv_type,
+ next_owner_perms,
+ group_perms,
+ everyone_perms);
+
+ body["asset_resources"] = asset_resources;
+
+ LLHTTPClient::post(
+ url,
+ body,
+ new LLNewAgentInventoryVariablePriceResponder(
+ uuid,
+ asset_type,
+ body));
+
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+LLAssetID generate_asset_id_for_new_upload(const LLTransactionID& tid)
+{
+ if ( gDisconnected )
+ {
+ LLAssetID rv;
+
+ rv.setNull();
+ return rv;
+ }
+
+ LLAssetID uuid = tid.makeAssetID(gAgent.getSecureSessionID());
+
+ return uuid;
+}
+
+void increase_new_upload_stats(LLAssetType::EType asset_type)
+{
+ if ( LLAssetType::AT_SOUND == asset_type )
+ {
+ LLViewerStats::getInstance()->incStat(
+ LLViewerStats::ST_UPLOAD_SOUND_COUNT );
+ }
+ else if ( LLAssetType::AT_TEXTURE == asset_type )
+ {
+ LLViewerStats::getInstance()->incStat(
+ LLViewerStats::ST_UPLOAD_TEXTURE_COUNT );
+ }
+ else if ( LLAssetType::AT_ANIMATION == asset_type )
+ {
+ LLViewerStats::getInstance()->incStat(
+ LLViewerStats::ST_UPLOAD_ANIM_COUNT );
}
}
+void assign_defaults_and_show_upload_message(
+ LLAssetType::EType asset_type,
+ LLInventoryType::EType& inventory_type,
+ std::string& name,
+ const std::string& display_name,
+ std::string& description)
+{
+ if ( LLInventoryType::IT_NONE == inventory_type )
+ {
+ inventory_type = LLInventoryType::defaultForAssetType(asset_type);
+ }
+ LLStringUtil::stripNonprintable(name);
+ LLStringUtil::stripNonprintable(description);
+
+ if ( name.empty() )
+ {
+ name = "(No Name)";
+ }
+ if ( description.empty() )
+ {
+ description = "(No Description)";
+ }
+
+ // At this point, we're ready for the upload.
+ std::string upload_message = "Uploading...\n\n";
+ upload_message.append(display_name);
+ LLUploadDialog::modalUploadDialog(upload_message);
+}
+
+
void init_menu_file()
{
view_listener_t::addCommit(new LLFileUploadImage(), "File.UploadImage");
view_listener_t::addCommit(new LLFileUploadSound(), "File.UploadSound");
view_listener_t::addCommit(new LLFileUploadAnim(), "File.UploadAnim");
+ view_listener_t::addCommit(new LLFileUploadModel(), "File.UploadModel");
view_listener_t::addCommit(new LLFileUploadBulk(), "File.UploadBulk");
view_listener_t::addCommit(new LLFileCloseWindow(), "File.CloseWindow");
view_listener_t::addCommit(new LLFileCloseAllWindows(), "File.CloseAllWindows");
@@ -1042,6 +1354,9 @@ void init_menu_file()
view_listener_t::addCommit(new LLFileQuit(), "File.Quit");
view_listener_t::addEnable(new LLFileEnableUpload(), "File.EnableUpload");
-
+ view_listener_t::addEnable(new LLFileEnableUploadModel(), "File.EnableUploadModel");
+ view_listener_t::addMenu(new LLMeshEnabled(), "File.MeshEnabled");
+ view_listener_t::addMenu(new LLMeshUploadVisible(), "File.VisibleUploadModel");
+
// "File.SaveTexture" moved to llpanelmaininventory so that it can be properly handled.
}
diff --git a/indra/newview/llviewermenufile.h b/indra/newview/llviewermenufile.h
index 56b9e19049..1597821504 100644
--- a/indra/newview/llviewermenufile.h
+++ b/indra/newview/llviewermenufile.h
@@ -30,39 +30,118 @@
#include "llfoldertype.h"
#include "llassetstorage.h"
#include "llinventorytype.h"
+#include "llfilepicker.h"
class LLTransactionID;
void init_menu_file();
-void upload_new_resource(const std::string& src_filename,
- std::string name,
- std::string desc,
- S32 compression_info,
- LLFolderType::EType destination_folder_type,
- LLInventoryType::EType inv_type,
- U32 next_owner_perms,
- U32 group_perms,
- U32 everyone_perms,
- const std::string& display_name,
- LLAssetStorage::LLStoreAssetCallback callback,
- S32 expected_upload_cost,
- void *userdata);
-
-void upload_new_resource(const LLTransactionID &tid,
- LLAssetType::EType type,
- std::string name,
- std::string desc,
- S32 compression_info,
- LLFolderType::EType destination_folder_type,
- LLInventoryType::EType inv_type,
- U32 next_owner_perms,
- U32 group_perms,
- U32 everyone_perms,
- const std::string& display_name,
- LLAssetStorage::LLStoreAssetCallback callback,
- S32 expected_upload_cost,
- void *userdata);
+LLUUID upload_new_resource(
+ const std::string& src_filename,
+ std::string name,
+ std::string desc,
+ S32 compression_info,
+ LLFolderType::EType destination_folder_type,
+ LLInventoryType::EType inv_type,
+ U32 next_owner_perms,
+ U32 group_perms,
+ U32 everyone_perms,
+ const std::string& display_name,
+ LLAssetStorage::LLStoreAssetCallback callback,
+ S32 expected_upload_cost,
+ void *userdata);
+
+void upload_new_resource(
+ const LLTransactionID &tid,
+ LLAssetType::EType type,
+ std::string name,
+ std::string desc,
+ S32 compression_info,
+ LLFolderType::EType destination_folder_type,
+ LLInventoryType::EType inv_type,
+ U32 next_owner_perms,
+ U32 group_perms,
+ U32 everyone_perms,
+ const std::string& display_name,
+ LLAssetStorage::LLStoreAssetCallback callback,
+ S32 expected_upload_cost,
+ void *userdata);
+
+// TODO* : Move all uploads to use this new function
+// since at some point, that upload path will be deprecated and no longer
+// used
+
+// We make a new function here to ensure that previous code is not broken
+BOOL upload_new_variable_price_resource(
+ const LLTransactionID& tid,
+ LLAssetType::EType type,
+ std::string name,
+ std::string desc,
+ LLFolderType::EType destination_folder_type,
+ LLInventoryType::EType inv_type,
+ U32 next_owner_perms,
+ U32 group_perms,
+ U32 everyone_perms,
+ const std::string& display_name,
+ const LLSD& asset_resources);
+
+LLAssetID generate_asset_id_for_new_upload(const LLTransactionID& tid);
+void increase_new_upload_stats(LLAssetType::EType asset_type);
+void assign_defaults_and_show_upload_message(
+ LLAssetType::EType asset_type,
+ LLInventoryType::EType& inventory_type,
+ std::string& name,
+ const std::string& display_name,
+ std::string& description);
+
+LLSD generate_new_resource_upload_capability_body(
+ LLAssetType::EType asset_type,
+ const std::string& name,
+ const std::string& desc,
+ LLFolderType::EType destination_folder_type,
+ LLInventoryType::EType inv_type,
+ U32 next_owner_perms,
+ U32 group_perms,
+ U32 everyone_perms);
+
+void on_new_single_inventory_upload_complete(
+ LLAssetType::EType asset_type,
+ LLInventoryType::EType inventory_type,
+ const std::string inventory_type_string,
+ const LLUUID& item_folder_id,
+ const std::string& item_name,
+ const std::string& item_description,
+ const LLSD& server_response,
+ S32 upload_price);
+
+class LLFilePickerThread : public LLThread
+{ //multi-threaded file picker (runs system specific file picker in background and calls "notify" from main thread)
+public:
+
+ static std::queue<LLFilePickerThread*> sDeadQ;
+ static LLMutex* sMutex;
+
+ static void initClass();
+ static void cleanupClass();
+ static void clearDead();
+
+ std::string mFile;
+
+ LLFilePicker::ELoadFilter mFilter;
+
+ LLFilePickerThread(LLFilePicker::ELoadFilter filter)
+ : LLThread("file picker"), mFilter(filter)
+ {
+
+ }
+
+ void getFile();
+
+ virtual void run();
+
+ virtual void notify(const std::string& filename) = 0;
+};
+
#endif
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 9b1f2e67c6..86b56df556 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -39,6 +39,7 @@
#include "llfloaterreg.h"
#include "llfollowcamparams.h"
#include "llinventorydefines.h"
+#include "lllslconstants.h"
#include "llregionhandle.h"
#include "llsdserialize.h"
#include "llteleportflags.h"
@@ -121,6 +122,7 @@
//
const F32 BIRD_AUDIBLE_RADIUS = 32.0f;
const F32 SIT_DISTANCE_FROM_TARGET = 0.25f;
+const F32 CAMERA_POSITION_THRESHOLD_SQUARED = 0.001f * 0.001f;
static const F32 LOGOUT_REPLY_TIME = 3.f; // Wait this long after LogoutReply before quitting.
// Determine how quickly residents' scripts can issue question dialogs
@@ -342,12 +344,11 @@ void process_layer_data(LLMessageSystem *mesgsys, void **user_data)
{
LLViewerRegion *regionp = LLWorld::getInstance()->getRegion(mesgsys->getSender());
- if (!regionp || gNoRender)
+ if(!regionp)
{
+ llwarns << "Invalid region for layer data." << llendl;
return;
}
-
-
S32 size;
S8 type;
@@ -638,7 +639,7 @@ bool join_group_response(const LLSD& notification, const LLSD& response)
if(option == 0 && !group_id.isNull())
{
// check for promotion or demotion.
- S32 max_groups = MAX_AGENT_GROUPS;
+ S32 max_groups = gMaxAgentGroups;
if(gAgent.isInGroup(group_id)) ++max_groups;
if(gAgent.mGroups.count() < max_groups)
@@ -1198,8 +1199,6 @@ void open_inventory_offer(const uuid_vec_t& objects, const std::string& from_nam
// Highlight item
const BOOL auto_open =
gSavedSettings.getBOOL("ShowInInventory") && // don't open if showininventory is false
- !(asset_type == LLAssetType::AT_CALLINGCARD) && // don't open if it's a calling card
- !(item && (item->getInventoryType() == LLInventoryType::IT_ATTACHMENT)) && // don't open if it's an item that's an attachment
!from_name.empty(); // don't open if it's not from anyone.
LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(auto_open);
if(active_panel)
@@ -1463,15 +1462,18 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD&
// This is an offer from an agent. In this case, the back
// end has already copied the items into your inventory,
// so we can fetch it out of our inventory.
- LLOpenAgentOffer* open_agent_offer = new LLOpenAgentOffer(mObjectID, from_string);
- open_agent_offer->startFetch();
- if(catp || (itemp && itemp->isFinished()))
- {
- open_agent_offer->done();
- }
- else
+ if (gSavedSettings.getBOOL("ShowOfferedInventory"))
{
- opener = open_agent_offer;
+ LLOpenAgentOffer* open_agent_offer = new LLOpenAgentOffer(mObjectID, from_string);
+ open_agent_offer->startFetch();
+ if(catp || (itemp && itemp->isFinished()))
+ {
+ open_agent_offer->done();
+ }
+ else
+ {
+ opener = open_agent_offer;
+ }
}
}
break;
@@ -1511,7 +1513,12 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD&
// MUTE falls through to decline
case IOR_DECLINE:
{
- log_message = LLTrans::getString("InvOfferYouDecline") + " " + mDesc + " " + LLTrans::getString("InvOfferFrom") + " " + mFromName +".";
+ {
+ LLStringUtil::format_map_t log_message_args;
+ log_message_args["DESC"] = mDesc;
+ log_message_args["NAME"] = mFromName;
+ log_message = LLTrans::getString("InvOfferDecline", log_message_args);
+ }
chat.mText = log_message;
if( LLMuteList::getInstance()->isMuted(mFromID ) && ! LLMuteList::getInstance()->isLinden(mFromName) ) // muting for SL-42269
{
@@ -1710,11 +1717,18 @@ bool LLOfferInfo::inventory_task_offer_callback(const LLSD& notification, const
msg->addBinaryDataFast(_PREHASH_BinaryBucket, EMPTY_BINARY_BUCKET, EMPTY_BINARY_BUCKET_SIZE);
// send the message
msg->sendReliable(mHost);
-
- log_message = LLTrans::getString("InvOfferYouDecline") + " " + mDesc + " " + LLTrans::getString("InvOfferFrom") + " " + mFromName +".";
- LLSD args;
- args["MESSAGE"] = log_message;
- LLNotificationsUtil::add("SystemMessage", args);
+
+ if (gSavedSettings.getBOOL("LogInventoryDecline"))
+ {
+ LLStringUtil::format_map_t log_message_args;
+ log_message_args["DESC"] = mDesc;
+ log_message_args["NAME"] = mFromName;
+ log_message = LLTrans::getString("InvOfferDecline", log_message_args);
+
+ LLSD args;
+ args["MESSAGE"] = log_message;
+ LLNotificationsUtil::add("SystemMessage", args);
+ }
if (busy && (!mFromGroup && !mFromObject))
{
@@ -2154,10 +2168,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;
@@ -2203,7 +2213,9 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
name = clean_name_from_im(name, dialog);
BOOL is_busy = gAgent.getBusy();
- BOOL is_muted = LLMuteList::getInstance()->isMuted(from_id, name, LLMute::flagTextChat);
+ BOOL is_muted = LLMuteList::getInstance()->isMuted(from_id, name, LLMute::flagTextChat)
+ // object IMs contain sender object id in session_id (STORM-1209)
+ || dialog == IM_FROM_TASK && LLMuteList::getInstance()->isMuted(session_id);
BOOL is_linden = LLMuteList::getInstance()->isLinden(name);
BOOL is_owned_by_me = FALSE;
BOOL is_friend = (LLAvatarTracker::instance().getBuddyInfo(from_id) == NULL) ? false : true;
@@ -2501,15 +2513,6 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
invite_bucket = (struct invite_bucket_t*) &binary_bucket[0];
S32 membership_fee = ntohl(invite_bucket->membership_fee);
- // IDEVO Clean up legacy name "Resident" in message constructed in
- // lldatagroups.cpp
- U32 pos = message.find(" has invited you to join a group.\n");
- if (pos != std::string::npos)
- {
- // use cleaned-up name from above
- message = name + message.substr(pos);
- }
-
LLSD payload;
payload["transaction_id"] = session_id;
payload["group_id"] = from_id;
@@ -2600,6 +2603,9 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
args["NAME"] = LLSLURL("agent", from_id, "completename").getSLURLString();;
LLSD payload;
payload["from_id"] = from_id;
+ // Passing the "SESSION_NAME" to use it for IM notification logging
+ // in LLTipHandler::processNotification(). See STORM-941.
+ payload["SESSION_NAME"] = name;
LLNotificationsUtil::add("InventoryAccepted", args, payload);
break;
}
@@ -2721,6 +2727,14 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
LLSD args;
args["slurl"] = location;
args["type"] = LLNotificationsUI::NT_NEARBYCHAT;
+
+ // Look for IRC-style emotes here so object name formatting is correct
+ std::string prefix = message.substr(0, 4);
+ if (prefix == "/me " || prefix == "/me'")
+ {
+ chat.mChatStyle = CHAT_STYLE_IRC;
+ }
+
LLNotificationsUI::LLNotificationManager::instance().onChat(chat, args);
}
@@ -2791,7 +2805,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
{
LLVector3 pos, look_at;
U64 region_handle;
- U8 region_access = SIM_ACCESS_MIN;
+ U8 region_access;
std::string region_info = ll_safe_string((char*)binary_bucket, binary_bucket_size);
std::string region_access_str = LLStringUtil::null;
std::string region_access_icn = LLStringUtil::null;
@@ -3032,6 +3046,7 @@ void process_offer_callingcard(LLMessageSystem* msg, void**)
}
else
{
+ args["NAME"] = source_name;
LLNotificationsUtil::add("OfferCallingCard", args, payload);
}
}
@@ -3346,6 +3361,8 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)
// then this info is news to us.
void process_teleport_start(LLMessageSystem *msg, void**)
{
+ // on teleport, don't tell them about destination guide anymore
+ LLFirstUse::notUsingDestinationGuide(false);
U32 teleport_flags = 0x0;
msg->getU32("Info", "TeleportFlags", teleport_flags);
@@ -3750,8 +3767,19 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**)
}
else
{
- // This is likely just the initial logging in phase.
+ // This is initial log-in or a region crossing
gAgent.setTeleportState( LLAgent::TELEPORT_NONE );
+
+ if(LLStartUp::getStartupState() < STATE_STARTED)
+ { // This is initial log-in, not a region crossing:
+ // Set the camera looking ahead of the AV so send_agent_update() below
+ // will report the correct location to the server.
+ LLVector3 look_at_point = look_at;
+ look_at_point = agent_pos + look_at_point.rotVec(gAgent.getQuat());
+
+ static LLVector3 up_direction(0.0f, 0.0f, 1.0f);
+ LLViewerCamera::getInstance()->lookAt(agent_pos, look_at_point, up_direction);
+ }
}
if ( LLTracker::isTracking(NULL) )
@@ -3820,37 +3848,6 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**)
return;
}
- if (!gLastVersionChannel.empty())
- {
- // work out the URL for this server's Release Notes
- std::string url ="http://wiki.secondlife.com/wiki/Release_Notes/";
- std::string server_version = version_channel;
- std::vector<std::string> s_vect;
- boost::algorithm::split(s_vect, server_version, isspace);
- for(U32 i = 0; i < s_vect.size(); i++)
- {
- if (i != (s_vect.size() - 1))
- {
- if(i != (s_vect.size() - 2))
- {
- url += s_vect[i] + "_";
- }
- else
- {
- url += s_vect[i] + "/";
- }
- }
- else
- {
- url += s_vect[i].substr(0,4);
- }
- }
-
- LLSD args;
- args["URL"] = url;
- LLNotificationsUtil::add("ServerVersionChanged", args);
- }
-
gLastVersionChannel = version_channel;
}
@@ -3867,6 +3864,7 @@ void process_crossed_region(LLMessageSystem* msg, void**)
return;
}
LL_INFOS("Messaging") << "process_crossed_region()" << LL_ENDL;
+ gAgentAvatarp->resetRegionCrossingTimer();
U32 sim_ip;
msg->getIPAddrFast(_PREHASH_RegionData, _PREHASH_SimIP, sim_ip);
@@ -3963,7 +3961,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 |
@@ -4282,7 +4282,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);
}
@@ -4756,7 +4756,7 @@ void process_avatar_sit_response(LLMessageSystem *mesgsys, void **user_data)
BOOL force_mouselook;
mesgsys->getBOOLFast(_PREHASH_SitTransform, _PREHASH_ForceMouselook, force_mouselook);
- if (isAgentAvatarValid() && dist_vec_squared(camera_eye, camera_at) > 0.0001f)
+ if (isAgentAvatarValid() && dist_vec_squared(camera_eye, camera_at) > CAMERA_POSITION_THRESHOLD_SQUARED)
{
gAgentCamera.setSitCamera(sitObjectID, camera_eye, camera_at);
}
@@ -5376,6 +5376,12 @@ bool attempt_standard_notification(LLMessageSystem* msgsystem)
{
// notification was specified using the new mechanism, so we can just handle it here
std::string notificationID;
+ msgsystem->getStringFast(_PREHASH_AlertInfo, _PREHASH_Message, notificationID);
+ if (!LLNotifications::getInstance()->templateExists(notificationID))
+ {
+ return false;
+ }
+
std::string llsdRaw;
LLSD llsdBlock;
msgsystem->getStringFast(_PREHASH_AlertInfo, _PREHASH_Message, notificationID);
@@ -5532,10 +5538,19 @@ void process_alert_core(const std::string& message, BOOL modal)
}
else
{
- LLSD args;
- std::string new_msg =LLNotifications::instance().getGlobalString(message);
- args["MESSAGE"] = new_msg;
- LLNotificationsUtil::add("SystemMessageTip", args);
+ // Hack fix for EXP-623 (blame fix on RN :)) to avoid a sim deploy
+ const std::string AUTOPILOT_CANCELED_MSG("Autopilot canceled");
+ if (message.find(AUTOPILOT_CANCELED_MSG) == std::string::npos )
+ {
+ LLSD args;
+ std::string new_msg =LLNotifications::instance().getGlobalString(message);
+
+ std::string localized_msg;
+ bool is_message_localized = LLTrans::findString(localized_msg, new_msg);
+
+ args["MESSAGE"] = is_message_localized ? localized_msg : new_msg;
+ LLNotificationsUtil::add("SystemMessageTip", args);
+ }
}
}
@@ -5544,21 +5559,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)
{
@@ -6302,6 +6308,9 @@ bool handle_lure_callback(const LLSD& notification, const LLSD& response)
payload["from_id"] = target_id;
payload["SUPPRESS_TOAST"] = true;
LLNotificationsUtil::add("TeleportOfferSent", args, payload);
+
+ // Add the recepient to the recent people list.
+ LLRecentPeople::instance().add(target_id);
}
}
gAgent.sendReliableMessage();
@@ -6435,8 +6444,22 @@ const char* SCRIPT_DIALOG_HEADER = "Script Dialog:\n";
bool callback_script_dialog(const LLSD& notification, const LLSD& response)
{
LLNotificationForm form(notification["form"]);
- std::string button = LLNotification::getSelectedOptionName(response);
- S32 button_idx = LLNotification::getSelectedOption(notification, response);
+
+ std::string rtn_text;
+ S32 button_idx;
+ button_idx = LLNotification::getSelectedOption(notification, response);
+ if (response[TEXTBOX_MAGIC_TOKEN].isDefined())
+ {
+ if (response[TEXTBOX_MAGIC_TOKEN].isString())
+ rtn_text = response[TEXTBOX_MAGIC_TOKEN].asString();
+ else
+ rtn_text.clear(); // bool marks empty string
+ }
+ else
+ {
+ rtn_text = LLNotification::getSelectedOptionName(response);
+ }
+
// Didn't click "Ignore"
if (button_idx != -1)
{
@@ -6449,7 +6472,7 @@ bool callback_script_dialog(const LLSD& notification, const LLSD& response)
msg->addUUID("ObjectID", notification["payload"]["object_id"].asUUID());
msg->addS32("ChatChannel", notification["payload"]["chat_channel"].asInteger());
msg->addS32("ButtonIndex", button_idx);
- msg->addString("ButtonLabel", button);
+ msg->addString("ButtonLabel", rtn_text);
msg->sendReliable(LLHost(notification["payload"]["sender"].asString()));
}
@@ -6464,9 +6487,12 @@ void process_script_dialog(LLMessageSystem* msg, void**)
LLSD payload;
LLUUID object_id;
+ LLUUID owner_id;
+
msg->getUUID("Data", "ObjectID", object_id);
+ msg->getUUID("OwnerData", "OwnerID", owner_id);
- if (LLMuteList::getInstance()->isMuted(object_id))
+ if (LLMuteList::getInstance()->isMuted(object_id) || LLMuteList::getInstance()->isMuted(owner_id))
{
return;
}
@@ -6670,6 +6696,8 @@ void process_initiate_download(LLMessageSystem* msg, void**)
void process_script_teleport_request(LLMessageSystem* msg, void**)
{
+ if (!gSavedSettings.getBOOL("ScriptsCanShowUI")) return;
+
std::string object_name;
std::string sim_name;
LLVector3 pos;
diff --git a/indra/newview/llviewermessage.h b/indra/newview/llviewermessage.h
index 6ff893f543..b4a9b8e677 100644
--- a/indra/newview/llviewermessage.h
+++ b/indra/newview/llviewermessage.h
@@ -117,7 +117,6 @@ void process_alert_core(const std::string& message, BOOL modal);
typedef std::list<LLMeanCollisionData*> mean_collision_list_t;
extern mean_collision_list_t gMeanCollisionList;
-void handle_show_mean_events(void *);
void process_mean_collision_alert_message(LLMessageSystem* msg, void**);
void process_frozen_message(LLMessageSystem* msg, void**);
diff --git a/indra/newview/llviewernetwork.cpp b/indra/newview/llviewernetwork.cpp
index b91e407c6d..a59afdc28a 100644
--- a/indra/newview/llviewernetwork.cpp
+++ b/indra/newview/llviewernetwork.cpp
@@ -31,6 +31,7 @@
#include "llviewercontrol.h"
#include "llsdserialize.h"
#include "llsecapi.h"
+#include "lltrans.h"
#include "llweb.h"
@@ -504,7 +505,8 @@ void LLGridManager::setGridChoice(const std::string& grid)
addGrid(grid_data);
}
mGrid = grid;
- gSavedSettings.setString("CurrentGrid", grid);
+ gSavedSettings.setString("CurrentGrid", grid);
+
updateIsInProductionGrid();
}
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index a58b0d68de..6d493bfcd5 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -47,6 +47,7 @@
#include "llprimitive.h"
#include "llquantize.h"
#include "llregionhandle.h"
+#include "llsdserialize.h"
#include "lltree_common.h"
#include "llxfermanager.h"
#include "message.h"
@@ -62,6 +63,7 @@
#include "lldrawable.h"
#include "llface.h"
#include "llfloaterproperties.h"
+#include "llfloatertools.h"
#include "llfollowcam.h"
#include "llhudtext.h"
#include "llselectmgr.h"
@@ -103,8 +105,8 @@
//#define DEBUG_UPDATE_TYPE
-BOOL gVelocityInterpolate = TRUE;
-BOOL gPingInterpolate = TRUE;
+BOOL LLViewerObject::sVelocityInterpolate = TRUE;
+BOOL LLViewerObject::sPingInterpolate = TRUE;
U32 LLViewerObject::sNumZombieObjects = 0;
S32 LLViewerObject::sNumObjects = 0;
@@ -115,6 +117,11 @@ S32 LLViewerObject::sAxisArrowLength(50);
BOOL LLViewerObject::sPulseEnabled(FALSE);
BOOL LLViewerObject::sUseSharedDrawables(FALSE); // TRUE
+// sMaxUpdateInterpolationTime must be greater than sPhaseOutUpdateInterpolationTime
+F64 LLViewerObject::sMaxUpdateInterpolationTime = 3.0; // For motion interpolation: after X seconds with no updates, don't predict object motion
+F64 LLViewerObject::sPhaseOutUpdateInterpolationTime = 2.0; // For motion interpolation: after Y seconds with no updates, taper off motion prediction
+
+
static LLFastTimer::DeclareTimer FTM_CREATE_OBJECT("Create Object");
// static
@@ -168,8 +175,10 @@ LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pco
res = new LLVOSurfacePatch(id, pcode, regionp); break;
case LL_VO_SKY:
res = new LLVOSky(id, pcode, regionp); break;
+ case LL_VO_VOID_WATER:
+ res = new LLVOVoidWater(id, pcode, regionp); break;
case LL_VO_WATER:
- res = new LLVOWater(id, pcode, regionp); break;
+ res = new LLVOWater(id, pcode, regionp); break;
case LL_VO_GROUND:
res = new LLVOGround(id, pcode, regionp); break;
case LL_VO_PART_GROUP:
@@ -195,6 +204,11 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe
mGLName(0),
mbCanSelect(TRUE),
mFlags(0),
+ mPhysicsShapeType(0),
+ mPhysicsGravity(0),
+ mPhysicsFriction(0),
+ mPhysicsDensity(0),
+ mPhysicsRestitution(0),
mDrawable(),
mCreateSelected(FALSE),
mRenderMedia(FALSE),
@@ -226,7 +240,15 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe
mState(0),
mMedia(NULL),
mClickAction(0),
- mAttachmentItemID(LLUUID::null)
+ mObjectCost(0),
+ mLinksetCost(0),
+ mPhysicsCost(0),
+ mLinksetPhysicsCost(0.f),
+ mCostStale(true),
+ mPhysicsShapeUnknown(true),
+ mAttachmentItemID(LLUUID::null),
+ mLastUpdateType(OUT_UNKNOWN),
+ mLastUpdateCached(FALSE)
{
if (!is_global)
{
@@ -460,15 +482,9 @@ 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();
- LLVOSky::initClass();
LLVOVolume::initClass();
}
@@ -508,20 +524,23 @@ void LLViewerObject::setNameValueList(const std::string& name_value_list)
// This method returns true if the object is over land owned by the
// agent.
-BOOL LLViewerObject::isOverAgentOwnedLand() const
+bool LLViewerObject::isReturnable()
{
- return mRegionp
- && mRegionp->getParcelOverlay()
- && mRegionp->getParcelOverlay()->isOwnedSelf(getPositionRegion());
-}
+ if (isAttachment())
+ {
+ return false;
+ }
+ std::vector<LLBBox> boxes;
+ boxes.push_back(LLBBox(getPositionRegion(), getRotationRegion(), getScale() * -0.5f, getScale() * 0.5f).getAxisAligned());
+ for (child_list_t::iterator iter = mChildList.begin();
+ iter != mChildList.end(); iter++)
+ {
+ LLViewerObject* child = *iter;
+ boxes.push_back(LLBBox(child->getPositionRegion(), child->getRotationRegion(), child->getScale() * -0.5f, child->getScale() * 0.5f).getAxisAligned());
+ }
-// This method returns true if the object is over land owned by the
-// agent.
-BOOL LLViewerObject::isOverGroupOwnedLand() const
-{
- return mRegionp
- && mRegionp->getParcelOverlay()
- && mRegionp->getParcelOverlay()->isOwnedGroup(getPositionRegion());
+ return mRegionp
+ && mRegionp->objectIsReturnable(getPositionRegion(), boxes);
}
BOOL LLViewerObject::setParent(LLViewerObject* parent)
@@ -839,6 +858,13 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
#ifdef DEBUG_UPDATE_TYPE
llinfos << "Full:" << getID() << llendl;
#endif
+ //clear cost and linkset cost
+ mCostStale = true;
+ if (isSelected())
+ {
+ gFloaterTools->dirty();
+ }
+
LLUUID audio_uuid;
LLUUID owner_id; // only valid if audio_uuid or particle system is not null
F32 gain;
@@ -1404,6 +1430,13 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
#ifdef DEBUG_UPDATE_TYPE
llinfos << "CompFull:" << getID() << llendl;
#endif
+ mCostStale = true;
+
+ if (isSelected())
+ {
+ gFloaterTools->dirty();
+ }
+
dp->unpackU32(crc, "CRC");
mTotalCRC = crc;
dp->unpackU8(material, "Material");
@@ -1839,7 +1872,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
new_rot.normQuat();
- if (gPingInterpolate)
+ if (sPingInterpolate)
{
LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(mesgsys->getSender());
if (cdp)
@@ -1860,6 +1893,8 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
//
//
+ // WTF? If we're going to skip this message, why are we
+ // doing all the parenting, etc above?
U32 packet_id = mesgsys->getCurrentRecvPacketID();
if (packet_id < mLatestRecvPacketID &&
mLatestRecvPacketID - packet_id < 65536)
@@ -2000,7 +2035,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
// U32 ping_delay = mesgsys->mCircuitInfo.getPingDelay();
mLastInterpUpdateSecs = LLFrameTimer::getElapsedSeconds();
- mLastMessageUpdateSecs = LLFrameTimer::getElapsedSeconds();
+ mLastMessageUpdateSecs = mLastInterpUpdateSecs;
if (mDrawable.notNull())
{
// Don't clear invisibility flag on update if still orphaned!
@@ -2027,6 +2062,8 @@ BOOL LLViewerObject::isActive() const
return TRUE;
}
+
+
BOOL LLViewerObject::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
{
static LLFastTimer::DeclareTimer ftm("Viewer Object");
@@ -2040,7 +2077,7 @@ BOOL LLViewerObject::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
// CRO - don't velocity interp linked objects!
// Leviathan - but DO velocity interp joints
- if (!mStatic && gVelocityInterpolate && !isSelected())
+ if (!mStatic && sVelocityInterpolate && !isSelected())
{
// calculate dt from last update
F32 dt_raw = (F32)(time - mLastInterpUpdateSecs);
@@ -2130,48 +2167,170 @@ BOOL LLViewerObject::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
return TRUE;
}
else
- {
- // linear motion
- // PHYSICS_TIMESTEP is used below to correct for the fact that the velocity in object
- // updates represents the average velocity of the last timestep, rather than the final velocity.
- // the time dilation above should guarantee that dt is never less than PHYSICS_TIMESTEP, theoretically
- //
- // There is a problem here if dt is negative. . .
-
- // *TODO: should also wrap linear accel/velocity in check
- // to see if object is selected, instead of explicitly
- // zeroing it out
- LLVector3 accel = getAcceleration();
- LLVector3 vel = getVelocity();
-
- if (!(accel.isExactlyZero() && vel.isExactlyZero()))
- {
- LLVector3 pos = (vel + (0.5f * (dt-PHYSICS_TIMESTEP)) * accel) * dt;
-
- // region local
- setPositionRegion(pos + getPositionRegion());
- setVelocity(vel + accel*dt);
-
- // for objects that are spinning but not translating, make sure to flag them as having moved
- setChanged(MOVED | SILHOUETTE);
- }
-
- mLastInterpUpdateSecs = time;
+ { // Move object based on it's velocity and rotation
+ interpolateLinearMotion(time, dt);
}
}
- if (gNoRender)
+ updateDrawable(FALSE);
+
+ return TRUE;
+}
+
+
+// Move an object due to idle-time viewer side updates by iterpolating motion
+void LLViewerObject::interpolateLinearMotion(const F64 & time, const F32 & dt)
+{
+ // linear motion
+ // PHYSICS_TIMESTEP is used below to correct for the fact that the velocity in object
+ // updates represents the average velocity of the last timestep, rather than the final velocity.
+ // the time dilation above should guarantee that dt is never less than PHYSICS_TIMESTEP, theoretically
+ //
+ // *TODO: should also wrap linear accel/velocity in check
+ // to see if object is selected, instead of explicitly
+ // zeroing it out
+
+ F64 time_since_last_update = time - mLastMessageUpdateSecs;
+ if (time_since_last_update <= 0.0 || dt <= 0.f)
{
- // Skip drawable stuff if not rendering.
- return TRUE;
+ return;
}
- updateDrawable(FALSE);
+ LLVector3 accel = getAcceleration();
+ LLVector3 vel = getVelocity();
+
+ if (sMaxUpdateInterpolationTime <= 0.0)
+ { // Old code path ... unbounded, simple interpolation
+ if (!(accel.isExactlyZero() && vel.isExactlyZero()))
+ {
+ LLVector3 pos = (vel + (0.5f * (dt-PHYSICS_TIMESTEP)) * accel) * dt;
+
+ // region local
+ setPositionRegion(pos + getPositionRegion());
+ setVelocity(vel + accel*dt);
+
+ // for objects that are spinning but not translating, make sure to flag them as having moved
+ setChanged(MOVED | SILHOUETTE);
+ }
+ }
+ else if (!accel.isExactlyZero() || !vel.isExactlyZero()) // object is moving
+ { // Object is moving, and hasn't been too long since we got an update from the server
+
+ // Calculate predicted position and velocity
+ LLVector3 new_pos = (vel + (0.5f * (dt-PHYSICS_TIMESTEP)) * accel) * dt;
+ LLVector3 new_v = accel * dt;
+
+ if (time_since_last_update > sPhaseOutUpdateInterpolationTime &&
+ sPhaseOutUpdateInterpolationTime > 0.0)
+ { // Haven't seen a viewer update in a while, check to see if the ciruit is still active
+ if (mRegionp)
+ { // The simulator will NOT send updates if the object continues normally on the path
+ // predicted by the velocity and the acceleration (often gravity) sent to the viewer
+ // So check to see if the circuit is blocked, which means the sim is likely in a long lag
+ LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit( mRegionp->getHost() );
+ if (cdp)
+ {
+ // Find out how many seconds since last packet arrived on the circuit
+ F64 time_since_last_packet = LLMessageSystem::getMessageTimeSeconds() - cdp->getLastPacketInTime();
- return TRUE;
+ if (!cdp->isAlive() || // Circuit is dead or blocked
+ cdp->isBlocked() || // or doesn't seem to be getting any packets
+ (time_since_last_packet > sPhaseOutUpdateInterpolationTime))
+ {
+ // Start to reduce motion interpolation since we haven't seen a server update in a while
+ F64 time_since_last_interpolation = time - mLastInterpUpdateSecs;
+ F64 phase_out = 1.0;
+ if (time_since_last_update > sMaxUpdateInterpolationTime)
+ { // Past the time limit, so stop the object
+ phase_out = 0.0;
+ //llinfos << "Motion phase out to zero" << llendl;
+
+ // Kill angular motion as well. Note - not adding this due to paranoia
+ // about stopping rotation for llTargetOmega objects and not having it restart
+ // setAngularVelocity(LLVector3::zero);
+ }
+ else if (mLastInterpUpdateSecs - mLastMessageUpdateSecs > sPhaseOutUpdateInterpolationTime)
+ { // Last update was already phased out a bit
+ phase_out = (sMaxUpdateInterpolationTime - time_since_last_update) /
+ (sMaxUpdateInterpolationTime - time_since_last_interpolation);
+ //llinfos << "Continuing motion phase out of " << (F32) phase_out << llendl;
+ }
+ else
+ { // Phase out from full value
+ phase_out = (sMaxUpdateInterpolationTime - time_since_last_update) /
+ (sMaxUpdateInterpolationTime - sPhaseOutUpdateInterpolationTime);
+ //llinfos << "Starting motion phase out of " << (F32) phase_out << llendl;
+ }
+ phase_out = llclamp(phase_out, 0.0, 1.0);
+
+ new_pos = new_pos * ((F32) phase_out);
+ new_v = new_v * ((F32) phase_out);
+ }
+ }
+ }
+ }
+
+ new_pos = new_pos + getPositionRegion();
+ new_v = new_v + vel;
+
+
+ // Clamp interpolated position to minimum underground and maximum region height
+ LLVector3d new_pos_global = mRegionp->getPosGlobalFromRegion(new_pos);
+ F32 min_height;
+ if (isAvatar())
+ { // Make a better guess about AVs not going underground
+ min_height = LLWorld::getInstance()->resolveLandHeightGlobal(new_pos_global);
+ min_height += (0.5f * getScale().mV[VZ]);
+ }
+ else
+ { // This will put the object underground, but we can't tell if it will stop
+ // at ground level or not
+ min_height = LLWorld::getInstance()->getMinAllowedZ(this, new_pos_global);
+ }
+
+ new_pos.mV[VZ] = llmax(min_height, new_pos.mV[VZ]);
+ new_pos.mV[VZ] = llmin(LLWorld::getInstance()->getRegionMaxHeight(), new_pos.mV[VZ]);
+
+ // Check to see if it's going off the region
+ LLVector3 temp(new_pos);
+ if (temp.clamp(0.f, mRegionp->getWidth()))
+ { // Going off this region, so see if we might end up on another region
+ LLVector3d old_pos_global = mRegionp->getPosGlobalFromRegion(getPositionRegion());
+ new_pos_global = mRegionp->getPosGlobalFromRegion(new_pos); // Re-fetch in case it got clipped above
+
+ // Clip the positions to known regions
+ LLVector3d clip_pos_global = LLWorld::getInstance()->clipToVisibleRegions(old_pos_global, new_pos_global);
+ if (clip_pos_global != new_pos_global)
+ { // Was clipped, so this means we hit a edge where there is no region to enter
+
+ //llinfos << "Hit empty region edge, clipped predicted position to " << mRegionp->getPosRegionFromGlobal(clip_pos_global)
+ // << " from " << new_pos << llendl;
+ new_pos = mRegionp->getPosRegionFromGlobal(clip_pos_global);
+
+ // Stop motion and get server update for bouncing on the edge
+ new_v.clear();
+ setAcceleration(LLVector3::zero);
+ }
+ else
+ { // Let predicted movement cross into another region
+ //llinfos << "Predicting region crossing to " << new_pos << llendl;
+ }
+ }
+
+ // Set new position and velocity
+ setPositionRegion(new_pos);
+ setVelocity(new_v);
+
+ // for objects that are spinning but not translating, make sure to flag them as having moved
+ setChanged(MOVED | SILHOUETTE);
+ }
+
+ // Update the last time we did anything
+ mLastInterpUpdateSecs = time;
}
+
BOOL LLViewerObject::setData(const U8 *datap, const U32 data_size)
{
LLMemType mt(LLMemType::MTYPE_OBJECT);
@@ -2865,6 +3024,8 @@ void LLViewerObject::setScale(const LLVector3 &scale, BOOL damped)
{
if (!mOnMap)
{
+ llassert_always(LLWorld::getInstance()->getRegionFromHandle(getRegion()->getHandle()));
+
gObjectList.addToMap(this);
mOnMap = TRUE;
}
@@ -2880,21 +3041,126 @@ void LLViewerObject::setScale(const LLVector3 &scale, BOOL damped)
}
}
-void LLViewerObject::updateSpatialExtents(LLVector3& newMin, LLVector3 &newMax)
+void LLViewerObject::setObjectCost(F32 cost)
{
- LLVector3 center = getRenderPosition();
- LLVector3 size = getScale();
- newMin.setVec(center-size);
- newMax.setVec(center+size);
- mDrawable->setPositionGroup((newMin + newMax) * 0.5f);
+ mObjectCost = cost;
+ mCostStale = false;
+
+ if (isSelected())
+ {
+ gFloaterTools->dirty();
+ }
+}
+
+void LLViewerObject::setLinksetCost(F32 cost)
+{
+ mLinksetCost = cost;
+ mCostStale = false;
+
+ if (isSelected())
+ {
+ gFloaterTools->dirty();
+ }
+}
+
+void LLViewerObject::setPhysicsCost(F32 cost)
+{
+ mPhysicsCost = cost;
+ mCostStale = false;
+
+ if (isSelected())
+ {
+ gFloaterTools->dirty();
+ }
+}
+
+void LLViewerObject::setLinksetPhysicsCost(F32 cost)
+{
+ mLinksetPhysicsCost = cost;
+ mCostStale = false;
+
+ if (isSelected())
+ {
+ gFloaterTools->dirty();
+ }
+}
+
+
+F32 LLViewerObject::getObjectCost()
+{
+ if (mCostStale)
+ {
+ gObjectList.updateObjectCost(this);
+ }
+
+ return mObjectCost;
+}
+
+F32 LLViewerObject::getLinksetCost()
+{
+ if (mCostStale)
+ {
+ gObjectList.updateObjectCost(this);
+ }
+
+ return mLinksetCost;
+}
+
+F32 LLViewerObject::getPhysicsCost()
+{
+ if (mCostStale)
+ {
+ gObjectList.updateObjectCost(this);
+ }
+
+ return mPhysicsCost;
+}
+
+F32 LLViewerObject::getLinksetPhysicsCost()
+{
+ if (mCostStale)
+ {
+ gObjectList.updateObjectCost(this);
+ }
+
+ return mLinksetPhysicsCost;
+}
+
+F32 LLViewerObject::getStreamingCost(S32* bytes, S32* visible_bytes)
+{
+ return 0.f;
+}
+
+U32 LLViewerObject::getTriangleCount()
+{
+ return 0;
+}
+
+U32 LLViewerObject::getHighLODTriangleCount()
+{
+ return 0;
+}
+
+void LLViewerObject::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax)
+{
+ LLVector4a center;
+ center.load3(getRenderPosition().mV);
+ LLVector4a size;
+ size.load3(getScale().mV);
+ newMin.setSub(center, size);
+ newMax.setAdd(center, size);
+
+ mDrawable->setPositionGroup(center);
}
F32 LLViewerObject::getBinRadius()
{
if (mDrawable.notNull())
{
- const LLVector3* ext = mDrawable->getSpatialExtents();
- return (ext[1]-ext[0]).magVec();
+ const LLVector4a* ext = mDrawable->getSpatialExtents();
+ LLVector4a diff;
+ diff.setSub(ext[1], ext[0]);
+ return diff.getLength3().getF32();
}
return getScale().magVec();
@@ -2960,7 +3226,7 @@ void LLViewerObject::boostTexturePriority(BOOL boost_children /* = TRUE */)
getTEImage(i)->setBoostLevel(LLViewerTexture::BOOST_SELECTED);
}
- if (isSculpted())
+ if (isSculpted() && !isMesh())
{
LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT);
LLUUID sculpt_id = sculpt_params->getSculptTexture();
@@ -3200,6 +3466,15 @@ const LLVector3 LLViewerObject::getPositionEdit() const
const LLVector3 LLViewerObject::getRenderPosition() const
{
+ if (mDrawable.notNull() && mDrawable->isState(LLDrawable::RIGGED))
+ {
+ LLVOAvatar* avatar = getAvatar();
+ if (avatar)
+ {
+ return avatar->getPositionAgent();
+ }
+ }
+
if (mDrawable.isNull() || mDrawable->getGeneration() < 0)
{
return getPositionAgent();
@@ -3218,6 +3493,11 @@ const LLVector3 LLViewerObject::getPivotPositionAgent() const
const LLQuaternion LLViewerObject::getRenderRotation() const
{
LLQuaternion ret;
+ if (mDrawable.notNull() && mDrawable->isState(LLDrawable::RIGGED))
+ {
+ return ret;
+ }
+
if (mDrawable.isNull() || mDrawable->isStatic())
{
ret = getRotationEdit();
@@ -3392,8 +3672,8 @@ void LLViewerObject::setPositionParent(const LLVector3 &pos_parent, BOOL damped)
// Set position relative to parent, if no parent, relative to region
if (!isRoot())
{
- LLViewerObject::setPosition(pos_parent);
- updateDrawable(damped);
+ LLViewerObject::setPosition(pos_parent, damped);
+ //updateDrawable(damped);
}
else
{
@@ -3434,6 +3714,7 @@ void LLViewerObject::setPositionEdit(const LLVector3 &pos_edit, BOOL damped)
LLVector3 position_offset = getPosition() * getParent()->getRotation();
((LLViewerObject *)getParent())->setPositionEdit(pos_edit - position_offset);
+ updateDrawable(damped);
}
else if (isJointChild())
{
@@ -3442,15 +3723,14 @@ void LLViewerObject::setPositionEdit(const LLVector3 &pos_edit, BOOL damped)
LLQuaternion inv_parent_rot = parent->getRotation();
inv_parent_rot.transQuat();
LLVector3 pos_parent = (pos_edit - parent->getPositionRegion()) * inv_parent_rot;
- LLViewerObject::setPosition(pos_parent);
+ LLViewerObject::setPosition(pos_parent, damped);
}
else
{
- LLViewerObject::setPosition(pos_edit);
+ LLViewerObject::setPosition(pos_edit, damped);
mPositionRegion = pos_edit;
mPositionAgent = mRegionp->getPosAgentFromRegion(mPositionRegion);
- }
- updateDrawable(damped);
+ }
}
@@ -3486,12 +3766,21 @@ BOOL LLViewerObject::lineSegmentBoundingBox(const LLVector3& start, const LLVect
return FALSE;
}
- const LLVector3* ext = mDrawable->getSpatialExtents();
+ const LLVector4a* ext = mDrawable->getSpatialExtents();
+
+ //VECTORIZE THIS
+ LLVector4a center;
+ center.setAdd(ext[1], ext[0]);
+ center.mul(0.5f);
+ LLVector4a size;
+ size.setSub(ext[1], ext[0]);
+ size.mul(0.5f);
- LLVector3 center = (ext[1]+ext[0])*0.5f;
- LLVector3 size = (ext[1]-ext[0])*0.5f;
+ LLVector4a starta, enda;
+ starta.load3(start.mV);
+ enda.load3(end.mV);
- return LLLineSegmentBoxIntersect(start, end, center, size);
+ return LLLineSegmentBoxIntersect(starta, enda, center, size);
}
U8 LLViewerObject::getMediaType() const
@@ -4972,6 +5261,20 @@ void LLViewerObject::setRegion(LLViewerRegion *regionp)
updateDrawable(FALSE);
}
+// virtual
+void LLViewerObject::updateRegion(LLViewerRegion *regionp)
+{
+// if (regionp)
+// {
+// F64 now = LLFrameTimer::getElapsedSeconds();
+// llinfos << "Updating to region " << regionp->getName()
+// << ", ms since last update message: " << (F32)((now - mLastMessageUpdateSecs) * 1000.0)
+// << ", ms since last interpolation: " << (F32)((now - mLastInterpUpdateSecs) * 1000.0)
+// << llendl;
+// }
+}
+
+
bool LLViewerObject::specialHoverCursor() const
{
return (mFlags & FLAGS_USE_PHYSICS)
@@ -4992,6 +5295,12 @@ void LLViewerObject::updateFlags()
gMessageSystem->addBOOL("IsTemporary", flagTemporaryOnRez() );
gMessageSystem->addBOOL("IsPhantom", flagPhantom() );
gMessageSystem->addBOOL("CastsShadows", flagCastShadows() );
+ gMessageSystem->nextBlock("ExtraPhysics");
+ gMessageSystem->addU8("PhysicsShapeType", getPhysicsShapeType() );
+ gMessageSystem->addF32("Density", getPhysicsDensity() );
+ gMessageSystem->addF32("Friction", getPhysicsFriction() );
+ gMessageSystem->addF32("Restitution", getPhysicsRestitution() );
+ gMessageSystem->addF32("GravityMultiplier", getPhysicsGravity() );
gMessageSystem->sendReliable( regionp->getHost() );
}
@@ -5024,6 +5333,44 @@ BOOL LLViewerObject::setFlags(U32 flags, BOOL state)
return setit;
}
+void LLViewerObject::setPhysicsShapeType(U8 type)
+{
+ mPhysicsShapeUnknown = false;
+ mPhysicsShapeType = type;
+ mCostStale = true;
+}
+
+void LLViewerObject::setPhysicsGravity(F32 gravity)
+{
+ mPhysicsGravity = gravity;
+}
+
+void LLViewerObject::setPhysicsFriction(F32 friction)
+{
+ mPhysicsFriction = friction;
+}
+
+void LLViewerObject::setPhysicsDensity(F32 density)
+{
+ mPhysicsDensity = density;
+}
+
+void LLViewerObject::setPhysicsRestitution(F32 restitution)
+{
+ mPhysicsRestitution = restitution;
+}
+
+U8 LLViewerObject::getPhysicsShapeType() const
+{
+ if (mPhysicsShapeUnknown)
+ {
+ mPhysicsShapeUnknown = false;
+ gObjectList.updatePhysicsFlags(this);
+ }
+
+ return mPhysicsShapeType;
+}
+
void LLViewerObject::applyAngularVelocity(F32 dt)
{
//do target omega here
@@ -5245,6 +5592,26 @@ void LLViewerObject::setAttachmentItemID(const LLUUID &id)
mAttachmentItemID = id;
}
+EObjectUpdateType LLViewerObject::getLastUpdateType() const
+{
+ return mLastUpdateType;
+}
+
+void LLViewerObject::setLastUpdateType(EObjectUpdateType last_update_type)
+{
+ mLastUpdateType = last_update_type;
+}
+
+BOOL LLViewerObject::getLastUpdateCached() const
+{
+ return mLastUpdateCached;
+}
+
+void LLViewerObject::setLastUpdateCached(BOOL last_update_cached)
+{
+ mLastUpdateCached = last_update_cached;
+}
+
const LLUUID &LLViewerObject::extractAttachmentItemID()
{
LLUUID item_id = LLUUID::null;
@@ -5260,3 +5627,75 @@ const LLUUID &LLViewerObject::extractAttachmentItemID()
setAttachmentItemID(item_id);
return getAttachmentItemID();
}
+
+//virtual
+LLVOAvatar* LLViewerObject::getAvatar() const
+{
+ if (isAttachment())
+ {
+ LLViewerObject* vobj = (LLViewerObject*) getParent();
+
+ while (vobj && !vobj->asAvatar())
+ {
+ vobj = (LLViewerObject*) vobj->getParent();
+ }
+
+ return (LLVOAvatar*) vobj;
+ }
+
+ return NULL;
+}
+
+
+class ObjectPhysicsProperties : public LLHTTPNode
+{
+public:
+ virtual void post(
+ ResponsePtr responder,
+ const LLSD& context,
+ const LLSD& input) const
+ {
+ LLSD object_data = input["body"]["ObjectData"];
+ S32 num_entries = object_data.size();
+
+ for ( S32 i = 0; i < num_entries; i++ )
+ {
+ LLSD& curr_object_data = object_data[i];
+ U32 local_id = curr_object_data["LocalID"].asInteger();
+
+ // Iterate through nodes at end, since it can be on both the regular AND hover list
+ struct f : public LLSelectedNodeFunctor
+ {
+ U32 mID;
+ f(const U32& id) : mID(id) {}
+ virtual bool apply(LLSelectNode* node)
+ {
+ return (node->getObject() && node->getObject()->mLocalID == mID );
+ }
+ } func(local_id);
+
+ LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode(&func);
+
+ if (node)
+ {
+ // The LLSD message builder doesn't know how to handle U8, so we need to send as S8 and cast
+ U8 type = (U8)curr_object_data["PhysicsShapeType"].asInteger();
+ F32 density = (F32)curr_object_data["Density"].asReal();
+ F32 friction = (F32)curr_object_data["Friction"].asReal();
+ F32 restitution = (F32)curr_object_data["Restitution"].asReal();
+ F32 gravity = (F32)curr_object_data["GravityMultiplier"].asReal();
+
+ node->getObject()->setPhysicsShapeType(type);
+ node->getObject()->setPhysicsGravity(gravity);
+ node->getObject()->setPhysicsFriction(friction);
+ node->getObject()->setPhysicsDensity(density);
+ node->getObject()->setPhysicsRestitution(restitution);
+ }
+ }
+
+ dialog_refresh_all();
+ };
+};
+
+LLHTTPRegistration<ObjectPhysicsProperties>
+ gHTTPRegistrationObjectPhysicsProperties("/message/ObjectPhysicsProperties");
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index 7d697a4a5f..e417343bec 100644
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -77,6 +77,7 @@ typedef enum e_object_update_type
OUT_TERSE_IMPROVED,
OUT_FULL_COMPRESSED,
OUT_FULL_CACHED,
+ OUT_UNKNOWN,
} EObjectUpdateType;
@@ -131,7 +132,7 @@ public:
typedef const child_list_t const_child_list_t;
- LLViewerObject(const LLUUID &id, const LLPCode type, LLViewerRegion *regionp, BOOL is_global = FALSE);
+ LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp, BOOL is_global = FALSE);
MEM_TYPE_NEW(LLMemType::MTYPE_OBJECT);
virtual void markDead(); // Mark this object as dead, and clean up its references
@@ -175,6 +176,7 @@ public:
void setOnActiveList(BOOL on_active) { mOnActiveList = on_active; }
virtual BOOL isAttachment() const { return FALSE; }
+ virtual LLVOAvatar* getAvatar() const; //get the avatar this object is attached to, or NULL if object is not an attachment
virtual BOOL isHUDAttachment() const { return FALSE; }
virtual void updateRadius() {};
virtual F32 getVObjRadius() const; // default implemenation is mDrawable->getRadius()
@@ -223,15 +225,13 @@ public:
virtual BOOL isFlexible() const { return FALSE; }
virtual BOOL isSculpted() const { return FALSE; }
+ virtual BOOL isMesh() const { return FALSE; }
virtual BOOL hasLightTexture() const { return FALSE; }
// This method returns true if the object is over land owned by
- // the agent.
- BOOL isOverAgentOwnedLand() const;
-
- // True if over land owned by group of which the agent is
- // either officer or member.
- BOOL isOverGroupOwnedLand() const;
+ // the agent, one of its groups, or it encroaches and
+ // anti-encroachment is enabled
+ bool isReturnable();
/*
// This method will scan through this object, and then query the
@@ -326,6 +326,22 @@ public:
virtual void setScale(const LLVector3 &scale, BOOL damped = FALSE);
+ virtual F32 getStreamingCost(S32* bytes = NULL, S32* visible_bytes = NULL);
+ virtual U32 getTriangleCount();
+ virtual U32 getHighLODTriangleCount();
+
+ void setObjectCost(F32 cost);
+ F32 getObjectCost();
+
+ void setLinksetCost(F32 cost);
+ F32 getLinksetCost();
+
+ void setPhysicsCost(F32 cost);
+ F32 getPhysicsCost();
+
+ void setLinksetPhysicsCost(F32 cost);
+ F32 getLinksetPhysicsCost();
+
void sendShapeUpdate();
U8 getState() { return mState; }
@@ -365,7 +381,7 @@ public:
void markForUpdate(BOOL priority);
void updateVolume(const LLVolumeParams& volume_params);
- virtual void updateSpatialExtents(LLVector3& min, LLVector3& max);
+ virtual void updateSpatialExtents(LLVector4a& min, LLVector4a& max);
virtual F32 getBinRadius();
LLBBox getBoundingBoxAgent() const;
@@ -378,7 +394,7 @@ public:
void clearDrawableState(U32 state, BOOL recursive = TRUE);
// Called when the drawable shifts
- virtual void onShift(const LLVector3 &shift_vector) { }
+ virtual void onShift(const LLVector4a &shift_vector) { }
//////////////////////////////////////
//
@@ -453,6 +469,12 @@ public:
inline BOOL flagCameraDecoupled() const { return ((mFlags & FLAGS_CAMERA_DECOUPLED) != 0); }
inline BOOL flagObjectMove() const { return ((mFlags & FLAGS_OBJECT_MOVE) != 0); }
+ U8 getPhysicsShapeType() const;
+ inline F32 getPhysicsGravity() const { return mPhysicsGravity; }
+ inline F32 getPhysicsFriction() const { return mPhysicsFriction; }
+ inline F32 getPhysicsDensity() const { return mPhysicsDensity; }
+ inline F32 getPhysicsRestitution() const { return mPhysicsRestitution; }
+
bool getIncludeInSearch() const;
void setIncludeInSearch(bool include_in_search);
@@ -464,10 +486,15 @@ public:
bool specialHoverCursor() const; // does it have a special hover cursor?
void setRegion(LLViewerRegion *regionp);
- virtual void updateRegion(LLViewerRegion *regionp) {}
+ virtual void updateRegion(LLViewerRegion *regionp);
void updateFlags();
BOOL setFlags(U32 flag, BOOL state);
+ void setPhysicsShapeType(U8 type);
+ void setPhysicsGravity(F32 gravity);
+ void setPhysicsFriction(F32 friction);
+ void setPhysicsDensity(F32 density);
+ void setPhysicsRestitution(F32 restitution);
virtual void dump() const;
static U32 getNumZombieObjects() { return sNumZombieObjects; }
@@ -510,6 +537,9 @@ private:
// and the update wasn't due to this agent's last action.
U32 checkMediaURL(const std::string &media_url);
+ // Motion prediction between updates
+ void interpolateLinearMotion(const F64 & time, const F32 & dt);
+
public:
//
// Viewer-side only types - use the LL_PCODE_APP mask.
@@ -518,17 +548,24 @@ public:
{
LL_VO_CLOUDS = LL_PCODE_APP | 0x20,
LL_VO_SURFACE_PATCH = LL_PCODE_APP | 0x30,
- //LL_VO_STARS = LL_PCODE_APP | 0x40,
+ LL_VO_WL_SKY = LL_PCODE_APP | 0x40,
LL_VO_SQUARE_TORUS = LL_PCODE_APP | 0x50,
LL_VO_SKY = LL_PCODE_APP | 0x60,
- LL_VO_WATER = LL_PCODE_APP | 0x70,
- LL_VO_GROUND = LL_PCODE_APP | 0x80,
- LL_VO_PART_GROUP = LL_PCODE_APP | 0x90,
- LL_VO_TRIANGLE_TORUS = LL_PCODE_APP | 0xa0,
- LL_VO_WL_SKY = LL_PCODE_APP | 0xb0, // should this be moved to 0x40?
+ LL_VO_VOID_WATER = LL_PCODE_APP | 0x70,
+ LL_VO_WATER = LL_PCODE_APP | 0x80,
+ LL_VO_GROUND = LL_PCODE_APP | 0x90,
+ LL_VO_PART_GROUP = LL_PCODE_APP | 0xa0,
+ LL_VO_TRIANGLE_TORUS = LL_PCODE_APP | 0xb0,
LL_VO_HUD_PART_GROUP = LL_PCODE_APP | 0xc0,
} EVOType;
+ typedef enum e_physics_shape_types
+ {
+ PHYSICS_SHAPE_PRIM = 0,
+ PHYSICS_SHAPE_NONE,
+ PHYSICS_SHAPE_CONVEX_HULL,
+ } EPhysicsShapeType;
+
LLUUID mID;
// unique within region, not unique across regions
@@ -547,6 +584,14 @@ public:
// Grabbed from UPDATE_FLAGS
U32 mFlags;
+ // Sent to sim in UPDATE_FLAGS, received in ObjectPhysicsProperties
+ U8 mPhysicsShapeType;
+ F32 mPhysicsGravity;
+ F32 mPhysicsFriction;
+ F32 mPhysicsDensity;
+ F32 mPhysicsRestitution;
+
+
// Pipeline classes
LLPointer<LLDrawable> mDrawable;
@@ -612,6 +657,7 @@ protected:
F64 mLastInterpUpdateSecs; // Last update for purposes of interpolation
F64 mLastMessageUpdateSecs; // Last update from a message from the simulator
TPACKETID mLatestRecvPacketID; // Latest time stamp on message from simulator
+
// extra data sent from the sim...currently only used for tree species info
U8* mData;
@@ -654,6 +700,13 @@ protected:
U8 mState; // legacy
LLViewerObjectMedia* mMedia; // NULL if no media associated
U8 mClickAction;
+ F32 mObjectCost; //resource cost of this object or -1 if unknown
+ F32 mLinksetCost;
+ F32 mPhysicsCost;
+ F32 mLinksetPhysicsCost;
+
+ bool mCostStale;
+ mutable bool mPhysicsShapeUnknown;
static U32 sNumZombieObjects; // Objects which are dead, but not deleted
@@ -669,9 +722,21 @@ protected:
mutable LLVector3 mPositionRegion;
mutable LLVector3 mPositionAgent;
+ static void setPhaseOutUpdateInterpolationTime(F32 value) { sPhaseOutUpdateInterpolationTime = (F64) value; }
+ static void setMaxUpdateInterpolationTime(F32 value) { sMaxUpdateInterpolationTime = (F64) value; }
+
+ static void setVelocityInterpolate(BOOL value) { sVelocityInterpolate = value; }
+ static void setPingInterpolate(BOOL value) { sPingInterpolate = value; }
+
private:
static S32 sNumObjects;
+ static F64 sPhaseOutUpdateInterpolationTime; // For motion interpolation
+ static F64 sMaxUpdateInterpolationTime; // For motion interpolation
+
+ static BOOL sVelocityInterpolate;
+ static BOOL sPingInterpolate;
+
//--------------------------------------------------------------------
// For objects that are attachments
//--------------------------------------------------------------------
@@ -679,8 +744,15 @@ public:
const LLUUID &getAttachmentItemID() const;
void setAttachmentItemID(const LLUUID &id);
const LLUUID &extractAttachmentItemID(); // find&set the inventory item ID of the attached object
+ EObjectUpdateType getLastUpdateType() const;
+ void setLastUpdateType(EObjectUpdateType last_update_type);
+ BOOL getLastUpdateCached() const;
+ void setLastUpdateCached(BOOL last_update_cached);
+
private:
LLUUID mAttachmentItemID; // ItemID of the associated object is in user inventory.
+ EObjectUpdateType mLastUpdateType;
+ BOOL mLastUpdateCached;
};
///////////////////
@@ -717,8 +789,8 @@ public:
class LLAlphaObject : public LLViewerObject
{
public:
- LLAlphaObject(const LLUUID &id, const LLPCode type, LLViewerRegion *regionp)
- : LLViewerObject(id,type,regionp)
+ LLAlphaObject(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
+ : LLViewerObject(id,pcode,regionp)
{ mDepth = 0.f; }
virtual F32 getPartSize(S32 idx);
@@ -735,14 +807,12 @@ public:
class LLStaticViewerObject : public LLViewerObject
{
public:
- LLStaticViewerObject(const LLUUID& id, const LLPCode type, LLViewerRegion* regionp, BOOL is_global = FALSE)
- : LLViewerObject(id,type,regionp, is_global)
+ LLStaticViewerObject(const LLUUID& id, const LLPCode pcode, LLViewerRegion* regionp, BOOL is_global = FALSE)
+ : LLViewerObject(id,pcode,regionp, is_global)
{ }
virtual void updateDrawable(BOOL force_damped);
};
-extern BOOL gVelocityInterpolate;
-extern BOOL gPingInterpolate;
#endif
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index b597e6148e..ab2e07e4df 100644
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -54,8 +54,10 @@
#include "llviewercamera.h"
#include "llselectmgr.h"
#include "llresmgr.h"
+#include "llsdutil.h"
#include "llviewerregion.h"
#include "llviewerstats.h"
+#include "llviewerstatsrecorder.h"
#include "llvoavatarself.h"
#include "lltoolmgr.h"
#include "lltoolpie.h"
@@ -159,14 +161,13 @@ U64 LLViewerObjectList::getIndex(const U32 local_id,
return (((U64)index) << 32) | (U64)local_id;
}
-BOOL LLViewerObjectList::removeFromLocalIDTable(const LLViewerObject &object)
+BOOL LLViewerObjectList::removeFromLocalIDTable(const LLViewerObject* objectp)
{
- if(object.getRegion())
+ if(objectp && objectp->getRegion())
{
- U32 local_id = object.mLocalID;
- LLHost region_host = object.getRegion()->getHost();
- U32 ip = region_host.getAddress();
- U32 port = region_host.getPort();
+ U32 local_id = objectp->mLocalID;
+ U32 ip = objectp->getRegion()->getHost().getAddress();
+ U32 port = objectp->getRegion()->getHost().getPort();
U64 ipport = (((U64)ip) << 32) | (U64)port;
U32 index = sIPAndPortToIndex[ipport];
@@ -181,7 +182,7 @@ BOOL LLViewerObjectList::removeFromLocalIDTable(const LLViewerObject &object)
}
// Found existing entry
- if (iter->second == object.getID())
+ if (iter->second == objectp->getID())
{ // Full UUIDs match, so remove the entry
sIndexAndLocalIDToUUID.erase(iter);
return TRUE;
@@ -297,8 +298,10 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
// have to transform to absolute coordinates.
num_objects = mesgsys->getNumberOfBlocksFast(_PREHASH_ObjectData);
+ // I don't think this case is ever hit. TODO* Test this.
if (!cached && !compressed && update_type != OUT_FULL)
{
+ //llinfos << "TEST: !cached && !compressed && update_type != OUT_FULL" << llendl;
gTerseObjectUpdates += num_objects;
S32 size;
if (mesgsys->getReceiveCompressedSize())
@@ -309,7 +312,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
{
size = mesgsys->getReceiveSize();
}
- // llinfos << "Received terse " << num_objects << " in " << size << " byte (" << size/num_objects << ")" << llendl;
+ //llinfos << "Received terse " << num_objects << " in " << size << " byte (" << size/num_objects << ")" << llendl;
}
else
{
@@ -340,9 +343,14 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
U8 compressed_dpbuffer[2048];
LLDataPackerBinaryBuffer compressed_dp(compressed_dpbuffer, 2048);
LLDataPacker *cached_dpp = NULL;
-
+
+#if LL_RECORD_VIEWER_STATS
+ LLViewerStatsRecorder::instance()->beginObjectUpdateEvents(regionp);
+#endif
+
for (i = 0; i < num_objects; i++)
{
+ // timer is unused?
LLTimer update_timer;
BOOL justCreated = FALSE;
@@ -354,9 +362,11 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_CRC, crc, i);
// Lookup data packer and add this id to cache miss lists if necessary.
- cached_dpp = regionp->getDP(id, crc);
+ U8 cache_miss_type = LLViewerRegion::CACHE_MISS_TYPE_NONE;
+ cached_dpp = regionp->getDP(id, crc, cache_miss_type);
if (cached_dpp)
{
+ // Cache Hit.
cached_dpp->reset();
cached_dpp->unpackUUID(fullid, "ID");
cached_dpp->unpackU32(local_id, "LocalID");
@@ -364,6 +374,11 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
}
else
{
+ // Cache Miss.
+ #if LL_RECORD_VIEWER_STATS
+ LLViewerStatsRecorder::instance()->recordCacheMissEvent(id, update_type, cache_miss_type);
+ #endif
+
continue; // no data packer, skip this object
}
}
@@ -375,13 +390,15 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
compressed_dp.reset();
U32 flags = 0;
- if (update_type != OUT_TERSE_IMPROVED)
+ if (update_type != OUT_TERSE_IMPROVED) // OUT_FULL_COMPRESSED only?
{
mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, i);
}
+ // I don't think we ever use this flag from the server. DK 2010/12/09
if (flags & FLAGS_ZLIB_COMPRESSED)
{
+ //llinfos << "TEST: flags & FLAGS_ZLIB_COMPRESSED" << llendl;
compressed_length = mesgsys->getSizeFast(_PREHASH_ObjectData, i, _PREHASH_Data);
mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_Data, compbuffer, 0, i);
uncompressed_length = 2048;
@@ -397,7 +414,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
}
- if (update_type != OUT_TERSE_IMPROVED)
+ if (update_type != OUT_TERSE_IMPROVED) // OUT_FULL_COMPRESSED only?
{
compressed_dp.unpackUUID(fullid, "ID");
compressed_dp.unpackU32(local_id, "LocalID");
@@ -417,7 +434,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
}
}
}
- else if (update_type != OUT_FULL)
+ else if (update_type != OUT_FULL) // !compressed, !OUT_FULL ==> OUT_FULL_CACHED only?
{
mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, local_id, i);
getUUIDFromLocal(fullid,
@@ -430,7 +447,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
mNumUnknownUpdates++;
}
}
- else
+ else // OUT_FULL only?
{
mesgsys->getUUIDFast(_PREHASH_ObjectData, _PREHASH_FullID, fullid, i);
mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, local_id, i);
@@ -455,19 +472,19 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
// << ", regionp " << (U32) regionp << ", object region " << (U32) objectp->getRegion()
// << llendl;
//}
- removeFromLocalIDTable(*objectp);
+ removeFromLocalIDTable(objectp);
setUUIDAndLocal(fullid,
local_id,
gMessageSystem->getSenderIP(),
gMessageSystem->getSenderPort());
if (objectp->mLocalID != local_id)
- { // Update local ID in object with the one sent from the region
+ { // Update local ID in object with the one sent from the region
objectp->mLocalID = local_id;
}
if (objectp->getRegion() != regionp)
- { // Object changed region, so update it
+ { // Object changed region, so update it
objectp->updateRegion(regionp); // for LLVOAvatar
}
}
@@ -478,18 +495,24 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
{
if (update_type == OUT_TERSE_IMPROVED)
{
- // llinfos << "terse update for an unknown object:" << fullid << llendl;
+ // llinfos << "terse update for an unknown object (compressed):" << fullid << llendl;
+ #if LL_RECORD_VIEWER_STATS
+ LLViewerStatsRecorder::instance()->recordObjectUpdateFailure(local_id, update_type);
+ #endif
continue;
}
}
- else if (cached)
+ else if (cached) // Cache hit only?
{
}
else
{
if (update_type != OUT_FULL)
{
- // llinfos << "terse update for an unknown object:" << fullid << llendl;
+ //llinfos << "terse update for an unknown object:" << fullid << llendl;
+ #if LL_RECORD_VIEWER_STATS
+ LLViewerStatsRecorder::instance()->recordObjectUpdateFailure(local_id, update_type);
+ #endif
continue;
}
@@ -499,7 +522,10 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
if (mDeadObjects.find(fullid) != mDeadObjects.end())
{
mNumDeadObjectUpdates++;
- // llinfos << "update for a dead object:" << fullid << llendl;
+ //llinfos << "update for a dead object:" << fullid << llendl;
+ #if LL_RECORD_VIEWER_STATS
+ LLViewerStatsRecorder::instance()->recordObjectUpdateFailure(local_id, update_type);
+ #endif
continue;
}
#endif
@@ -507,6 +533,10 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
objectp = createObject(pcode, regionp, fullid, local_id, gMessageSystem->getSender());
if (!objectp)
{
+ llinfos << "createObject failure for object: " << fullid << llendl;
+ #if LL_RECORD_VIEWER_STATS
+ LLViewerStatsRecorder::instance()->recordObjectUpdateFailure(local_id, update_type);
+ #endif
continue;
}
justCreated = TRUE;
@@ -519,19 +549,26 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
llwarns << "Dead object " << objectp->mID << " in UUID map 1!" << llendl;
}
+ bool bCached = false;
if (compressed)
{
- if (update_type != OUT_TERSE_IMPROVED)
+ if (update_type != OUT_TERSE_IMPROVED) // OUT_FULL_COMPRESSED only?
{
objectp->mLocalID = local_id;
}
processUpdateCore(objectp, user_data, i, update_type, &compressed_dp, justCreated);
- if (update_type != OUT_TERSE_IMPROVED)
+ if (update_type != OUT_TERSE_IMPROVED) // OUT_FULL_COMPRESSED only?
{
+ bCached = true;
+ #if LL_RECORD_VIEWER_STATS
+ LLViewerRegion::eCacheUpdateResult result = objectp->mRegionp->cacheFullUpdate(objectp, compressed_dp);
+ LLViewerStatsRecorder::instance()->recordCacheFullUpdate(local_id, update_type, result, objectp);
+ #else
objectp->mRegionp->cacheFullUpdate(objectp, compressed_dp);
+ #endif
}
}
- else if (cached)
+ else if (cached) // Cache hit only?
{
objectp->mLocalID = local_id;
processUpdateCore(objectp, user_data, i, update_type, cached_dpp, justCreated);
@@ -544,8 +581,17 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
}
processUpdateCore(objectp, user_data, i, update_type, NULL, justCreated);
}
+ #if LL_RECORD_VIEWER_STATS
+ LLViewerStatsRecorder::instance()->recordObjectUpdateEvent(local_id, update_type, objectp);
+ #endif
+ objectp->setLastUpdateType(update_type);
+ objectp->setLastUpdateCached(bCached);
}
+#if LL_RECORD_VIEWER_STATS
+ LLViewerStatsRecorder::instance()->endObjectUpdateEvents();
+#endif
+
LLVOAvatar::cullAvatarsByPixelArea();
}
@@ -591,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();
}
}
@@ -650,23 +693,221 @@ void LLViewerObjectList::updateApparentAngles(LLAgent &agent)
LLVOAvatar::cullAvatarsByPixelArea();
}
+class LLObjectCostResponder : public LLCurl::Responder
+{
+public:
+ LLObjectCostResponder(const LLSD& object_ids)
+ : mObjectIDs(object_ids)
+ {
+ }
+
+ // Clear's the global object list's pending
+ // request list for all objects requested
+ void clear_object_list_pending_requests()
+ {
+ // TODO*: No more hard coding
+ for (
+ LLSD::array_iterator iter = mObjectIDs.beginArray();
+ iter != mObjectIDs.endArray();
+ ++iter)
+ {
+ gObjectList.onObjectCostFetchFailure(iter->asUUID());
+ }
+ }
+
+ void error(U32 statusNum, const std::string& reason)
+ {
+ llwarns
+ << "Transport error requesting object cost "
+ << "HTTP status: " << statusNum << ", reason: "
+ << reason << "." << llendl;
+
+ // TODO*: Error message to user
+ // For now just clear the request from the pending list
+ clear_object_list_pending_requests();
+ }
+
+ void result(const LLSD& content)
+ {
+ if ( !content.isMap() || content.has("error") )
+ {
+ // Improper response or the request had an error,
+ // show an error to the user?
+ llwarns
+ << "Application level error when fetching object "
+ << "cost. Message: " << content["error"]["message"].asString()
+ << ", identifier: " << content["error"]["identifier"].asString()
+ << llendl;
+
+ // TODO*: Adaptively adjust request size if the
+ // service says we've requested too many and retry
+
+ // TODO*: Error message if not retrying
+ clear_object_list_pending_requests();
+ return;
+ }
+
+ // Success, grab the resource cost and linked set costs
+ // for an object if one was returned
+ for (
+ LLSD::array_iterator iter = mObjectIDs.beginArray();
+ iter != mObjectIDs.endArray();
+ ++iter)
+ {
+ LLUUID object_id = iter->asUUID();
+
+ // Check to see if the request contains data for the object
+ if ( content.has(iter->asString()) )
+ {
+ F32 link_cost =
+ content[iter->asString()]["linked_set_resource_cost"].asReal();
+ F32 object_cost =
+ content[iter->asString()]["resource_cost"].asReal();
+
+ F32 physics_cost = content[iter->asString()]["physics_cost"].asReal();
+ F32 link_physics_cost = content[iter->asString()]["linked_set_physics_cost"].asReal();
+
+ gObjectList.updateObjectCost(object_id, object_cost, link_cost, physics_cost, link_physics_cost);
+ }
+ else
+ {
+ // TODO*: Give user feedback about the missing data?
+ gObjectList.onObjectCostFetchFailure(object_id);
+ }
+ }
+ }
+
+private:
+ LLSD mObjectIDs;
+};
+
+
+class LLPhysicsFlagsResponder : public LLCurl::Responder
+{
+public:
+ LLPhysicsFlagsResponder(const LLSD& object_ids)
+ : mObjectIDs(object_ids)
+ {
+ }
+
+ // Clear's the global object list's pending
+ // request list for all objects requested
+ void clear_object_list_pending_requests()
+ {
+ // TODO*: No more hard coding
+ for (
+ LLSD::array_iterator iter = mObjectIDs.beginArray();
+ iter != mObjectIDs.endArray();
+ ++iter)
+ {
+ gObjectList.onPhysicsFlagsFetchFailure(iter->asUUID());
+ }
+ }
+
+ void error(U32 statusNum, const std::string& reason)
+ {
+ llwarns
+ << "Transport error requesting object physics flags "
+ << "HTTP status: " << statusNum << ", reason: "
+ << reason << "." << llendl;
+
+ // TODO*: Error message to user
+ // For now just clear the request from the pending list
+ clear_object_list_pending_requests();
+ }
+
+ void result(const LLSD& content)
+ {
+ if ( !content.isMap() || content.has("error") )
+ {
+ // Improper response or the request had an error,
+ // show an error to the user?
+ llwarns
+ << "Application level error when fetching object "
+ << "physics flags. Message: " << content["error"]["message"].asString()
+ << ", identifier: " << content["error"]["identifier"].asString()
+ << llendl;
+
+ // TODO*: Adaptively adjust request size if the
+ // service says we've requested too many and retry
+
+ // TODO*: Error message if not retrying
+ clear_object_list_pending_requests();
+ return;
+ }
+
+ // Success, grab the resource cost and linked set costs
+ // for an object if one was returned
+ for (
+ LLSD::array_iterator iter = mObjectIDs.beginArray();
+ iter != mObjectIDs.endArray();
+ ++iter)
+ {
+ LLUUID object_id = iter->asUUID();
+
+ // Check to see if the request contains data for the object
+ if ( content.has(iter->asString()) )
+ {
+ const LLSD& data = content[iter->asString()];
+
+ S32 shape_type = data["PhysicsShapeType"].asInteger();
+
+ gObjectList.updatePhysicsShapeType(object_id, shape_type);
+
+ if (data.has("Density"))
+ {
+ F32 density = data["Density"].asReal();
+ F32 friction = data["Friction"].asReal();
+ F32 restitution = data["Restitution"].asReal();
+ F32 gravity_multiplier = data["GravityMultiplier"].asReal();
+
+ gObjectList.updatePhysicsProperties(object_id,
+ density, friction, restitution, gravity_multiplier);
+ }
+ }
+ else
+ {
+ // TODO*: Give user feedback about the missing data?
+ gObjectList.onPhysicsFlagsFetchFailure(object_id);
+ }
+ }
+ }
+
+private:
+ LLSD mObjectIDs;
+};
void LLViewerObjectList::update(LLAgent &agent, LLWorld &world)
{
LLMemType mt(LLMemType::MTYPE_OBJECT);
+
// Update globals
- gVelocityInterpolate = gSavedSettings.getBOOL("VelocityInterpolate");
- gPingInterpolate = gSavedSettings.getBOOL("PingInterpolate");
+ LLViewerObject::setVelocityInterpolate( gSavedSettings.getBOOL("VelocityInterpolate") );
+ LLViewerObject::setPingInterpolate( gSavedSettings.getBOOL("PingInterpolate") );
+
+ F32 interp_time = gSavedSettings.getF32("InterpolationTime");
+ F32 phase_out_time = gSavedSettings.getF32("InterpolationPhaseOut");
+ if (interp_time < 0.0 ||
+ phase_out_time < 0.0 ||
+ phase_out_time > interp_time)
+ {
+ llwarns << "Invalid values for InterpolationTime or InterpolationPhaseOut, resetting to defaults" << llendl;
+ interp_time = 3.0f;
+ phase_out_time = 1.0f;
+ }
+ LLViewerObject::setPhaseOutUpdateInterpolationTime( interp_time );
+ LLViewerObject::setMaxUpdateInterpolationTime( phase_out_time );
+
gAnimateTextures = gSavedSettings.getBOOL("AnimateTextures");
// update global timer
F32 last_time = gFrameTimeSeconds;
- U64 time = totalTime(); // this will become the new gFrameTime when the update is done
+ U64 time = totalTime(); // this will become the new gFrameTime when the update is done
// Time _can_ go backwards, for example if the user changes the system clock.
// It doesn't cause any fatal problems (just some oddness with stats), so we shouldn't assert here.
// llassert(time > gFrameTime);
F64 time_diff = U64_to_F64(time - gFrameTime)/(F64)SEC_TO_MICROSEC;
- gFrameTime = time;
+ gFrameTime = time;
F64 time_since_start = U64_to_F64(gFrameTime - gStartTime)/(F64)SEC_TO_MICROSEC;
gFrameTimeSeconds = (F32)time_since_start;
@@ -747,6 +988,9 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world)
}
}
+ fetchObjectCosts();
+ fetchPhysicsFlags();
+
mNumSizeCulled = 0;
mNumVisCulled = 0;
@@ -768,7 +1012,7 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world)
{
std::string id_str;
objectp->mID.toString(id_str);
- std::string tmpstr = std::string("Par: ") + id_str;
+ std::string tmpstr = std::string("Par: ") + id_str;
addDebugBeacon(objectp->getPositionAgent(),
tmpstr,
LLColor4(1.f,0.f,0.f,1.f),
@@ -788,12 +1032,12 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world)
std::string tmpstr;
if (objectp->getParent())
{
- tmpstr = std::string("ChP: ") + id_str;
+ tmpstr = std::string("ChP: ") + id_str;
text_color = LLColor4(0.f, 1.f, 0.f, 1.f);
}
else
{
- tmpstr = std::string("ChNoP: ") + id_str;
+ tmpstr = std::string("ChNoP: ") + id_str;
text_color = LLColor4(1.f, 0.f, 0.f, 1.f);
}
id = sIndexAndLocalIDToUUID[oi.mParentInfo];
@@ -812,6 +1056,119 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world)
LLViewerStats::getInstance()->mNumVisCulledStat.addValue(mNumVisCulled);
}
+void LLViewerObjectList::fetchObjectCosts()
+{
+ // issue http request for stale object physics costs
+ if (!mStaleObjectCost.empty())
+ {
+ LLViewerRegion* regionp = gAgent.getRegion();
+
+ if (regionp)
+ {
+ std::string url = regionp->getCapability("GetObjectCost");
+
+ if (!url.empty())
+ {
+ LLSD id_list;
+ U32 object_index = 0;
+
+ for (
+ std::set<LLUUID>::iterator iter = mStaleObjectCost.begin();
+ iter != mStaleObjectCost.end();
+ ++iter)
+ {
+ // Check to see if a request for this object
+ // has already been made.
+ if ( mPendingObjectCost.find(*iter) ==
+ mPendingObjectCost.end() )
+ {
+ mPendingObjectCost.insert(*iter);
+ id_list[object_index++] = *iter;
+ }
+ }
+
+ // id_list should now contain all
+ // requests in mStaleObjectCost before, so clear
+ // it now
+ mStaleObjectCost.clear();
+
+ if ( id_list.size() > 0 )
+ {
+ LLSD post_data = LLSD::emptyMap();
+
+ post_data["object_ids"] = id_list;
+ LLHTTPClient::post(
+ url,
+ post_data,
+ new LLObjectCostResponder(id_list));
+ }
+ }
+ else
+ {
+ mStaleObjectCost.clear();
+ mPendingObjectCost.clear();
+ }
+ }
+ }
+}
+
+void LLViewerObjectList::fetchPhysicsFlags()
+{
+ // issue http request for stale object physics flags
+ if (!mStalePhysicsFlags.empty())
+ {
+ LLViewerRegion* regionp = gAgent.getRegion();
+
+ if (regionp)
+ {
+ std::string url = regionp->getCapability("GetObjectPhysicsData");
+
+ if (!url.empty())
+ {
+ LLSD id_list;
+ U32 object_index = 0;
+
+ for (
+ std::set<LLUUID>::iterator iter = mStalePhysicsFlags.begin();
+ iter != mStalePhysicsFlags.end();
+ ++iter)
+ {
+ // Check to see if a request for this object
+ // has already been made.
+ if ( mPendingPhysicsFlags.find(*iter) ==
+ mPendingPhysicsFlags.end() )
+ {
+ mPendingPhysicsFlags.insert(*iter);
+ id_list[object_index++] = *iter;
+ }
+ }
+
+ // id_list should now contain all
+ // requests in mStalePhysicsFlags before, so clear
+ // it now
+ mStalePhysicsFlags.clear();
+
+ if ( id_list.size() > 0 )
+ {
+ LLSD post_data = LLSD::emptyMap();
+
+ post_data["object_ids"] = id_list;
+ LLHTTPClient::post(
+ url,
+ post_data,
+ new LLPhysicsFlagsResponder(id_list));
+ }
+ }
+ else
+ {
+ mStalePhysicsFlags.clear();
+ mPendingPhysicsFlags.clear();
+ }
+ }
+ }
+}
+
+
void LLViewerObjectList::clearDebugText()
{
for (vobj_list_t::iterator iter = mObjects.begin(); iter != mObjects.end(); ++iter)
@@ -824,13 +1181,14 @@ void LLViewerObjectList::clearDebugText()
void LLViewerObjectList::cleanupReferences(LLViewerObject *objectp)
{
LLMemType mt(LLMemType::MTYPE_OBJECT);
- if (mDeadObjects.count(objectp->mID))
+ if (mDeadObjects.find(objectp->mID) != mDeadObjects.end())
{
- llinfos << "Object " << objectp->mID << " already on dead list, ignoring cleanup!" << llendl;
- return;
+ llinfos << "Object " << objectp->mID << " already on dead list!" << llendl;
+ }
+ else
+ {
+ mDeadObjects.insert(objectp->mID);
}
-
- mDeadObjects.insert(std::pair<LLUUID, LLPointer<LLViewerObject> >(objectp->mID, objectp));
// Cleanup any references we have to this object
// Remove from object map so noone can look it up.
@@ -844,7 +1202,7 @@ void LLViewerObjectList::cleanupReferences(LLViewerObject *objectp)
// << objectp->getRegion()->getHost().getPort() << llendl;
//}
- removeFromLocalIDTable(*objectp);
+ removeFromLocalIDTable(objectp);
if (objectp->onActiveList())
{
@@ -865,8 +1223,12 @@ void LLViewerObjectList::cleanupReferences(LLViewerObject *objectp)
mNumDeadObjects++;
}
+static LLFastTimer::DeclareTimer FTM_REMOVE_DRAWABLE("Remove Drawable");
+
void LLViewerObjectList::removeDrawable(LLDrawable* drawablep)
{
+ LLFastTimer t(FTM_REMOVE_DRAWABLE);
+
if (!drawablep)
{
return;
@@ -1031,7 +1393,69 @@ void LLViewerObjectList::updateActive(LLViewerObject *objectp)
}
}
+void LLViewerObjectList::updateObjectCost(LLViewerObject* object)
+{
+ mStaleObjectCost.insert(object->getID());
+}
+
+void LLViewerObjectList::updateObjectCost(const LLUUID& object_id, F32 object_cost, F32 link_cost, F32 physics_cost, F32 link_physics_cost)
+{
+ mPendingObjectCost.erase(object_id);
+
+ LLViewerObject* object = findObject(object_id);
+ if (object)
+ {
+ object->setObjectCost(object_cost);
+ object->setLinksetCost(link_cost);
+ object->setPhysicsCost(physics_cost);
+ object->setLinksetPhysicsCost(link_physics_cost);
+ }
+}
+
+void LLViewerObjectList::onObjectCostFetchFailure(const LLUUID& object_id)
+{
+ //llwarns << "Failed to fetch object cost for object: " << object_id << llendl;
+ mPendingObjectCost.erase(object_id);
+}
+
+void LLViewerObjectList::updatePhysicsFlags(const LLViewerObject* object)
+{
+ mStalePhysicsFlags.insert(object->getID());
+}
+void LLViewerObjectList::updatePhysicsShapeType(const LLUUID& object_id, S32 type)
+{
+ mPendingPhysicsFlags.erase(object_id);
+ LLViewerObject* object = findObject(object_id);
+ if (object)
+ {
+ object->setPhysicsShapeType(type);
+ }
+}
+
+void LLViewerObjectList::updatePhysicsProperties(const LLUUID& object_id,
+ F32 density,
+ F32 friction,
+ F32 restitution,
+ F32 gravity_multiplier)
+{
+ mPendingPhysicsFlags.erase(object_id);
+
+ LLViewerObject* object = findObject(object_id);
+ if (object)
+ {
+ object->setPhysicsDensity(density);
+ object->setPhysicsFriction(friction);
+ object->setPhysicsGravity(gravity_multiplier);
+ object->setPhysicsRestitution(restitution);
+ }
+}
+
+void LLViewerObjectList::onPhysicsFlagsFetchFailure(const LLUUID& object_id)
+{
+ //llwarns << "Failed to fetch physics flags for object: " << object_id << llendl;
+ mPendingPhysicsFlags.erase(object_id);
+}
void LLViewerObjectList::shiftObjects(const LLVector3 &offset)
{
@@ -1039,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;
}
@@ -1064,6 +1488,62 @@ void LLViewerObjectList::shiftObjects(const LLVector3 &offset)
LLWorld::getInstance()->shiftRegions(offset);
}
+//debug code
+bool LLViewerObjectList::hasMapObjectInRegion(LLViewerRegion* regionp)
+{
+ for (vobj_list_t::iterator iter = mMapObjects.begin(); iter != mMapObjects.end(); ++iter)
+ {
+ LLViewerObject* objectp = *iter;
+
+ if(objectp->isDead() || objectp->getRegion() == regionp)
+ {
+ return true ;
+ }
+ }
+
+ return false ;
+}
+
+//make sure the region is cleaned up.
+void LLViewerObjectList::clearAllMapObjectsInRegion(LLViewerRegion* regionp)
+{
+ std::set<LLViewerObject*> dead_object_list ;
+ std::set<LLViewerObject*> region_object_list ;
+ for (vobj_list_t::iterator iter = mMapObjects.begin(); iter != mMapObjects.end(); ++iter)
+ {
+ LLViewerObject* objectp = *iter;
+
+ if(objectp->isDead())
+ {
+ dead_object_list.insert(objectp) ;
+ }
+ else if(objectp->getRegion() == regionp)
+ {
+ region_object_list.insert(objectp) ;
+ }
+ }
+
+ if(dead_object_list.size() > 0)
+ {
+ llwarns << "There are " << dead_object_list.size() << " dead objects on the map!" << llendl ;
+
+ for(std::set<LLViewerObject*>::iterator iter = dead_object_list.begin(); iter != dead_object_list.end(); ++iter)
+ {
+ cleanupReferences(*iter) ;
+ }
+ }
+ if(region_object_list.size() > 0)
+ {
+ llwarns << "There are " << region_object_list.size() << " objects not removed from the deleted region!" << llendl ;
+
+ for(std::set<LLViewerObject*>::iterator iter = region_object_list.begin(); iter != region_object_list.end(); ++iter)
+ {
+ (*iter)->markDead() ;
+ }
+ }
+}
+
+
void LLViewerObjectList::renderObjectsForMap(LLNetMap &netmap)
{
LLColor4 above_water_color = LLUIColorTable::instance().getColor( "NetMapOtherOwnAboveWater" );
@@ -1082,6 +1562,12 @@ void LLViewerObjectList::renderObjectsForMap(LLNetMap &netmap)
for (vobj_list_t::iterator iter = mMapObjects.begin(); iter != mMapObjects.end(); ++iter)
{
LLViewerObject* objectp = *iter;
+
+ if(objectp->isDead())//some dead objects somehow not cleaned.
+ {
+ continue ;
+ }
+
if (!objectp->getRegion() || objectp->isOrphaned() || objectp->isAttachment())
{
continue;
@@ -1269,34 +1755,6 @@ void LLViewerObjectList::generatePickList(LLCamera &camera)
}
}
-void LLViewerObjectList::renderPickList(const LLRect& screen_rect, BOOL pick_parcel_wall, BOOL render_transparent)
-{
- gRenderForSelect = TRUE;
-
- gPipeline.renderForSelect(mSelectPickList, render_transparent, screen_rect);
-
- //
- // Render pass for selected objects
- //
- gGL.color4f(1,1,1,1);
- gViewerWindow->renderSelections( TRUE, pick_parcel_wall, FALSE );
-
- //fix for DEV-19335. Don't pick hud objects when customizing avatar (camera mode doesn't play nice with nametags).
- if (!gAgentCamera.cameraCustomizeAvatar())
- {
- // render pickable ui elements, like names, etc.
- LLHUDObject::renderAllForSelect();
- }
-
- gGL.flush();
- LLVertexBuffer::unbind();
-
- gRenderForSelect = FALSE;
-
- //llinfos << "Rendered " << count << " for select" << llendl;
- //llinfos << "Took " << pick_timer.getElapsedTimeF32()*1000.f << "ms to pick" << llendl;
-}
-
LLViewerObject *LLViewerObjectList::getSelectedObject(const U32 object_id)
{
std::set<LLViewerObject*>::iterator pick_it;
@@ -1397,7 +1855,7 @@ LLViewerObject *LLViewerObjectList::replaceObject(const LLUUID &id, const LLPCod
LLViewerObject *old_instance = findObject(id);
if (old_instance)
{
- cleanupReferences(old_instance);
+ //cleanupReferences(old_instance);
old_instance->markDead();
return createObject(pcode, regionp, id, old_instance->getLocalID(), LLHost());
@@ -1473,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
@@ -1527,8 +1980,8 @@ void LLViewerObjectList::findOrphans(LLViewerObject* objectp, U32 ip, U32 port)
llinfos << "Agent: " << objectp->getPositionAgent() << llendl;
addDebugBeacon(objectp->getPositionAgent(),"");
#endif
- gPipeline.markMoved(objectp->mDrawable);
- objectp->setChanged(LLXform::MOVED | LLXform::SILHOUETTE);
+ gPipeline.markMoved(objectp->mDrawable);
+ objectp->setChanged(LLXform::MOVED | LLXform::SILHOUETTE);
// Flag the object as no longer orphaned
childp->mOrphaned = FALSE;
diff --git a/indra/newview/llviewerobjectlist.h b/indra/newview/llviewerobjectlist.h
index eba5584b57..65374bca70 100644
--- a/indra/newview/llviewerobjectlist.h
+++ b/indra/newview/llviewerobjectlist.h
@@ -85,8 +85,26 @@ public:
void updateApparentAngles(LLAgent &agent);
void update(LLAgent &agent, LLWorld &world);
+ void fetchObjectCosts();
+ void fetchPhysicsFlags();
+
+ void updateObjectCost(LLViewerObject* object);
+ void updateObjectCost(const LLUUID& object_id, F32 object_cost, F32 link_cost, F32 physics_cost, F32 link_physics_cost);
+ void onObjectCostFetchFailure(const LLUUID& object_id);
+
+ void updatePhysicsFlags(const LLViewerObject* object);
+ void onPhysicsFlagsFetchFailure(const LLUUID& object_id);
+ void updatePhysicsShapeType(const LLUUID& object_id, S32 type);
+ void updatePhysicsProperties(const LLUUID& object_id,
+ F32 density,
+ F32 friction,
+ F32 restitution,
+ F32 gravity_multiplier);
+
void shiftObjects(const LLVector3 &offset);
+ bool hasMapObjectInRegion(LLViewerRegion* regionp) ;
+ void clearAllMapObjectsInRegion(LLViewerRegion* regionp) ;
void renderObjectsForMap(LLNetMap &netmap);
void renderObjectBounds(const LLVector3 &center);
@@ -104,7 +122,6 @@ public:
// Selection related stuff
void generatePickList(LLCamera &camera);
- void renderPickList(const LLRect& screen_rect, BOOL pick_parcel_wall, BOOL render_transparent);
LLViewerObject *getSelectedObject(const U32 object_id);
@@ -161,7 +178,7 @@ public:
const U32 ip,
const U32 port); // Requires knowledge of message system info!
- static BOOL removeFromLocalIDTable(const LLViewerObject &object);
+ static BOOL removeFromLocalIDTable(const LLViewerObject* objectp);
// Used ONLY by the orphaned object code.
static U64 getIndex(const U32 local_id, const U32 ip, const U32 port);
@@ -181,11 +198,18 @@ protected:
vobj_list_t mMapObjects;
- typedef std::map<LLUUID, LLPointer<LLViewerObject> > vo_map;
- vo_map mDeadObjects; // Need to keep multiple entries per UUID
+ std::set<LLUUID> mDeadObjects;
std::map<LLUUID, LLPointer<LLViewerObject> > mUUIDObjectMap;
+ //set of objects that need to update their cost
+ std::set<LLUUID> mStaleObjectCost;
+ std::set<LLUUID> mPendingObjectCost;
+
+ //set of objects that need to update their physics flags
+ std::set<LLUUID> mStalePhysicsFlags;
+ std::set<LLUUID> mPendingPhysicsFlags;
+
std::vector<LLDebugBeacon> mDebugBeacons;
S32 mCurLazyUpdateIndex;
diff --git a/indra/newview/llviewerparcelmedia.cpp b/indra/newview/llviewerparcelmedia.cpp
index 99e869dafc..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;
@@ -586,6 +592,18 @@ void LLViewerParcelMedia::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent
LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_GEOMETRY_CHANGE, uuid is " << self->getClickUUID() << LL_ENDL;
}
break;
+
+ case MEDIA_EVENT_AUTH_REQUEST:
+ {
+ LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_AUTH_REQUEST, url " << self->getAuthURL() << ", realm " << self->getAuthRealm() << LL_ENDL;
+ }
+ break;
+
+ case MEDIA_EVENT_LINK_HOVERED:
+ {
+ LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_LINK_HOVERED, hover text is: " << self->getHoverText() << LL_ENDL;
+ };
+ break;
};
}
diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp
index 11de377410..5ae4e872f3 100644
--- a/indra/newview/llviewerparcelmgr.cpp
+++ b/indra/newview/llviewerparcelmgr.cpp
@@ -42,6 +42,7 @@
// Viewer includes
#include "llagent.h"
+#include "llagentaccess.h"
#include "llviewerwindow.h"
#include "llviewercontrol.h"
//#include "llfirstuse.h"
@@ -54,6 +55,7 @@
#include "llresmgr.h"
#include "llsdutil.h"
#include "llsdutil_math.h"
+#include "llslurl.h"
#include "llstatusbar.h"
#include "llui.h"
#include "llviewertexture.h"
@@ -850,7 +852,7 @@ LLParcel* LLViewerParcelMgr::getCollisionParcel() const
void LLViewerParcelMgr::render()
{
- if (mSelected && mRenderSelection)
+ if (mSelected && mRenderSelection && gSavedSettings.getBOOL("RenderParcelSelection"))
{
// Rendering is done in agent-coordinates, so need to supply
// an appropriate offset to the render code.
@@ -1383,11 +1385,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);
@@ -1784,8 +1781,7 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use
void optionally_start_music(const std::string& music_url)
{
- if (gSavedSettings.getBOOL("AudioStreamingMusic") &&
- gSavedSettings.getBOOL("AudioStreamingMedia"))
+ if (gSavedSettings.getBOOL("AudioStreamingMusic"))
{
// only play music when you enter a new parcel if the UI control for this
// was not *explicitly* stopped by the user. (part of SL-4878)
@@ -2206,7 +2202,10 @@ bool LLViewerParcelMgr::canAgentBuyParcel(LLParcel* parcel, bool forGroup) const
= parcelOwner == (forGroup ? gAgent.getGroupID() : gAgent.getID());
bool isAuthorized
- = (authorizeBuyer.isNull() || (gAgent.getID() == authorizeBuyer));
+ = (authorizeBuyer.isNull()
+ || (gAgent.getID() == authorizeBuyer)
+ || (gAgent.hasPowerInGroup(authorizeBuyer,GP_LAND_DEED)
+ && gAgent.hasPowerInGroup(authorizeBuyer,GP_LAND_SET_SALE_INFO)));
return isForSale && !isOwner && isAuthorized && isEmpowered;
}
diff --git a/indra/newview/llviewerparceloverlay.cpp b/indra/newview/llviewerparceloverlay.cpp
index eee653b0c1..26765bdd01 100644
--- a/indra/newview/llviewerparceloverlay.cpp
+++ b/indra/newview/llviewerparceloverlay.cpp
@@ -145,6 +145,35 @@ BOOL LLViewerParcelOverlay::isOwnedOther(const LLVector3& pos) const
return (PARCEL_OWNED == overlay || PARCEL_FOR_SALE == overlay);
}
+bool LLViewerParcelOverlay::encroachesOwned(const std::vector<LLBBox>& boxes) const
+{
+ // boxes are expected to already be axis aligned
+ for (U32 i = 0; i < boxes.size(); ++i)
+ {
+ LLVector3 min = boxes[i].getMinAgent();
+ LLVector3 max = boxes[i].getMaxAgent();
+
+ S32 left = S32(llclamp((min.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1));
+ S32 right = S32(llclamp((max.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1));
+ S32 top = S32(llclamp((min.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1));
+ S32 bottom = S32(llclamp((max.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1));
+
+ for (S32 row = top; row <= bottom; row++)
+ {
+ for (S32 column = left; column <= right; column++)
+ {
+ U8 type = ownership(row, column);
+ if ((PARCEL_SELF == type)
+ || (PARCEL_GROUP == type))
+ {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
BOOL LLViewerParcelOverlay::isSoundLocal(const LLVector3& pos) const
{
S32 row = S32(pos.mV[VY] / PARCEL_GRID_STEP_METERS);
@@ -804,7 +833,7 @@ S32 LLViewerParcelOverlay::renderPropertyLines ()
U8* colorp;
bool render_hidden = LLSelectMgr::sRenderHiddenSelections && LLFloaterReg::instanceVisible("build");
- const F32 PROPERTY_LINE_CLIP_DIST = 256.f;
+ const F32 PROPERTY_LINE_CLIP_DIST_SQUARED = 256.f * 256.f;
for (i = 0; i < mVertexCount; i += vertex_per_edge)
{
@@ -815,7 +844,7 @@ S32 LLViewerParcelOverlay::renderPropertyLines ()
vertex.mV[VY] = *(vertexp+1);
vertex.mV[VZ] = *(vertexp+2);
- if (dist_vec_squared2D(vertex, camera_region) > PROPERTY_LINE_CLIP_DIST*PROPERTY_LINE_CLIP_DIST)
+ if (dist_vec_squared2D(vertex, camera_region) > PROPERTY_LINE_CLIP_DIST_SQUARED)
{
continue;
}
diff --git a/indra/newview/llviewerparceloverlay.h b/indra/newview/llviewerparceloverlay.h
index 61be220312..c80baedda6 100644
--- a/indra/newview/llviewerparceloverlay.h
+++ b/indra/newview/llviewerparceloverlay.h
@@ -30,6 +30,7 @@
// The ownership data for land parcels.
// One of these structures per region.
+#include "llbbox.h"
#include "lldarray.h"
#include "llframetimer.h"
#include "lluuid.h"
@@ -54,6 +55,12 @@ public:
BOOL isOwnedSelf(const LLVector3& pos) const;
BOOL isOwnedGroup(const LLVector3& pos) const;
BOOL isOwnedOther(const LLVector3& pos) const;
+
+ // "encroaches" means the prim hangs over the parcel, but its center
+ // might be in another parcel. for now, we simply test axis aligned
+ // bounding boxes which isn't perfect, but is close
+ bool encroachesOwned(const std::vector<LLBBox>& boxes) const;
+
BOOL isSoundLocal(const LLVector3& pos) const;
BOOL isBuildCameraAllowed(const LLVector3& pos) const;
diff --git a/indra/newview/llviewerpartsim.cpp b/indra/newview/llviewerpartsim.cpp
index 4fee85e45c..6b3e04348a 100644
--- a/indra/newview/llviewerpartsim.cpp
+++ b/indra/newview/llviewerpartsim.cpp
@@ -155,8 +155,8 @@ LLViewerPartGroup::LLViewerPartGroup(const LLVector3 &center_agent, const F32 bo
if (group != NULL)
{
- LLVector3 center(group->mOctreeNode->getCenter());
- LLVector3 size(group->mOctreeNode->getSize());
+ LLVector3 center(group->mOctreeNode->getCenter().getF32ptr());
+ LLVector3 size(group->mOctreeNode->getSize().getF32ptr());
size += LLVector3(0.01f, 0.01f, 0.01f);
mMinObjPos = center - size;
mMaxObjPos = center + size;
diff --git a/indra/newview/llviewerprecompiledheaders.h b/indra/newview/llviewerprecompiledheaders.h
index ab07adce5d..45c9b3e91f 100644
--- a/indra/newview/llviewerprecompiledheaders.h
+++ b/indra/newview/llviewerprecompiledheaders.h
@@ -99,8 +99,6 @@
#include "llcoord.h"
#include "llcoordframe.h"
#include "llcrc.h"
-#include "llinterp.h"
-#include "llperlin.h"
#include "llplane.h"
#include "llquantize.h"
#include "llrand.h"
@@ -109,7 +107,6 @@
#include "m3math.h"
#include "m4math.h"
#include "llquaternion.h"
-#include "raytrace.h"
#include "v2math.h"
#include "v3color.h"
#include "v3dmath.h"
@@ -117,16 +114,12 @@
#include "v4color.h"
#include "v4coloru.h"
#include "v4math.h"
-////#include "vmath.h"
#include "xform.h"
// Library includes from llvfs
#include "lldir.h"
-
-// Library includes from llmessage project
+
+// Library includes from llmessage project
#include "llcachename.h"
-// llxuixml
-#include "llinitparam.h"
-
#endif
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 7fb259e012..f835351c04 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -46,6 +46,7 @@
#include "llagentcamera.h"
#include "llcallingcard.h"
#include "llcaphttpsender.h"
+#include "llcapabilitylistener.h"
#include "llcommandhandler.h"
#include "lldir.h"
#include "lleventpoll.h"
@@ -59,6 +60,7 @@
#include "llurldispatcher.h"
#include "llviewerobjectlist.h"
#include "llviewerparceloverlay.h"
+#include "llviewerstatsrecorder.h"
#include "llvlmanager.h"
#include "llvlcomposition.h"
#include "llvocache.h"
@@ -66,16 +68,80 @@
#include "llworld.h"
#include "llspatialpartition.h"
#include "stringize.h"
+#include "llviewercontrol.h"
#ifdef LL_WINDOWS
#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;
+typedef std::map<std::string, std::string> CapabilityMap;
+
+class LLViewerRegionImpl {
+public:
+ LLViewerRegionImpl(LLViewerRegion * region, LLHost const & host)
+ : mHost(host),
+ mCompositionp(NULL),
+ mEventPoll(NULL),
+ // I'd prefer to set the LLCapabilityListener name to match the region
+ // name -- it's disappointing that's not available at construction time.
+ // We could instead store an LLCapabilityListener*, making
+ // setRegionNameAndZone() replace the instance. Would that pose
+ // consistency problems? Can we even request a capability before calling
+ // setRegionNameAndZone()?
+ // For testability -- the new Michael Feathers paradigm --
+ // LLCapabilityListener binds all the globals it expects to need at
+ // construction time.
+ mCapabilityListener(host.getString(), gMessageSystem, *region,
+ gAgent.getID(), gAgent.getSessionID())
+ {
+ }
+
+ // The surfaces and other layers
+ LLSurface* mLandp;
+
+ // Region geometry data
+ LLVector3d mOriginGlobal; // Location of southwest corner of region (meters)
+ LLVector3d mCenterGlobal; // Location of center in world space (meters)
+ LLHost mHost;
+
+ // The unique ID for this region.
+ LLUUID mRegionID;
+
+ // region/estate owner - usually null.
+ LLUUID mOwnerID;
+
+ // Network statistics for the region's circuit...
+ LLTimer mLastNetUpdate;
+
+ // Misc
+ LLVLComposition *mCompositionp; // Composition layer for the surface
+
+ LLVOCacheEntry::vocache_entry_map_t mCacheMap;
+ // time?
+ // LRU info?
+
+ // Cache ID is unique per-region, across renames, moving locations,
+ // etc.
+ LLUUID mCacheID;
+
+ CapabilityMap mCapabilities;
+
+ LLEventPoll* mEventPoll;
+
+ /// Post an event to this LLCapabilityListener to invoke a capability message on
+ /// this LLViewerRegion's server
+ /// (https://wiki.lindenlab.com/wiki/Viewer:Messaging/Messaging_Notes#Capabilities)
+ LLCapabilityListener mCapabilityListener;
+
+ //spatial partitions for objects in this region
+ std::vector<LLSpatialPartition*> mObjectPartition;
+
+ LLHTTPClient::ResponderPtr mHttpResponderPtr ;
+};
+
// support for secondlife:///app/region/{REGION} SLapps
// N.B. this is defined to work exactly like the classic secondlife://{REGION}
// However, the later syntax cannot support spaces in the region name because
@@ -109,7 +175,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;
}
};
@@ -191,15 +257,12 @@ LLViewerRegion::LLViewerRegion(const U64 &handle,
const U32 grids_per_region_edge,
const U32 grids_per_patch_edge,
const F32 region_width_meters)
-: mCenterGlobal(),
+: mImpl(new LLViewerRegionImpl(this, host)),
mHandle(handle),
- mHost( host ),
mTimeDilation(1.0f),
mName(""),
mZoning(""),
- mOwnerID(),
mIsEstateManager(FALSE),
- mCompositionp(NULL),
mRegionFlags( REGION_FLAGS_DEFAULT ),
mSimAccess( SIM_ACCESS_MIN ),
mBillableFactor(1.0),
@@ -212,49 +275,30 @@ LLViewerRegion::LLViewerRegion(const U64 &handle,
mHttpUrl(""),
mCacheLoaded(FALSE),
mCacheDirty(FALSE),
- mCacheID(),
- mEventPoll(NULL),
mReleaseNotesRequested(FALSE),
- // I'd prefer to set the LLCapabilityListener name to match the region
- // name -- it's disappointing that's not available at construction time.
- // We could instead store an LLCapabilityListener*, making
- // setRegionNameAndZone() replace the instance. Would that pose
- // consistency problems? Can we even request a capability before calling
- // setRegionNameAndZone()?
- // For testability -- the new Michael Feathers paradigm --
- // LLCapabilityListener binds all the globals it expects to need at
- // construction time.
- mCapabilityListener(host.getString(), gMessageSystem, *this,
- gAgent.getID(), gAgent.getSessionID()),
mCapabilitiesReceived(false)
{
mWidth = region_width_meters;
- mOriginGlobal = from_region_handle(handle);
+ mImpl->mOriginGlobal = from_region_handle(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);
- }
+ mImpl->mLandp = new LLSurface('l', NULL);
- if (!gNoRender)
- {
- mParcelOverlay = new LLViewerParcelOverlay(this, region_width_meters);
- }
- else
- {
- mParcelOverlay = NULL;
- }
+ // Create the composition layer for the surface
+ mImpl->mCompositionp =
+ new LLVLComposition(mImpl->mLandp,
+ grids_per_region_edge,
+ region_width_meters / grids_per_region_edge);
+ mImpl->mCompositionp->setSurface(mImpl->mLandp);
+
+ // Create the surfaces
+ mImpl->mLandp->setRegion(this);
+ mImpl->mLandp->create(grids_per_region_edge,
+ grids_per_patch_edge,
+ mImpl->mOriginGlobal,
+ mWidth);
+
+ mParcelOverlay = new LLViewerParcelOverlay(this, region_width_meters);
setOriginGlobal(from_region_handle(handle));
calculateCenterGlobal();
@@ -264,23 +308,24 @@ LLViewerRegion::LLViewerRegion(const U64 &handle,
//create object partitions
//MUST MATCH declaration of eObjectPartitions
- mObjectPartition.push_back(new LLHUDPartition()); //PARTITION_HUD
- mObjectPartition.push_back(new LLTerrainPartition()); //PARTITION_TERRAIN
- mObjectPartition.push_back(new LLWaterPartition()); //PARTITION_WATER
- mObjectPartition.push_back(new LLTreePartition()); //PARTITION_TREE
- mObjectPartition.push_back(new LLParticlePartition()); //PARTITION_PARTICLE
- mObjectPartition.push_back(new LLCloudPartition()); //PARTITION_CLOUD
- mObjectPartition.push_back(new LLGrassPartition()); //PARTITION_GRASS
- mObjectPartition.push_back(new LLVolumePartition()); //PARTITION_VOLUME
- mObjectPartition.push_back(new LLBridgePartition()); //PARTITION_BRIDGE
- mObjectPartition.push_back(new LLHUDParticlePartition());//PARTITION_HUD_PARTICLE
- mObjectPartition.push_back(NULL); //PARTITION_NONE
+ mImpl->mObjectPartition.push_back(new LLHUDPartition()); //PARTITION_HUD
+ mImpl->mObjectPartition.push_back(new LLTerrainPartition()); //PARTITION_TERRAIN
+ mImpl->mObjectPartition.push_back(new LLVoidWaterPartition()); //PARTITION_VOIDWATER
+ mImpl->mObjectPartition.push_back(new LLWaterPartition()); //PARTITION_WATER
+ mImpl->mObjectPartition.push_back(new LLTreePartition()); //PARTITION_TREE
+ mImpl->mObjectPartition.push_back(new LLParticlePartition()); //PARTITION_PARTICLE
+ mImpl->mObjectPartition.push_back(new LLCloudPartition()); //PARTITION_CLOUD
+ mImpl->mObjectPartition.push_back(new LLGrassPartition()); //PARTITION_GRASS
+ mImpl->mObjectPartition.push_back(new LLVolumePartition()); //PARTITION_VOLUME
+ mImpl->mObjectPartition.push_back(new LLBridgePartition()); //PARTITION_BRIDGE
+ mImpl->mObjectPartition.push_back(new LLHUDParticlePartition());//PARTITION_HUD_PARTICLE
+ mImpl->mObjectPartition.push_back(NULL); //PARTITION_NONE
}
void LLViewerRegion::initStats()
{
- mLastNetUpdate.reset();
+ mImpl->mLastNetUpdate.reset();
mPacketsIn = 0;
mBitsIn = 0;
mLastBitsIn = 0;
@@ -295,9 +340,9 @@ void LLViewerRegion::initStats()
LLViewerRegion::~LLViewerRegion()
{
- if(mHttpResponderPtr)
+ if(mImpl->mHttpResponderPtr)
{
- (static_cast<BaseCapabilitiesComplete*>(mHttpResponderPtr.get()))->setRegion(NULL) ;
+ (static_cast<BaseCapabilitiesComplete*>(mImpl->mHttpResponderPtr.get()))->setRegion(NULL) ;
}
gVLManager.cleanupData(this);
@@ -309,15 +354,44 @@ LLViewerRegion::~LLViewerRegion()
gObjectList.killObjects(this);
- delete mCompositionp;
+ delete mImpl->mCompositionp;
delete mParcelOverlay;
- delete mLandp;
- delete mEventPoll;
- LLHTTPSender::clearSender(mHost);
+ delete mImpl->mLandp;
+ delete mImpl->mEventPoll;
+ LLHTTPSender::clearSender(mImpl->mHost);
saveObjectCache();
- std::for_each(mObjectPartition.begin(), mObjectPartition.end(), DeletePointer());
+ std::for_each(mImpl->mObjectPartition.begin(), mImpl->mObjectPartition.end(), DeletePointer());
+
+ delete mImpl;
+ mImpl = NULL;
+}
+
+LLEventPump& LLViewerRegion::getCapAPI() const
+{
+ return mImpl->mCapabilityListener.getCapAPI();
+}
+
+/*virtual*/
+const LLHost& LLViewerRegion::getHost() const
+{
+ return mImpl->mHost;
+}
+
+LLSurface & LLViewerRegion::getLand() const
+{
+ return *mImpl->mLandp;
+}
+
+const LLUUID& LLViewerRegion::getRegionID() const
+{
+ return mImpl->mRegionID;
+}
+
+void LLViewerRegion::setRegionID(const LLUUID& region_id)
+{
+ mImpl->mRegionID = region_id;
}
void LLViewerRegion::loadObjectCache()
@@ -332,7 +406,7 @@ void LLViewerRegion::loadObjectCache()
if(LLVOCache::hasInstance())
{
- LLVOCache::getInstance()->readFromCache(mHandle, mCacheID, mCacheMap) ;
+ LLVOCache::getInstance()->readFromCache(mHandle, mImpl->mCacheID, mImpl->mCacheMap) ;
}
}
@@ -344,32 +418,32 @@ void LLViewerRegion::saveObjectCache()
return;
}
- if (mCacheMap.empty())
+ if (mImpl->mCacheMap.empty())
{
return;
}
if(LLVOCache::hasInstance())
{
- LLVOCache::getInstance()->writeToCache(mHandle, mCacheID, mCacheMap, mCacheDirty) ;
+ LLVOCache::getInstance()->writeToCache(mHandle, mImpl->mCacheID, mImpl->mCacheMap, mCacheDirty) ;
mCacheDirty = FALSE;
}
- for(LLVOCacheEntry::vocache_entry_map_t::iterator iter = mCacheMap.begin(); iter != mCacheMap.end(); ++iter)
+ for(LLVOCacheEntry::vocache_entry_map_t::iterator iter = mImpl->mCacheMap.begin(); iter != mImpl->mCacheMap.end(); ++iter)
{
delete iter->second;
}
- mCacheMap.clear();
+ mImpl->mCacheMap.clear();
}
void LLViewerRegion::sendMessage()
{
- gMessageSystem->sendMessage(mHost);
+ gMessageSystem->sendMessage(mImpl->mHost);
}
void LLViewerRegion::sendReliableMessage()
{
- gMessageSystem->sendReliable(mHost);
+ gMessageSystem->sendReliable(mImpl->mHost);
}
void LLViewerRegion::setFlags(BOOL b, U32 flags)
@@ -386,12 +460,12 @@ void LLViewerRegion::setFlags(BOOL b, U32 flags)
void LLViewerRegion::setWaterHeight(F32 water_level)
{
- mLandp->setWaterHeight(water_level);
+ mImpl->mLandp->setWaterHeight(water_level);
}
F32 LLViewerRegion::getWaterHeight() const
{
- return mLandp->getWaterHeight();
+ return mImpl->mLandp->getWaterHeight();
}
BOOL LLViewerRegion::isVoiceEnabled() const
@@ -407,9 +481,9 @@ void LLViewerRegion::setRegionFlags(U32 flags)
void LLViewerRegion::setOriginGlobal(const LLVector3d &origin_global)
{
- mOriginGlobal = origin_global;
+ mImpl->mOriginGlobal = origin_global;
updateRenderMatrix();
- mLandp->setOriginGlobal(origin_global);
+ mImpl->mLandp->setOriginGlobal(origin_global);
mWind.setOriginGlobal(origin_global);
mCloudLayer.setOriginGlobal(origin_global);
calculateCenterGlobal();
@@ -425,16 +499,34 @@ void LLViewerRegion::setTimeDilation(F32 time_dilation)
mTimeDilation = time_dilation;
}
+const LLVector3d & LLViewerRegion::getOriginGlobal() const
+{
+ return mImpl->mOriginGlobal;
+}
LLVector3 LLViewerRegion::getOriginAgent() const
{
- return gAgent.getPosAgentFromGlobal(mOriginGlobal);
+ return gAgent.getPosAgentFromGlobal(mImpl->mOriginGlobal);
}
+const LLVector3d & LLViewerRegion::getCenterGlobal() const
+{
+ return mImpl->mCenterGlobal;
+}
LLVector3 LLViewerRegion::getCenterAgent() const
{
- return gAgent.getPosAgentFromGlobal(mCenterGlobal);
+ return gAgent.getPosAgentFromGlobal(mImpl->mCenterGlobal);
+}
+
+void LLViewerRegion::setOwner(const LLUUID& owner_id)
+{
+ mImpl->mOwnerID = owner_id;
+}
+
+const LLUUID& LLViewerRegion::getOwner() const
+{
+ return mImpl->mOwnerID;
}
void LLViewerRegion::setRegionNameAndZone (const std::string& name_zone)
@@ -559,7 +651,10 @@ void LLViewerRegion::processRegionInfo(LLMessageSystem* msg, void**)
LLFloaterReporter::processRegionInfo(msg);
}
-
+void LLViewerRegion::setCacheID(const LLUUID& id)
+{
+ mImpl->mCacheID = id;
+}
S32 LLViewerRegion::renderPropertyLines()
{
@@ -587,7 +682,7 @@ BOOL LLViewerRegion::idleUpdate(F32 max_update_time)
{
LLMemType mt_ivr(LLMemType::MTYPE_IDLE_UPDATE_VIEWER_REGION);
// did_update returns TRUE if we did at least one significant update
- BOOL did_update = mLandp->idleUpdate(max_update_time);
+ BOOL did_update = mImpl->mLandp->idleUpdate(max_update_time);
if (mParcelOverlay)
{
@@ -602,7 +697,7 @@ BOOL LLViewerRegion::idleUpdate(F32 max_update_time)
// As above, but forcibly do the update.
void LLViewerRegion::forceUpdate()
{
- mLandp->idleUpdate(0.f);
+ mImpl->mLandp->idleUpdate(0.f);
if (mParcelOverlay)
{
@@ -612,17 +707,21 @@ void LLViewerRegion::forceUpdate()
void LLViewerRegion::connectNeighbor(LLViewerRegion *neighborp, U32 direction)
{
- mLandp->connectNeighbor(neighborp->mLandp, direction);
+ mImpl->mLandp->connectNeighbor(neighborp->mImpl->mLandp, direction);
mCloudLayer.connectNeighbor(&(neighborp->mCloudLayer), direction);
}
void LLViewerRegion::disconnectAllNeighbors()
{
- mLandp->disconnectAllNeighbors();
+ mImpl->mLandp->disconnectAllNeighbors();
mCloudLayer.disconnectAllNeighbors();
}
+LLVLComposition * LLViewerRegion::getComposition() const
+{
+ return mImpl->mCompositionp;
+}
F32 LLViewerRegion::getCompositionXY(const S32 x, const S32 y) const
{
@@ -716,10 +815,10 @@ F32 LLViewerRegion::getCompositionXY(const S32 x, const S32 y) const
void LLViewerRegion::calculateCenterGlobal()
{
- mCenterGlobal = mOriginGlobal;
- mCenterGlobal.mdV[VX] += 0.5 * mWidth;
- mCenterGlobal.mdV[VY] += 0.5 * mWidth;
- mCenterGlobal.mdV[VZ] = 0.5*mLandp->getMinZ() + mLandp->getMaxZ();
+ mImpl->mCenterGlobal = mImpl->mOriginGlobal;
+ mImpl->mCenterGlobal.mdV[VX] += 0.5 * mWidth;
+ mImpl->mCenterGlobal.mdV[VY] += 0.5 * mWidth;
+ mImpl->mCenterGlobal.mdV[VZ] = 0.5 * mImpl->mLandp->getMinZ() + mImpl->mLandp->getMaxZ();
}
void LLViewerRegion::calculateCameraDistance()
@@ -730,7 +829,7 @@ void LLViewerRegion::calculateCameraDistance()
std::ostream& operator<<(std::ostream &s, const LLViewerRegion &region)
{
s << "{ ";
- s << region.mHost;
+ s << region.mImpl->mHost;
s << " mOriginGlobal = " << region.getOriginGlobal()<< "\n";
std::string name(region.getName()), zone(region.getZoning());
if (! name.empty())
@@ -750,9 +849,9 @@ std::ostream& operator<<(std::ostream &s, const LLViewerRegion &region)
void LLViewerRegion::updateNetStats()
{
- F32 dt = mLastNetUpdate.getElapsedTimeAndResetF32();
+ F32 dt = mImpl->mLastNetUpdate.getElapsedTimeAndResetF32();
- LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(mHost);
+ LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(mImpl->mHost);
if (!cdp)
{
mAlive = false;
@@ -781,10 +880,10 @@ void LLViewerRegion::updateNetStats()
U32 LLViewerRegion::getPacketsLost() const
{
- LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(mHost);
+ LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(mImpl->mHost);
if (!cdp)
{
- llinfos << "LLViewerRegion::getPacketsLost couldn't find circuit for " << mHost << llendl;
+ llinfos << "LLViewerRegion::getPacketsLost couldn't find circuit for " << mImpl->mHost << llendl;
return 0;
}
else
@@ -793,6 +892,16 @@ U32 LLViewerRegion::getPacketsLost() const
}
}
+void LLViewerRegion::setHttpResponderPtrNULL()
+{
+ mImpl->mHttpResponderPtr = NULL;
+}
+
+const LLHTTPClient::ResponderPtr LLViewerRegion::getHttpResponderPtr() const
+{
+ return mImpl->mHttpResponderPtr;
+}
+
BOOL LLViewerRegion::pointInRegionGlobal(const LLVector3d &point_global) const
{
LLVector3 pos_region = getPosRegionFromGlobal(point_global);
@@ -819,7 +928,7 @@ BOOL LLViewerRegion::pointInRegionGlobal(const LLVector3d &point_global) const
LLVector3 LLViewerRegion::getPosRegionFromGlobal(const LLVector3d &point_global) const
{
LLVector3 pos_region;
- pos_region.setVec(point_global - mOriginGlobal);
+ pos_region.setVec(point_global - mImpl->mOriginGlobal);
return pos_region;
}
@@ -827,7 +936,7 @@ LLVector3d LLViewerRegion::getPosGlobalFromRegion(const LLVector3 &pos_region) c
{
LLVector3d pos_region_d;
pos_region_d.setVec(pos_region);
- return pos_region_d + mOriginGlobal;
+ return pos_region_d + mImpl->mOriginGlobal;
}
LLVector3 LLViewerRegion::getPosAgentFromRegion(const LLVector3 &pos_region) const
@@ -844,7 +953,7 @@ LLVector3 LLViewerRegion::getPosRegionFromAgent(const LLVector3 &pos_agent) cons
F32 LLViewerRegion::getLandHeightRegion(const LLVector3& region_pos)
{
- return mLandp->resolveHeightRegion( region_pos );
+ return mImpl->mLandp->resolveHeightRegion( region_pos );
}
bool LLViewerRegion::isAlive()
@@ -996,7 +1105,7 @@ void LLViewerRegion::updateCoarseLocations(LLMessageSystem* msg)
// treat the target specially for the map
if(i == target_index)
{
- LLVector3d global_pos(mOriginGlobal);
+ LLVector3d global_pos(mImpl->mOriginGlobal);
global_pos.mdV[VX] += (F64)(x_pos);
global_pos.mdV[VY] += (F64)(y_pos);
global_pos.mdV[VZ] += (F64)(z_pos) * 4.0;
@@ -1031,12 +1140,12 @@ void LLViewerRegion::getInfo(LLSD& info)
info["Region"]["Handle"]["y"] = (LLSD::Integer)y;
}
-void LLViewerRegion::cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp)
+LLViewerRegion::eCacheUpdateResult LLViewerRegion::cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp)
{
U32 local_id = objectp->getLocalID();
U32 crc = objectp->getCRC();
- LLVOCacheEntry* entry = get_if_there(mCacheMap, local_id, (LLVOCacheEntry*)NULL);
+ LLVOCacheEntry* entry = get_if_there(mImpl->mCacheMap, local_id, (LLVOCacheEntry*)NULL);
if (entry)
{
@@ -1045,39 +1154,40 @@ void LLViewerRegion::cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinary
{
// Record a hit
entry->recordDupe();
+ return CACHE_UPDATE_DUPE;
}
- else
- {
- // Update the cache entry
- mCacheMap.erase(local_id);
- delete entry;
- entry = new LLVOCacheEntry(local_id, crc, dp);
- mCacheMap[local_id] = entry;
- }
- }
- else
- {
- // we haven't seen this object before
- // Create new entry and add to map
- if (mCacheMap.size() > MAX_OBJECT_CACHE_ENTRIES)
- {
- mCacheMap.erase(mCacheMap.begin());
- }
+ // Update the cache entry
+ mImpl->mCacheMap.erase(local_id);
+ delete entry;
entry = new LLVOCacheEntry(local_id, crc, dp);
+ mImpl->mCacheMap[local_id] = entry;
+ return CACHE_UPDATE_CHANGED;
+ }
- mCacheMap[local_id] = entry;
+ // we haven't seen this object before
+
+ // Create new entry and add to map
+ eCacheUpdateResult result = CACHE_UPDATE_ADDED;
+ if (mImpl->mCacheMap.size() > MAX_OBJECT_CACHE_ENTRIES)
+ {
+ mImpl->mCacheMap.erase(mImpl->mCacheMap.begin());
+ result = CACHE_UPDATE_REPLACED;
+
}
- return ;
+ entry = new LLVOCacheEntry(local_id, crc, dp);
+
+ mImpl->mCacheMap[local_id] = entry;
+ return result;
}
// Get data packer for this object, if we have cached data
// AND the CRC matches. JC
-LLDataPacker *LLViewerRegion::getDP(U32 local_id, U32 crc)
+LLDataPacker *LLViewerRegion::getDP(U32 local_id, U32 crc, U8 &cache_miss_type)
{
- llassert(mCacheLoaded);
+ //llassert(mCacheLoaded); This assert failes often, changing to early-out -- davep, 2010/10/18
- LLVOCacheEntry* entry = get_if_there(mCacheMap, local_id, (LLVOCacheEntry*)NULL);
+ LLVOCacheEntry* entry = get_if_there(mImpl->mCacheMap, local_id, (LLVOCacheEntry*)NULL);
if (entry)
{
@@ -1086,19 +1196,23 @@ LLDataPacker *LLViewerRegion::getDP(U32 local_id, U32 crc)
{
// Record a hit
entry->recordHit();
+ cache_miss_type = CACHE_MISS_TYPE_NONE;
return entry->getDP(crc);
}
else
{
// llinfos << "CRC miss for " << local_id << llendl;
+ cache_miss_type = CACHE_MISS_TYPE_CRC;
mCacheMissCRC.put(local_id);
}
}
else
{
// llinfos << "Cache miss for " << local_id << llendl;
+ cache_miss_type = CACHE_MISS_TYPE_FULL;
mCacheMissFull.put(local_id);
}
+
return NULL;
}
@@ -1118,9 +1232,6 @@ void LLViewerRegion::requestCacheMisses()
S32 blocks = 0;
S32 i;
- const U8 CACHE_MISS_TYPE_FULL = 0;
- const U8 CACHE_MISS_TYPE_CRC = 1;
-
// Send full cache miss updates. For these, we KNOW we don't
// have a viewer object.
for (i = 0; i < full_count; i++)
@@ -1183,6 +1294,11 @@ void LLViewerRegion::requestCacheMisses()
mCacheDirty = TRUE ;
// llinfos << "KILLDEBUG Sent cache miss full " << full_count << " crc " << crc_count << llendl;
+ #if LL_RECORD_VIEWER_STATS
+ LLViewerStatsRecorder::instance()->beginObjectUpdateEvents(this);
+ LLViewerStatsRecorder::instance()->recordRequestCacheMissesEvent(full_count + crc_count);
+ LLViewerStatsRecorder::instance()->endObjectUpdateEvents();
+ #endif
}
void LLViewerRegion::dumpCache()
@@ -1199,7 +1315,7 @@ void LLViewerRegion::dumpCache()
}
LLVOCacheEntry *entry;
- for(LLVOCacheEntry::vocache_entry_map_t::iterator iter = mCacheMap.begin(); iter != mCacheMap.end(); ++iter)
+ for(LLVOCacheEntry::vocache_entry_map_t::iterator iter = mImpl->mCacheMap.begin(); iter != mImpl->mCacheMap.end(); ++iter)
{
entry = iter->second ;
@@ -1213,7 +1329,7 @@ void LLViewerRegion::dumpCache()
change_bin[changes]++;
}
- llinfos << "Count " << mCacheMap.size() << llendl;
+ llinfos << "Count " << mImpl->mCacheMap.size() << llendl;
for (i = 0; i < BINS; i++)
{
llinfos << "Hits " << i << " " << hit_bin[i] << llendl;
@@ -1356,10 +1472,10 @@ void LLViewerRegion::setSeedCapability(const std::string& url)
return;
}
- delete mEventPoll;
- mEventPoll = NULL;
+ delete mImpl->mEventPoll;
+ mImpl->mEventPoll = NULL;
- mCapabilities.clear();
+ mImpl->mCapabilities.clear();
setCapability("Seed", url);
LLSD capabilityNames = LLSD::emptyArray();
@@ -1371,19 +1487,30 @@ void LLViewerRegion::setSeedCapability(const std::string& url)
capabilityNames.append("DispatchRegionInfo");
capabilityNames.append("EstateChangeInfo");
capabilityNames.append("EventQueueGet");
- capabilityNames.append("FetchInventory");
capabilityNames.append("ObjectMedia");
capabilityNames.append("ObjectMediaNavigate");
- capabilityNames.append("FetchLib");
- capabilityNames.append("FetchLibDescendents");
+
+ if (gSavedSettings.getBOOL("UseHTTPInventory"))
+ {
+ capabilityNames.append("FetchLib2");
+ capabilityNames.append("FetchLibDescendents2");
+ capabilityNames.append("FetchInventory2");
+ capabilityNames.append("FetchInventoryDescendents2");
+ }
+
capabilityNames.append("GetDisplayNames");
capabilityNames.append("GetTexture");
+ capabilityNames.append("GetMesh");
+ capabilityNames.append("GetObjectCost");
+ capabilityNames.append("GetObjectPhysicsData");
capabilityNames.append("GroupProposalBallot");
capabilityNames.append("HomeLocation");
capabilityNames.append("LandResources");
capabilityNames.append("MapLayer");
capabilityNames.append("MapLayerGod");
capabilityNames.append("NewFileAgentInventory");
+ capabilityNames.append("NewFileAgentInventoryVariablePrice");
+ capabilityNames.append("ObjectAdd");
capabilityNames.append("ParcelPropertiesUpdate");
capabilityNames.append("ParcelMediaURLFilterList");
capabilityNames.append("ParcelNavigateMedia");
@@ -1398,7 +1525,10 @@ void LLViewerRegion::setSeedCapability(const std::string& url)
capabilityNames.append("SendUserReport");
capabilityNames.append("SendUserReportWithScreenshot");
capabilityNames.append("ServerReleaseNotes");
+ capabilityNames.append("SimConsole");
+ capabilityNames.append("SimulatorFeatures");
capabilityNames.append("SetDisplayName");
+ capabilityNames.append("SimConsoleAsync");
capabilityNames.append("StartGroupProposal");
capabilityNames.append("TextureStats");
capabilityNames.append("UntrustedSimulatorMessage");
@@ -1411,33 +1541,34 @@ void LLViewerRegion::setSeedCapability(const std::string& url)
capabilityNames.append("UpdateNotecardTaskInventory");
capabilityNames.append("UpdateScriptTask");
capabilityNames.append("UploadBakedTexture");
+ capabilityNames.append("UploadObjectAsset");
+ capabilityNames.append("ViewerMetrics");
capabilityNames.append("ViewerStartAuction");
capabilityNames.append("ViewerStats");
- capabilityNames.append("WebFetchInventoryDescendents");
// Please add new capabilities alphabetically to reduce
// merge conflicts.
llinfos << "posting to seed " << url << llendl;
- mHttpResponderPtr = BaseCapabilitiesComplete::build(this) ;
- LLHTTPClient::post(url, capabilityNames, mHttpResponderPtr);
+ mImpl->mHttpResponderPtr = BaseCapabilitiesComplete::build(this) ;
+ LLHTTPClient::post(url, capabilityNames, mImpl->mHttpResponderPtr);
}
void LLViewerRegion::setCapability(const std::string& name, const std::string& url)
{
if(name == "EventQueueGet")
{
- delete mEventPoll;
- mEventPoll = NULL;
- mEventPoll = new LLEventPoll(url, getHost());
+ delete mImpl->mEventPoll;
+ mImpl->mEventPoll = NULL;
+ mImpl->mEventPoll = new LLEventPoll(url, getHost());
}
else if(name == "UntrustedSimulatorMessage")
{
- LLHTTPSender::setSender(mHost, new LLCapHTTPSender(url));
+ LLHTTPSender::setSender(mImpl->mHost, new LLCapHTTPSender(url));
}
else
{
- mCapabilities[name] = url;
+ mImpl->mCapabilities[name] = url;
if(name == "GetTexture")
{
mHttpUrl = url ;
@@ -1452,11 +1583,12 @@ bool LLViewerRegion::isSpecialCapabilityName(const std::string &name)
std::string LLViewerRegion::getCapability(const std::string& name) const
{
- CapabilityMap::const_iterator iter = mCapabilities.find(name);
- if(iter == mCapabilities.end())
+ CapabilityMap::const_iterator iter = mImpl->mCapabilities.find(name);
+ if(iter == mImpl->mCapabilities.end())
{
return "";
}
+
return iter->second;
}
@@ -1474,7 +1606,7 @@ void LLViewerRegion::logActiveCapabilities() const
{
int count = 0;
CapabilityMap::const_iterator iter;
- for (iter = mCapabilities.begin(); iter != mCapabilities.end(); iter++, count++)
+ for (iter = mImpl->mCapabilities.begin(); iter != mImpl->mCapabilities.end(); ++iter, ++count)
{
if (!iter->second.empty())
{
@@ -1486,13 +1618,27 @@ void LLViewerRegion::logActiveCapabilities() const
LLSpatialPartition* LLViewerRegion::getSpatialPartition(U32 type)
{
- if (type < mObjectPartition.size())
+ if (type < mImpl->mObjectPartition.size())
{
- return mObjectPartition[type];
+ return mImpl->mObjectPartition[type];
}
return NULL;
}
+// the viewer can not yet distinquish between normal- and estate-owned objects
+// so we collapse these two bits and enable the UI if either are set
+const U32 ALLOW_RETURN_ENCROACHING_OBJECT = REGION_FLAGS_ALLOW_RETURN_ENCROACHING_OBJECT
+ | REGION_FLAGS_ALLOW_RETURN_ENCROACHING_ESTATE_OBJECT;
+
+bool LLViewerRegion::objectIsReturnable(const LLVector3& pos, const std::vector<LLBBox>& boxes) const
+{
+ return (mParcelOverlay != NULL)
+ && (mParcelOverlay->isOwnedSelf(pos)
+ || mParcelOverlay->isOwnedGroup(pos)
+ || ((mRegionFlags & ALLOW_RETURN_ENCROACHING_OBJECT)
+ && mParcelOverlay->encroachesOwned(boxes)) );
+}
+
void LLViewerRegion::showReleaseNotes()
{
std::string url = this->getCapability("ServerReleaseNotes");
diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h
index 1ba025312b..9c5b85b77f 100644
--- a/indra/newview/llviewerregion.h
+++ b/indra/newview/llviewerregion.h
@@ -36,21 +36,18 @@
#include "llcloud.h"
#include "llstat.h"
#include "v3dmath.h"
-#include "llhost.h"
#include "llstring.h"
#include "llregionflags.h"
#include "lluuid.h"
-#include "lldatapacker.h"
-#include "llvocache.h"
#include "llweb.h"
#include "llcapabilityprovider.h"
-#include "llcapabilitylistener.h"
#include "m4math.h" // LLMatrix4
+#include "llhttpclient.h"
// Surface id's
#define LAND 1
#define WATER 2
-const U32 MAX_OBJECT_CACHE_ENTRIES = 10000;
+const U32 MAX_OBJECT_CACHE_ENTRIES = 50000;
class LLEventPoll;
@@ -64,6 +61,13 @@ class LLVOCache;
class LLVOCacheEntry;
class LLSpatialPartition;
class LLEventPump;
+class LLCapabilityListener;
+class LLDataPacker;
+class LLDataPackerBinaryBuffer;
+class LLHost;
+class LLBBox;
+
+class LLViewerRegionImpl;
class LLViewerRegion: public LLCapabilityProvider // implements this interface
{
@@ -73,6 +77,7 @@ public:
{
PARTITION_HUD=0,
PARTITION_TERRAIN,
+ PARTITION_VOIDWATER,
PARTITION_WATER,
PARTITION_TREE,
PARTITION_PARTICLE,
@@ -157,19 +162,19 @@ public:
F32 getTimeDilation() const { return mTimeDilation; }
// Origin height is at zero.
- const LLVector3d &getOriginGlobal() const { return mOriginGlobal; }
+ const LLVector3d &getOriginGlobal() const;
LLVector3 getOriginAgent() const;
// Center is at the height of the water table.
- const LLVector3d &getCenterGlobal() const { return mCenterGlobal; }
+ const LLVector3d &getCenterGlobal() const;
LLVector3 getCenterAgent() const;
void setRegionNameAndZone(const std::string& name_and_zone);
const std::string& getName() const { return mName; }
const std::string& getZoning() const { return mZoning; }
- void setOwner(const LLUUID& owner_id) { mOwnerID = owner_id; }
- const LLUUID& getOwner() const { return mOwnerID; }
+ void setOwner(const LLUUID& owner_id);
+ const LLUUID& getOwner() const;
// Is the current agent on the estate manager list for this region?
void setIsEstateManager(BOOL b) { mIsEstateManager = b; }
@@ -204,7 +209,7 @@ public:
// can process the message.
static void processRegionInfo(LLMessageSystem* msg, void**);
- void setCacheID(const LLUUID& id) { mCacheID = id; }
+ void setCacheID(const LLUUID& id);
F32 getWidth() const { return mWidth; }
@@ -220,8 +225,8 @@ public:
U32 getPacketsLost() const;
- void setHttpResponderPtrNULL() {mHttpResponderPtr = NULL ;}
- const LLHTTPClient::ResponderPtr getHttpResponderPtr() const {return mHttpResponderPtr ;}
+ void setHttpResponderPtrNULL();
+ const LLHTTPClient::ResponderPtr getHttpResponderPtr() const;
// Get/set named capability URLs for this region.
void setSeedCapability(const std::string& url);
@@ -236,21 +241,19 @@ public:
static bool isSpecialCapabilityName(const std::string &name);
void logActiveCapabilities() const;
- /// Capability-request exception
- typedef LLCapabilityListener::ArgError ArgError;
/// Get LLEventPump on which we listen for capability requests
/// (https://wiki.lindenlab.com/wiki/Viewer:Messaging/Messaging_Notes#Capabilities)
- LLEventPump& getCapAPI() { return mCapabilityListener.getCapAPI(); }
+ LLEventPump& getCapAPI() const;
/// implements LLCapabilityProvider
- virtual LLHost getHost() const { return mHost; }
+ /*virtual*/ const LLHost& getHost() const;
const U64 &getHandle() const { return mHandle; }
- LLSurface &getLand() const { return *mLandp; }
+ LLSurface &getLand() const;
// set and get the region id
- const LLUUID& getRegionID() const { return mRegionID; }
- void setRegionID(const LLUUID& region_id) { mRegionID = region_id; }
+ const LLUUID& getRegionID() const;
+ void setRegionID(const LLUUID& region_id);
BOOL pointInRegionGlobal(const LLVector3d &point_global) const;
LLVector3 getPosRegionFromGlobal(const LLVector3d &point_global) const;
@@ -258,7 +261,7 @@ public:
LLVector3 getPosAgentFromRegion(const LLVector3 &region_pos) const;
LLVector3d getPosGlobalFromRegion(const LLVector3 &offset) const;
- LLVLComposition *getComposition() const { return mCompositionp; }
+ LLVLComposition *getComposition() const;
F32 getCompositionXY(const S32 x, const S32 y) const;
BOOL isOwnedSelf(const LLVector3& pos);
@@ -273,9 +276,24 @@ public:
void getInfo(LLSD& info);
+ typedef enum
+ {
+ CACHE_MISS_TYPE_FULL = 0,
+ CACHE_MISS_TYPE_CRC,
+ CACHE_MISS_TYPE_NONE
+ } eCacheMissType;
+
+ typedef enum
+ {
+ CACHE_UPDATE_DUPE = 0,
+ CACHE_UPDATE_CHANGED,
+ CACHE_UPDATE_ADDED,
+ CACHE_UPDATE_REPLACED
+ } eCacheUpdateResult;
+
// handle a full update message
- void cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp);
- LLDataPacker *getDP(U32 local_id, U32 crc);
+ eCacheUpdateResult cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp);
+ LLDataPacker *getDP(U32 local_id, U32 crc, U8 &cache_miss_type);
void requestCacheMisses();
void addCacheMissFull(const U32 local_id);
@@ -292,6 +310,8 @@ public:
std::string getHttpUrl() const { return mHttpUrl ;}
LLSpatialPartition* getSpatialPartition(U32 type);
+
+ bool objectIsReturnable(const LLVector3& pos, const std::vector<LLBBox>& boxes) const;
public:
struct CompareDistance
{
@@ -328,34 +348,19 @@ public:
LLDynamicArray<LLUUID> mMapAvatarIDs;
private:
- // The surfaces and other layers
- LLSurface* mLandp;
+ LLViewerRegionImpl * mImpl;
- // Region geometry data
- LLVector3d mOriginGlobal; // Location of southwest corner of region (meters)
- LLVector3d mCenterGlobal; // Location of center in world space (meters)
F32 mWidth; // Width of region on a side (meters)
-
U64 mHandle;
- LLHost mHost;
-
- // The unique ID for this region.
- LLUUID mRegionID;
-
F32 mTimeDilation; // time dilation of physics simulation on simulator
// simulator name
std::string mName;
std::string mZoning;
- // region/estate owner - usually null.
- LLUUID mOwnerID;
-
// Is this agent on the estate managers list for this region?
BOOL mIsEstateManager;
- // Network statistics for the region's circuit...
- LLTimer mLastNetUpdate;
U32 mPacketsIn;
U32 mBitsIn;
U32 mLastBitsIn;
@@ -367,9 +372,6 @@ private:
U32 mPingDelay;
F32 mDeltaTime; // Time since last measurement of lastPackets, Bits, etc
- // Misc
- LLVLComposition *mCompositionp; // Composition layer for the surface
-
U32 mRegionFlags; // includes damage flags
U8 mSimAccess;
F32 mBillableFactor;
@@ -379,46 +381,24 @@ private:
// Information for Homestead / CR-53
S32 mClassID;
S32 mCPURatio;
+
std::string mColoName;
std::string mProductSKU;
std::string mProductName;
std::string mHttpUrl ;
-
// Maps local ids to cache entries.
// Regions can have order 10,000 objects, so assume
// a structure of size 2^14 = 16,000
BOOL mCacheLoaded;
BOOL mCacheDirty;
- LLVOCacheEntry::vocache_entry_map_t mCacheMap;
+
LLDynamicArray<U32> mCacheMissFull;
LLDynamicArray<U32> mCacheMissCRC;
- // time?
- // LRU info?
-
- // Cache ID is unique per-region, across renames, moving locations,
- // etc.
- LLUUID mCacheID;
-
- typedef std::map<std::string, std::string> CapabilityMap;
- CapabilityMap mCapabilities;
-
- LLEventPoll* mEventPoll;
- /// Post an event to this LLCapabilityListener to invoke a capability message on
- /// this LLViewerRegion's server
- /// (https://wiki.lindenlab.com/wiki/Viewer:Messaging/Messaging_Notes#Capabilities)
- LLCapabilityListener mCapabilityListener;
-
-private:
bool mAlive; // can become false if circuit disconnects
bool mCapabilitiesReceived;
- //spatial partitions for objects in this region
- std::vector<LLSpatialPartition*> mObjectPartition;
-
- LLHTTPClient::ResponderPtr mHttpResponderPtr ;
-
BOOL mReleaseNotesRequested;
};
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index d078c15316..3e85802ba6 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -68,9 +68,21 @@ LLGLSLShader gObjectFullbrightProgram;
LLGLSLShader gObjectFullbrightWaterProgram;
LLGLSLShader gObjectFullbrightShinyProgram;
+LLGLSLShader gObjectFullbrightShinyWaterProgram;
LLGLSLShader gObjectShinyProgram;
LLGLSLShader gObjectShinyWaterProgram;
+//object hardware skinning shaders
+LLGLSLShader gSkinnedObjectSimpleProgram;
+LLGLSLShader gSkinnedObjectFullbrightProgram;
+LLGLSLShader gSkinnedObjectFullbrightShinyProgram;
+LLGLSLShader gSkinnedObjectShinySimpleProgram;
+
+LLGLSLShader gSkinnedObjectSimpleWaterProgram;
+LLGLSLShader gSkinnedObjectFullbrightWaterProgram;
+LLGLSLShader gSkinnedObjectFullbrightShinyWaterProgram;
+LLGLSLShader gSkinnedObjectShinySimpleWaterProgram;
+
//environment shaders
LLGLSLShader gTerrainProgram;
LLGLSLShader gTerrainWaterProgram;
@@ -101,6 +113,9 @@ LLGLSLShader gDeferredImpostorProgram;
LLGLSLShader gDeferredEdgeProgram;
LLGLSLShader gDeferredWaterProgram;
LLGLSLShader gDeferredDiffuseProgram;
+LLGLSLShader gDeferredSkinnedDiffuseProgram;
+LLGLSLShader gDeferredSkinnedBumpProgram;
+LLGLSLShader gDeferredSkinnedAlphaProgram;
LLGLSLShader gDeferredBumpProgram;
LLGLSLShader gDeferredTerrainProgram;
LLGLSLShader gDeferredTreeProgram;
@@ -115,12 +130,14 @@ LLGLSLShader gDeferredBlurLightProgram;
LLGLSLShader gDeferredSoftenProgram;
LLGLSLShader gDeferredShadowProgram;
LLGLSLShader gDeferredAvatarShadowProgram;
+LLGLSLShader gDeferredAttachmentShadowProgram;
LLGLSLShader gDeferredAlphaProgram;
LLGLSLShader gDeferredFullbrightProgram;
LLGLSLShader gDeferredGIProgram;
LLGLSLShader gDeferredGIFinalProgram;
LLGLSLShader gDeferredPostGIProgram;
LLGLSLShader gDeferredPostProgram;
+LLGLSLShader gDeferredPostNoDoFProgram;
LLGLSLShader gLuminanceGatherProgram;
@@ -142,6 +159,15 @@ LLViewerShaderMgr::LLViewerShaderMgr() :
mShaderList.push_back(&gObjectSimpleProgram);
mShaderList.push_back(&gObjectFullbrightProgram);
mShaderList.push_back(&gObjectFullbrightShinyProgram);
+ mShaderList.push_back(&gObjectFullbrightShinyWaterProgram);
+ mShaderList.push_back(&gSkinnedObjectSimpleProgram);
+ mShaderList.push_back(&gSkinnedObjectFullbrightProgram);
+ mShaderList.push_back(&gSkinnedObjectFullbrightShinyProgram);
+ mShaderList.push_back(&gSkinnedObjectShinySimpleProgram);
+ mShaderList.push_back(&gSkinnedObjectSimpleWaterProgram);
+ mShaderList.push_back(&gSkinnedObjectFullbrightWaterProgram);
+ mShaderList.push_back(&gSkinnedObjectFullbrightShinyWaterProgram);
+ mShaderList.push_back(&gSkinnedObjectShinySimpleWaterProgram);
mShaderList.push_back(&gTerrainProgram);
mShaderList.push_back(&gTerrainWaterProgram);
mShaderList.push_back(&gObjectSimpleWaterProgram);
@@ -155,6 +181,7 @@ LLViewerShaderMgr::LLViewerShaderMgr() :
mShaderList.push_back(&gDeferredLightProgram);
mShaderList.push_back(&gDeferredMultiLightProgram);
mShaderList.push_back(&gDeferredAlphaProgram);
+ mShaderList.push_back(&gDeferredSkinnedAlphaProgram);
mShaderList.push_back(&gDeferredFullbrightProgram);
mShaderList.push_back(&gDeferredPostGIProgram);
mShaderList.push_back(&gDeferredEdgeProgram);
@@ -189,6 +216,7 @@ void LLViewerShaderMgr::initAttribsAndUniforms(void)
mReservedAttribs.push_back("materialColor");
mReservedAttribs.push_back("specularColor");
mReservedAttribs.push_back("binormal");
+ mReservedAttribs.push_back("object_weight");
mAvatarAttribs.reserve(5);
mAvatarAttribs.push_back("weight");
@@ -335,8 +363,8 @@ void LLViewerShaderMgr::setShaders()
}
else
{
- LLPipeline::sRenderGlow =
- LLPipeline::sWaterReflections = FALSE;
+ LLPipeline::sRenderGlow = FALSE;
+ LLPipeline::sWaterReflections = FALSE;
}
//hack to reset buffers that change behavior with shaders
@@ -370,7 +398,9 @@ void LLViewerShaderMgr::setShaders()
S32 deferred_class = 0;
if (LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") &&
- gSavedSettings.getBOOL("RenderDeferred"))
+ gSavedSettings.getBOOL("RenderDeferred") &&
+ gSavedSettings.getBOOL("RenderAvatarVP") &&
+ gSavedSettings.getBOOL("WindLightUseAtmosShaders"))
{
if (gSavedSettings.getS32("RenderShadowDetail") > 0)
{
@@ -388,14 +418,11 @@ void LLViewerShaderMgr::setShaders()
deferred_class = 1;
}
- //make sure framebuffer objects are enabled
- gSavedSettings.setBOOL("RenderUseFBO", TRUE);
-
//make sure hardware skinning is enabled
- gSavedSettings.setBOOL("RenderAvatarVP", TRUE);
+ //gSavedSettings.setBOOL("RenderAvatarVP", TRUE);
//make sure atmospheric shaders are enabled
- gSavedSettings.setBOOL("WindLightUseAtmosShaders", TRUE);
+ //gSavedSettings.setBOOL("WindLightUseAtmosShaders", TRUE);
}
@@ -438,7 +465,6 @@ void LLViewerShaderMgr::setShaders()
// Load all shaders to set max levels
loadShadersEnvironment();
loadShadersWater();
- loadShadersObject();
loadShadersWindLight();
loadShadersEffects();
loadShadersInterface();
@@ -446,14 +472,9 @@ void LLViewerShaderMgr::setShaders()
// Load max avatar shaders to set the max level
mVertexShaderLevel[SHADER_AVATAR] = 3;
mMaxAvatarShaderLevel = 3;
- loadShadersAvatar();
-
-#if 0 && LL_DARWIN // force avatar shaders off for mac
- mVertexShaderLevel[SHADER_AVATAR] = 0;
- sMaxAvatarShaderLevel = 0;
-#else
- if (gSavedSettings.getBOOL("RenderAvatarVP"))
- {
+
+ if (gSavedSettings.getBOOL("RenderAvatarVP") && loadShadersObject())
+ { //hardware skinning is enabled and rigged attachment shaders loaded correctly
BOOL avatar_cloth = gSavedSettings.getBOOL("RenderAvatarCloth");
S32 avatar_class = 1;
@@ -484,17 +505,28 @@ void LLViewerShaderMgr::setShaders()
}
}
else
- {
+ { //hardware skinning not possible, neither is deferred rendering
mVertexShaderLevel[SHADER_AVATAR] = 0;
- gSavedSettings.setBOOL("RenderAvatarCloth", FALSE);
+ mVertexShaderLevel[SHADER_DEFERRED] = 0;
+
+ if (gSavedSettings.getBOOL("RenderAvatarVP"))
+ {
+ gSavedSettings.setBOOL("RenderDeferred", FALSE);
+ gSavedSettings.setBOOL("RenderAvatarCloth", FALSE);
+ gSavedSettings.setBOOL("RenderAvatarVP", FALSE);
+ }
+
loadShadersAvatar(); // unloads
+ loadShadersObject();
}
if (!loadShadersDeferred())
{
gSavedSettings.setBOOL("RenderDeferred", FALSE);
+ reentrance = false;
+ setShaders();
+ return;
}
-#endif
}
else
{
@@ -542,7 +574,20 @@ void LLViewerShaderMgr::unloadShaders()
gObjectShinyProgram.unload();
gObjectFullbrightShinyProgram.unload();
+ gObjectFullbrightShinyWaterProgram.unload();
gObjectShinyWaterProgram.unload();
+
+ gSkinnedObjectSimpleProgram.unload();
+ gSkinnedObjectFullbrightProgram.unload();
+ gSkinnedObjectFullbrightShinyProgram.unload();
+ gSkinnedObjectShinySimpleProgram.unload();
+
+ gSkinnedObjectSimpleWaterProgram.unload();
+ gSkinnedObjectFullbrightWaterProgram.unload();
+ gSkinnedObjectFullbrightShinyWaterProgram.unload();
+ gSkinnedObjectShinySimpleWaterProgram.unload();
+
+
gWaterProgram.unload();
gUnderWaterProgram.unload();
gTerrainProgram.unload();
@@ -562,6 +607,9 @@ void LLViewerShaderMgr::unloadShaders()
gPostNightVisionProgram.unload();
gDeferredDiffuseProgram.unload();
+ gDeferredSkinnedDiffuseProgram.unload();
+ gDeferredSkinnedBumpProgram.unload();
+ gDeferredSkinnedAlphaProgram.unload();
mVertexShaderLevel[SHADER_LIGHTING] = 0;
mVertexShaderLevel[SHADER_OBJECT] = 0;
@@ -620,6 +668,7 @@ BOOL LLViewerShaderMgr::loadBasicShaders()
shaders.push_back( make_pair( "lighting/lightSpecularV.glsl", mVertexShaderLevel[SHADER_LIGHTING] ) );
shaders.push_back( make_pair( "windlight/atmosphericsV.glsl", mVertexShaderLevel[SHADER_WINDLIGHT] ) );
shaders.push_back( make_pair( "avatar/avatarSkinV.glsl", 1 ) );
+ shaders.push_back( make_pair( "avatar/objectSkinV.glsl", 1 ) );
// We no longer have to bind the shaders to global glhandles, they are automatically added to a map now.
for (U32 i = 0; i < shaders.size(); i++)
@@ -635,7 +684,7 @@ BOOL LLViewerShaderMgr::loadBasicShaders()
// (in order of shader function call depth for reference purposes, deepest level first)
shaders.clear();
- shaders.reserve(12);
+ shaders.reserve(13);
shaders.push_back( make_pair( "windlight/atmosphericsVarsF.glsl", mVertexShaderLevel[SHADER_WINDLIGHT] ) );
shaders.push_back( make_pair( "windlight/gammaF.glsl", mVertexShaderLevel[SHADER_WINDLIGHT]) );
shaders.push_back( make_pair( "windlight/atmosphericsF.glsl", mVertexShaderLevel[SHADER_WINDLIGHT] ) );
@@ -648,6 +697,7 @@ BOOL LLViewerShaderMgr::loadBasicShaders()
shaders.push_back( make_pair( "lighting/lightShinyF.glsl", mVertexShaderLevel[SHADER_LIGHTING] ) );
shaders.push_back( make_pair( "lighting/lightFullbrightShinyF.glsl", mVertexShaderLevel[SHADER_LIGHTING] ) );
shaders.push_back( make_pair( "lighting/lightShinyWaterF.glsl", mVertexShaderLevel[SHADER_LIGHTING] ) );
+ shaders.push_back( make_pair( "lighting/lightFullbrightShinyWaterF.glsl", mVertexShaderLevel[SHADER_LIGHTING] ) );
for (U32 i = 0; i < shaders.size(); i++)
{
@@ -875,6 +925,9 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
{
gDeferredTreeProgram.unload();
gDeferredDiffuseProgram.unload();
+ gDeferredSkinnedDiffuseProgram.unload();
+ gDeferredSkinnedBumpProgram.unload();
+ gDeferredSkinnedAlphaProgram.unload();
gDeferredBumpProgram.unload();
gDeferredImpostorProgram.unload();
gDeferredTerrainProgram.unload();
@@ -887,6 +940,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
gDeferredSoftenProgram.unload();
gDeferredShadowProgram.unload();
gDeferredAvatarShadowProgram.unload();
+ gDeferredAttachmentShadowProgram.unload();
gDeferredAvatarProgram.unload();
gDeferredAvatarAlphaProgram.unload();
gDeferredAlphaProgram.unload();
@@ -898,7 +952,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
gDeferredGIProgram.unload();
gDeferredGIFinalProgram.unload();
gDeferredWaterProgram.unload();
- return FALSE;
+ return TRUE;
}
mVertexShaderLevel[SHADER_AVATAR] = 1;
@@ -917,6 +971,44 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
if (success)
{
+ gDeferredSkinnedDiffuseProgram.mName = "Deferred Skinned Diffuse Shader";
+ gDeferredSkinnedDiffuseProgram.mFeatures.hasObjectSkinning = true;
+ gDeferredSkinnedDiffuseProgram.mShaderFiles.clear();
+ gDeferredSkinnedDiffuseProgram.mShaderFiles.push_back(make_pair("deferred/diffuseSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
+ gDeferredSkinnedDiffuseProgram.mShaderFiles.push_back(make_pair("deferred/diffuseF.glsl", GL_FRAGMENT_SHADER_ARB));
+ gDeferredSkinnedDiffuseProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+ success = gDeferredSkinnedDiffuseProgram.createShader(NULL, NULL);
+ }
+
+ if (success)
+ {
+ gDeferredSkinnedBumpProgram.mName = "Deferred Skinned Bump Shader";
+ gDeferredSkinnedBumpProgram.mFeatures.hasObjectSkinning = true;
+ gDeferredSkinnedBumpProgram.mShaderFiles.clear();
+ gDeferredSkinnedBumpProgram.mShaderFiles.push_back(make_pair("deferred/bumpSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
+ gDeferredSkinnedBumpProgram.mShaderFiles.push_back(make_pair("deferred/bumpF.glsl", GL_FRAGMENT_SHADER_ARB));
+ gDeferredSkinnedBumpProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+ success = gDeferredSkinnedBumpProgram.createShader(NULL, NULL);
+ }
+
+ if (success)
+ {
+ gDeferredSkinnedAlphaProgram.mName = "Deferred Skinned Alpha Shader";
+ gDeferredSkinnedAlphaProgram.mFeatures.hasObjectSkinning = true;
+ gDeferredSkinnedAlphaProgram.mFeatures.calculatesLighting = true;
+ gDeferredSkinnedAlphaProgram.mFeatures.calculatesAtmospherics = true;
+ gDeferredSkinnedAlphaProgram.mFeatures.hasGamma = true;
+ gDeferredSkinnedAlphaProgram.mFeatures.hasAtmospherics = true;
+ gDeferredSkinnedAlphaProgram.mFeatures.hasLighting = true;
+ gDeferredSkinnedAlphaProgram.mShaderFiles.clear();
+ gDeferredSkinnedAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
+ gDeferredSkinnedAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaF.glsl", GL_FRAGMENT_SHADER_ARB));
+ gDeferredSkinnedAlphaProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+ success = gDeferredSkinnedAlphaProgram.createShader(NULL, NULL);
+ }
+
+ if (success)
+ {
gDeferredBumpProgram.mName = "Deferred Bump Shader";
gDeferredBumpProgram.mShaderFiles.clear();
gDeferredBumpProgram.mShaderFiles.push_back(make_pair("deferred/bumpV.glsl", GL_VERTEX_SHADER_ARB));
@@ -959,7 +1051,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
{
gDeferredMultiLightProgram.mName = "Deferred MultiLight Shader";
gDeferredMultiLightProgram.mShaderFiles.clear();
- gDeferredMultiLightProgram.mShaderFiles.push_back(make_pair("deferred/pointLightV.glsl", GL_VERTEX_SHADER_ARB));
+ gDeferredMultiLightProgram.mShaderFiles.push_back(make_pair("deferred/multiPointLightV.glsl", GL_VERTEX_SHADER_ARB));
gDeferredMultiLightProgram.mShaderFiles.push_back(make_pair("deferred/multiPointLightF.glsl", GL_FRAGMENT_SHADER_ARB));
gDeferredMultiLightProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
success = gDeferredMultiLightProgram.createShader(NULL, NULL);
@@ -1065,7 +1157,14 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
gDeferredSoftenProgram.mShaderFiles.clear();
gDeferredSoftenProgram.mShaderFiles.push_back(make_pair("deferred/softenLightV.glsl", GL_VERTEX_SHADER_ARB));
gDeferredSoftenProgram.mShaderFiles.push_back(make_pair("deferred/softenLightF.glsl", GL_FRAGMENT_SHADER_ARB));
+
gDeferredSoftenProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+
+ if (gSavedSettings.getBOOL("RenderDeferredSSAO"))
+ { //if using SSAO, take screen space light map into account as if shadows are enabled
+ gDeferredSoftenProgram.mShaderLevel = llmax(gDeferredSoftenProgram.mShaderLevel, 2);
+ }
+
success = gDeferredSoftenProgram.createShader(NULL, NULL);
}
@@ -1092,6 +1191,17 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
if (success)
{
+ gDeferredAttachmentShadowProgram.mName = "Deferred Attachment Shadow Shader";
+ gDeferredAttachmentShadowProgram.mFeatures.hasObjectSkinning = true;
+ gDeferredAttachmentShadowProgram.mShaderFiles.clear();
+ gDeferredAttachmentShadowProgram.mShaderFiles.push_back(make_pair("deferred/attachmentShadowV.glsl", GL_VERTEX_SHADER_ARB));
+ gDeferredAttachmentShadowProgram.mShaderFiles.push_back(make_pair("deferred/attachmentShadowF.glsl", GL_FRAGMENT_SHADER_ARB));
+ gDeferredAttachmentShadowProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+ success = gDeferredAttachmentShadowProgram.createShader(NULL, NULL);
+ }
+
+ if (success)
+ {
gTerrainProgram.mName = "Deferred Terrain Shader";
gDeferredTerrainProgram.mShaderFiles.clear();
gDeferredTerrainProgram.mShaderFiles.push_back(make_pair("deferred/terrainV.glsl", GL_VERTEX_SHADER_ARB));
@@ -1122,11 +1232,31 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
gDeferredAvatarAlphaProgram.mFeatures.hasLighting = true;
gDeferredAvatarAlphaProgram.mShaderFiles.clear();
gDeferredAvatarAlphaProgram.mShaderFiles.push_back(make_pair("deferred/avatarAlphaV.glsl", GL_VERTEX_SHADER_ARB));
- gDeferredAvatarAlphaProgram.mShaderFiles.push_back(make_pair("deferred/avatarAlphaF.glsl", GL_FRAGMENT_SHADER_ARB));
+ gDeferredAvatarAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaF.glsl", GL_FRAGMENT_SHADER_ARB));
gDeferredAvatarAlphaProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
success = gDeferredAvatarAlphaProgram.createShader(&mAvatarAttribs, &mAvatarUniforms);
}
+ if (success)
+ {
+ gDeferredPostProgram.mName = "Deferred Post Shader";
+ gDeferredPostProgram.mShaderFiles.clear();
+ gDeferredPostProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredV.glsl", GL_VERTEX_SHADER_ARB));
+ gDeferredPostProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredF.glsl", GL_FRAGMENT_SHADER_ARB));
+ gDeferredPostProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+ success = gDeferredPostProgram.createShader(NULL, NULL);
+ }
+
+ if (success)
+ {
+ gDeferredPostNoDoFProgram.mName = "Deferred Post Shader";
+ gDeferredPostNoDoFProgram.mShaderFiles.clear();
+ gDeferredPostNoDoFProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredV.glsl", GL_VERTEX_SHADER_ARB));
+ gDeferredPostNoDoFProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredNoDoFF.glsl", GL_FRAGMENT_SHADER_ARB));
+ gDeferredPostNoDoFProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+ success = gDeferredPostNoDoFProgram.createShader(NULL, NULL);
+ }
+
if (mVertexShaderLevel[SHADER_DEFERRED] > 1)
{
if (success)
@@ -1142,15 +1272,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
if (mVertexShaderLevel[SHADER_DEFERRED] > 2)
{
- if (success)
- {
- gDeferredPostProgram.mName = "Deferred Post Shader";
- gDeferredPostProgram.mShaderFiles.clear();
- gDeferredPostProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredV.glsl", GL_VERTEX_SHADER_ARB));
- gDeferredPostProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredF.glsl", GL_FRAGMENT_SHADER_ARB));
- gDeferredPostProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
- success = gDeferredPostProgram.createShader(NULL, NULL);
- }
+
if (success)
{
@@ -1204,12 +1326,22 @@ BOOL LLViewerShaderMgr::loadShadersObject()
{
gObjectShinyProgram.unload();
gObjectFullbrightShinyProgram.unload();
+ gObjectFullbrightShinyWaterProgram.unload();
gObjectShinyWaterProgram.unload();
gObjectSimpleProgram.unload();
gObjectSimpleWaterProgram.unload();
gObjectFullbrightProgram.unload();
gObjectFullbrightWaterProgram.unload();
- return FALSE;
+ gSkinnedObjectSimpleProgram.unload();
+ gSkinnedObjectFullbrightProgram.unload();
+ gSkinnedObjectFullbrightShinyProgram.unload();
+ gSkinnedObjectShinySimpleProgram.unload();
+ gSkinnedObjectSimpleWaterProgram.unload();
+ gSkinnedObjectFullbrightWaterProgram.unload();
+ gSkinnedObjectFullbrightShinyWaterProgram.unload();
+ gSkinnedObjectShinySimpleWaterProgram.unload();
+
+ return TRUE;
}
if (success)
@@ -1318,6 +1450,159 @@ BOOL LLViewerShaderMgr::loadShadersObject()
success = gObjectFullbrightShinyProgram.createShader(NULL, &mShinyUniforms);
}
+ if (success)
+ {
+ gObjectFullbrightShinyWaterProgram.mName = "Fullbright Shiny Water Shader";
+ gObjectFullbrightShinyWaterProgram.mFeatures.calculatesAtmospherics = true;
+ gObjectFullbrightShinyWaterProgram.mFeatures.isFullbright = true;
+ gObjectFullbrightShinyWaterProgram.mFeatures.isShiny = true;
+ gObjectFullbrightShinyWaterProgram.mFeatures.hasGamma = true;
+ gObjectFullbrightShinyWaterProgram.mFeatures.hasTransport = true;
+ gObjectFullbrightShinyWaterProgram.mFeatures.hasWaterFog = true;
+ gObjectFullbrightShinyWaterProgram.mShaderFiles.clear();
+ gObjectFullbrightShinyWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyV.glsl", GL_VERTEX_SHADER_ARB));
+ gObjectFullbrightShinyWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
+ gObjectFullbrightShinyWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
+ gObjectFullbrightShinyWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
+ success = gObjectFullbrightShinyWaterProgram.createShader(NULL, &mShinyUniforms);
+ }
+
+ if (mVertexShaderLevel[SHADER_AVATAR] > 0)
+ { //load hardware skinned attachment shaders
+ if (success)
+ {
+ gSkinnedObjectSimpleProgram.mName = "Skinned Simple Shader";
+ gSkinnedObjectSimpleProgram.mFeatures.calculatesLighting = true;
+ gSkinnedObjectSimpleProgram.mFeatures.calculatesAtmospherics = true;
+ gSkinnedObjectSimpleProgram.mFeatures.hasGamma = true;
+ gSkinnedObjectSimpleProgram.mFeatures.hasAtmospherics = true;
+ gSkinnedObjectSimpleProgram.mFeatures.hasLighting = true;
+ gSkinnedObjectSimpleProgram.mFeatures.hasObjectSkinning = true;
+ gSkinnedObjectSimpleProgram.mShaderFiles.clear();
+ gSkinnedObjectSimpleProgram.mShaderFiles.push_back(make_pair("objects/simpleSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
+ gSkinnedObjectSimpleProgram.mShaderFiles.push_back(make_pair("objects/simpleF.glsl", GL_FRAGMENT_SHADER_ARB));
+ gSkinnedObjectSimpleProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
+ success = gSkinnedObjectSimpleProgram.createShader(NULL, NULL);
+ }
+
+ if (success)
+ {
+ gSkinnedObjectFullbrightProgram.mName = "Skinned Fullbright Shader";
+ gSkinnedObjectFullbrightProgram.mFeatures.calculatesAtmospherics = true;
+ gSkinnedObjectFullbrightProgram.mFeatures.hasGamma = true;
+ gSkinnedObjectFullbrightProgram.mFeatures.hasTransport = true;
+ gSkinnedObjectFullbrightProgram.mFeatures.isFullbright = true;
+ gSkinnedObjectFullbrightProgram.mFeatures.hasObjectSkinning = true;
+ gSkinnedObjectFullbrightProgram.mShaderFiles.clear();
+ gSkinnedObjectFullbrightProgram.mShaderFiles.push_back(make_pair("objects/fullbrightSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
+ gSkinnedObjectFullbrightProgram.mShaderFiles.push_back(make_pair("objects/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB));
+ gSkinnedObjectFullbrightProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
+ success = gSkinnedObjectFullbrightProgram.createShader(NULL, NULL);
+ }
+
+ if (success)
+ {
+ gSkinnedObjectFullbrightShinyProgram.mName = "Skinned Fullbright Shiny Shader";
+ gSkinnedObjectFullbrightShinyProgram.mFeatures.calculatesAtmospherics = true;
+ gSkinnedObjectFullbrightShinyProgram.mFeatures.hasGamma = true;
+ gSkinnedObjectFullbrightShinyProgram.mFeatures.hasTransport = true;
+ gSkinnedObjectFullbrightShinyProgram.mFeatures.isShiny = true;
+ gSkinnedObjectFullbrightShinyProgram.mFeatures.isFullbright = true;
+ gSkinnedObjectFullbrightShinyProgram.mFeatures.hasObjectSkinning = true;
+ gSkinnedObjectFullbrightShinyProgram.mShaderFiles.clear();
+ gSkinnedObjectFullbrightShinyProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinySkinnedV.glsl", GL_VERTEX_SHADER_ARB));
+ gSkinnedObjectFullbrightShinyProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyF.glsl", GL_FRAGMENT_SHADER_ARB));
+ gSkinnedObjectFullbrightShinyProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
+ success = gSkinnedObjectFullbrightShinyProgram.createShader(NULL, &mShinyUniforms);
+ }
+
+ if (success)
+ {
+ gSkinnedObjectShinySimpleProgram.mName = "Skinned Shiny Simple Shader";
+ gSkinnedObjectShinySimpleProgram.mFeatures.calculatesLighting = true;
+ gSkinnedObjectShinySimpleProgram.mFeatures.calculatesAtmospherics = true;
+ gSkinnedObjectShinySimpleProgram.mFeatures.hasGamma = true;
+ gSkinnedObjectShinySimpleProgram.mFeatures.hasAtmospherics = true;
+ gSkinnedObjectShinySimpleProgram.mFeatures.hasObjectSkinning = true;
+ gSkinnedObjectShinySimpleProgram.mFeatures.isShiny = true;
+ gSkinnedObjectShinySimpleProgram.mShaderFiles.clear();
+ gSkinnedObjectShinySimpleProgram.mShaderFiles.push_back(make_pair("objects/shinySimpleSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
+ gSkinnedObjectShinySimpleProgram.mShaderFiles.push_back(make_pair("objects/shinyF.glsl", GL_FRAGMENT_SHADER_ARB));
+ gSkinnedObjectShinySimpleProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
+ success = gSkinnedObjectShinySimpleProgram.createShader(NULL, &mShinyUniforms);
+ }
+
+ if (success)
+ {
+ gSkinnedObjectSimpleWaterProgram.mName = "Skinned Simple Water Shader";
+ gSkinnedObjectSimpleWaterProgram.mFeatures.calculatesLighting = true;
+ gSkinnedObjectSimpleWaterProgram.mFeatures.calculatesAtmospherics = true;
+ gSkinnedObjectSimpleWaterProgram.mFeatures.hasGamma = true;
+ gSkinnedObjectSimpleWaterProgram.mFeatures.hasAtmospherics = true;
+ gSkinnedObjectSimpleWaterProgram.mFeatures.hasLighting = true;
+ gSkinnedObjectSimpleWaterProgram.mFeatures.hasWaterFog = true;
+ gSkinnedObjectSimpleWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
+ gSkinnedObjectSimpleWaterProgram.mFeatures.hasObjectSkinning = true;
+ gSkinnedObjectSimpleWaterProgram.mShaderFiles.clear();
+ gSkinnedObjectSimpleWaterProgram.mShaderFiles.push_back(make_pair("objects/simpleSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
+ gSkinnedObjectSimpleWaterProgram.mShaderFiles.push_back(make_pair("objects/simpleWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
+ gSkinnedObjectSimpleWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
+ success = gSkinnedObjectSimpleWaterProgram.createShader(NULL, NULL);
+ }
+
+ if (success)
+ {
+ gSkinnedObjectFullbrightWaterProgram.mName = "Skinned Fullbright Water Shader";
+ gSkinnedObjectFullbrightWaterProgram.mFeatures.calculatesAtmospherics = true;
+ gSkinnedObjectFullbrightWaterProgram.mFeatures.hasGamma = true;
+ gSkinnedObjectFullbrightWaterProgram.mFeatures.hasTransport = true;
+ gSkinnedObjectFullbrightWaterProgram.mFeatures.isFullbright = true;
+ gSkinnedObjectFullbrightWaterProgram.mFeatures.hasObjectSkinning = true;
+ gSkinnedObjectFullbrightWaterProgram.mFeatures.hasWaterFog = true;
+ gSkinnedObjectFullbrightWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
+ gSkinnedObjectFullbrightWaterProgram.mShaderFiles.clear();
+ gSkinnedObjectFullbrightWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
+ gSkinnedObjectFullbrightWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
+ gSkinnedObjectFullbrightWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
+ success = gSkinnedObjectFullbrightWaterProgram.createShader(NULL, NULL);
+ }
+
+ if (success)
+ {
+ gSkinnedObjectFullbrightShinyWaterProgram.mName = "Skinned Fullbright Shiny Water Shader";
+ gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.calculatesAtmospherics = true;
+ gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.hasGamma = true;
+ gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.hasTransport = true;
+ gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.isShiny = true;
+ gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.isFullbright = true;
+ gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.hasObjectSkinning = true;
+ gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.hasWaterFog = true;
+ gSkinnedObjectFullbrightShinyWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
+ gSkinnedObjectFullbrightShinyWaterProgram.mShaderFiles.clear();
+ gSkinnedObjectFullbrightShinyWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinySkinnedV.glsl", GL_VERTEX_SHADER_ARB));
+ gSkinnedObjectFullbrightShinyWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
+ gSkinnedObjectFullbrightShinyWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
+ success = gSkinnedObjectFullbrightShinyWaterProgram.createShader(NULL, &mShinyUniforms);
+ }
+
+ if (success)
+ {
+ gSkinnedObjectShinySimpleWaterProgram.mName = "Skinned Shiny Simple Water Shader";
+ gSkinnedObjectShinySimpleWaterProgram.mFeatures.calculatesLighting = true;
+ gSkinnedObjectShinySimpleWaterProgram.mFeatures.calculatesAtmospherics = true;
+ gSkinnedObjectShinySimpleWaterProgram.mFeatures.hasGamma = true;
+ gSkinnedObjectShinySimpleWaterProgram.mFeatures.hasAtmospherics = true;
+ gSkinnedObjectShinySimpleWaterProgram.mFeatures.hasObjectSkinning = true;
+ gSkinnedObjectShinySimpleWaterProgram.mFeatures.isShiny = true;
+ gSkinnedObjectShinySimpleWaterProgram.mFeatures.hasWaterFog = true;
+ gSkinnedObjectShinySimpleWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
+ gSkinnedObjectShinySimpleWaterProgram.mShaderFiles.clear();
+ gSkinnedObjectShinySimpleWaterProgram.mShaderFiles.push_back(make_pair("objects/shinySimpleSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
+ gSkinnedObjectShinySimpleWaterProgram.mShaderFiles.push_back(make_pair("objects/shinyWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
+ gSkinnedObjectShinySimpleWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
+ success = gSkinnedObjectShinySimpleWaterProgram.createShader(NULL, &mShinyUniforms);
+ }
+ }
if( !success )
{
diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h
index db880fded6..72ac5e02ee 100644
--- a/indra/newview/llviewershadermgr.h
+++ b/indra/newview/llviewershadermgr.h
@@ -76,6 +76,7 @@ public:
MATERIAL_COLOR = 0,
SPECULAR_COLOR,
BINORMAL,
+ OBJECT_WEIGHT,
END_RESERVED_ATTRIBS
} eGLSLReservedAttribs;
@@ -304,9 +305,20 @@ extern LLGLSLShader gObjectSimpleLODProgram;
extern LLGLSLShader gObjectFullbrightLODProgram;
extern LLGLSLShader gObjectFullbrightShinyProgram;
+extern LLGLSLShader gObjectFullbrightShinyWaterProgram;
extern LLGLSLShader gObjectShinyProgram;
extern LLGLSLShader gObjectShinyWaterProgram;
+extern LLGLSLShader gSkinnedObjectSimpleProgram;
+extern LLGLSLShader gSkinnedObjectFullbrightProgram;
+extern LLGLSLShader gSkinnedObjectFullbrightShinyProgram;
+extern LLGLSLShader gSkinnedObjectShinySimpleProgram;
+
+extern LLGLSLShader gSkinnedObjectSimpleWaterProgram;
+extern LLGLSLShader gSkinnedObjectFullbrightWaterProgram;
+extern LLGLSLShader gSkinnedObjectFullbrightShinyWaterProgram;
+extern LLGLSLShader gSkinnedObjectShinySimpleWaterProgram;
+
//environment shaders
extern LLGLSLShader gTerrainProgram;
extern LLGLSLShader gTerrainWaterProgram;
@@ -337,6 +349,9 @@ extern LLGLSLShader gDeferredImpostorProgram;
extern LLGLSLShader gDeferredEdgeProgram;
extern LLGLSLShader gDeferredWaterProgram;
extern LLGLSLShader gDeferredDiffuseProgram;
+extern LLGLSLShader gDeferredSkinnedDiffuseProgram;
+extern LLGLSLShader gDeferredSkinnedBumpProgram;
+extern LLGLSLShader gDeferredSkinnedAlphaProgram;
extern LLGLSLShader gDeferredBumpProgram;
extern LLGLSLShader gDeferredTerrainProgram;
extern LLGLSLShader gDeferredTreeProgram;
@@ -353,7 +368,9 @@ extern LLGLSLShader gDeferredSoftenProgram;
extern LLGLSLShader gDeferredShadowProgram;
extern LLGLSLShader gDeferredPostGIProgram;
extern LLGLSLShader gDeferredPostProgram;
+extern LLGLSLShader gDeferredPostNoDoFProgram;
extern LLGLSLShader gDeferredAvatarShadowProgram;
+extern LLGLSLShader gDeferredAttachmentShadowProgram;
extern LLGLSLShader gDeferredAlphaProgram;
extern LLGLSLShader gDeferredFullbrightProgram;
extern LLGLSLShader gDeferredAvatarAlphaProgram;
diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp
index 42266ad233..0fb94bc44b 100644
--- a/indra/newview/llviewerstats.cpp
+++ b/indra/newview/llviewerstats.cpp
@@ -48,6 +48,7 @@
#include "llagent.h"
#include "llagentcamera.h"
#include "llviewercontrol.h"
+#include "llversioninfo.h"
#include "llfloatertools.h"
#include "lldebugview.h"
#include "llfasttimerview.h"
@@ -58,6 +59,7 @@
#include "llworld.h"
#include "llfeaturemanager.h"
#include "llviewernetwork.h"
+#include "llmeshrepository.h" //for LLMeshRepository::sBytesReceived
class StatAttributes
@@ -558,7 +560,7 @@ F32 gWorstLandCompression = 0.f, gWorstWaterCompression = 0.f;
U32 gTotalWorldBytes = 0, gTotalObjectBytes = 0, gTotalTextureBytes = 0, gSimPingCount = 0;
U32 gObjectBits = 0;
F32 gAvgSimPing = 0.f;
-
+U32 gTotalTextureBytesPerBoostLevel[LLViewerTexture::MAX_GL_IMAGE_CATEGORY] = {0};
extern U32 gVisCompared;
extern U32 gVisTested;
@@ -710,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;
}
@@ -749,7 +751,7 @@ void send_stats()
// send fps only for time app spends in foreground
agent["fps"] = (F32)gForegroundFrameCount / gForegroundTime.getElapsedTimeF32();
- agent["version"] = gCurrentVersion;
+ agent["version"] = LLVersionInfo::getChannelAndVersion();
std::string language = LLUI::getLanguage();
agent["language"] = language;
@@ -793,6 +795,7 @@ void send_stats()
download["world_kbytes"] = gTotalWorldBytes / 1024.0;
download["object_kbytes"] = gTotalObjectBytes / 1024.0;
download["texture_kbytes"] = gTotalTextureBytes / 1024.0;
+ download["mesh_kbytes"] = LLMeshRepository::sBytesReceived/1024.0;
LLSD &in = body["stats"]["net"]["in"];
@@ -851,6 +854,8 @@ void send_stats()
body["DisplayNamesEnabled"] = gSavedSettings.getBOOL("UseDisplayNames");
body["DisplayNamesShowUsername"] = gSavedSettings.getBOOL("NameTagShowUsernames");
+ body["MinimalSkin"] = !gSavedSettings.getString("SessionSettingsFile").empty();
+
LLViewerStats::getInstance()->addToMessage(body);
LLHTTPClient::post(url, body, new ViewerStatsResponder());
}
diff --git a/indra/newview/llviewerstats.h b/indra/newview/llviewerstats.h
index ca977d4599..f91a1241fe 100644
--- a/indra/newview/llviewerstats.h
+++ b/indra/newview/llviewerstats.h
@@ -196,8 +196,15 @@ public:
S32 mCount;
F32 mSum;
F32 mSumOfSquares;
+ F32 mMinValue;
+ F32 mMaxValue;
U32 mCountOfNextUpdatesToIgnore;
+ inline StatsAccumulator()
+ {
+ reset();
+ }
+
inline void push( F32 val )
{
if ( mCountOfNextUpdatesToIgnore > 0 )
@@ -209,13 +216,31 @@ public:
mCount++;
mSum += val;
mSumOfSquares += val * val;
+ if (mCount == 1 || val > mMaxValue)
+ {
+ mMaxValue = val;
+ }
+ if (mCount == 1 || val < mMinValue)
+ {
+ mMinValue = val;
+ }
}
inline F32 getMean() const
{
return (mCount == 0) ? 0.f : ((F32)mSum)/mCount;
}
-
+
+ inline F32 getMinValue() const
+ {
+ return mMinValue;
+ }
+
+ inline F32 getMaxValue() const
+ {
+ return mMaxValue;
+ }
+
inline F32 getStdDev() const
{
const F32 mean = getMean();
@@ -231,6 +256,8 @@ public:
{
mCount = 0;
mSum = mSumOfSquares = 0.f;
+ mMinValue = 0.0f;
+ mMaxValue = 0.0f;
mCountOfNextUpdatesToIgnore = 0;
}
@@ -240,6 +267,8 @@ public:
data["mean"] = getMean();
data["std_dev"] = getStdDev();
data["count"] = (S32)mCount;
+ data["min"] = getMinValue();
+ data["max"] = getMaxValue();
return data;
}
};
@@ -264,4 +293,6 @@ void send_stats();
extern std::map<S32,LLFrameTimer> gDebugTimers;
extern std::map<S32,std::string> gDebugTimerLabel;
extern U32 gTotalTextureBytes;
+extern U32 gTotalObjectBytes;
+extern U32 gTotalTextureBytesPerBoostLevel[] ;
#endif // LL_LLVIEWERSTATS_H
diff --git a/indra/newview/llviewerstatsrecorder.cpp b/indra/newview/llviewerstatsrecorder.cpp
new file mode 100644
index 0000000000..e9d21b4848
--- /dev/null
+++ b/indra/newview/llviewerstatsrecorder.cpp
@@ -0,0 +1,258 @@
+/**
+ * @file llviewerstatsrecorder.cpp
+ * @brief record info about viewer events to a metrics log file
+ *
+ * $LicenseInfo:firstyear=2010&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 "llviewerstatsrecorder.h"
+
+#if LL_RECORD_VIEWER_STATS
+
+#include "llfile.h"
+#include "llviewerregion.h"
+#include "llviewerobject.h"
+
+
+// To do - something using region name or global position
+#if LL_WINDOWS
+ static const std::string STATS_FILE_NAME("C:\\ViewerObjectCacheStats.csv");
+#else
+ static const std::string STATS_FILE_NAME("/tmp/viewerstats.csv");
+#endif
+
+LLViewerStatsRecorder* LLViewerStatsRecorder::sInstance = NULL;
+LLViewerStatsRecorder::LLViewerStatsRecorder() :
+ mObjectCacheFile(NULL),
+ mTimer(),
+ mRegionp(NULL),
+ mStartTime(0.f),
+ mProcessingTime(0.f)
+{
+ if (NULL != sInstance)
+ {
+ llerrs << "Attempted to create multiple instances of LLViewerStatsRecorder!" << llendl;
+ }
+ sInstance = this;
+ clearStats();
+}
+
+LLViewerStatsRecorder::~LLViewerStatsRecorder()
+{
+ if (mObjectCacheFile != NULL)
+ {
+ LLFile::close(mObjectCacheFile);
+ mObjectCacheFile = NULL;
+ }
+}
+
+// static
+void LLViewerStatsRecorder::initClass()
+{
+ sInstance = new LLViewerStatsRecorder();
+}
+
+// static
+void LLViewerStatsRecorder::cleanupClass()
+{
+ delete sInstance;
+ sInstance = NULL;
+}
+
+
+void LLViewerStatsRecorder::initStatsRecorder(LLViewerRegion *regionp)
+{
+ if (mObjectCacheFile == NULL)
+ {
+ mStartTime = LLTimer::getTotalTime();
+ mObjectCacheFile = LLFile::fopen(STATS_FILE_NAME, "wb");
+ if (mObjectCacheFile)
+ { // Write column headers
+ std::ostringstream data_msg;
+ data_msg << "EventTime, "
+ << "ProcessingTime, "
+ << "CacheHits, "
+ << "CacheFullMisses, "
+ << "CacheCrcMisses, "
+ << "FullUpdates, "
+ << "TerseUpdates, "
+ << "CacheMissRequests, "
+ << "CacheMissResponses, "
+ << "CacheUpdateDupes, "
+ << "CacheUpdateChanges, "
+ << "CacheUpdateAdds, "
+ << "CacheUpdateReplacements, "
+ << "UpdateFailures"
+ << "\n";
+
+ fwrite(data_msg.str().c_str(), 1, data_msg.str().size(), mObjectCacheFile );
+ }
+ }
+}
+
+void LLViewerStatsRecorder::beginObjectUpdateEvents(LLViewerRegion *regionp)
+{
+ initStatsRecorder(regionp);
+ mRegionp = regionp;
+ mProcessingTime = LLTimer::getTotalTime();
+ clearStats();
+}
+
+void LLViewerStatsRecorder::clearStats()
+{
+ mObjectCacheHitCount = 0;
+ mObjectCacheMissFullCount = 0;
+ mObjectCacheMissCrcCount = 0;
+ mObjectFullUpdates = 0;
+ mObjectTerseUpdates = 0;
+ mObjectCacheMissRequests = 0;
+ mObjectCacheMissResponses = 0;
+ mObjectCacheUpdateDupes = 0;
+ mObjectCacheUpdateChanges = 0;
+ mObjectCacheUpdateAdds = 0;
+ mObjectCacheUpdateReplacements = 0;
+ mObjectUpdateFailures = 0;
+}
+
+
+void LLViewerStatsRecorder::recordObjectUpdateFailure(U32 local_id, const EObjectUpdateType update_type)
+{
+ mObjectUpdateFailures++;
+}
+
+void LLViewerStatsRecorder::recordCacheMissEvent(U32 local_id, const EObjectUpdateType update_type, U8 cache_miss_type)
+{
+ if (LLViewerRegion::CACHE_MISS_TYPE_FULL == cache_miss_type)
+ {
+ mObjectCacheMissFullCount++;
+ }
+ else
+ {
+ mObjectCacheMissCrcCount++;
+ }
+}
+
+void LLViewerStatsRecorder::recordObjectUpdateEvent(U32 local_id, const EObjectUpdateType update_type, LLViewerObject * objectp)
+{
+ switch (update_type)
+ {
+ case OUT_FULL:
+ mObjectFullUpdates++;
+ break;
+ case OUT_TERSE_IMPROVED:
+ mObjectTerseUpdates++;
+ break;
+ case OUT_FULL_COMPRESSED:
+ mObjectCacheMissResponses++;
+ break;
+ case OUT_FULL_CACHED:
+ mObjectCacheHitCount++;
+ break;
+ default:
+ llwarns << "Unknown update_type" << llendl;
+ break;
+ };
+}
+
+void LLViewerStatsRecorder::recordCacheFullUpdate(U32 local_id, const EObjectUpdateType update_type, LLViewerRegion::eCacheUpdateResult update_result, LLViewerObject* objectp)
+{
+ switch (update_result)
+ {
+ case LLViewerRegion::CACHE_UPDATE_DUPE:
+ mObjectCacheUpdateDupes++;
+ break;
+ case LLViewerRegion::CACHE_UPDATE_CHANGED:
+ mObjectCacheUpdateChanges++;
+ break;
+ case LLViewerRegion::CACHE_UPDATE_ADDED:
+ mObjectCacheUpdateAdds++;
+ break;
+ case LLViewerRegion::CACHE_UPDATE_REPLACED:
+ mObjectCacheUpdateReplacements++;
+ break;
+ default:
+ llwarns << "Unknown update_result type" << llendl;
+ break;
+ };
+}
+
+void LLViewerStatsRecorder::recordRequestCacheMissesEvent(S32 count)
+{
+ mObjectCacheMissRequests += count;
+}
+
+void LLViewerStatsRecorder::endObjectUpdateEvents()
+{
+ llinfos << "ILX: "
+ << mObjectCacheHitCount << " hits, "
+ << mObjectCacheMissFullCount << " full misses, "
+ << mObjectCacheMissCrcCount << " crc misses, "
+ << mObjectFullUpdates << " full updates, "
+ << mObjectTerseUpdates << " terse updates, "
+ << mObjectCacheMissRequests << " cache miss requests, "
+ << mObjectCacheMissResponses << " cache miss responses, "
+ << mObjectCacheUpdateDupes << " cache update dupes, "
+ << mObjectCacheUpdateChanges << " cache update changes, "
+ << mObjectCacheUpdateAdds << " cache update adds, "
+ << mObjectCacheUpdateReplacements << " cache update replacements, "
+ << mObjectUpdateFailures << " update failures"
+ << llendl;
+
+ S32 total_objects = mObjectCacheHitCount + mObjectCacheMissCrcCount + mObjectCacheMissFullCount + mObjectFullUpdates + mObjectTerseUpdates + mObjectCacheMissRequests + mObjectCacheMissResponses + mObjectCacheUpdateDupes + mObjectCacheUpdateChanges + mObjectCacheUpdateAdds + mObjectCacheUpdateReplacements + mObjectUpdateFailures;
+ if (mObjectCacheFile != NULL &&
+ total_objects > 0)
+ {
+ std::ostringstream data_msg;
+ F32 processing32 = (F32) ((LLTimer::getTotalTime() - mProcessingTime) / 1000.0);
+
+ data_msg << getTimeSinceStart()
+ << ", " << processing32
+ << ", " << mObjectCacheHitCount
+ << ", " << mObjectCacheMissFullCount
+ << ", " << mObjectCacheMissCrcCount
+ << ", " << mObjectFullUpdates
+ << ", " << mObjectTerseUpdates
+ << ", " << mObjectCacheMissRequests
+ << ", " << mObjectCacheMissResponses
+ << ", " << mObjectCacheUpdateDupes
+ << ", " << mObjectCacheUpdateChanges
+ << ", " << mObjectCacheUpdateAdds
+ << ", " << mObjectCacheUpdateReplacements
+ << ", " << mObjectUpdateFailures
+ << "\n";
+
+ fwrite(data_msg.str().c_str(), 1, data_msg.str().size(), mObjectCacheFile );
+ }
+
+ clearStats();
+}
+
+F32 LLViewerStatsRecorder::getTimeSinceStart()
+{
+ return (F32) ((LLTimer::getTotalTime() - mStartTime) / 1000.0);
+}
+
+#endif
+
+
+
diff --git a/indra/newview/llviewerstatsrecorder.h b/indra/newview/llviewerstatsrecorder.h
new file mode 100644
index 0000000000..612ac380f7
--- /dev/null
+++ b/indra/newview/llviewerstatsrecorder.h
@@ -0,0 +1,97 @@
+/**
+ * @file llviewerstatsrecorder.h
+ * @brief record info about viewer events to a metrics log file
+ *
+ * $LicenseInfo:firstyear=2010&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 LLVIEWERSTATSRECORDER_H
+#define LLVIEWERSTATSRECORDER_H
+
+
+// This is a diagnostic class used to record information from the viewer
+// for analysis.
+
+// This is normally 0. Set to 1 to enable viewer stats recording
+#define LL_RECORD_VIEWER_STATS 0
+
+
+#if LL_RECORD_VIEWER_STATS
+#include "llframetimer.h"
+#include "llviewerobject.h"
+#include "llviewerregion.h"
+
+class LLMutex;
+class LLViewerRegion;
+class LLViewerObject;
+
+class LLViewerStatsRecorder
+{
+ public:
+ LLViewerStatsRecorder();
+ ~LLViewerStatsRecorder();
+
+ static void initClass();
+ static void cleanupClass();
+ static LLViewerStatsRecorder* instance() {return sInstance; }
+
+ void initStatsRecorder(LLViewerRegion *regionp);
+
+ void beginObjectUpdateEvents(LLViewerRegion *regionp);
+ void recordObjectUpdateFailure(U32 local_id, const EObjectUpdateType update_type);
+ void recordCacheMissEvent(U32 local_id, const EObjectUpdateType update_type, U8 cache_miss_type);
+ void recordObjectUpdateEvent(U32 local_id, const EObjectUpdateType update_type, LLViewerObject * objectp);
+ void recordCacheFullUpdate(U32 local_id, const EObjectUpdateType update_type, LLViewerRegion::eCacheUpdateResult update_result, LLViewerObject* objectp);
+ void recordRequestCacheMissesEvent(S32 count);
+ void endObjectUpdateEvents();
+
+ F32 getTimeSinceStart();
+
+private:
+ static LLViewerStatsRecorder* sInstance;
+
+ LLFILE * mObjectCacheFile; // File to write data into
+ LLFrameTimer mTimer;
+ LLViewerRegion* mRegionp;
+ F64 mStartTime;
+ F64 mProcessingTime;
+
+ S32 mObjectCacheHitCount;
+ S32 mObjectCacheMissFullCount;
+ S32 mObjectCacheMissCrcCount;
+ S32 mObjectFullUpdates;
+ S32 mObjectTerseUpdates;
+ S32 mObjectCacheMissRequests;
+ S32 mObjectCacheMissResponses;
+ S32 mObjectCacheUpdateDupes;
+ S32 mObjectCacheUpdateChanges;
+ S32 mObjectCacheUpdateAdds;
+ S32 mObjectCacheUpdateReplacements;
+ S32 mObjectUpdateFailures;
+
+
+ void clearStats();
+};
+#endif // LL_RECORD_VIEWER_STATS
+
+#endif // LLVIEWERSTATSRECORDER_H
+
diff --git a/indra/newview/llviewertexteditor.cpp b/indra/newview/llviewertexteditor.cpp
index 0c36970878..4798bb536f 100644
--- a/indra/newview/llviewertexteditor.cpp
+++ b/indra/newview/llviewertexteditor.cpp
@@ -537,6 +537,7 @@ LLUIImagePtr LLEmbeddedItems::getItemImage(llwchar ext_char) const
case LLAssetType::AT_BODYPART: img_name = "Inv_Skin"; break;
case LLAssetType::AT_ANIMATION: img_name = "Inv_Animation"; break;
case LLAssetType::AT_GESTURE: img_name = "Inv_Gesture"; break;
+ case LLAssetType::AT_MESH: img_name = "Inv_Mesh"; break;
default: llassert(0);
}
@@ -846,17 +847,18 @@ BOOL LLViewerTextEditor::handleDragAndDrop(S32 x, S32 y, MASK mask,
{
switch( cargo_type )
{
- case DAD_CALLINGCARD:
- case DAD_TEXTURE:
- case DAD_SOUND:
- case DAD_LANDMARK:
- case DAD_SCRIPT:
- case DAD_CLOTHING:
- case DAD_OBJECT:
- case DAD_NOTECARD:
- case DAD_BODYPART:
- case DAD_ANIMATION:
- case DAD_GESTURE:
+ case DAD_CALLINGCARD:
+ case DAD_TEXTURE:
+ case DAD_SOUND:
+ case DAD_LANDMARK:
+ case DAD_SCRIPT:
+ case DAD_CLOTHING:
+ case DAD_OBJECT:
+ case DAD_NOTECARD:
+ case DAD_BODYPART:
+ case DAD_ANIMATION:
+ case DAD_GESTURE:
+ case DAD_MESH:
{
LLInventoryItem *item = (LLInventoryItem *)cargo_data;
if( item && allowsEmbeddedItems() )
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index 5c262838ae..af06421bf9 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -72,6 +72,7 @@ LLPointer<LLViewerFetchedTexture> LLViewerFetchedTexture::sDefaultImagep = NULL;
LLPointer<LLViewerFetchedTexture> LLViewerFetchedTexture::sSmokeImagep = NULL;
LLViewerMediaTexture::media_map_t LLViewerMediaTexture::sMediaMap ;
LLTexturePipelineTester* LLViewerTextureManager::sTesterp = NULL ;
+const std::string sTesterName("TextureTester");
S32 LLViewerTexture::sImageCount = 0;
S32 LLViewerTexture::sRawCount = 0;
@@ -341,9 +342,14 @@ void LLViewerTextureManager::init()
LLViewerTexture::initClass() ;
- if(LLFastTimer::sMetricLog)
+ if (LLMetricPerformanceTesterBasic::isMetricLogRequested(sTesterName) && !LLMetricPerformanceTesterBasic::getTester(sTesterName))
{
- LLViewerTextureManager::sTesterp = new LLTexturePipelineTester() ;
+ sTesterp = new LLTexturePipelineTester() ;
+ if (!sTesterp->isValid())
+ {
+ delete sTesterp;
+ sTesterp = NULL;
+ }
}
}
@@ -408,9 +414,10 @@ void LLViewerTexture::updateClass(const F32 velocity, const F32 angular_velocity
{
sCurrentTime = gFrameTimeSeconds ;
- if(LLViewerTextureManager::sTesterp)
+ LLTexturePipelineTester* tester = (LLTexturePipelineTester*)LLMetricPerformanceTesterBasic::getTester(sTesterName);
+ if (tester)
{
- LLViewerTextureManager::sTesterp->update() ;
+ tester->update() ;
}
LLViewerMediaTexture::updateClass() ;
@@ -603,9 +610,10 @@ bool LLViewerTexture::bindDefaultImage(S32 stage)
//check if there is cached raw image and switch to it if possible
switchToCachedImage() ;
- if(LLViewerTextureManager::sTesterp)
+ LLTexturePipelineTester* tester = (LLTexturePipelineTester*)LLMetricPerformanceTesterBasic::getTester(sTesterName);
+ if (tester)
{
- LLViewerTextureManager::sTesterp->updateGrayTextureBinding() ;
+ tester->updateGrayTextureBinding() ;
}
return res;
}
@@ -827,7 +835,7 @@ BOOL LLViewerTexture::createGLTexture(S32 discard_level, const LLImageRaw* image
llassert(mGLTexturep.notNull()) ;
BOOL ret = mGLTexturep->createGLTexture(discard_level, imageraw, usename, to_create, category) ;
-
+
if(ret)
{
mFullWidth = mGLTexturep->getCurrentWidth() ;
@@ -1066,9 +1074,10 @@ BOOL LLViewerTexture::isLargeImage()
//virtual
void LLViewerTexture::updateBindStatsForTester()
{
- if(LLViewerTextureManager::sTesterp)
+ LLTexturePipelineTester* tester = (LLTexturePipelineTester*)LLMetricPerformanceTesterBasic::getTester(sTesterName);
+ if (tester)
{
- LLViewerTextureManager::sTesterp->updateTextureBindingStats(this) ;
+ tester->updateTextureBindingStats(this) ;
}
}
@@ -1130,7 +1139,7 @@ void LLViewerFetchedTexture::init(bool firstinit)
// does not contain this image.
mIsMissingAsset = FALSE;
- mLoadedCallbackDesiredDiscardLevel = 0;
+ mLoadedCallbackDesiredDiscardLevel = S8_MAX;
mPauseLoadedCallBacks = TRUE ;
mNeedsCreateTexture = FALSE;
@@ -1155,9 +1164,11 @@ void LLViewerFetchedTexture::init(bool firstinit)
mSavedRawImage = NULL ;
mForceToSaveRawImage = FALSE ;
+ mSaveRawImage = FALSE ;
mSavedRawDiscardLevel = -1 ;
mDesiredSavedRawDiscardLevel = -1 ;
mLastReferencedSavedRawImageTime = 0.0f ;
+ mLastCallBackActiveTime = 0.f;
}
LLViewerFetchedTexture::~LLViewerFetchedTexture()
@@ -1203,12 +1214,15 @@ void LLViewerFetchedTexture::cleanup()
void LLViewerFetchedTexture::setForSculpt()
{
+ static const S32 MAX_INTERVAL = 8 ; //frames
+
mForSculpt = TRUE ;
if(isForSculptOnly() && !getBoundRecently())
{
destroyGLTexture() ; //sculpt image does not need gl texture.
}
checkCachedRawSculptImage() ;
+ setMaxVirtualSizeResetInterval(MAX_INTERVAL) ;
}
BOOL LLViewerFetchedTexture::isForSculptOnly() const
@@ -1401,63 +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();
- // 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;
- }
-
- 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;
+ { // leave black border, do not scale image content
+ mRawImage->expandToPowerOfTwo(MAX_IMAGE_SIZE, 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();
@@ -1503,7 +1522,7 @@ void LLViewerFetchedTexture::processTextureStats()
}
else if(!mFullWidth || !mFullHeight)
{
- mDesiredDiscardLevel = getMaxDiscardLevel() ;
+ mDesiredDiscardLevel = llmin(getMaxDiscardLevel(), (S32)mLoadedCallbackDesiredDiscardLevel) ;
}
else
{
@@ -1571,7 +1590,7 @@ F32 LLViewerFetchedTexture::calcDecodePriority()
S32 cur_discard = getCurrentDiscardLevelForFetching();
bool have_all_data = (cur_discard >= 0 && (cur_discard <= mDesiredDiscardLevel));
- F32 pixel_priority = fsqrtf(mMaxVirtualSize);
+ F32 pixel_priority = (F32) sqrt(mMaxVirtualSize);
F32 priority = 0.f;
@@ -1846,10 +1865,11 @@ bool LLViewerFetchedTexture::updateFetch()
// We may have data ready regardless of whether or not we are finished (e.g. waiting on write)
if (mRawImage.notNull())
{
- if(LLViewerTextureManager::sTesterp)
+ LLTexturePipelineTester* tester = (LLTexturePipelineTester*)LLMetricPerformanceTesterBasic::getTester(sTesterName);
+ if (tester)
{
mIsFetched = TRUE ;
- LLViewerTextureManager::sTesterp->updateTextureLoadingStats(this, mRawImage, LLAppViewer::getTextureFetch()->isFromLocalCache(mID)) ;
+ tester->updateTextureLoadingStats(this, mRawImage, LLAppViewer::getTextureFetch()->isFromLocalCache(mID)) ;
}
mRawDiscardLevel = fetch_discard;
if ((mRawImage->getDataSize() > 0 && mRawDiscardLevel >= 0) &&
@@ -2074,13 +2094,14 @@ void LLViewerFetchedTexture::setLoadedCallback( loaded_callback_func loaded_call
mNeedsAux |= needs_aux;
if(keep_imageraw)
{
- forceToSaveRawImage(discard_level, true) ;
+ mSaveRawImage = TRUE ;
}
if (mNeedsAux && mAuxRawImage.isNull() && getDiscardLevel() >= 0)
{
// We need aux data, but we've already loaded the image, and it didn't have any
llwarns << "No aux data available for callback for image:" << getID() << llendl;
}
+ mLastCallBackActiveTime = sCurrentTime ;
}
void LLViewerFetchedTexture::clearCallbackEntryList()
@@ -2103,9 +2124,8 @@ void LLViewerFetchedTexture::clearCallbackEntryList()
}
gTextureList.mCallbackList.erase(this);
- mMinDesiredDiscardLevel = MAX_DISCARD_LEVEL + 1;
mLoadedCallbackDesiredDiscardLevel = S8_MAX ;
- if(mForceToSaveRawImage)
+ if(needsToSaveRawImage())
{
destroySavedRawImage() ;
}
@@ -2151,14 +2171,13 @@ void LLViewerFetchedTexture::deleteCallbackEntry(const LLLoadedCallbackEntry::so
{
// If we have no callbacks, take us off of the image callback list.
gTextureList.mCallbackList.erase(this);
- mMinDesiredDiscardLevel = MAX_DISCARD_LEVEL + 1;
-
- if(mForceToSaveRawImage)
+
+ if(needsToSaveRawImage())
{
destroySavedRawImage() ;
}
}
- else if(mForceToSaveRawImage && mBoostLevel != LLViewerTexture::BOOST_PREVIEW)
+ else if(needsToSaveRawImage() && mBoostLevel != LLViewerTexture::BOOST_PREVIEW)
{
if(desired_raw_discard != INVALID_DISCARD_LEVEL)
{
@@ -2196,7 +2215,7 @@ void LLViewerFetchedTexture::unpauseLoadedCallbacks(const LLLoadedCallbackEntry:
mPauseLoadedCallBacks = FALSE ;
if(need_raw)
{
- mForceToSaveRawImage = TRUE ;
+ mSaveRawImage = TRUE ;
}
}
@@ -2227,16 +2246,23 @@ void LLViewerFetchedTexture::pauseLoadedCallbacks(const LLLoadedCallbackEntry::s
{
mPauseLoadedCallBacks = TRUE ;//when set, loaded callback is paused.
resetTextureStats();
- mForceToSaveRawImage = FALSE ;
+ mSaveRawImage = FALSE ;
}
}
bool LLViewerFetchedTexture::doLoadedCallbacks()
{
+ static const F32 MAX_INACTIVE_TIME = 120.f ; //seconds
+
if (mNeedsCreateTexture)
{
return false;
}
+ if(sCurrentTime - mLastCallBackActiveTime > MAX_INACTIVE_TIME)
+ {
+ clearCallbackEntryList() ; //remove all callbacks.
+ return false ;
+ }
bool res = false;
@@ -2302,13 +2328,11 @@ bool LLViewerFetchedTexture::doLoadedCallbacks()
bool run_raw_callbacks = false;
bool need_readback = false;
- mMinDesiredDiscardLevel = MAX_DISCARD_LEVEL + 1;
for(callback_list_t::iterator iter = mLoadedCallbackList.begin();
iter != mLoadedCallbackList.end(); )
{
LLLoadedCallbackEntry *entryp = *iter++;
- mMinDesiredDiscardLevel = llmin(mMinDesiredDiscardLevel, (S8)entryp->mDesiredDiscard) ;
-
+
if (entryp->mNeedsImageRaw)
{
if (mNeedsAux)
@@ -2382,7 +2406,8 @@ bool LLViewerFetchedTexture::doLoadedCallbacks()
// to satisfy the interested party, then this is the last time that
// we're going to call them.
- llassert_always(mRawImage.notNull());
+ mLastCallBackActiveTime = sCurrentTime ;
+ //llassert_always(mRawImage.notNull());
if(mNeedsAux && mAuxRawImage.isNull())
{
llwarns << "Raw Image with no Aux Data for callback" << llendl;
@@ -2417,6 +2442,7 @@ bool LLViewerFetchedTexture::doLoadedCallbacks()
LLLoadedCallbackEntry *entryp = *curiter;
if (!entryp->mNeedsImageRaw && (entryp->mLastUsedDiscard > gl_discard))
{
+ mLastCallBackActiveTime = sCurrentTime ;
BOOL final = gl_discard <= entryp->mDesiredDiscard ? TRUE : FALSE;
entryp->mLastUsedDiscard = gl_discard;
entryp->mCallback(TRUE, this, NULL, NULL, gl_discard, final, entryp->mUserData);
@@ -2436,7 +2462,6 @@ bool LLViewerFetchedTexture::doLoadedCallbacks()
if (mLoadedCallbackList.empty())
{
gTextureList.mCallbackList.erase(this);
- mMinDesiredDiscardLevel = MAX_DISCARD_LEVEL + 1;
}
// Done with any raw image data at this point (will be re-created if we still have callbacks)
@@ -2516,6 +2541,11 @@ LLImageRaw* LLViewerFetchedTexture::reloadRawImage(S8 discard_level)
return mRawImage;
}
+bool LLViewerFetchedTexture::needsToSaveRawImage()
+{
+ return mForceToSaveRawImage || mSaveRawImage ;
+}
+
void LLViewerFetchedTexture::destroyRawImage()
{
if (mAuxRawImage.notNull()) sAuxCount--;
@@ -2526,7 +2556,7 @@ void LLViewerFetchedTexture::destroyRawImage()
if(mIsRawImageValid)
{
- if(mForceToSaveRawImage)
+ if(needsToSaveRawImage())
{
saveRawImage() ;
}
@@ -2658,7 +2688,7 @@ void LLViewerFetchedTexture::saveRawImage()
mSavedRawDiscardLevel = mRawDiscardLevel ;
mSavedRawImage = new LLImageRaw(mRawImage->getData(), mRawImage->getWidth(), mRawImage->getHeight(), mRawImage->getComponents()) ;
- if(mSavedRawDiscardLevel <= mDesiredSavedRawDiscardLevel)
+ if(mForceToSaveRawImage && mSavedRawDiscardLevel <= mDesiredSavedRawDiscardLevel)
{
mForceToSaveRawImage = FALSE ;
}
@@ -2666,12 +2696,10 @@ void LLViewerFetchedTexture::saveRawImage()
mLastReferencedSavedRawImageTime = sCurrentTime ;
}
-void LLViewerFetchedTexture::forceToSaveRawImage(S32 desired_discard, bool from_callback)
+void LLViewerFetchedTexture::forceToSaveRawImage(S32 desired_discard)
{
if(!mForceToSaveRawImage || mDesiredSavedRawDiscardLevel < 0 || mDesiredSavedRawDiscardLevel > desired_discard)
{
- llassert_always(from_callback || mBoostLevel == LLViewerTexture::BOOST_PREVIEW) ;
-
mForceToSaveRawImage = TRUE ;
mDesiredSavedRawDiscardLevel = desired_discard ;
@@ -2690,14 +2718,14 @@ void LLViewerFetchedTexture::forceToSaveRawImage(S32 desired_discard, bool from_
}
void LLViewerFetchedTexture::destroySavedRawImage()
{
- clearCallbackEntryList() ;
- //if(mForceToSaveRawImage && mDesiredSavedRawDiscardLevel >= 0 && mDesiredSavedRawDiscardLevel < getDiscardLevel())
- //{
- // return ; //can not destroy the saved raw image before it is fully fetched, otherwise causing callbacks hanging there.
- //}
+ mForceToSaveRawImage = FALSE ;
+ mSaveRawImage = FALSE ;
+ clearCallbackEntryList() ;
+
mSavedRawImage = NULL ;
mForceToSaveRawImage = FALSE ;
+ mSaveRawImage = FALSE ;
mSavedRawDiscardLevel = -1 ;
mDesiredSavedRawDiscardLevel = -1 ;
mLastReferencedSavedRawImageTime = 0.0f ;
@@ -2852,7 +2880,7 @@ BOOL LLViewerFetchedTexture::insertToAtlas()
}
//process the waiting_list
- for(ll_face_list_t::iterator iter = waiting_list.begin(); iter != waiting_list.end(); ++iter)
+ for(std::vector<LLFace*>::iterator iter = waiting_list.begin(); iter != waiting_list.end(); ++iter)
{
facep = (LLFace*)*iter ;
groupp = facep->getDrawable()->getSpatialGroup() ;
@@ -3066,9 +3094,10 @@ void LLViewerLODTexture::scaleDown()
{
switchToCachedImage() ;
- if(LLViewerTextureManager::sTesterp)
+ LLTexturePipelineTester* tester = (LLTexturePipelineTester*)LLMetricPerformanceTesterBasic::getTester(sTesterName);
+ if (tester)
{
- LLViewerTextureManager::sTesterp->setStablizingTime() ;
+ tester->setStablizingTime() ;
}
}
}
@@ -3578,23 +3607,22 @@ F32 LLViewerMediaTexture::getMaxVirtualSize()
//----------------------------------------------------------------------------------------------
//start of LLTexturePipelineTester
//----------------------------------------------------------------------------------------------
-LLTexturePipelineTester::LLTexturePipelineTester() :
- LLMetricPerformanceTester("TextureTester", FALSE)
-{
- addMetricString("TotalBytesLoaded") ;
- addMetricString("TotalBytesLoadedFromCache") ;
- addMetricString("TotalBytesLoadedForLargeImage") ;
- addMetricString("TotalBytesLoadedForSculpties") ;
- addMetricString("StartFetchingTime") ;
- addMetricString("TotalGrayTime") ;
- addMetricString("TotalStablizingTime") ;
- addMetricString("StartTimeLoadingSculpties") ;
- addMetricString("EndTimeLoadingSculpties") ;
-
- addMetricString("Time") ;
- addMetricString("TotalBytesBound") ;
- addMetricString("TotalBytesBoundForLargeImage") ;
- addMetricString("PercentageBytesBound") ;
+LLTexturePipelineTester::LLTexturePipelineTester() : LLMetricPerformanceTesterWithSession(sTesterName)
+{
+ addMetric("TotalBytesLoaded") ;
+ addMetric("TotalBytesLoadedFromCache") ;
+ addMetric("TotalBytesLoadedForLargeImage") ;
+ addMetric("TotalBytesLoadedForSculpties") ;
+ addMetric("StartFetchingTime") ;
+ addMetric("TotalGrayTime") ;
+ addMetric("TotalStablizingTime") ;
+ addMetric("StartTimeLoadingSculpties") ;
+ addMetric("EndTimeLoadingSculpties") ;
+
+ addMetric("Time") ;
+ addMetric("TotalBytesBound") ;
+ addMetric("TotalBytesBoundForLargeImage") ;
+ addMetric("PercentageBytesBound") ;
mTotalBytesLoaded = 0 ;
mTotalBytesLoadedFromCache = 0 ;
@@ -3606,7 +3634,7 @@ LLTexturePipelineTester::LLTexturePipelineTester() :
LLTexturePipelineTester::~LLTexturePipelineTester()
{
- LLViewerTextureManager::sTesterp = NULL ;
+ LLViewerTextureManager::sTesterp = NULL;
}
void LLTexturePipelineTester::update()
@@ -3672,22 +3700,23 @@ void LLTexturePipelineTester::reset()
//virtual
void LLTexturePipelineTester::outputTestRecord(LLSD *sd)
{
- (*sd)[mCurLabel]["TotalBytesLoaded"] = (LLSD::Integer)mTotalBytesLoaded ;
- (*sd)[mCurLabel]["TotalBytesLoadedFromCache"] = (LLSD::Integer)mTotalBytesLoadedFromCache ;
- (*sd)[mCurLabel]["TotalBytesLoadedForLargeImage"] = (LLSD::Integer)mTotalBytesLoadedForLargeImage ;
- (*sd)[mCurLabel]["TotalBytesLoadedForSculpties"] = (LLSD::Integer)mTotalBytesLoadedForSculpties ;
+ std::string currentLabel = getCurrentLabelName();
+ (*sd)[currentLabel]["TotalBytesLoaded"] = (LLSD::Integer)mTotalBytesLoaded ;
+ (*sd)[currentLabel]["TotalBytesLoadedFromCache"] = (LLSD::Integer)mTotalBytesLoadedFromCache ;
+ (*sd)[currentLabel]["TotalBytesLoadedForLargeImage"] = (LLSD::Integer)mTotalBytesLoadedForLargeImage ;
+ (*sd)[currentLabel]["TotalBytesLoadedForSculpties"] = (LLSD::Integer)mTotalBytesLoadedForSculpties ;
- (*sd)[mCurLabel]["StartFetchingTime"] = (LLSD::Real)mStartFetchingTime ;
- (*sd)[mCurLabel]["TotalGrayTime"] = (LLSD::Real)mTotalGrayTime ;
- (*sd)[mCurLabel]["TotalStablizingTime"] = (LLSD::Real)mTotalStablizingTime ;
+ (*sd)[currentLabel]["StartFetchingTime"] = (LLSD::Real)mStartFetchingTime ;
+ (*sd)[currentLabel]["TotalGrayTime"] = (LLSD::Real)mTotalGrayTime ;
+ (*sd)[currentLabel]["TotalStablizingTime"] = (LLSD::Real)mTotalStablizingTime ;
- (*sd)[mCurLabel]["StartTimeLoadingSculpties"] = (LLSD::Real)mStartTimeLoadingSculpties ;
- (*sd)[mCurLabel]["EndTimeLoadingSculpties"] = (LLSD::Real)mEndTimeLoadingSculpties ;
+ (*sd)[currentLabel]["StartTimeLoadingSculpties"] = (LLSD::Real)mStartTimeLoadingSculpties ;
+ (*sd)[currentLabel]["EndTimeLoadingSculpties"] = (LLSD::Real)mEndTimeLoadingSculpties ;
- (*sd)[mCurLabel]["Time"] = LLImageGL::sLastFrameTime ;
- (*sd)[mCurLabel]["TotalBytesBound"] = (LLSD::Integer)mLastTotalBytesUsed ;
- (*sd)[mCurLabel]["TotalBytesBoundForLargeImage"] = (LLSD::Integer)mLastTotalBytesUsedForLargeImage ;
- (*sd)[mCurLabel]["PercentageBytesBound"] = (LLSD::Real)(100.f * mLastTotalBytesUsed / mTotalBytesLoaded) ;
+ (*sd)[currentLabel]["Time"] = LLImageGL::sLastFrameTime ;
+ (*sd)[currentLabel]["TotalBytesBound"] = (LLSD::Integer)mLastTotalBytesUsed ;
+ (*sd)[currentLabel]["TotalBytesBoundForLargeImage"] = (LLSD::Integer)mLastTotalBytesUsedForLargeImage ;
+ (*sd)[currentLabel]["PercentageBytesBound"] = (LLSD::Real)(100.f * mLastTotalBytesUsed / mTotalBytesLoaded) ;
}
void LLTexturePipelineTester::updateTextureBindingStats(const LLViewerTexture* imagep)
@@ -3776,7 +3805,7 @@ void LLTexturePipelineTester::compareTestSessions(std::ofstream* os)
}
//compare and output the comparison
- *os << llformat("%s\n", mName.c_str()) ;
+ *os << llformat("%s\n", getTesterName().c_str()) ;
*os << llformat("AggregateResults\n") ;
compareTestResults(os, "TotalFetchingTime", base_sessionp->mTotalFetchingTime, current_sessionp->mTotalFetchingTime) ;
@@ -3831,7 +3860,7 @@ void LLTexturePipelineTester::compareTestSessions(std::ofstream* os)
}
//virtual
-LLMetricPerformanceTester::LLTestSession* LLTexturePipelineTester::loadTestSession(LLSD* log)
+LLMetricPerformanceTesterWithSession::LLTestSession* LLTexturePipelineTester::loadTestSession(LLSD* log)
{
LLTexturePipelineTester::LLTextureTestSession* sessionp = new LLTexturePipelineTester::LLTextureTestSession() ;
if(!sessionp)
@@ -3858,12 +3887,11 @@ LLMetricPerformanceTester::LLTestSession* LLTexturePipelineTester::loadTestSessi
sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mTime = 0.f ;
//load a session
- BOOL in_log = (*log).has(mCurLabel) ;
- while(in_log)
+ std::string currentLabel = getCurrentLabelName();
+ BOOL in_log = (*log).has(currentLabel) ;
+ while (in_log)
{
- LLSD::String label = mCurLabel ;
- incLabel() ;
- in_log = (*log).has(mCurLabel) ;
+ LLSD::String label = currentLabel ;
if(sessionp->mInstantPerformanceListCounter >= (S32)sessionp->mInstantPerformanceList.size())
{
@@ -3929,7 +3957,11 @@ LLMetricPerformanceTester::LLTestSession* LLTexturePipelineTester::loadTestSessi
sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAverageBytesUsedForLargeImagePerSecond = 0 ;
sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAveragePercentageBytesUsedPerSecond = 0.f ;
sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mTime = 0.f ;
- }
+ }
+ // Next label
+ incrementCurrentCount() ;
+ currentLabel = getCurrentLabelName();
+ in_log = (*log).has(currentLabel) ;
}
sessionp->mTotalFetchingTime += total_fetching_time ;
diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h
index 7cb8bea4c8..d512f8ec3a 100644
--- a/indra/newview/llviewertexture.h
+++ b/indra/newview/llviewertexture.h
@@ -441,6 +441,7 @@ public:
LLImageRaw* reloadRawImage(S8 discard_level) ;
void destroyRawImage();
+ bool needsToSaveRawImage();
const std::string& getUrl() const {return mUrl;}
//---------------
@@ -464,7 +465,7 @@ public:
S32 getCachedRawImageLevel() const {return mCachedRawDiscardLevel;}
BOOL isCachedRawImageReady() const {return mCachedRawImageReady ;}
BOOL isRawImageValid()const { return mIsRawImageValid ; }
- void forceToSaveRawImage(S32 desired_discard = 0, bool from_callback = false) ;
+ void forceToSaveRawImage(S32 desired_discard = 0) ;
/*virtual*/ void setCachedRawImage(S32 discard_level, LLImageRaw* imageraw) ;
void destroySavedRawImage() ;
LLImageRaw* getSavedRawImage() ;
@@ -532,6 +533,7 @@ protected:
S8 mLoadedCallbackDesiredDiscardLevel;
BOOL mPauseLoadedCallBacks;
callback_list_t mLoadedCallbackList;
+ F32 mLastCallBackActiveTime;
LLPointer<LLImageRaw> mRawImage;
S32 mRawDiscardLevel;
@@ -543,6 +545,7 @@ protected:
//keep a copy of mRawImage for some special purposes
//when mForceToSaveRawImage is set.
BOOL mForceToSaveRawImage ;
+ BOOL mSaveRawImage;
LLPointer<LLImageRaw> mSavedRawImage;
S32 mSavedRawDiscardLevel;
S32 mDesiredSavedRawDiscardLevel;
@@ -732,7 +735,7 @@ public:
//it tracks the activities of the texture pipeline
//records them, and outputs them to log files
//
-class LLTexturePipelineTester : public LLMetricPerformanceTester
+class LLTexturePipelineTester : public LLMetricPerformanceTesterWithSession
{
enum
{
@@ -748,8 +751,6 @@ public:
void updateGrayTextureBinding() ;
void setStablizingTime() ;
- /*virtual*/ void analyzePerformance(std::ofstream* os, LLSD* base, LLSD* current) ;
-
private:
void reset() ;
void updateStablizingTime() ;
@@ -820,7 +821,7 @@ private:
S32 mInstantPerformanceListCounter ;
};
- /*virtual*/ LLMetricPerformanceTester::LLTestSession* loadTestSession(LLSD* log) ;
+ /*virtual*/ LLMetricPerformanceTesterWithSession::LLTestSession* loadTestSession(LLSD* log) ;
/*virtual*/ void compareTestSessions(std::ofstream* os) ;
};
diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp
index bbf7c8e60e..d9ff931575 100644
--- a/indra/newview/llviewertexturelist.cpp
+++ b/indra/newview/llviewertexturelist.cpp
@@ -76,26 +76,26 @@ LLStat LLViewerTextureList::sFormattedMemStat(32, TRUE);
LLViewerTextureList gTextureList;
static LLFastTimer::DeclareTimer FTM_PROCESS_IMAGES("Process Images");
+U32 LLViewerTextureList::sRenderThreadID = 0 ;
///////////////////////////////////////////////////////////////////////////////
LLViewerTextureList::LLViewerTextureList()
: mForceResetTextureStats(FALSE),
mUpdateStats(FALSE),
mMaxResidentTexMemInMegaBytes(0),
- mMaxTotalTextureMemInMegaBytes(0)
+ mMaxTotalTextureMemInMegaBytes(0),
+ mInitialized(FALSE)
{
}
void LLViewerTextureList::init()
{
+ sRenderThreadID = LLThread::currentID() ;
+
+ mInitialized = TRUE ;
sNumImages = 0;
mMaxResidentTexMemInMegaBytes = 0;
mMaxTotalTextureMemInMegaBytes = 0 ;
- if (gNoRender)
- {
- // Don't initialize GL stuff if we're not rendering.
- return;
- }
mUpdateStats = TRUE;
@@ -110,6 +110,10 @@ void LLViewerTextureList::doPreloadImages()
{
LL_DEBUGS("ViewerImages") << "Preloading images..." << LL_ENDL;
+ llassert_always(mInitialized) ;
+ llassert_always(mImageList.empty()) ;
+ llassert_always(mUUIDMap.empty()) ;
+
// Set the "missing asset" image
LLViewerFetchedTexture::sMissingAssetImagep = LLViewerTextureManager::getFetchedTextureFromFile("missing_asset.tga", MIPMAP_NO, LLViewerFetchedTexture::BOOST_UI);
@@ -305,6 +309,7 @@ void LLViewerTextureList::destroyGL(BOOL save_state)
void LLViewerTextureList::restoreGL()
{
+ llassert_always(mInitialized) ;
LLImageGL::restoreGL();
}
@@ -345,13 +350,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())
@@ -489,8 +487,10 @@ LLViewerFetchedTexture *LLViewerTextureList::findImage(const LLUUID &image_id)
return iter->second;
}
-void LLViewerTextureList::addImageToList(LLViewerFetchedTexture *image)
+void LLViewerTextureList::addImageToList(LLViewerFetchedTexture *image, U32 thread_id)
{
+ llassert_always(mInitialized) ;
+ llassert_always(sRenderThreadID == thread_id);
llassert(image);
if (image->isInImageList())
{
@@ -504,8 +504,10 @@ void LLViewerTextureList::addImageToList(LLViewerFetchedTexture *image)
image->setInImageList(TRUE) ;
}
-void LLViewerTextureList::removeImageFromList(LLViewerFetchedTexture *image)
+void LLViewerTextureList::removeImageFromList(LLViewerFetchedTexture *image, U32 thread_id)
{
+ llassert_always(mInitialized) ;
+ llassert_always(sRenderThreadID == thread_id);
llassert(image);
if (!image->isInImageList())
{
@@ -702,9 +704,9 @@ void LLViewerTextureList::updateImagesDecodePriorities()
if ((decode_priority_test < old_priority_test * .8f) ||
(decode_priority_test > old_priority_test * 1.25f))
{
- removeImageFromList(imagep);
+ removeImageFromList(imagep, sRenderThreadID);
imagep->setDecodePriority(decode_priority);
- addImageToList(imagep);
+ addImageToList(imagep, sRenderThreadID);
}
update_counter--;
}
@@ -741,7 +743,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
@@ -781,9 +783,8 @@ void LLViewerTextureList::forceImmediateUpdate(LLViewerFetchedTexture* imagep)
imagep->processTextureStats();
F32 decode_priority = LLViewerFetchedTexture::maxDecodePriority() ;
imagep->setDecodePriority(decode_priority);
- mImageList.insert(imagep);
- imagep->setInImageList(TRUE) ;
-
+ addImageToList(imagep);
+
return ;
}
@@ -834,7 +835,7 @@ F32 LLViewerTextureList::updateImagesFetchTextures(F32 max_time)
for (entries_list_t::iterator iter3 = entries.begin();
iter3 != entries.end(); )
{
- LLPointer<LLViewerFetchedTexture> imagep = *iter3++;
+ LLViewerFetchedTexture* imagep = *iter3++;
bool fetching = imagep->updateFetch();
if (fetching)
@@ -876,8 +877,9 @@ void LLViewerTextureList::updateImagesUpdateStats()
void LLViewerTextureList::decodeAllImages(F32 max_time)
{
LLTimer timer;
- if(gNoRender) return;
-
+
+ llassert_always(sRenderThreadID == LLThread::currentID());
+
// Update texture stats and priorities
std::vector<LLPointer<LLViewerFetchedTexture> > image_list;
for (image_priority_list_t::iterator iter = mImageList.begin();
@@ -895,8 +897,7 @@ void LLViewerTextureList::decodeAllImages(F32 max_time)
imagep->processTextureStats();
F32 decode_priority = imagep->calcDecodePriority();
imagep->setDecodePriority(decode_priority);
- mImageList.insert(imagep);
- imagep->setInImageList(TRUE) ;
+ addImageToList(imagep);
}
image_list.clear();
@@ -940,99 +941,54 @@ void LLViewerTextureList::decodeAllImages(F32 max_time)
BOOL LLViewerTextureList::createUploadFile(const std::string& filename,
const std::string& out_filename,
const U8 codec)
-{
- // First, load the image.
+{
+ // Load the image
+ LLPointer<LLImageFormatted> image = LLImageFormatted::createFromType(codec);
+ if (image.isNull())
+ {
+ image->setLastError("Couldn't open the image to be uploaded.");
+ return FALSE;
+ }
+ if (!image->load(filename))
+ {
+ image->setLastError("Couldn't load the image to be uploaded.");
+ return FALSE;
+ }
+ // Decompress or expand it in a raw image structure
LLPointer<LLImageRaw> raw_image = new LLImageRaw;
-
- switch (codec)
+ if (!image->decode(raw_image, 0.0f))
{
- case IMG_CODEC_BMP:
- {
- LLPointer<LLImageBMP> bmp_image = new LLImageBMP;
-
- if (!bmp_image->load(filename))
- {
- return FALSE;
- }
-
- if (!bmp_image->decode(raw_image, 0.0f))
- {
- return FALSE;
- }
- }
- break;
- case IMG_CODEC_TGA:
- {
- LLPointer<LLImageTGA> tga_image = new LLImageTGA;
-
- if (!tga_image->load(filename))
- {
- return FALSE;
- }
-
- if (!tga_image->decode(raw_image))
- {
- return FALSE;
- }
-
- if( (tga_image->getComponents() != 3) &&
- (tga_image->getComponents() != 4) )
- {
- tga_image->setLastError( "Image files with less than 3 or more than 4 components are not supported." );
- return FALSE;
- }
- }
- break;
- case IMG_CODEC_JPEG:
- {
- LLPointer<LLImageJPEG> jpeg_image = new LLImageJPEG;
-
- if (!jpeg_image->load(filename))
- {
- return FALSE;
- }
-
- if (!jpeg_image->decode(raw_image, 0.0f))
- {
- return FALSE;
- }
- }
- break;
- case IMG_CODEC_PNG:
- {
- LLPointer<LLImagePNG> png_image = new LLImagePNG;
-
- if (!png_image->load(filename))
- {
- return FALSE;
- }
-
- if (!png_image->decode(raw_image, 0.0f))
- {
- return FALSE;
- }
- }
- break;
- default:
- return FALSE;
+ image->setLastError("Couldn't decode the image to be uploaded.");
+ return FALSE;
}
-
- LLPointer<LLImageJ2C> compressedImage = convertToUploadFile(raw_image);
-
- if( !compressedImage->save(out_filename) )
+ // Check the image constraints
+ if ((image->getComponents() != 3) && (image->getComponents() != 4))
{
- llinfos << "Couldn't create output file " << out_filename << llendl;
+ image->setLastError("Image files with less than 3 or more than 4 components are not supported.");
return FALSE;
}
-
- // test to see if the encode and save worked.
+ // Convert to j2c (JPEG2000) and save the file locally
+ LLPointer<LLImageJ2C> compressedImage = convertToUploadFile(raw_image);
+ if (compressedImage.isNull())
+ {
+ image->setLastError("Couldn't convert the image to jpeg2000.");
+ llinfos << "Couldn't convert to j2c, file : " << filename << llendl;
+ return FALSE;
+ }
+ if (!compressedImage->save(out_filename))
+ {
+ image->setLastError("Couldn't create the jpeg2000 image for upload.");
+ llinfos << "Couldn't create output file : " << out_filename << llendl;
+ return FALSE;
+ }
+ // Test to see if the encode and save worked
LLPointer<LLImageJ2C> integrity_test = new LLImageJ2C;
- if( !integrity_test->loadAndValidate( out_filename ) )
+ if (!integrity_test->loadAndValidate( out_filename ))
{
- llinfos << "Image: " << out_filename << " is corrupt." << llendl;
+ image->setLastError("The created jpeg2000 image is corrupt.");
+ llinfos << "Image file : " << out_filename << " is corrupt" << llendl;
return FALSE;
}
-
return TRUE;
}
@@ -1047,7 +1003,25 @@ LLPointer<LLImageJ2C> LLViewerTextureList::convertToUploadFile(LLPointer<LLImage
(raw_image->getWidth() * raw_image->getHeight() <= LL_IMAGE_REZ_LOSSLESS_CUTOFF * LL_IMAGE_REZ_LOSSLESS_CUTOFF))
compressedImage->setReversible(TRUE);
- compressedImage->encode(raw_image, 0.0f);
+
+ if (gSavedSettings.getBOOL("Jpeg2000AdvancedCompression"))
+ {
+ // This test option will create jpeg2000 images with precincts for each level, RPCL ordering
+ // and PLT markers. The block size is also optionally modifiable.
+ // Note: the images hence created are compatible with older versions of the viewer.
+ // Read the blocks and precincts size settings
+ S32 block_size = gSavedSettings.getS32("Jpeg2000BlocksSize");
+ S32 precinct_size = gSavedSettings.getS32("Jpeg2000PrecinctsSize");
+ llinfos << "Advanced JPEG2000 Compression: precinct = " << precinct_size << ", block = " << block_size << llendl;
+ compressedImage->initEncode(*raw_image, block_size, precinct_size, 0);
+ }
+
+ if (!compressedImage->encode(raw_image, 0.0f))
+ {
+ llinfos << "convertToUploadFile : encode returns with error!!" << llendl;
+ // Clear up the pointer so we don't leak that one
+ compressedImage = NULL;
+ }
return compressedImage;
}
@@ -1161,6 +1135,8 @@ void LLViewerTextureList::updateMaxResidentTexMem(S32 mem)
// static
void LLViewerTextureList::receiveImageHeader(LLMessageSystem *msg, void **user_data)
{
+ static LLCachedControl<bool> log_texture_traffic(gSavedSettings,"LogTextureNetworkTraffic") ;
+
LLFastTimer t(FTM_PROCESS_IMAGES);
// Receive image header, copy into image object and decompresses
@@ -1171,14 +1147,16 @@ void LLViewerTextureList::receiveImageHeader(LLMessageSystem *msg, void **user_d
char ip_string[256];
u32_to_ip_string(msg->getSenderIP(),ip_string);
+ U32 received_size ;
if (msg->getReceiveCompressedSize())
{
- gTextureList.sTextureBits += msg->getReceiveCompressedSize() * 8;
+ received_size = msg->getReceiveCompressedSize() ;
}
else
{
- gTextureList.sTextureBits += msg->getReceiveSize() * 8;
+ received_size = msg->getReceiveSize() ;
}
+ gTextureList.sTextureBits += received_size * 8;
gTextureList.sTexturePackets++;
U8 codec;
@@ -1213,6 +1191,11 @@ void LLViewerTextureList::receiveImageHeader(LLMessageSystem *msg, void **user_d
delete [] data;
return;
}
+ if(log_texture_traffic)
+ {
+ gTotalTextureBytesPerBoostLevel[image->getBoostLevel()] += received_size ;
+ }
+
//image->getLastPacketTimer()->reset();
bool res = LLAppViewer::getTextureFetch()->receiveImageHeader(msg->getSender(), id, codec, packets, totalbytes, data_size, data);
if (!res)
@@ -1224,6 +1207,8 @@ void LLViewerTextureList::receiveImageHeader(LLMessageSystem *msg, void **user_d
// static
void LLViewerTextureList::receiveImagePacket(LLMessageSystem *msg, void **user_data)
{
+ static LLCachedControl<bool> log_texture_traffic(gSavedSettings,"LogTextureNetworkTraffic") ;
+
LLMemType mt1(LLMemType::MTYPE_APPFMTIMAGE);
LLFastTimer t(FTM_PROCESS_IMAGES);
@@ -1236,14 +1221,16 @@ void LLViewerTextureList::receiveImagePacket(LLMessageSystem *msg, void **user_d
char ip_string[256];
u32_to_ip_string(msg->getSenderIP(),ip_string);
+ U32 received_size ;
if (msg->getReceiveCompressedSize())
{
- gTextureList.sTextureBits += msg->getReceiveCompressedSize() * 8;
+ received_size = msg->getReceiveCompressedSize() ;
}
else
{
- gTextureList.sTextureBits += msg->getReceiveSize() * 8;
+ received_size = msg->getReceiveSize() ;
}
+ gTextureList.sTextureBits += received_size * 8;
gTextureList.sTexturePackets++;
//llprintline("Start decode, image header...");
@@ -1277,6 +1264,11 @@ void LLViewerTextureList::receiveImagePacket(LLMessageSystem *msg, void **user_d
delete [] data;
return;
}
+ if(log_texture_traffic)
+ {
+ gTotalTextureBytesPerBoostLevel[image->getBoostLevel()] += received_size ;
+ }
+
//image->getLastPacketTimer()->reset();
bool res = LLAppViewer::getTextureFetch()->receiveImagePacket(msg->getSender(), id, packet_num, data_size, data);
if (!res)
@@ -1513,42 +1505,45 @@ bool LLUIImageList::initFromFile()
return false;
}
- std::vector<std::string> paths;
- // path to current selected skin
- paths.push_back(gDirUtilp->getSkinDir()
- + gDirUtilp->getDirDelimiter()
- + "textures"
- + gDirUtilp->getDirDelimiter()
- + "textures.xml");
- // path to user overrides on current skin
- paths.push_back(gDirUtilp->getUserSkinDir()
- + gDirUtilp->getDirDelimiter()
- + "textures"
- + gDirUtilp->getDirDelimiter()
- + "textures.xml");
-
- // apply skinned xml files incrementally
- for(std::vector<std::string>::iterator path_it = paths.begin();
- path_it != paths.end();
- ++path_it)
- {
- // don't reapply base file to itself
- if (!path_it->empty() && (*path_it) != base_file_path)
- {
- LLXMLNodePtr update_root;
- if (LLXMLNode::parseFile(*path_it, update_root, NULL))
- {
- LLXMLNode::updateNode(root, update_root);
- }
- }
- }
-
UIImageDeclarations images;
LLXUIParser parser;
parser.readXUI(root, images, base_file_path);
+ // add components defined in current skin
+ std::string skin_update_path = gDirUtilp->getSkinDir()
+ + gDirUtilp->getDirDelimiter()
+ + "textures"
+ + gDirUtilp->getDirDelimiter()
+ + "textures.xml";
+ LLXMLNodePtr update_root;
+ if (skin_update_path != base_file_path
+ && LLXMLNode::parseFile(skin_update_path, update_root, NULL))
+ {
+ parser.readXUI(update_root, images, skin_update_path);
+ }
+
+ // add components defined in user override of current skin
+ skin_update_path = gDirUtilp->getUserSkinDir()
+ + gDirUtilp->getDirDelimiter()
+ + "textures"
+ + gDirUtilp->getDirDelimiter()
+ + "textures.xml";
+ if (skin_update_path != base_file_path
+ && LLXMLNode::parseFile(skin_update_path, update_root, NULL))
+ {
+ parser.readXUI(update_root, images, skin_update_path);
+ }
+
if (!images.validateBlock()) return false;
+ std::map<std::string, UIImageDeclaration> merged_declarations;
+ for (LLInitParam::ParamIterator<UIImageDeclaration>::const_iterator image_it = images.textures.begin();
+ image_it != images.textures.end();
+ ++image_it)
+ {
+ merged_declarations[image_it->name].overwriteFrom(*image_it);
+ }
+
enum e_decode_pass
{
PASS_DECODE_NOW,
@@ -1558,19 +1553,20 @@ bool LLUIImageList::initFromFile()
for (S32 cur_pass = PASS_DECODE_NOW; cur_pass < NUM_PASSES; cur_pass++)
{
- for (LLInitParam::ParamIterator<UIImageDeclaration>::const_iterator image_it = images.textures.begin();
- image_it != images.textures.end();
+ for (std::map<std::string, UIImageDeclaration>::const_iterator image_it = merged_declarations.begin();
+ image_it != merged_declarations.end();
++image_it)
{
- std::string file_name = image_it->file_name.isProvided() ? image_it->file_name() : image_it->name();
+ const UIImageDeclaration& image = image_it->second;
+ std::string file_name = image.file_name.isProvided() ? image.file_name() : image.name();
// load high priority textures on first pass (to kick off decode)
- enum e_decode_pass decode_pass = image_it->preload ? PASS_DECODE_NOW : PASS_DECODE_LATER;
+ enum e_decode_pass decode_pass = image.preload ? PASS_DECODE_NOW : PASS_DECODE_LATER;
if (decode_pass != cur_pass)
{
continue;
}
- preloadUIImage(image_it->name, file_name, image_it->use_mips, image_it->scale);
+ preloadUIImage(image.name, file_name, image.use_mips, image.scale);
}
if (cur_pass == PASS_DECODE_NOW && !gSavedSettings.getBOOL("NoPreload"))
diff --git a/indra/newview/llviewertexturelist.h b/indra/newview/llviewertexturelist.h
index d508ce1ac6..d02b6be6b5 100644
--- a/indra/newview/llviewertexturelist.h
+++ b/indra/newview/llviewertexturelist.h
@@ -83,6 +83,7 @@ public:
void dump();
void destroyGL(BOOL save_state = TRUE);
void restoreGL();
+ BOOL isInitialized() const {return mInitialized;}
LLViewerFetchedTexture *findImage(const LLUUID &image_id);
@@ -120,8 +121,8 @@ private:
void addImage(LLViewerFetchedTexture *image);
void deleteImage(LLViewerFetchedTexture *image);
- void addImageToList(LLViewerFetchedTexture *image);
- void removeImageFromList(LLViewerFetchedTexture *image);
+ void addImageToList(LLViewerFetchedTexture *image, U32 thread_id = LLThread::currentID());
+ void removeImageFromList(LLViewerFetchedTexture *image, U32 thread_id = LLThread::currentID());
LLViewerFetchedTexture * getImage(const LLUUID &image_id,
BOOL usemipmap = TRUE,
@@ -187,6 +188,7 @@ private:
// simply holds on to LLViewerFetchedTexture references to stop them from being purged too soon
std::set<LLPointer<LLViewerFetchedTexture> > mImagePreloads;
+ BOOL mInitialized ;
BOOL mUpdateStats;
S32 mMaxResidentTexMemInMegaBytes;
S32 mMaxTotalTextureMemInMegaBytes;
@@ -206,30 +208,33 @@ public:
private:
static S32 sNumImages;
static void (*sUUIDCallback)(void**, const LLUUID &);
+
+ //debug use
+ static U32 sRenderThreadID;
};
class LLUIImageList : public LLImageProviderInterface, public LLSingleton<LLUIImageList>
{
public:
// LLImageProviderInterface
- /*virtual*/ LLUIImagePtr getUIImageByID(const LLUUID& id, S32 priority);
- /*virtual*/ LLUIImagePtr getUIImage(const std::string& name, S32 priority);
+ /*virtual*/ LLPointer<LLUIImage> getUIImageByID(const LLUUID& id, S32 priority);
+ /*virtual*/ LLPointer<LLUIImage> getUIImage(const std::string& name, S32 priority);
void cleanUp();
bool initFromFile();
- LLUIImagePtr preloadUIImage(const std::string& name, const std::string& filename, BOOL use_mips, const LLRect& scale_rect);
+ LLPointer<LLUIImage> preloadUIImage(const std::string& name, const std::string& filename, BOOL use_mips, const LLRect& scale_rect);
static void onUIImageLoaded( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata );
private:
- LLUIImagePtr loadUIImageByName(const std::string& name, const std::string& filename,
+ LLPointer<LLUIImage> loadUIImageByName(const std::string& name, const std::string& filename,
BOOL use_mips = FALSE, const LLRect& scale_rect = LLRect::null,
LLViewerTexture::EBoostLevel boost_priority = LLViewerTexture::BOOST_UI);
- LLUIImagePtr loadUIImageByID(const LLUUID& id,
+ LLPointer<LLUIImage> loadUIImageByID(const LLUUID& id,
BOOL use_mips = FALSE, const LLRect& scale_rect = LLRect::null,
LLViewerTexture::EBoostLevel boost_priority = LLViewerTexture::BOOST_UI);
- LLUIImagePtr loadUIImage(LLViewerFetchedTexture* imagep, const std::string& name, BOOL use_mips = FALSE, const LLRect& scale_rect = LLRect::null);
+ LLPointer<LLUIImage> loadUIImage(LLViewerFetchedTexture* imagep, const std::string& name, BOOL use_mips = FALSE, const LLRect& scale_rect = LLRect::null);
struct LLUIImageLoadData
diff --git a/indra/newview/llviewerthrottle.cpp b/indra/newview/llviewerthrottle.cpp
index b614ccdbc2..5147272122 100644
--- a/indra/newview/llviewerthrottle.cpp
+++ b/indra/newview/llviewerthrottle.cpp
@@ -46,7 +46,7 @@ const F32 MAX_FRACTIONAL = 1.5f;
const F32 MIN_FRACTIONAL = 0.2f;
const F32 MIN_BANDWIDTH = 50.f;
-const F32 MAX_BANDWIDTH = 1500.f;
+const F32 MAX_BANDWIDTH = 3000.f;
const F32 STEP_FRACTIONAL = 0.1f;
const F32 TIGHTEN_THROTTLE_THRESHOLD = 3.0f; // packet loss % per s
const F32 EASE_THROTTLE_THRESHOLD = 0.5f; // packet loss % per s
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index ebcb6e3738..6fe79c2e85 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -25,7 +25,6 @@
*/
#include "llviewerprecompiledheaders.h"
-
#include "llviewerwindow.h"
#if LL_WINDOWS
@@ -41,6 +40,7 @@
#include "llagent.h"
#include "llagentcamera.h"
#include "llfloaterreg.h"
+#include "llmeshrepository.h"
#include "llpanellogin.h"
#include "llviewerkeyboard.h"
#include "llviewermenu.h"
@@ -79,6 +79,7 @@
#include "lltooltip.h"
#include "llmediaentry.h"
#include "llurldispatcher.h"
+#include "raytrace.h"
// newview includes
#include "llagent.h"
@@ -227,6 +228,8 @@ LLVector2 gDebugRaycastTexCoord;
LLVector3 gDebugRaycastNormal;
LLVector3 gDebugRaycastBinormal;
S32 gDebugRaycastFaceHit;
+LLVector3 gDebugRaycastStart;
+LLVector3 gDebugRaycastEnd;
// HUD display lines in lower right
BOOL gDisplayWindInfo = FALSE;
@@ -234,17 +237,12 @@ BOOL gDisplayCameraPos = FALSE;
BOOL gDisplayFOV = FALSE;
BOOL gDisplayBadge = FALSE;
-S32 CHAT_BAR_HEIGHT = 28;
-S32 OVERLAY_BAR_HEIGHT = 20;
-
-const U8 NO_FACE = 255;
+static const U8 NO_FACE = 255;
BOOL gQuietSnapshot = FALSE;
const F32 MIN_AFK_TIME = 2.f; // minimum time after setting away state before coming back
-const F32 MAX_FAST_FRAME_TIME = 0.5f;
-const F32 FAST_FRAME_INCREMENT = 0.1f;
-const F32 MIN_DISPLAY_SCALE = 0.75f;
+static const F32 MIN_DISPLAY_SCALE = 0.75f;
std::string LLViewerWindow::sSnapshotBaseName;
std::string LLViewerWindow::sSnapshotDir;
@@ -296,31 +294,45 @@ private:
line_list_t mLineList;
LLColor4 mTextColor;
-public:
- LLDebugText(LLViewerWindow* window) : mWindow(window) {}
-
void addText(S32 x, S32 y, const std::string &text)
{
mLineList.push_back(Line(text, x, y));
}
+
+ void clearText() { mLineList.clear(); }
+
+public:
+ LLDebugText(LLViewerWindow* window) : mWindow(window) {}
void update()
{
+ static LLCachedControl<bool> log_texture_traffic(gSavedSettings,"LogTextureNetworkTraffic") ;
+
std::string wind_vel_text;
std::string wind_vector_text;
std::string rwind_vel_text;
std::string rwind_vector_text;
std::string audio_text;
+ static const std::string beacon_particle = LLTrans::getString("BeaconParticle");
+ static const std::string beacon_physical = LLTrans::getString("BeaconPhysical");
+ static const std::string beacon_scripted = LLTrans::getString("BeaconScripted");
+ static const std::string beacon_scripted_touch = LLTrans::getString("BeaconScriptedTouch");
+ static const std::string beacon_sound = LLTrans::getString("BeaconSound");
+ static const std::string beacon_media = LLTrans::getString("BeaconMedia");
+ static const std::string particle_hiding = LLTrans::getString("ParticleHiding");
+
// Draw the statistics in a light gray
// and in a thin font
mTextColor = LLColor4( 0.86f, 0.86f, 0.86f, 1.f );
// Draw stuff growing up from right lower corner of screen
- U32 xpos = mWindow->getWindowWidthScaled() - 350;
+ U32 xpos = mWindow->getWorldViewWidthScaled() - 350;
U32 ypos = 64;
const U32 y_inc = 20;
+ clearText();
+
if (gSavedSettings.getBOOL("DebugShowTime"))
{
const U32 y_inc2 = 15;
@@ -345,6 +357,14 @@ public:
addText(xpos, ypos, llformat("Time: %d:%02d:%02d", hours,mins,secs)); ypos += y_inc;
}
+#if LL_WINDOWS
+ if (gSavedSettings.getBOOL("DebugShowMemory"))
+ {
+ addText(xpos, ypos, llformat("Memory: %d (KB)", LLMemory::getWorkingSetSize() / 1024));
+ ypos += y_inc;
+ }
+#endif
+
if (gDisplayCameraPos)
{
std::string camera_view_text;
@@ -441,6 +461,79 @@ public:
addText(xpos, ypos, "Shaders Disabled");
ypos += y_inc;
}
+
+ if (gGLManager.mHasATIMemInfo)
+ {
+ S32 meminfo[4];
+ glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, meminfo);
+
+ addText(xpos, ypos, llformat("%.2f MB Texture Memory Free", meminfo[0]/1024.f));
+ ypos += y_inc;
+
+ if (gGLManager.mHasVertexBufferObject)
+ {
+ glGetIntegerv(GL_VBO_FREE_MEMORY_ATI, meminfo);
+ addText(xpos, ypos, llformat("%.2f MB VBO Memory Free", meminfo[0]/1024.f));
+ ypos += y_inc;
+ }
+ }
+ else if (gGLManager.mHasNVXMemInfo)
+ {
+ S32 free_memory;
+ glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &free_memory);
+ addText(xpos, ypos, llformat("%.2f MB Video Memory Free", free_memory/1024.f));
+ ypos += y_inc;
+ }
+
+ //show streaming cost/triangle count of known prims in current region OR selection
+ {
+ F32 cost = 0.f;
+ S32 count = 0;
+ S32 object_count = 0;
+ S32 total_bytes = 0;
+ S32 visible_bytes = 0;
+
+ const char* label = "Region";
+ if (LLSelectMgr::getInstance()->getSelection()->getObjectCount() == 0)
+ { //region
+ LLViewerRegion* region = gAgent.getRegion();
+ if (region)
+ {
+ for (U32 i = 0; i < gObjectList.getNumObjects(); ++i)
+ {
+ LLViewerObject* object = gObjectList.getObject(i);
+ if (object &&
+ object->getRegion() == region &&
+ object->getVolume())
+ {
+ object_count++;
+ S32 bytes = 0;
+ S32 visible = 0;
+ cost += object->getStreamingCost(&bytes, &visible);
+ count += object->getTriangleCount();
+ total_bytes += bytes;
+ visible_bytes += visible;
+ }
+ }
+ }
+ }
+ else
+ {
+ label = "Selection";
+ cost = LLSelectMgr::getInstance()->getSelection()->getSelectedObjectStreamingCost(&total_bytes, &visible_bytes);
+ count = LLSelectMgr::getInstance()->getSelection()->getSelectedObjectTriangleCount();
+ object_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount();
+ }
+
+ addText(xpos,ypos, llformat("%s streaming cost: %.1f", label, cost));
+ ypos += y_inc;
+
+ addText(xpos, ypos, llformat(" %.1f KTris, %.1f/%.1f KB, %d objects",
+ count/1024.f, visible_bytes/1024.f, total_bytes/1024.f, object_count));
+ ypos += y_inc;
+
+ }
+
addText(xpos, ypos, llformat("%d MB Vertex Data", LLVertexBuffer::sAllocatedBytes/(1024*1024)));
ypos += y_inc;
@@ -493,6 +586,12 @@ public:
ypos += y_inc;
+ if (!LLSpatialGroup::sPendingQueries.empty())
+ {
+ addText(xpos,ypos, llformat("%d Queries pending", LLSpatialGroup::sPendingQueries.size()));
+ ypos += y_inc;
+ }
+
addText(xpos,ypos, llformat("%d Avatars visible", LLVOAvatar::sNumVisibleAvatars));
@@ -502,6 +601,22 @@ public:
ypos += y_inc;
+ if (gSavedSettings.getBOOL("MeshEnabled"))
+ {
+ addText(xpos, ypos, llformat("%.3f MB Mesh Data Received", LLMeshRepository::sBytesReceived/(1024.f*1024.f)));
+
+ ypos += y_inc;
+
+ addText(xpos, ypos, llformat("%d/%d Mesh HTTP Requests/Retries", LLMeshRepository::sHTTPRequestCount,
+ LLMeshRepository::sHTTPRetryCount));
+
+ ypos += y_inc;
+
+ addText(xpos, ypos, llformat("%.3f/%.3f MB Mesh Cache Read/Write ", LLMeshRepository::sCacheBytesRead/(1024.f*1024.f), LLMeshRepository::sCacheBytesWritten/(1024.f*1024.f)));
+
+ ypos += y_inc;
+ }
+
LLVertexBuffer::sBindCount = LLImageGL::sBindCount =
LLVertexBuffer::sSetCount = LLImageGL::sUniqueCount =
gPipeline.mNumVisibleNodes = LLPipeline::sVisibleLightCount = 0;
@@ -550,38 +665,156 @@ public:
// only display these messages if we are actually rendering beacons at this moment
if (LLPipeline::getRenderBeacons(NULL) && LLFloaterReg::instanceVisible("beacons"))
{
- if (LLPipeline::getRenderParticleBeacons(NULL))
+ if (LLPipeline::getRenderMOAPBeacons(NULL))
{
- addText(xpos, ypos, "Viewing particle beacons (blue)");
+ addText(xpos, ypos, "Viewing media beacons (white)");
ypos += y_inc;
}
+
if (LLPipeline::toggleRenderTypeControlNegated((void*)LLPipeline::RENDER_TYPE_PARTICLES))
{
- addText(xpos, ypos, "Hiding particles");
+ addText(xpos, ypos, particle_hiding);
ypos += y_inc;
}
- if (LLPipeline::getRenderPhysicalBeacons(NULL))
+
+ if (LLPipeline::getRenderParticleBeacons(NULL))
{
- addText(xpos, ypos, "Viewing physical object beacons (green)");
+ addText(xpos, ypos, "Viewing particle beacons (blue)");
ypos += y_inc;
}
+
+ if (LLPipeline::getRenderSoundBeacons(NULL))
+ {
+ addText(xpos, ypos, "Viewing sound beacons (yellow)");
+ ypos += y_inc;
+ }
+
if (LLPipeline::getRenderScriptedBeacons(NULL))
{
- addText(xpos, ypos, "Viewing scripted object beacons (red)");
+ addText(xpos, ypos, beacon_scripted);
ypos += y_inc;
}
else
if (LLPipeline::getRenderScriptedTouchBeacons(NULL))
{
- addText(xpos, ypos, "Viewing scripted object with touch function beacons (red)");
+ addText(xpos, ypos, beacon_scripted_touch);
ypos += y_inc;
}
- if (LLPipeline::getRenderSoundBeacons(NULL))
+
+ if (LLPipeline::getRenderPhysicalBeacons(NULL))
{
- addText(xpos, ypos, "Viewing sound beacons (yellow)");
+ addText(xpos, ypos, "Viewing physical object beacons (green)");
+ ypos += y_inc;
+ }
+ }
+
+ if(log_texture_traffic)
+ {
+ U32 old_y = ypos ;
+ for(S32 i = LLViewerTexture::BOOST_NONE; i < LLViewerTexture::MAX_GL_IMAGE_CATEGORY; i++)
+ {
+ if(gTotalTextureBytesPerBoostLevel[i] > 0)
+ {
+ addText(xpos, ypos, llformat("Boost_Level %d: %.3f MB", i, (F32)gTotalTextureBytesPerBoostLevel[i] / (1024 * 1024)));
+ ypos += y_inc;
+ }
+ }
+ if(ypos != old_y)
+ {
+ addText(xpos, ypos, "Network traffic for textures:");
+ ypos += y_inc;
+ }
+ }
+
+ if (gSavedSettings.getBOOL("DebugShowUploadCost"))
+ {
+ addText(xpos, ypos, llformat(" Meshes: L$%d", gPipeline.mDebugMeshUploadCost));
+ ypos += y_inc/2;
+ addText(xpos, ypos, llformat(" Sculpties: L$%d", gPipeline.mDebugSculptUploadCost));
+ ypos += y_inc/2;
+ addText(xpos, ypos, llformat(" Textures: L$%d", gPipeline.mDebugTextureUploadCost));
+ ypos += y_inc/2;
+ addText(xpos, ypos, "Upload Cost: ");
+
+ ypos += y_inc;
+ }
+
+ //temporary hack to give feedback on mesh upload progress
+ if (!gMeshRepo.mUploads.empty())
+ {
+ for (std::vector<LLMeshUploadThread*>::iterator iter = gMeshRepo.mUploads.begin();
+ iter != gMeshRepo.mUploads.end(); ++iter)
+ {
+ LLMeshUploadThread* thread = *iter;
+
+ addText(xpos, ypos, llformat("Mesh Upload -- price quote: %d:%d | upload: %d:%d | create: %d",
+ thread->mPendingConfirmations, thread->mUploadQ.size()+thread->mTextureQ.size(),
+ thread->mPendingUploads, thread->mConfirmedQ.size()+thread->mConfirmedTextureQ.size(),
+ thread->mInstanceQ.size()));
ypos += y_inc;
}
}
+
+ if (!gMeshRepo.mPendingRequests.empty() ||
+ !gMeshRepo.mThread->mHeaderReqQ.empty() ||
+ !gMeshRepo.mThread->mLODReqQ.empty())
+ {
+ LLMutexLock lock(gMeshRepo.mThread->mMutex);
+ S32 pending = (S32) gMeshRepo.mPendingRequests.size();
+ S32 header = (S32) gMeshRepo.mThread->mHeaderReqQ.size();
+ S32 lod = (S32) gMeshRepo.mThread->mLODReqQ.size();
+
+ addText(xpos, ypos, llformat ("Mesh Queue - %d pending (%d:%d header | %d:%d LOD)",
+ pending,
+ LLMeshRepoThread::sActiveHeaderRequests, header,
+ LLMeshRepoThread::sActiveLODRequests, lod));
+
+ ypos += y_inc;
+ }
+
+ if (gSavedSettings.getBOOL("DebugShowTextureInfo"))
+ {
+ LLViewerObject* objectp = NULL ;
+ //objectp = = gAgentCamera.getFocusObject();
+
+ LLSelectNode* nodep = LLSelectMgr::instance().getHoverNode();
+ if (nodep)
+ {
+ objectp = nodep->getObject();
+ }
+ if (objectp && !objectp->isDead())
+ {
+ S32 num_faces = objectp->mDrawable->getNumFaces() ;
+
+ for(S32 i = 0 ; i < num_faces; i++)
+ {
+ LLFace* facep = objectp->mDrawable->getFace(i) ;
+ if(facep)
+ {
+ //addText(xpos, ypos, llformat("ts_min: %.3f ts_max: %.3f tt_min: %.3f tt_max: %.3f", facep->mTexExtents[0].mV[0], facep->mTexExtents[1].mV[0],
+ // facep->mTexExtents[0].mV[1], facep->mTexExtents[1].mV[1]));
+ //ypos += y_inc;
+
+ addText(xpos, ypos, llformat("v_size: %.3f: p_size: %.3f", facep->getVirtualSize(), facep->getPixelArea()));
+ ypos += y_inc;
+
+ //const LLTextureEntry *tep = facep->getTextureEntry();
+ //if(tep)
+ //{
+ // addText(xpos, ypos, llformat("scale_s: %.3f: scale_t: %.3f", tep->mScaleS, tep->mScaleT)) ;
+ // ypos += y_inc;
+ //}
+
+ LLViewerTexture* tex = facep->getTexture() ;
+ if(tex)
+ {
+ addText(xpos, ypos, llformat("ID: %s v_size: %.3f", tex->getID().asString().c_str(), tex->getMaxVirtualSize()));
+ ypos += y_inc;
+ }
+ }
+ }
+ }
+ }
}
void draw()
@@ -832,7 +1065,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;
@@ -1158,8 +1391,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;
@@ -1189,7 +1423,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;
}
@@ -1223,7 +1457,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();
@@ -1337,17 +1572,26 @@ 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("RenderUseFBO") ? 0 : gSavedSettings.getU32("RenderFSAASamples")); //don't use window level anti-aliasing if FBOs are enabled
+ gSavedSettings.getBOOL("RenderDeferred") ? 0 : gSavedSettings.getU32("RenderFSAASamples")); //don't use window level anti-aliasing if FBOs are enabled
if (!LLAppViewer::instance()->restoreErrorTrap())
{
LL_WARNS("Window") << " Someone took over my signal/exception handler (post createWindow)!" << LL_ENDL;
}
+ LLCoordScreen scr;
+ mWindow->getSize(&scr);
+
+ if(fullscreen && ( scr.mX!=width || scr.mY!=height))
+ {
+ llwarns << "Fullscreen has forced us in to a different resolution now using "<<scr.mX<<" x "<<scr.mY<<llendl;
+ gSavedSettings.setS32("FullScreenWidth",scr.mX);
+ gSavedSettings.setS32("FullScreenHeight",scr.mY);
+ }
if (NULL == mWindow)
{
@@ -1359,7 +1603,7 @@ LLViewerWindow::LLViewerWindow(
LL_WARNS("Window") << "Unable to create window, be sure screen is set at 32-bit color in Control Panels->Display->Settings"
<< LL_ENDL;
#endif
- LLAppViewer::instance()->forceExit(1);
+ LLAppViewer::instance()->fastQuit(1);
}
// Get the real window rect the window was created with (since there are various OS-dependent reasons why
@@ -1393,7 +1637,7 @@ LLViewerWindow::LLViewerWindow(
{
gSavedSettings.setBOOL("RenderVBOEnable", FALSE);
}
- LLVertexBuffer::initClass(gSavedSettings.getBOOL("RenderVBOEnable"));
+ LLVertexBuffer::initClass(gSavedSettings.getBOOL("RenderVBOEnable"), gSavedSettings.getBOOL("RenderVBOMappingDisable"));
if (LLFeatureManager::getInstance()->isSafe()
|| (gSavedSettings.getS32("LastFeatureVersion") != LLFeatureManager::getInstance()->getVersion())
@@ -1404,6 +1648,11 @@ LLViewerWindow::LLViewerWindow(
gSavedSettings.setBOOL("ProbeHardwareOnStartup", FALSE);
}
+ if (!gGLManager.mHasDepthClamp)
+ {
+ LL_INFOS("RenderInit") << "Missing feature GL_ARB_depth_clamp. Void water might disappear in rare cases." << LL_ENDL;
+ }
+
// If we crashed while initializng GL stuff last time, disable certain features
if (gSavedSettings.getBOOL("RenderInitError"))
{
@@ -1521,11 +1770,13 @@ void LLViewerWindow::initBase()
mWorldViewPlaceholder = main_view->getChildView("world_view_rect")->getHandle();
mNonSideTrayView = main_view->getChildView("non_side_tray_view")->getHandle();
mFloaterViewHolder = main_view->getChildView("floater_view_holder")->getHandle();
- mPopupView = main_view->findChild<LLPopupView>("popup_holder");
+ mPopupView = main_view->getChild<LLPopupView>("popup_holder");
mHintHolder = main_view->getChild<LLView>("hint_holder")->getHandle();
+ mLoginPanelHolder = main_view->getChild<LLView>("login_panel_holder")->getHandle();
// Constrain floaters to inside the menu and status bar regions.
gFloaterView = main_view->getChild<LLFloaterView>("Floater View");
+ gFloaterView->setFloaterSnapView(main_view->getChild<LLView>("floater_snap_region")->getHandle());
gSnapshotFloaterView = main_view->getChild<LLSnapshotFloaterView>("Snapshot Floater View");
@@ -1656,7 +1907,7 @@ void LLViewerWindow::initWorldUI()
{
LLRect hud_rect = full_window;
hud_rect.mBottom += 50;
- if (gMenuBarView)
+ if (gMenuBarView && gMenuBarView->isInVisibleChain())
{
hud_rect.mTop -= gMenuBarView->getRect().getHeight();
}
@@ -1685,6 +1936,25 @@ void LLViewerWindow::initWorldUI()
buttons_panel->setShape(buttons_panel_container->getLocalRect());
buttons_panel->setFollowsAll();
buttons_panel_container->addChild(buttons_panel);
+
+ LLView* avatar_picker_destination_guide_container = gViewerWindow->getRootView()->getChild<LLView>("avatar_picker_and_destination_guide_container");
+ avatar_picker_destination_guide_container->getChild<LLButton>("close")->setCommitCallback(boost::bind(toggle_destination_and_avatar_picker, LLSD()));
+ LLMediaCtrl* destinations = avatar_picker_destination_guide_container->findChild<LLMediaCtrl>("destination_guide_contents");
+ 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");
+ }
+
+ // show destinations by default
+ toggle_destination_and_avatar_picker(gSavedSettings.getS32("DestinationsAndAvatarsVisibility"));
}
// Destroy the UI
@@ -1766,11 +2036,8 @@ void LLViewerWindow::shutdownGL()
LLVertexBuffer::cleanupClass();
llinfos << "Stopping GL during shutdown" << llendl;
- if (!gNoRender)
- {
- stopGL(FALSE);
- stop_glerror();
- }
+ stopGL(FALSE);
+ stop_glerror();
gGL.shutdown();
}
@@ -1834,10 +2101,7 @@ void LLViewerWindow::reshape(S32 width, S32 height)
// may have been destructed.
if (!LLApp::isExiting())
{
- if (gNoRender)
- {
- return;
- }
+ gWindowResized = TRUE;
// update our window rectangle
mWindowRectRaw.mRight = mWindowRectRaw.mLeft + width;
@@ -2240,6 +2504,20 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask)
return TRUE;
}
+ // If "Pressing letter keys starts local chat" option is selected, we are not in mouselook,
+ // no view has keyboard focus, this is a printable character key (and no modifier key is
+ // pressed except shift), then give focus to nearby chat (STORM-560)
+ if ( gSavedSettings.getS32("LetterKeysFocusChatBar") && !gAgentCamera.cameraMouselook() &&
+ !keyboard_focus && key < 0x80 && (mask == MASK_NONE || mask == MASK_SHIFT) )
+ {
+ LLLineEditor* chat_editor = LLBottomTray::instanceExists() ? LLBottomTray::getInstance()->getNearbyChatBar()->getChatBox() : NULL;
+ if (chat_editor)
+ {
+ // passing NULL here, character will be added later when it is handled by character handler.
+ LLBottomTray::getInstance()->getNearbyChatBar()->startChat(NULL);
+ return TRUE;
+ }
+ }
// give menus a chance to handle unmodified accelerator keys
if ((gMenuBarView && gMenuBarView->handleAcceleratorKey(key, mask))
@@ -2459,12 +2737,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))
{
@@ -2474,7 +2748,9 @@ void LLViewerWindow::updateUI()
&gDebugRaycastIntersection,
&gDebugRaycastTexCoord,
&gDebugRaycastNormal,
- &gDebugRaycastBinormal);
+ &gDebugRaycastBinormal,
+ &gDebugRaycastStart,
+ &gDebugRaycastEnd);
}
updateMouseDelta();
@@ -2855,7 +3131,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
{
@@ -2935,18 +3212,20 @@ void LLViewerWindow::updateKeyboardFocus()
LLUICtrl* parent = cur_focus->getParentUICtrl();
const LLUICtrl* focus_root = cur_focus->findRootMostFocusRoot();
+ bool new_focus_found = false;
while(parent)
{
- if (parent->isCtrl() &&
- (parent->hasTabStop() || parent == focus_root) &&
- !parent->getIsChrome() &&
- parent->isInVisibleChain() &&
- parent->isInEnabledChain())
+ if (parent->isCtrl()
+ && (parent->hasTabStop() || parent == focus_root)
+ && !parent->getIsChrome()
+ && parent->isInVisibleChain()
+ && parent->isInEnabledChain())
{
if (!parent->focusFirstItem())
{
parent->setFocus(TRUE);
}
+ new_focus_found = true;
break;
}
parent = parent->getParentUICtrl();
@@ -2955,7 +3234,7 @@ void LLViewerWindow::updateKeyboardFocus()
// if we didn't find a better place to put focus, just release it
// hasFocus() will return true if and only if we didn't touch focus since we
// are only moving focus higher in the hierarchy
- if (cur_focus->hasFocus())
+ if (!new_focus_found)
{
cur_focus->setFocus(FALSE);
}
@@ -2979,7 +3258,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);
@@ -3292,11 +3572,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)
{
@@ -3332,11 +3607,6 @@ void LLViewerWindow::schedulePick(LLPickInfo& pick_info)
void LLViewerWindow::performPick()
{
- if (gNoRender)
- {
- return;
- }
-
if (!mPicks.empty())
{
std::vector<LLPickInfo>::iterator pick_it;
@@ -3368,11 +3638,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)
{
@@ -3382,7 +3647,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;
@@ -3419,7 +3685,9 @@ LLViewerObject* LLViewerWindow::cursorIntersect(S32 mouse_x, S32 mouse_y, F32 de
LLVector3 *intersection,
LLVector2 *uv,
LLVector3 *normal,
- LLVector3 *binormal)
+ LLVector3 *binormal,
+ LLVector3* start,
+ LLVector3* end)
{
S32 x = mouse_x;
S32 y = mouse_y;
@@ -3451,7 +3719,22 @@ LLViewerObject* LLViewerWindow::cursorIntersect(S32 mouse_x, S32 mouse_y, F32 de
LLVector3 mouse_world_start = mouse_point_global;
LLVector3 mouse_world_end = mouse_point_global + mouse_direction_global * depth;
-
+ if (!LLViewerJoystick::getInstance()->getOverrideCamera())
+ { //always set raycast intersection to mouse_world_end unless
+ //flycam is on (for DoF effect)
+ gDebugRaycastIntersection = mouse_world_end;
+ }
+
+ if (start)
+ {
+ *start = mouse_world_start;
+ }
+
+ if (end)
+ {
+ *end = mouse_world_end;
+ }
+
LLViewerObject* found = NULL;
if (this_object) // check only this object
@@ -3463,8 +3746,7 @@ LLViewerObject* LLViewerWindow::cursorIntersect(S32 mouse_x, S32 mouse_y, F32 de
{
found = this_object;
}
- }
-
+ }
else // is a world object
{
if (this_object->lineSegmentIntersect(mouse_world_start, mouse_world_end, this_face, pick_transparent,
@@ -3472,21 +3754,22 @@ LLViewerObject* LLViewerWindow::cursorIntersect(S32 mouse_x, S32 mouse_y, F32 de
{
found = this_object;
}
- }
- }
-
+ }
+ }
else // check ALL objects
- {
+ {
found = gPipeline.lineSegmentIntersectInHUD(mouse_hud_start, mouse_hud_end, pick_transparent,
face_hit, intersection, uv, normal, binormal);
if (!found) // if not found in HUD, look in world:
-
- {
+ {
found = gPipeline.lineSegmentIntersectInWorld(mouse_world_start, mouse_world_end, pick_transparent,
face_hit, intersection, uv, normal, binormal);
+ if (found && !pick_transparent)
+ {
+ gDebugRaycastIntersection = *intersection;
}
-
+ }
}
return found;
@@ -3844,7 +4127,9 @@ BOOL LLViewerWindow::thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 p
return rawSnapshot(raw, preview_width, preview_height, FALSE, FALSE, show_ui, do_rebuild, type);
}
-// Saves the image from the screen to the specified filename and path.
+// Saves the image from the screen to a raw image
+// Since the required size might be bigger than the available screen, this method rerenders the scene in parts (called subimages) and copy
+// the results over to the final raw image.
BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_height,
BOOL keep_window_aspect, BOOL is_texture, BOOL show_ui, BOOL do_rebuild, ESnapshotType type, S32 max_size)
{
@@ -3862,8 +4147,6 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei
// Hide all the UI widgets first and draw a frame
BOOL prev_draw_ui = gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI) ? TRUE : FALSE;
- show_ui = show_ui ? TRUE : FALSE;
-
if ( prev_draw_ui != show_ui)
{
LLPipeline::toggleRenderDebugFeature((void*)LLPipeline::RENDER_DEBUG_FEATURE_UI);
@@ -3875,95 +4158,78 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei
LLPipeline::sShowHUDAttachments = FALSE;
}
+ // if not showing ui, use full window to render world view
+ updateWorldViewRect(!show_ui);
+
// Copy screen to a buffer
// crop sides or top and bottom, if taking a snapshot of different aspect ratio
// from window
- S32 snapshot_width = mWindowRectRaw.getWidth();
- S32 snapshot_height = mWindowRectRaw.getHeight();
+ LLRect window_rect = show_ui ? getWindowRectRaw() : getWorldViewRectRaw();
+
+ S32 snapshot_width = window_rect.getWidth();
+ S32 snapshot_height = window_rect.getHeight();
// SNAPSHOT
- S32 window_width = mWindowRectRaw.getWidth();
- S32 window_height = mWindowRectRaw.getHeight();
- LLRect window_rect = mWindowRectRaw;
- BOOL use_fbo = FALSE;
+ S32 window_width = snapshot_width;
+ S32 window_height = snapshot_height;
+
+ // Note: Scaling of the UI is currently *not* supported so we limit the output size if UI is requested
+ if (show_ui)
+ {
+ // If the user wants the UI, limit the output size to the available screen size
+ image_width = llmin(image_width, window_width);
+ image_height = llmin(image_height, window_height);
+ }
- LLRenderTarget target;
F32 scale_factor = 1.0f ;
- if(!keep_window_aspect) //image cropping
- {
+ if (!keep_window_aspect || (image_width > window_width) || (image_height > window_height))
+ {
+ // if image cropping or need to enlarge the scene, compute a scale_factor
F32 ratio = llmin( (F32)window_width / image_width , (F32)window_height / image_height) ;
- snapshot_width = (S32)(ratio * image_width) ;
+ snapshot_width = (S32)(ratio * image_width) ;
snapshot_height = (S32)(ratio * image_height) ;
scale_factor = llmax(1.0f, 1.0f / ratio) ;
}
- else //the scene(window) proportion needs to be maintained.
+
+ if (show_ui && scale_factor > 1.f)
{
- if(image_width > window_width || image_height > window_height) //need to enlarge the scene
- {
- if (!LLPipeline::sRenderDeferred && gGLManager.mHasFramebufferObject && !show_ui)
- {
- GLint max_size = 0;
- glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE_EXT, &max_size);
-
- if (image_width <= max_size && image_height <= max_size) //re-project the scene
- {
- use_fbo = TRUE;
-
- snapshot_width = image_width;
- snapshot_height = image_height;
- target.allocate(snapshot_width, snapshot_height, GL_RGBA, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, TRUE);
- window_width = snapshot_width;
- window_height = snapshot_height;
- scale_factor = 1.f;
- mWindowRectRaw.set(0, snapshot_height, snapshot_width, 0);
- target.bindTarget();
- }
- }
-
- if(!use_fbo) //no re-projection, so tiling the scene
- {
- F32 ratio = llmin( (F32)window_width / image_width , (F32)window_height / image_height) ;
- snapshot_width = (S32)(ratio * image_width) ;
- snapshot_height = (S32)(ratio * image_height) ;
- scale_factor = llmax(1.0f, 1.0f / ratio) ;
- }
- }
- //else: keep the current scene scale, re-scale it if necessary after reading out.
+ // Note: we should never get there...
+ llwarns << "over scaling UI not supported." << llendl;
}
-
- // if not showing ui, use full window to render world view
- updateWorldViewRect(!show_ui);
- S32 buffer_x_offset = llfloor(((window_width - snapshot_width) * scale_factor) / 2.f);
+ S32 buffer_x_offset = llfloor(((window_width - snapshot_width) * scale_factor) / 2.f);
S32 buffer_y_offset = llfloor(((window_height - snapshot_height) * scale_factor) / 2.f);
- S32 image_buffer_x = llfloor(snapshot_width*scale_factor) ;
- S32 image_buffer_y = llfloor(snapshot_height *scale_factor) ;
- if(image_buffer_x > max_size || image_buffer_y > max_size) //boundary check to avoid memory overflow
+ S32 image_buffer_x = llfloor(snapshot_width * scale_factor) ;
+ S32 image_buffer_y = llfloor(snapshot_height * scale_factor) ;
+
+ if ((image_buffer_x > max_size) || (image_buffer_y > max_size)) // boundary check to avoid memory overflow
{
scale_factor *= llmin((F32)max_size / image_buffer_x, (F32)max_size / image_buffer_y) ;
- image_buffer_x = llfloor(snapshot_width*scale_factor) ;
- image_buffer_y = llfloor(snapshot_height *scale_factor) ;
+ image_buffer_x = llfloor(snapshot_width * scale_factor) ;
+ image_buffer_y = llfloor(snapshot_height * scale_factor) ;
}
- if(image_buffer_x > 0 && image_buffer_y > 0)
+ if ((image_buffer_x > 0) && (image_buffer_y > 0))
{
- raw->resize(image_buffer_x, image_buffer_y, 3);
+ raw->resize(image_buffer_x, image_buffer_y, 3);
}
else
{
return FALSE ;
}
- if(raw->isBufferInvalid())
+ if (raw->isBufferInvalid())
{
return FALSE ;
}
BOOL high_res = scale_factor >= 2.f; // Font scaling is slow, only do so if rez is much higher
- if (high_res)
+ if (high_res && show_ui)
{
- send_agent_pause();
+ // Note: we should never get there...
+ llwarns << "High res UI snapshot not supported. " << llendl;
+ /*send_agent_pause();
//rescale fonts
initFonts(scale_factor);
- LLHUDObject::reshapeAll();
+ LLHUDObject::reshapeAll();*/
}
S32 output_buffer_offset_y = 0;
@@ -3973,6 +4239,8 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei
gObjectList.generatePickList(*LLViewerCamera::getInstance());
+ // Subimages are in fact partial rendering of the final view. This happens when the final view is bigger than the screen.
+ // In most common cases, scale_factor is 1 and there's no more than 1 iteration on x and y
for (int subimage_y = 0; subimage_y < scale_factor; ++subimage_y)
{
S32 subimage_y_offset = llclamp(buffer_y_offset - (subimage_y * window_height), 0, window_height);;
@@ -3985,81 +4253,71 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei
{
gDisplaySwapBuffers = FALSE;
gDepthDirty = TRUE;
- if (type == SNAPSHOT_TYPE_OBJECT_ID)
- {
- glClearColor(0.f, 0.f, 0.f, 0.f);
- glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
-
- LLViewerCamera::getInstance()->setZoomParameters(scale_factor, subimage_x+(subimage_y*llceil(scale_factor)));
- setup3DRender();
- gObjectList.renderPickList(gViewerWindow->getWindowRectScaled(), FALSE, FALSE);
- }
- else
- {
- const U32 subfield = subimage_x+(subimage_y*llceil(scale_factor));
-
- if (LLPipeline::sRenderDeferred)
- {
- display(do_rebuild, scale_factor, subfield, TRUE);
- }
- else
- {
- display(do_rebuild, scale_factor, subfield, TRUE);
- // Required for showing the GUI in snapshots and performing bloom composite overlay
- // Call even if show_ui is FALSE
- render_ui(scale_factor, subfield);
- }
- }
S32 subimage_x_offset = llclamp(buffer_x_offset - (subimage_x * window_width), 0, window_width);
// handle fractional rows
U32 read_width = llmax(0, (window_width - subimage_x_offset) -
llmax(0, (window_width * (subimage_x + 1)) - (buffer_x_offset + raw->getWidth())));
- for(U32 out_y = 0; out_y < read_height ; out_y++)
+
+ // Skip rendering and sampling altogether if either width or height is degenerated to 0 (common in cropping cases)
+ if (read_width && read_height)
{
- S32 output_buffer_offset = (
- (out_y * (raw->getWidth())) // ...plus iterated y...
- + (window_width * subimage_x) // ...plus subimage start in x...
- + (raw->getWidth() * window_height * subimage_y) // ...plus subimage start in y...
- - output_buffer_offset_x // ...minus buffer padding x...
- - (output_buffer_offset_y * (raw->getWidth())) // ...minus buffer padding y...
- ) * raw->getComponents();
+ const U32 subfield = subimage_x+(subimage_y*llceil(scale_factor));
+ display(do_rebuild, scale_factor, subfield, TRUE);
- // Ping the wathdog thread every 100 lines to keep us alive (arbitrary number, feel free to change)
- if (out_y % 100 == 0)
+ if (!LLPipeline::sRenderDeferred)
{
- LLAppViewer::instance()->pingMainloopTimeout("LLViewerWindow::rawSnapshot");
+ // Required for showing the GUI in snapshots and performing bloom composite overlay
+ // Call even if show_ui is FALSE
+ render_ui(scale_factor, subfield);
}
- if (type == SNAPSHOT_TYPE_OBJECT_ID || type == SNAPSHOT_TYPE_COLOR)
- {
- glReadPixels(
- subimage_x_offset, out_y + subimage_y_offset,
- read_width, 1,
- GL_RGB, GL_UNSIGNED_BYTE,
- raw->getData() + output_buffer_offset
- );
- }
- else // SNAPSHOT_TYPE_DEPTH
+ for (U32 out_y = 0; out_y < read_height ; out_y++)
{
- LLPointer<LLImageRaw> depth_line_buffer = new LLImageRaw(read_width, 1, sizeof(GL_FLOAT)); // need to store floating point values
- glReadPixels(
- subimage_x_offset, out_y + subimage_y_offset,
- read_width, 1,
- GL_DEPTH_COMPONENT, GL_FLOAT,
- depth_line_buffer->getData()// current output pixel is beginning of buffer...
- );
-
- for (S32 i = 0; i < (S32)read_width; i++)
+ S32 output_buffer_offset = (
+ (out_y * (raw->getWidth())) // ...plus iterated y...
+ + (window_width * subimage_x) // ...plus subimage start in x...
+ + (raw->getWidth() * window_height * subimage_y) // ...plus subimage start in y...
+ - output_buffer_offset_x // ...minus buffer padding x...
+ - (output_buffer_offset_y * (raw->getWidth())) // ...minus buffer padding y...
+ ) * raw->getComponents();
+
+ // Ping the watchdog thread every 100 lines to keep us alive (arbitrary number, feel free to change)
+ if (out_y % 100 == 0)
{
- F32 depth_float = *(F32*)(depth_line_buffer->getData() + (i * sizeof(F32)));
-
- F32 linear_depth_float = 1.f / (depth_conversion_factor_1 - (depth_float * depth_conversion_factor_2));
- U8 depth_byte = F32_to_U8(linear_depth_float, LLViewerCamera::getInstance()->getNear(), LLViewerCamera::getInstance()->getFar());
- //write converted scanline out to result image
- for(S32 j = 0; j < raw->getComponents(); j++)
+ LLAppViewer::instance()->pingMainloopTimeout("LLViewerWindow::rawSnapshot");
+ }
+
+ if (type == SNAPSHOT_TYPE_COLOR)
+ {
+ glReadPixels(
+ subimage_x_offset, out_y + subimage_y_offset,
+ read_width, 1,
+ GL_RGB, GL_UNSIGNED_BYTE,
+ raw->getData() + output_buffer_offset
+ );
+ }
+ else // SNAPSHOT_TYPE_DEPTH
+ {
+ LLPointer<LLImageRaw> depth_line_buffer = new LLImageRaw(read_width, 1, sizeof(GL_FLOAT)); // need to store floating point values
+ glReadPixels(
+ subimage_x_offset, out_y + subimage_y_offset,
+ read_width, 1,
+ GL_DEPTH_COMPONENT, GL_FLOAT,
+ depth_line_buffer->getData()// current output pixel is beginning of buffer...
+ );
+
+ for (S32 i = 0; i < (S32)read_width; i++)
{
- *(raw->getData() + output_buffer_offset + (i * raw->getComponents()) + j) = depth_byte;
+ F32 depth_float = *(F32*)(depth_line_buffer->getData() + (i * sizeof(F32)));
+
+ F32 linear_depth_float = 1.f / (depth_conversion_factor_1 - (depth_float * depth_conversion_factor_2));
+ U8 depth_byte = F32_to_U8(linear_depth_float, LLViewerCamera::getInstance()->getNear(), LLViewerCamera::getInstance()->getFar());
+ // write converted scanline out to result image
+ for (S32 j = 0; j < raw->getComponents(); j++)
+ {
+ *(raw->getData() + output_buffer_offset + (i * raw->getComponents()) + j) = depth_byte;
+ }
}
}
}
@@ -4070,12 +4328,6 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei
output_buffer_offset_y += subimage_y_offset;
}
- if (use_fbo)
- {
- mWindowRectRaw = window_rect;
- target.flush();
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
- }
gDisplaySwapBuffers = FALSE;
gDepthDirty = TRUE;
@@ -4090,11 +4342,11 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei
LLPipeline::sShowHUDAttachments = TRUE;
}
- if (high_res)
+ /*if (high_res)
{
initFonts(1.f);
LLHUDObject::reshapeAll();
- }
+ }*/
// Pre-pad image to number of pixels such that the line length is a multiple of 4 bytes (for BMP encoding)
// Note: this formula depends on the number of components being 3. Not obvious, but it's correct.
@@ -4252,17 +4504,8 @@ void LLViewerWindow::setup3DRender()
void LLViewerWindow::setup3DViewport(S32 x_offset, S32 y_offset)
{
- if (LLRenderTarget::getCurrentBoundTarget() != NULL)
- {
- // don't use translation component of mWorldViewRectRaw, as we are already in a properly sized render target
- gGLViewport[0] = x_offset;
- gGLViewport[1] = y_offset;
- }
- else
- {
- gGLViewport[0] = mWorldViewRectRaw.mLeft + x_offset;
- gGLViewport[1] = mWorldViewRectRaw.mBottom + y_offset;
- }
+ gGLViewport[0] = mWorldViewRectRaw.mLeft + x_offset;
+ gGLViewport[1] = mWorldViewRectRaw.mBottom + y_offset;
gGLViewport[2] = mWorldViewRectRaw.getWidth();
gGLViewport[3] = mWorldViewRectRaw.getHeight();
glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]);
@@ -4415,6 +4658,7 @@ void LLViewerWindow::restoreGL(const std::string& progress_message)
LLVOAvatar::restoreGL();
gResizeScreenTexture = TRUE;
+ gWindowResized = TRUE;
if (isAgentAvatarValid() && !gAgentAvatarp->isUsingBakedTextures())
{
@@ -4492,6 +4736,7 @@ BOOL LLViewerWindow::changeDisplaySettings(LLCoordScreen size, BOOL disable_vsyn
//gResizeScreenTexture = TRUE;
+
//U32 fsaa = gSavedSettings.getU32("RenderFSAASamples");
//U32 old_fsaa = mWindow->getFSAASamples();
@@ -4675,12 +4920,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/llviewerwindow.h b/indra/newview/llviewerwindow.h
index 633c3a41d2..df6928aa1d 100644
--- a/indra/newview/llviewerwindow.h
+++ b/indra/newview/llviewerwindow.h
@@ -38,13 +38,12 @@
#include "v3dmath.h"
#include "v2math.h"
+#include "llcursortypes.h"
#include "llwindowcallbacks.h"
#include "lltimer.h"
#include "llstat.h"
#include "llmousehandler.h"
-#include "llcursortypes.h"
#include "llhandle.h"
-#include "llimage.h"
#include <boost/function.hpp>
#include <boost/signals2.hpp>
@@ -59,6 +58,7 @@ class LLTool;
class LLVelocityBar;
class LLPanel;
class LLImageRaw;
+class LLImageFormatted;
class LLHUDIcon;
class LLWindow;
class LLRootView;
@@ -186,11 +186,6 @@ public:
/*virtual*/ std::string translateString(const char* tag,
const std::map<std::string, std::string>& args);
- // signal on bottom tray width changed
- typedef boost::function<void (void)> bottom_tray_callback_t;
- typedef boost::signals2::signal<void (void)> bottom_tray_signal_t;
- bottom_tray_signal_t mOnBottomTrayWidthChanged;
- boost::signals2::connection setOnBottomTrayWidthChanged(bottom_tray_callback_t cb) { return mOnBottomTrayWidthChanged.connect(cb); }
// signal on update of WorldView rect
typedef boost::function<void (LLRect old_world_rect, LLRect new_world_rect)> world_rect_callback_t;
typedef boost::signals2::signal<void (LLRect old_world_rect, LLRect new_world_rect)> world_rect_signal_t;
@@ -288,6 +283,7 @@ public:
LLView* getNonSideTrayView() { return mNonSideTrayView.get(); }
LLView* getFloaterViewHolder() { return mFloaterViewHolder.get(); }
LLView* getHintHolder() { return mHintHolder.get(); }
+ LLView* getLoginPanelHolder() { return mLoginPanelHolder.get(); }
BOOL handleKey(KEY key, MASK mask);
void handleScrollWheel (S32 clicks);
@@ -316,8 +312,7 @@ public:
typedef enum
{
SNAPSHOT_TYPE_COLOR,
- SNAPSHOT_TYPE_DEPTH,
- SNAPSHOT_TYPE_OBJECT_ID
+ SNAPSHOT_TYPE_DEPTH
} ESnapshotType;
BOOL saveSnapshot(const std::string& filename, S32 image_width, S32 image_height, BOOL show_ui = TRUE, BOOL do_rebuild = FALSE, ESnapshotType type = SNAPSHOT_TYPE_COLOR);
BOOL rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_height, BOOL keep_window_aspect = TRUE, BOOL is_texture = FALSE,
@@ -351,7 +346,9 @@ public:
LLVector3 *intersection = NULL,
LLVector2 *uv = NULL,
LLVector3 *normal = NULL,
- LLVector3 *binormal = NULL);
+ LLVector3 *binormal = NULL,
+ LLVector3* start = NULL,
+ LLVector3* end = NULL);
// Returns a pointer to the last object hit
@@ -448,6 +445,7 @@ protected:
LLHandle<LLView> mNonSideTrayView; // parent of world view + bottom bar, etc...everything but the side tray
LLHandle<LLView> mFloaterViewHolder; // container for floater_view
LLHandle<LLView> mHintHolder; // container for hints
+ LLHandle<LLView> mLoginPanelHolder; // container for login panel
LLPopupView* mPopupView; // container for transient popups
class LLDebugText* mDebugText; // Internal class for debug text
@@ -469,12 +467,6 @@ private:
LLPointer<LLViewerObject> mDragHoveredObject;
};
-void toggle_flying(void*);
-void toggle_first_person();
-void toggle_build(void*);
-void reset_viewer_state_on_sim(void);
-void update_saved_window_size(const std::string& control,S32 delta_width, S32 delta_height);
-
//
// Globals
//
@@ -490,8 +482,8 @@ extern LLVector2 gDebugRaycastTexCoord;
extern LLVector3 gDebugRaycastNormal;
extern LLVector3 gDebugRaycastBinormal;
extern S32 gDebugRaycastFaceHit;
-
-extern S32 CHAT_BAR_HEIGHT;
+extern LLVector3 gDebugRaycastStart;
+extern LLVector3 gDebugRaycastEnd;
extern BOOL gDisplayCameraPos;
extern BOOL gDisplayWindInfo;
diff --git a/indra/newview/llviewerwindowlistener.cpp b/indra/newview/llviewerwindowlistener.cpp
index 4473b5820d..1fe5fc9800 100644
--- a/indra/newview/llviewerwindowlistener.cpp
+++ b/indra/newview/llviewerwindowlistener.cpp
@@ -54,7 +54,7 @@ LLViewerWindowListener::LLViewerWindowListener(LLViewerWindow* llviewerwindow):
// saveSnapshotArgs["type"] = LLSD::String();
add("saveSnapshot",
"Save screenshot: [\"filename\"], [\"width\"], [\"height\"], [\"showui\"], [\"rebuild\"], [\"type\"]\n"
- "type: \"COLOR\", \"DEPTH\", \"OBJECT_ID\"\n"
+ "type: \"COLOR\", \"DEPTH\"\n"
"Post on [\"reply\"] an event containing [\"ok\"]",
&LLViewerWindowListener::saveSnapshot,
saveSnapshotArgs);
@@ -65,13 +65,11 @@ 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
tp(COLOR);
tp(DEPTH);
- tp(OBJECT_ID);
#undef tp
// Our add() call should ensure that the incoming LLSD does in fact
// contain our required arguments. Deal with the optional ones.
@@ -99,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 8738ad7687..ec2b5a4c98 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -38,9 +38,9 @@
#include <ctype.h>
#include "llaudioengine.h"
-#include "llcachename.h"
#include "noise.h"
#include "sound_ids.h"
+#include "raytrace.h"
#include "llagent.h" // Get state values from here
#include "llagentcamera.h"
@@ -48,6 +48,7 @@
#include "llanimationstates.h"
#include "llavatarnamecache.h"
#include "llavatarpropertiesprocessor.h"
+#include "llphysicsmotion.h"
#include "llviewercontrol.h"
#include "llcallingcard.h" // IDEVO for LLAvatarTracker
#include "lldrawpoolavatar.h"
@@ -63,6 +64,8 @@
#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"
@@ -80,6 +83,7 @@
#include "llviewermenu.h"
#include "llviewerobjectlist.h"
#include "llviewerparcelmgr.h"
+#include "llviewershadermgr.h"
#include "llviewerstats.h"
#include "llvoavatarself.h"
#include "llvovolume.h"
@@ -108,6 +112,8 @@ extern F32 ANIM_SPEED_MIN;
#include <boost/lexical_cast.hpp>
+// #define OUTPUT_BREAST_DATA
+
using namespace LLVOAvatarDefines;
//-----------------------------------------------------------------------------
@@ -123,6 +129,7 @@ const LLUUID ANIM_AGENT_HEAD_ROT = LLUUID("e6e8d1dd-e643-fff7-b238-c6b4b056a68d"
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"
//-----------------------------------------------------------------------------
@@ -599,16 +606,16 @@ F32 LLVOAvatar::sRenderDistance = 256.f;
S32 LLVOAvatar::sNumVisibleAvatars = 0;
S32 LLVOAvatar::sNumLODChangesThisFrame = 0;
-const LLUUID LLVOAvatar::sStepSoundOnLand = LLUUID("e8af4a28-aa83-4310-a7c4-c047e15ea0df");
+const LLUUID LLVOAvatar::sStepSoundOnLand("e8af4a28-aa83-4310-a7c4-c047e15ea0df");
const LLUUID LLVOAvatar::sStepSounds[LL_MCODE_END] =
{
- LLUUID(SND_STONE_RUBBER),
- LLUUID(SND_METAL_RUBBER),
- LLUUID(SND_GLASS_RUBBER),
- LLUUID(SND_WOOD_RUBBER),
- LLUUID(SND_FLESH_RUBBER),
- LLUUID(SND_RUBBER_PLASTIC),
- LLUUID(SND_RUBBER_RUBBER)
+ 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;
@@ -620,6 +627,7 @@ 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;
@@ -674,12 +682,14 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
mTexHairColor( NULL ),
mTexEyeColor( NULL ),
mNeedsSkin(FALSE),
+ mLastSkinTime(0.f),
mUpdatePeriod(1),
mFullyLoaded(FALSE),
mPreviousFullyLoaded(FALSE),
mFullyLoadedInitialized(FALSE),
mSupportsAlphaLayers(FALSE),
- mLoadedCallbacksPaused(FALSE)
+ mLoadedCallbacksPaused(FALSE),
+ mHasPelvisOffset( FALSE )
{
LLMemType mt(LLMemType::MTYPE_AVATAR);
//VTResume(); // VTune
@@ -754,6 +764,10 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
mRuthTimer.reset();
mRuthDebugTimer.reset();
mDebugExistenceTimer.reset();
+ mPelvisOffset = LLVector3(0.0f,0.0f,0.0f);
+ mLastPelvisToFoot = 0.0f;
+ mPelvisFixup = 0.0f;
+ mLastPelvisFixup = 0.0f;
}
//------------------------------------------------------------------------
@@ -1144,6 +1158,7 @@ void LLVOAvatar::initClass()
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");
@@ -1282,6 +1297,7 @@ void LLVOAvatar::initInstance(void)
// 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 );
@@ -1295,18 +1311,8 @@ void LLVOAvatar::initInstance(void)
}
- if (gNoRender)
- {
- return;
- }
-
buildCharacter();
- if (gNoRender)
- {
- return;
- }
-
// preload specific motions here
createMotion( ANIM_AGENT_CUSTOMIZE);
createMotion( ANIM_AGENT_CUSTOMIZE_DONE);
@@ -1325,7 +1331,17 @@ const LLVector3 LLVOAvatar::getRenderPosition() const
}
else if (isRoot())
{
- return mDrawable->getPositionAgent();
+ 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
{
@@ -1338,42 +1354,47 @@ void LLVOAvatar::updateDrawable(BOOL force_damped)
clearChanged(SHIFTED);
}
-void LLVOAvatar::onShift(const LLVector3& shift_vector)
+void LLVOAvatar::onShift(const LLVector4a& shift_vector)
{
- mLastAnimExtents[0] += shift_vector;
- mLastAnimExtents[1] += shift_vector;
+ const LLVector3& shift = reinterpret_cast<const LLVector3&>(shift_vector);
+ mLastAnimExtents[0] += shift;
+ mLastAnimExtents[1] += shift;
mNeedsImpostorUpdate = TRUE;
mNeedsAnimUpdate = TRUE;
}
-void LLVOAvatar::updateSpatialExtents(LLVector3& newMin, LLVector3 &newMax)
+void LLVOAvatar::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax)
{
if (isImpostor() && !needsImpostorUpdate())
{
LLVector3 delta = getRenderPosition() -
- ((LLVector3(mDrawable->getPositionGroup())-mImpostorOffset));
+ ((LLVector3(mDrawable->getPositionGroup().getF32ptr())-mImpostorOffset));
- newMin = mLastAnimExtents[0] + delta;
- newMax = mLastAnimExtents[1] + delta;
+ newMin.load3( (mLastAnimExtents[0] + delta).mV);
+ newMax.load3( (mLastAnimExtents[1] + delta).mV);
}
else
{
getSpatialExtents(newMin,newMax);
- mLastAnimExtents[0] = newMin;
- mLastAnimExtents[1] = newMax;
- LLVector3 pos_group = (newMin+newMax)*0.5f;
- mImpostorOffset = pos_group-getRenderPosition();
+ 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(LLVector3& newMin, LLVector3& newMax)
+void LLVOAvatar::getSpatialExtents(LLVector4a& newMin, LLVector4a& newMax)
{
- LLVector3 buffer(0.25f, 0.25f, 0.25f);
- LLVector3 pos = getRenderPosition();
- newMin = pos - buffer;
- newMax = pos + buffer;
- float max_attachment_span = DEFAULT_MAX_PRIM_SCALE * 5.0f;
+ 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)
@@ -1381,12 +1402,20 @@ void LLVOAvatar::getSpatialExtents(LLVector3& newMin, LLVector3& newMax)
LLPolyMesh* mesh = i->second;
for (S32 joint_num = 0; joint_num < mesh->mJointRenderData.count(); joint_num++)
{
- update_min_max(newMin, newMax,
- mesh->mJointRenderData[joint_num]->mWorldMatrix->getTranslation());
+ LLVector4a trans;
+ trans.load3( mesh->mJointRenderData[joint_num]->mWorldMatrix->getTranslation().mV);
+ update_min_max(newMin, newMax, trans);
}
}
- mPixelArea = LLPipeline::calcPixelArea((newMin+newMax)*0.5f, (newMax-newMin)*0.5f, *LLViewerCamera::getInstance());
+ 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();
@@ -1408,20 +1437,22 @@ void LLVOAvatar::getSpatialExtents(LLVector3& newMin, LLVector3& newMax)
if (attached_object && !attached_object->isHUDAttachment())
{
LLDrawable* drawable = attached_object->mDrawable;
- if (drawable)
+ if (drawable && !drawable->isState(LLDrawable::RIGGED))
{
LLSpatialBridge* bridge = drawable->getSpatialBridge();
if (bridge)
{
- const LLVector3* ext = bridge->getSpatialExtents();
- LLVector3 distance = (ext[1] - ext[0]);
+ 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 (distance.mV[0] < max_attachment_span
- && distance.mV[1] < max_attachment_span
- && distance.mV[2] < max_attachment_span)
+ if (lt == 0x7)
{
update_min_max(newMin,newMax,ext[0]);
update_min_max(newMin,newMax,ext[1]);
@@ -1433,8 +1464,9 @@ void LLVOAvatar::getSpatialExtents(LLVector3& newMin, LLVector3& newMax)
}
//pad bounding box
- newMin -= buffer;
- newMax += buffer;
+
+ newMin.sub(buffer);
+ newMax.add(buffer);
}
//-----------------------------------------------------------------------------
@@ -1609,7 +1641,8 @@ BOOL LLVOAvatar::setupBone(const LLVOAvatarBoneInfo* info, LLViewerJoint* parent
info->mRot.mV[VZ], LLQuaternion::XYZ));
joint->setScale(info->mScale);
-
+ joint->setDefaultFromCurrentXform();
+
if (info->mIsJoint)
{
joint->setSkinOffset( info->mPivot );
@@ -1695,6 +1728,7 @@ void LLVOAvatar::startDefaultMotions()
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 );
@@ -1747,12 +1781,6 @@ void LLVOAvatar::buildCharacter()
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;
@@ -1992,26 +2020,29 @@ void LLVOAvatar::updateMeshData()
bool terse_update = false;
- if(facep->mVertexBuffer.isNull())
+ facep->setGeomIndex(0);
+ facep->setIndicesIndex(0);
+
+ LLVertexBuffer* buff = facep->getVertexBuffer();
+ if(!facep->getVertexBuffer())
{
- facep->mVertexBuffer = new LLVertexBufferAvatar();
- facep->mVertexBuffer->allocateBuffer(num_vertices, num_indices, TRUE);
+ buff = new LLVertexBufferAvatar();
+ buff->allocateBuffer(num_vertices, num_indices, TRUE);
+ facep->setVertexBuffer(buff);
}
else
{
- if (facep->mVertexBuffer->getRequestedIndices() == num_indices &&
- facep->mVertexBuffer->getRequestedVerts() == num_vertices)
+ if (buff->getRequestedIndices() == num_indices &&
+ buff->getRequestedVerts() == num_vertices)
{
terse_update = true;
}
else
{
- facep->mVertexBuffer->resizeBuffer(num_vertices, num_indices) ;
- }
+ buff->resizeBuffer(num_vertices, num_indices);
+ }
}
-
- facep->setGeomIndex(0);
- facep->setIndicesIndex(0);
+
// 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)
@@ -2026,7 +2057,7 @@ void LLVOAvatar::updateMeshData()
}
stop_glerror();
- facep->mVertexBuffer->setBuffer(0);
+ buff->setBuffer(0);
if(!f_num)
{
@@ -2106,31 +2137,6 @@ void LLVOAvatar::computeBodySize()
gAgent.sendAgentSetAppearance();
}
}
-
-/* debug spam
- std::cout << "skull = " << skull << std::endl; // adebug
- std::cout << "head = " << head << std::endl; // adebug
- std::cout << "head_scale = " << head_scale << std::endl; // adebug
- std::cout << "neck = " << neck << std::endl; // adebug
- std::cout << "neck_scale = " << neck_scale << std::endl; // adebug
- std::cout << "chest = " << chest << std::endl; // adebug
- std::cout << "chest_scale = " << chest_scale << std::endl; // adebug
- std::cout << "torso = " << torso << std::endl; // adebug
- std::cout << "torso_scale = " << torso_scale << std::endl; // adebug
- std::cout << std::endl; // adebug
-
- std::cout << "pelvis_scale = " << pelvis_scale << std::endl;// adebug
- std::cout << std::endl; // adebug
-
- std::cout << "hip = " << hip << std::endl; // adebug
- std::cout << "hip_scale = " << hip_scale << std::endl; // adebug
- std::cout << "ankle = " << ankle << std::endl; // adebug
- std::cout << "ankle_scale = " << ankle_scale << std::endl; // adebug
- std::cout << "foot = " << foot << std::endl; // adebug
- std::cout << "mBodySize = " << mBodySize << std::endl; // adebug
- std::cout << "mPelvisToFoot = " << mPelvisToFoot << std::endl; // adebug
- std::cout << std::endl; // adebug
-*/
}
//------------------------------------------------------------------------
@@ -2248,7 +2254,7 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
setPixelAreaAndAngle(gAgent);
// force asynchronous drawable update
- if(mDrawable.notNull() && !gNoRender)
+ if(mDrawable.notNull())
{
LLFastTimer t(FTM_JOINT_UPDATE);
@@ -2305,11 +2311,6 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
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);
@@ -2333,8 +2334,19 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled)
{
- // disable voice visualizer when in mouselook
- mVoiceVisualizer->setVoiceEnabled( voice_enabled && !(isSelf() && gAgentCamera.cameraMouselook()) );
+ 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 )
{
//----------------------------------------------------------------
@@ -2413,9 +2425,19 @@ void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled)
// 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)
//--------------------------------------------------------------------------------------------
- LLVector3 headOffset = LLVector3( 0.0f, 0.0f, mHeadOffset.mV[2] );
- mVoiceVisualizer->setVoiceSourceWorldPosition( mRoot.getWorldPosition() + headOffset );
+ 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 )
}
@@ -2479,7 +2501,7 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update)
if (isImpostor() && !mNeedsImpostorUpdate)
{
- LLVector3 ext[2];
+ LLVector4a ext[2];
F32 distance;
LLVector3 angle;
@@ -2508,12 +2530,22 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update)
}
else
{
+ //VECTORIZE THIS
getSpatialExtents(ext[0], ext[1]);
- if ((ext[1]-mImpostorExtents[1]).length() > 0.05f ||
- (ext[0]-mImpostorExtents[0]).length() > 0.05f)
+ 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;
+ }
+ }
}
}
}
@@ -2852,10 +2884,8 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last)
}
LLVector3 name_position = idleUpdateNameTagPosition(root_pos_last);
- mNameText->setPositionAgent(name_position);
-
- idleUpdateNameTagText(new_name);
-
+ mNameText->setPositionAgent(name_position);
+ idleUpdateNameTagText(new_name);
idleUpdateNameTagAlpha(new_name, alpha);
}
@@ -3024,7 +3054,7 @@ void LLVOAvatar::idleUpdateNameTagText(BOOL new_name)
std::deque<LLChat>::iterator chat_iter = mChats.begin();
mNameText->clearString();
- LLColor4 new_chat = LLUIColorTable::instance().getColor( "NameTagChat" );
+ 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)
@@ -3141,8 +3171,9 @@ void LLVOAvatar::invalidateNameTags()
if (avatar->isDead()) continue;
avatar->clearNameTag();
- }
- }
+
+ }
+}
// Compute name tag position during idle update
LLVector3 LLVOAvatar::idleUpdateNameTagPosition(const LLVector3& root_pos_last)
@@ -3161,12 +3192,14 @@ LLVector3 LLVOAvatar::idleUpdateNameTagPosition(const LLVector3& root_pos_last)
local_camera_up.scaleVec(mBodySize * 0.5f);
local_camera_at.scaleVec(mBodySize * 0.5f);
- LLVector3 name_position = mRoot.getWorldPosition() +
- (local_camera_up * root_rot) -
- (projected_vec(local_camera_at * root_rot, camera_to_av));
+ 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)
{
@@ -3271,17 +3304,6 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
}
}
- if (gNoRender)
- {
- // Hack if we're running drones...
- if (isSelf())
- {
- gAgent.setPositionAgent(getPositionAgent());
- }
- return FALSE;
- }
-
-
LLVector3d root_pos_global;
if (!mIsBuilt)
@@ -3298,20 +3320,28 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
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)
+ 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)
@@ -3422,7 +3452,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
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]);
+ 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);
@@ -3436,13 +3466,12 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
// 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
+ mRoot.setWorldPosition( newPosition ); // regular update
}
@@ -3718,7 +3747,6 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
return TRUE;
}
-
//-----------------------------------------------------------------------------
// updateHeadOffset()
//-----------------------------------------------------------------------------
@@ -3743,7 +3771,41 @@ void LLVOAvatar::updateHeadOffset()
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()
//------------------------------------------------------------------------
@@ -3893,6 +3955,46 @@ bool LLVOAvatar::shouldAlphaMask()
}
+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()
//-----------------------------------------------------------------------------
@@ -3907,7 +4009,7 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass)
LLFace* face = mDrawable->getFace(0);
- bool needs_rebuild = !face || face->mVertexBuffer.isNull() || mDrawable->isState(LLDrawable::REBUILD_GEOMETRY);
+ 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
@@ -3940,8 +4042,9 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass)
mMeshLOD[MESH_ID_HAIR]->updateJointGeometry();
}
mNeedsSkin = FALSE;
-
- LLVertexBuffer* vb = mDrawable->getFace(0)->mVertexBuffer;
+ mLastSkinTime = gFrameTimeSeconds;
+
+ LLVertexBuffer* vb = mDrawable->getFace(0)->getVertexBuffer();
if (vb)
{
vb->setBuffer(0);
@@ -3992,7 +4095,7 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass)
// *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 (!gRenderForSelect && sShowFootPlane && mDrawable.notNull())
+ if (sShowFootPlane && mDrawable.notNull())
{
LLVector3 slaved_pos = mDrawable->getPositionAgent();
LLVector3 foot_plane_normal(mFootPlane.mV[VX], mFootPlane.mV[VY], mFootPlane.mV[VZ]);
@@ -4208,7 +4311,7 @@ void LLVOAvatar::updateTextures()
{
BOOL render_avatar = TRUE;
- if (mIsDummy || gNoRender)
+ if (mIsDummy)
{
return;
}
@@ -4288,7 +4391,7 @@ void LLVOAvatar::updateTextures()
if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_AREA))
{
- setDebugText(llformat("%4.0f:%4.0f", fsqrtf(mMinPixelArea),fsqrtf(mMaxPixelArea)));
+ setDebugText(llformat("%4.0f:%4.0f", (F32) sqrt(mMinPixelArea),(F32) sqrt(mMaxPixelArea)));
}
}
@@ -4430,7 +4533,6 @@ void LLVOAvatar::resolveRayCollisionAgent(const LLVector3d start_pt, const LLVec
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);
@@ -4482,11 +4584,6 @@ 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);
@@ -4832,6 +4929,80 @@ LLJoint *LLVOAvatar::getJoint( const std::string &name )
}
//-----------------------------------------------------------------------------
+// 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()
@@ -4881,7 +5052,7 @@ void LLVOAvatar::getGround(const LLVector3 &in_pos_agent, LLVector3 &out_pos_age
LLVector3d z_vec(0.0f, 0.0f, 1.0f);
LLVector3d p0_global, p1_global;
- if (gNoRender || mIsDummy)
+ if (mIsDummy)
{
outNorm.setVec(z_vec);
out_pos_agent = in_pos_agent;
@@ -5453,11 +5624,6 @@ BOOL LLVOAvatar::loadLayersets()
//-----------------------------------------------------------------------------
void LLVOAvatar::updateVisualParams()
{
- if (gNoRender)
- {
- return;
- }
-
setSex( (getVisualParamWeight( "male" ) > 0.5f) ? SEX_MALE : SEX_FEMALE );
LLCharacter::updateVisualParams();
@@ -5493,9 +5659,13 @@ void LLVOAvatar::setPixelAreaAndAngle(LLAgent &agent)
return;
}
- const LLVector3* ext = mDrawable->getSpatialExtents();
- LLVector3 center = (ext[1] + ext[0]) * 0.5f;
- LLVector3 size = (ext[1]-ext[0])*0.5f;
+ 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());
@@ -5507,7 +5677,7 @@ void LLVOAvatar::setPixelAreaAndAngle(LLAgent &agent)
}
else
{
- F32 radius = size.length();
+ F32 radius = size.getLength3().getF32();
mAppAngle = (F32) atan2( radius, range) * RAD_TO_DEG;
}
@@ -5818,6 +5988,52 @@ void LLVOAvatar::resetHUDAttachments()
}
}
+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()
//-----------------------------------------------------------------------------
@@ -5828,14 +6044,23 @@ BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object)
++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;
}
@@ -6188,8 +6413,6 @@ LLMotion* LLVOAvatar::findMotion(const LLUUID& id) const
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++)
{
@@ -6225,11 +6448,9 @@ void LLVOAvatar::updateMeshTextures()
// 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);
@@ -6845,11 +7066,6 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
}
}
- if (gNoRender)
- {
- return;
- }
-
ESex old_sex = getSex();
// llinfos << "LLVOAvatar::processAvatarAppearance()" << llendl;
@@ -7864,6 +8080,7 @@ BOOL LLVOAvatar::LLVOAvatarXmlInfo::parseXmlMorphNodes(LLXmlTreeNode* root)
//virtual
void LLVOAvatar::updateRegion(LLViewerRegion *regionp)
{
+ LLViewerObject::updateRegion(regionp);
}
std::string LLVOAvatar::getFullname() const
@@ -7920,7 +8137,7 @@ BOOL LLVOAvatar::updateLOD()
BOOL res = updateJointLODs();
LLFace* facep = mDrawable->getFace(0);
- if (facep->mVertexBuffer.isNull())
+ if (!facep->getVertexBuffer())
{
dirtyMesh(2);
}
@@ -7932,12 +8149,16 @@ BOOL LLVOAvatar::updateLOD()
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
@@ -7989,9 +8210,9 @@ void LLVOAvatar::cacheImpostorValues()
getImpostorValues(mImpostorExtents, mImpostorAngle, mImpostorDistance);
}
-void LLVOAvatar::getImpostorValues(LLVector3* extents, LLVector3& angle, F32& distance) const
+void LLVOAvatar::getImpostorValues(LLVector4a* extents, LLVector3& angle, F32& distance) const
{
- const LLVector3* ext = mDrawable->getSpatialExtents();
+ const LLVector4a* ext = mDrawable->getSpatialExtents();
extents[0] = ext[0];
extents[1] = ext[1];
@@ -8054,7 +8275,9 @@ void LLVOAvatar::idleUpdateRenderCost()
}
}
}
+
}
+
// 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.
@@ -8094,6 +8317,7 @@ void LLVOAvatar::idleUpdateRenderCost()
}
}
}
+
cost += textures.size() * LLVOVolume::ARC_TEXTURE_COST;
setDebugText(llformat("%d", cost));
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index a779a1735c..295799fd24 100644
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -50,6 +50,7 @@
extern const LLUUID ANIM_AGENT_BODY_NOISE;
extern const LLUUID ANIM_AGENT_BREATHE_ROT;
+extern const LLUUID ANIM_AGENT_PHYSICS_MOTION;
extern const LLUUID ANIM_AGENT_EDITING;
extern const LLUUID ANIM_AGENT_EYE;
extern const LLUUID ANIM_AGENT_FLY_ADJUST;
@@ -122,10 +123,11 @@ public:
virtual BOOL idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time);
virtual BOOL updateLOD();
BOOL updateJointLODs();
+ void updateLODRiggedAttachments( void );
virtual BOOL isActive() const; // Whether this object needs to do an idleUpdate.
virtual void updateTextures();
virtual S32 setTETexture(const U8 te, const LLUUID& uuid); // If setting a baked texture, need to request it from a non-local sim.
- virtual void onShift(const LLVector3& shift_vector);
+ virtual void onShift(const LLVector4a& shift_vector);
virtual U32 getPartitionType() const;
virtual const LLVector3 getRenderPosition() const;
virtual void updateDrawable(BOOL force_damped);
@@ -133,8 +135,8 @@ public:
virtual BOOL updateGeometry(LLDrawable *drawable);
virtual void setPixelAreaAndAngle(LLAgent &agent);
virtual void updateRegion(LLViewerRegion *regionp);
- virtual void updateSpatialExtents(LLVector3& newMin, LLVector3 &newMax);
- virtual void getSpatialExtents(LLVector3& newMin, LLVector3& newMax);
+ virtual void updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax);
+ virtual void getSpatialExtents(LLVector4a& newMin, LLVector4a& newMax);
virtual BOOL lineSegmentIntersect(const LLVector3& start, const LLVector3& end,
S32 face = -1, // which face to check, -1 = ALL_SIDES
BOOL pick_transparent = FALSE,
@@ -166,7 +168,11 @@ public:
virtual LLJoint* getJoint(const std::string &name);
virtual LLJoint* getRootJoint() { return &mRoot; }
-
+
+ void resetJointPositions( void );
+ void resetJointPositionsToDefault( void );
+ void resetSpecificJointPosition( const std::string& name );
+
virtual const char* getAnimationPrefix() { return "avatar"; }
virtual const LLUUID& getID();
virtual LLVector3 getVolumePos(S32 joint_index, LLVector3& volume_offset);
@@ -195,6 +201,10 @@ public:
public:
virtual bool isSelf() const { return false; } // True if this avatar is for this viewer's agent
bool isBuilt() const { return mIsBuilt; }
+
+private: //aligned members
+ LLVector4a mImpostorExtents[2];
+
private:
BOOL mSupportsAlphaLayers; // For backwards compatibility, TRUE for 1.23+ clients
@@ -240,6 +250,7 @@ public:
static BOOL sDebugInvisible;
static BOOL sShowAttachmentPoints;
static F32 sLODFactor; // user-settable LOD factor
+ static F32 sPhysicsLODFactor; // user-settable physics LOD factor
static BOOL sJointDebug; // output total number of joints being touched for each avatar
static BOOL sDebugAvatarRotation;
@@ -283,6 +294,16 @@ protected:
public:
void updateHeadOffset();
F32 getPelvisToFoot() const { return mPelvisToFoot; }
+ void setPelvisOffset( bool hasOffset, const LLVector3& translation, F32 offset ) ;
+ bool hasPelvisOffset( void ) { return mHasPelvisOffset; }
+ void postPelvisSetRecalc( void );
+ void setPelvisOffset( F32 pelvixFixupAmount );
+
+ bool mHasPelvisOffset;
+ LLVector3 mPelvisOffset;
+ F32 mLastPelvisToFoot;
+ F32 mPelvisFixup;
+ F32 mLastPelvisFixup;
LLVector3 mHeadOffset; // current head position
LLViewerJoint mRoot;
@@ -350,6 +371,8 @@ public:
U32 renderImpostor(LLColor4U color = LLColor4U(255,255,255,255), S32 diffuse_channel = 0);
U32 renderRigid();
U32 renderSkinned(EAvatarRenderPass pass);
+ F32 getLastSkinTime() { return mLastSkinTime; }
+ U32 renderSkinnedAttachments();
U32 renderTransparent(BOOL first_pass);
void renderCollisionVolumes();
static void deleteCachedImages(bool clearAll=true);
@@ -361,6 +384,8 @@ private:
bool shouldAlphaMask();
BOOL mNeedsSkin; // avatar has been animated and verts have not been updated
+ F32 mLastSkinTime; //value of gFrameTimeSeconds at last skin update
+
S32 mUpdatePeriod;
S32 mNumInitFaces; //number of faces generated when creating the avatar drawable, does not inculde splitted faces due to long vertex buffer.
@@ -400,7 +425,7 @@ public:
BOOL needsImpostorUpdate() const;
const LLVector3& getImpostorOffset() const;
const LLVector2& getImpostorDim() const;
- void getImpostorValues(LLVector3* extents, LLVector3& angle, F32& distance) const;
+ void getImpostorValues(LLVector4a* extents, LLVector3& angle, F32& distance) const;
void cacheImpostorValues();
void setImpostorDim(const LLVector2& dim);
static void resetImpostors();
@@ -411,7 +436,6 @@ private:
LLVector3 mImpostorOffset;
LLVector2 mImpostorDim;
BOOL mNeedsAnimUpdate;
- LLVector3 mImpostorExtents[2];
LLVector3 mImpostorAngle;
F32 mImpostorDistance;
F32 mImpostorPixelArea;
@@ -669,10 +693,12 @@ public:
void clampAttachmentPositions();
virtual const LLViewerJointAttachment* attachObject(LLViewerObject *viewer_object);
virtual BOOL detachObject(LLViewerObject *viewer_object);
+ void cleanupAttachedMesh( LLViewerObject* pVO );
static LLVOAvatar* findAvatarFromAttachment(LLViewerObject* obj);
protected:
LLViewerJointAttachment* getTargetAttachmentPoint(LLViewerObject* viewer_object);
void lazyAttach();
+ void rebuildRiggedAttachments( void );
//--------------------------------------------------------------------
// Map of attachment points, by ID
@@ -784,6 +810,7 @@ protected:
//--------------------------------------------------------------------
public:
void resolveHeightGlobal(const LLVector3d &inPos, LLVector3d &outPos, LLVector3 &outNorm);
+ bool distanceToGround( const LLVector3d &startPoint, LLVector3d &collisionPoint, F32 distToIntersectionAlongRay );
void resolveHeightAgent(const LLVector3 &inPos, LLVector3 &outPos, LLVector3 &outNorm);
void resolveRayCollisionAgent(const LLVector3d start_pt, const LLVector3d end_pt, LLVector3d &out_pos, LLVector3 &out_norm);
void slamPosition(); // Slam position to transmitted position (for teleport);
diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp
index e5cbf65682..59883e0bb1 100644
--- a/indra/newview/llvoavatarself.cpp
+++ b/indra/newview/llvoavatarself.cpp
@@ -56,6 +56,8 @@
#include "llviewerstats.h"
#include "llviewerregion.h"
#include "llappearancemgr.h"
+#include "llmeshrepository.h"
+#include "llvovolume.h"
#if LL_MSVC
// disable boost::lexical_cast warning
@@ -623,6 +625,7 @@ BOOL LLVOAvatarSelf::updateCharacter(LLAgent &agent)
mScreenp->updateWorldMatrixChildren();
resetHUDAttachments();
}
+
return LLVOAvatar::updateCharacter(agent);
}
@@ -648,7 +651,11 @@ LLJoint *LLVOAvatarSelf::getJoint(const std::string &name)
}
return LLVOAvatar::getJoint(name);
}
-
+//virtual
+void LLVOAvatarSelf::resetJointPositions( void )
+{
+ return LLVOAvatar::resetJointPositions();
+}
// virtual
BOOL LLVOAvatarSelf::setVisualParamWeight(LLVisualParam *which_param, F32 weight, BOOL upload_bake )
{
@@ -783,11 +790,19 @@ void LLVOAvatarSelf::removeMissingBakedTextures()
for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
{
const S32 te = mBakedTextureDatas[i].mTextureIndex;
- LLViewerTexture* tex = getTEImage(te) ;
+ const LLViewerTexture* tex = getTEImage(te);
+
+ // Replace with default if we can't find the asset, assuming the
+ // default is actually valid (which it should be unless something
+ // is seriously wrong).
if (!tex || tex->isMissingAsset())
{
- setTEImage(te, LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT_AVATAR));
- removed = TRUE;
+ LLViewerTexture *imagep = LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT_AVATAR);
+ if (imagep)
+ {
+ setTEImage(te, imagep);
+ removed = TRUE;
+ }
}
}
@@ -806,7 +821,23 @@ void LLVOAvatarSelf::removeMissingBakedTextures()
//virtual
void LLVOAvatarSelf::updateRegion(LLViewerRegion *regionp)
{
+ // Save the global position
+ LLVector3d global_pos_from_old_region = getPositionGlobal();
+
+ // Change the region
setRegion(regionp);
+
+ if (regionp)
+ { // Set correct region-relative position from global coordinates
+ setPositionGlobal(global_pos_from_old_region);
+
+ // Diagnostic info
+ //LLVector3d pos_from_new_region = getPositionGlobal();
+ //llinfos << "pos_from_old_region is " << global_pos_from_old_region
+ // << " while pos_from_new_region is " << pos_from_new_region
+ // << llendl;
+ }
+
if (!regionp || (regionp->getHandle() != mLastRegionHandle))
{
if (mLastRegionHandle != 0)
@@ -820,6 +851,9 @@ void LLVOAvatarSelf::updateRegion(LLViewerRegion *regionp)
F64 max = (mRegionCrossingCount == 1) ? 0 : LLViewerStats::getInstance()->getStat(LLViewerStats::ST_CROSSING_MAX);
max = llmax(delta, max);
LLViewerStats::getInstance()->setStat(LLViewerStats::ST_CROSSING_MAX, max);
+
+ // Diagnostics
+ llinfos << "Region crossing took " << (F32)(delta * 1000.0) << " ms " << llendl;
}
if (regionp)
{
@@ -827,6 +861,7 @@ void LLVOAvatarSelf::updateRegion(LLViewerRegion *regionp)
}
}
mRegionCrossingTimer.reset();
+ LLViewerObject::updateRegion(regionp);
}
//--------------------------------------------------------------------
@@ -989,6 +1024,13 @@ void LLVOAvatarSelf::wearableUpdated( LLWearableType::EType type, BOOL upload_re
}
}
}
+
+ // Physics type has no associated baked textures, but change of params needs to be sent to
+ // other avatars.
+ if (type == LLWearableType::WT_PHYSICS)
+ {
+ gAgent.sendAgentSetAppearance();
+ }
}
//-----------------------------------------------------------------------------
@@ -1104,6 +1146,7 @@ const LLViewerJointAttachment *LLVOAvatarSelf::attachObject(LLViewerObject *view
LLAppearanceMgr::instance().registerAttachment(attachment_id);
// Clear any pending requests once the attachment arrives.
removeAttachmentRequest(attachment_id);
+ updateLODRiggedAttachments();
}
return attachment;
@@ -1113,8 +1156,10 @@ const LLViewerJointAttachment *LLVOAvatarSelf::attachObject(LLViewerObject *view
BOOL LLVOAvatarSelf::detachObject(LLViewerObject *viewer_object)
{
const LLUUID attachment_id = viewer_object->getAttachmentItemID();
- if (LLVOAvatar::detachObject(viewer_object))
+ if ( LLVOAvatar::detachObject(viewer_object) )
{
+ LLVOAvatar::cleanupAttachedMesh( viewer_object );
+
// the simulator should automatically handle permission revocation
stopMotionFromSource(attachment_id);
@@ -2478,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/llvoavatarself.h b/indra/newview/llvoavatarself.h
index 23a799ea3a..51f06dee5f 100644
--- a/indra/newview/llvoavatarself.h
+++ b/indra/newview/llvoavatarself.h
@@ -83,7 +83,9 @@ public:
/*virtual*/ void stopMotionFromSource(const LLUUID& source_id);
/*virtual*/ void requestStopMotion(LLMotion* motion);
/*virtual*/ LLJoint* getJoint(const std::string &name);
-
+
+ void resetJointPositions( void );
+
/*virtual*/ BOOL setVisualParamWeight(LLVisualParam *which_param, F32 weight, BOOL upload_bake = FALSE );
/*virtual*/ BOOL setVisualParamWeight(const char* param_name, F32 weight, BOOL upload_bake = FALSE );
/*virtual*/ BOOL setVisualParamWeight(S32 index, F32 weight, BOOL upload_bake = FALSE );
@@ -123,6 +125,8 @@ public:
//--------------------------------------------------------------------
// Region state
//--------------------------------------------------------------------
+ void resetRegionCrossingTimer() { mRegionCrossingTimer.reset(); }
+
private:
U64 mLastRegionHandle;
LLFrameTimer mRegionCrossingTimer;
diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp
index b1c6ea26cc..b888a263d0 100644
--- a/indra/newview/llvocache.cpp
+++ b/indra/newview/llvocache.cpp
@@ -28,6 +28,7 @@
#include "llvocache.h"
#include "llerror.h"
#include "llregionhandle.h"
+#include "llviewercontrol.h"
BOOL check_read(LLAPRFile* apr_file, void* src, S32 n_bytes)
{
@@ -39,6 +40,7 @@ BOOL check_write(LLAPRFile* apr_file, void* src, S32 n_bytes)
return apr_file->write(src, n_bytes) == n_bytes ;
}
+
//---------------------------------------------------------------------------
// LLVOCacheEntry
//---------------------------------------------------------------------------
@@ -69,6 +71,7 @@ LLVOCacheEntry::LLVOCacheEntry()
}
LLVOCacheEntry::LLVOCacheEntry(LLAPRFile* apr_file)
+ : mBuffer(NULL)
{
S32 size = -1;
BOOL success;
@@ -133,7 +136,10 @@ LLVOCacheEntry::LLVOCacheEntry(LLAPRFile* apr_file)
LLVOCacheEntry::~LLVOCacheEntry()
{
- delete [] mBuffer;
+ if(mBuffer)
+ {
+ delete[] mBuffer;
+ }
}
@@ -211,8 +217,8 @@ BOOL LLVOCacheEntry::writeToFile(LLAPRFile* apr_file) const
if(success)
{
success = check_write(apr_file, (void*)mBuffer, size);
+ }
}
-}
return success ;
}
@@ -223,7 +229,9 @@ BOOL LLVOCacheEntry::writeToFile(LLAPRFile* apr_file) const
// Format string used to construct filename for the object cache
static const char OBJECT_CACHE_FILENAME[] = "objects_%d_%d.slc";
-const U32 NUM_ENTRIES_TO_PURGE = 16 ;
+const U32 MAX_NUM_OBJECT_ENTRIES = 128 ;
+const U32 MIN_ENTRIES_TO_PURGE = 16 ;
+const U32 INVALID_TIME = 0 ;
const char* object_cache_dirname = "objectcache";
const char* header_filename = "object.cache";
@@ -231,11 +239,11 @@ LLVOCache* LLVOCache::sInstance = NULL;
//static
LLVOCache* LLVOCache::getInstance()
-{
+{
if(!sInstance)
{
sInstance = new LLVOCache() ;
-}
+ }
return sInstance ;
}
@@ -261,13 +269,17 @@ LLVOCache::LLVOCache():
mNumEntries(0),
mCacheSize(1)
{
+ mEnabled = gSavedSettings.getBOOL("ObjectCacheEnabled");
mLocalAPRFilePoolp = new LLVolatileAPRPool() ;
}
LLVOCache::~LLVOCache()
{
- writeCacheHeader();
- clearCacheInMemory();
+ if(mEnabled)
+ {
+ writeCacheHeader();
+ clearCacheInMemory();
+ }
delete mLocalAPRFilePoolp;
}
@@ -281,22 +293,27 @@ void LLVOCache::setDirNames(ELLPath location)
void LLVOCache::initCache(ELLPath location, U32 size, U32 cache_version)
{
+ if(!mEnabled)
+ {
+ llwarns << "Not initializing cache: Cache is currently disabled." << llendl;
+ return ;
+ }
+
if(mInitialized)
{
+ llwarns << "Cache already initialized." << llendl;
return ;
}
+ mInitialized = TRUE ;
setDirNames(location);
if (!mReadOnly)
{
LLFile::mkdir(mObjectCacheDirName);
}
-
- mCacheSize = size;
-
+ mCacheSize = llclamp(size, MIN_ENTRIES_TO_PURGE, MAX_NUM_OBJECT_ENTRIES);
mMetaInfo.mVersion = cache_version;
- readCacheHeader();
- mInitialized = TRUE ;
+ readCacheHeader();
if(mMetaInfo.mVersion != cache_version)
{
@@ -316,12 +333,16 @@ void LLVOCache::removeCache(ELLPath location)
{
if(mReadOnly)
{
+ llwarns << "Not removing cache at " << location << ": Cache is currently in read-only mode." << llendl;
return ;
}
+ llinfos << "about to remove the object cache due to settings." << llendl ;
+
std::string delem = gDirUtilp->getDirDelimiter();
std::string mask = delem + "*";
std::string cache_dir = gDirUtilp->getExpandedFilename(location, object_cache_dirname);
+ llinfos << "Removing cache at " << cache_dir << llendl;
gDirUtilp->deleteFilesInDir(cache_dir, mask); //delete all files
LLFile::rmdir(cache_dir);
@@ -334,17 +355,56 @@ void LLVOCache::removeCache()
llassert_always(mInitialized) ;
if(mReadOnly)
{
+ llwarns << "Not clearing object cache: Cache is currently in read-only mode." << llendl;
return ;
}
+ llinfos << "about to remove the object cache due to some error." << llendl ;
+
std::string delem = gDirUtilp->getDirDelimiter();
std::string mask = delem + "*";
+ llinfos << "Removing cache at " << mObjectCacheDirName << llendl;
gDirUtilp->deleteFilesInDir(mObjectCacheDirName, mask);
clearCacheInMemory() ;
writeCacheHeader();
}
+void LLVOCache::removeEntry(HeaderEntryInfo* entry)
+{
+ llassert_always(mInitialized) ;
+ if(mReadOnly)
+ {
+ return ;
+ }
+ if(!entry)
+ {
+ return ;
+ }
+
+ header_entry_queue_t::iterator iter = mHeaderEntryQueue.find(entry) ;
+ if(iter != mHeaderEntryQueue.end())
+ {
+ mHandleEntryMap.erase(entry->mHandle) ;
+ mHeaderEntryQueue.erase(iter) ;
+ removeFromCache(entry) ;
+ delete entry ;
+
+ mNumEntries = mHandleEntryMap.size() ;
+ }
+}
+
+void LLVOCache::removeEntry(U64 handle)
+{
+ handle_entry_map_t::iterator iter = mHandleEntryMap.find(handle) ;
+ if(iter == mHandleEntryMap.end()) //no cache
+ {
+ return ;
+ }
+ HeaderEntryInfo* entry = iter->second ;
+ removeEntry(entry) ;
+}
+
void LLVOCache::clearCacheInMemory()
{
if(!mHeaderEntryQueue.empty())
@@ -357,6 +417,7 @@ void LLVOCache::clearCacheInMemory()
mHandleEntryMap.clear();
mNumEntries = 0 ;
}
+
}
void LLVOCache::getObjectCacheFilename(U64 handle, std::string& filename)
@@ -370,280 +431,326 @@ void LLVOCache::getObjectCacheFilename(U64 handle, std::string& filename)
return ;
}
-void LLVOCache::removeFromCache(U64 handle)
+void LLVOCache::removeFromCache(HeaderEntryInfo* entry)
{
if(mReadOnly)
{
+ llwarns << "Not removing cache for handle " << entry->mHandle << ": Cache is currently in read-only mode." << llendl;
return ;
}
std::string filename;
- getObjectCacheFilename(handle, filename);
- LLAPRFile::remove(filename, mLocalAPRFilePoolp);
+ getObjectCacheFilename(entry->mHandle, filename);
+ LLAPRFile::remove(filename, mLocalAPRFilePoolp);
+ entry->mTime = INVALID_TIME ;
+ updateEntry(entry) ; //update the head file.
}
-BOOL LLVOCache::checkRead(LLAPRFile* apr_file, void* src, S32 n_bytes)
-{
- if(!check_read(apr_file, src, n_bytes))
- {
- delete apr_file ;
- removeCache() ;
- return FALSE ;
- }
-
- return TRUE ;
-}
-
-BOOL LLVOCache::checkWrite(LLAPRFile* apr_file, void* src, S32 n_bytes)
+void LLVOCache::readCacheHeader()
{
- if(!check_write(apr_file, src, n_bytes))
+ if(!mEnabled)
{
- delete apr_file ;
- removeCache() ;
- return FALSE ;
+ llwarns << "Not reading cache header: Cache is currently disabled." << llendl;
+ return;
}
- return TRUE ;
-}
-
-void LLVOCache::readCacheHeader()
-{
//clear stale info.
clearCacheInMemory();
+ bool success = true ;
if (LLAPRFile::isExist(mHeaderFileName, mLocalAPRFilePoolp))
{
- LLAPRFile* apr_file = new LLAPRFile(mHeaderFileName, APR_READ|APR_BINARY, mLocalAPRFilePoolp);
+ LLAPRFile apr_file(mHeaderFileName, APR_READ|APR_BINARY, mLocalAPRFilePoolp);
//read the meta element
- if(!checkRead(apr_file, &mMetaInfo, sizeof(HeaderMetaInfo)))
- {
- return ;
- }
-
- HeaderEntryInfo* entry ;
- mNumEntries = 0 ;
- while(mNumEntries < mCacheSize)
+ success = check_read(&apr_file, &mMetaInfo, sizeof(HeaderMetaInfo)) ;
+
+ if(success)
{
- entry = new HeaderEntryInfo() ;
- if(!checkRead(apr_file, entry, sizeof(HeaderEntryInfo)))
+ HeaderEntryInfo* entry = NULL ;
+ mNumEntries = 0 ;
+ U32 num_read = 0 ;
+ while(num_read++ < MAX_NUM_OBJECT_ENTRIES)
{
- delete entry ;
- return ;
+ if(!entry)
+ {
+ entry = new HeaderEntryInfo() ;
+ }
+ success = check_read(&apr_file, entry, sizeof(HeaderEntryInfo));
+
+ if(!success) //failed
+ {
+ llwarns << "Error reading cache header entry. (entry_index=" << mNumEntries << ")" << llendl;
+ delete entry ;
+ entry = NULL ;
+ break ;
+ }
+ else if(entry->mTime == INVALID_TIME)
+ {
+ continue ; //an empty entry
+ }
+
+ entry->mIndex = mNumEntries++ ;
+ mHeaderEntryQueue.insert(entry) ;
+ mHandleEntryMap[entry->mHandle] = entry ;
+ entry = NULL ;
}
- else if(!entry->mTime) //end of the cache.
+ if(entry)
{
delete entry ;
- return ;
}
-
- entry->mIndex = mNumEntries++ ;
- mHeaderEntryQueue.insert(entry) ;
- mHandleEntryMap[entry->mHandle] = entry ;
}
- delete apr_file ;
+ //---------
+ //debug code
+ //----------
+ //std::string name ;
+ //for(header_entry_queue_t::iterator iter = mHeaderEntryQueue.begin() ; success && iter != mHeaderEntryQueue.end(); ++iter)
+ //{
+ // getObjectCacheFilename((*iter)->mHandle, name) ;
+ // llinfos << name << llendl ;
+ //}
+ //-----------
}
else
{
writeCacheHeader() ;
}
+
+ if(!success)
+ {
+ removeCache() ; //failed to read header, clear the cache
+ }
+ else if(mNumEntries >= mCacheSize)
+ {
+ purgeEntries(mCacheSize) ;
+ }
+
+ return ;
}
void LLVOCache::writeCacheHeader()
{
- if(mReadOnly)
+ if (!mEnabled)
{
- return ;
- }
-
- LLAPRFile* apr_file = new LLAPRFile(mHeaderFileName, APR_CREATE|APR_WRITE|APR_BINARY, mLocalAPRFilePoolp);
+ llwarns << "Not writing cache header: Cache is currently disabled." << llendl;
+ return;
+ }
- //write the meta element
- if(!checkWrite(apr_file, &mMetaInfo, sizeof(HeaderMetaInfo)))
+ if(mReadOnly)
{
- return ;
+ llwarns << "Not writing cache header: Cache is currently in read-only mode." << llendl;
+ return;
}
- mNumEntries = 0 ;
- for(header_entry_queue_t::iterator iter = mHeaderEntryQueue.begin() ; iter != mHeaderEntryQueue.end(); ++iter)
+ bool success = true ;
{
- (*iter)->mIndex = mNumEntries++ ;
- if(!checkWrite(apr_file, (void*)*iter, sizeof(HeaderEntryInfo)))
+ LLAPRFile apr_file(mHeaderFileName, APR_CREATE|APR_WRITE|APR_BINARY, mLocalAPRFilePoolp);
+
+ //write the meta element
+ success = check_write(&apr_file, &mMetaInfo, sizeof(HeaderMetaInfo)) ;
+
+
+ mNumEntries = 0 ;
+ for(header_entry_queue_t::iterator iter = mHeaderEntryQueue.begin() ; success && iter != mHeaderEntryQueue.end(); ++iter)
{
- return ;
+ (*iter)->mIndex = mNumEntries++ ;
+ success = check_write(&apr_file, (void*)*iter, sizeof(HeaderEntryInfo));
}
- }
-
- mNumEntries = mHeaderEntryQueue.size() ;
- if(mNumEntries < mCacheSize)
- {
- HeaderEntryInfo* entry = new HeaderEntryInfo() ;
- for(U32 i = mNumEntries ; i < mCacheSize; i++)
+
+ mNumEntries = mHeaderEntryQueue.size() ;
+ if(success && mNumEntries < MAX_NUM_OBJECT_ENTRIES)
{
- //fill the cache with the default entry.
- if(!checkWrite(apr_file, entry, sizeof(HeaderEntryInfo)))
+ HeaderEntryInfo* entry = new HeaderEntryInfo() ;
+ entry->mTime = INVALID_TIME ;
+ for(S32 i = mNumEntries ; success && i < MAX_NUM_OBJECT_ENTRIES ; i++)
{
- mReadOnly = TRUE ; //disable the cache.
- return ;
+ //fill the cache with the default entry.
+ success = check_write(&apr_file, entry, sizeof(HeaderEntryInfo)) ;
+
}
+ delete entry ;
}
- delete entry ;
}
- delete apr_file ;
+
+ if(!success)
+ {
+ clearCacheInMemory() ;
+ mReadOnly = TRUE ; //disable the cache.
+ }
+ return ;
}
BOOL LLVOCache::updateEntry(const HeaderEntryInfo* entry)
{
- LLAPRFile* apr_file = new LLAPRFile(mHeaderFileName, APR_WRITE|APR_BINARY, mLocalAPRFilePoolp);
- apr_file->seek(APR_SET, entry->mIndex * sizeof(HeaderEntryInfo) + sizeof(HeaderMetaInfo)) ;
+ LLAPRFile apr_file(mHeaderFileName, APR_WRITE|APR_BINARY, mLocalAPRFilePoolp);
+ apr_file.seek(APR_SET, entry->mIndex * sizeof(HeaderEntryInfo) + sizeof(HeaderMetaInfo)) ;
- return checkWrite(apr_file, (void*)entry, sizeof(HeaderEntryInfo)) ;
+ return check_write(&apr_file, (void*)entry, sizeof(HeaderEntryInfo)) ;
}
void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_entry_map_t& cache_entry_map)
{
+ if(!mEnabled)
+ {
+ llwarns << "Not reading cache for handle " << handle << "): Cache is currently disabled." << llendl;
+ return ;
+ }
llassert_always(mInitialized);
handle_entry_map_t::iterator iter = mHandleEntryMap.find(handle) ;
if(iter == mHandleEntryMap.end()) //no cache
{
+ llwarns << "No handle map entry for " << handle << llendl;
return ;
}
- std::string filename;
- getObjectCacheFilename(handle, filename);
- LLAPRFile* apr_file = new LLAPRFile(filename, APR_READ|APR_BINARY, mLocalAPRFilePoolp);
-
- LLUUID cache_id ;
- if(!checkRead(apr_file, cache_id.mData, UUID_BYTES))
+ bool success = true ;
{
- return ;
- }
- if(cache_id != id)
- {
- llinfos << "Cache ID doesn't match for this region, discarding"<< llendl;
-
- delete apr_file ;
- return ;
- }
+ std::string filename;
+ getObjectCacheFilename(handle, filename);
+ LLAPRFile apr_file(filename, APR_READ|APR_BINARY, mLocalAPRFilePoolp);
+
+ LLUUID cache_id ;
+ success = check_read(&apr_file, cache_id.mData, UUID_BYTES) ;
+
+ if(success)
+ {
+ if(cache_id != id)
+ {
+ llinfos << "Cache ID doesn't match for this region, discarding"<< llendl;
+ success = false ;
+ }
- S32 num_entries;
- if(!checkRead(apr_file, &num_entries, sizeof(S32)))
- {
- return ;
+ if(success)
+ {
+ S32 num_entries;
+ success = check_read(&apr_file, &num_entries, sizeof(S32)) ;
+
+ for (S32 i = 0; success && i < num_entries; i++)
+ {
+ LLVOCacheEntry* entry = new LLVOCacheEntry(&apr_file);
+ if (!entry->getLocalID())
+ {
+ llwarns << "Aborting cache file load for " << filename << ", cache file corruption!" << llendl;
+ delete entry ;
+ success = false ;
+ }
+ cache_entry_map[entry->getLocalID()] = entry;
+ }
+ }
+ }
}
- for (S32 i = 0; i < num_entries; i++)
+ if(!success)
{
- LLVOCacheEntry* entry = new LLVOCacheEntry(apr_file);
- if (!entry->getLocalID())
+ if(cache_entry_map.empty())
{
- llwarns << "Aborting cache file load for " << filename << ", cache file corruption!" << llendl;
- delete entry ;
- break;
+ removeEntry(iter->second) ;
}
- cache_entry_map[entry->getLocalID()] = entry;
}
- num_entries = cache_entry_map.size() ;
- delete apr_file ;
return ;
}
-void LLVOCache::purgeEntries()
+void LLVOCache::purgeEntries(U32 size)
{
- U32 limit = mCacheSize - NUM_ENTRIES_TO_PURGE ;
- while(mHeaderEntryQueue.size() > limit)
+ while(mHeaderEntryQueue.size() > size)
{
header_entry_queue_t::iterator iter = mHeaderEntryQueue.begin() ;
- HeaderEntryInfo* entry = *iter ;
-
- removeFromCache(entry->mHandle) ;
- mHandleEntryMap.erase(entry->mHandle) ;
+ HeaderEntryInfo* entry = *iter ;
+ mHandleEntryMap.erase(entry->mHandle);
mHeaderEntryQueue.erase(iter) ;
- delete entry ;
+ removeFromCache(entry) ;
+ delete entry;
}
-
- writeCacheHeader() ;
- readCacheHeader() ;
mNumEntries = mHandleEntryMap.size() ;
}
void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry::vocache_entry_map_t& cache_entry_map, BOOL dirty_cache)
{
+ if(!mEnabled)
+ {
+ llwarns << "Not writing cache for handle " << handle << "): Cache is currently disabled." << llendl;
+ return ;
+ }
llassert_always(mInitialized);
if(mReadOnly)
{
+ llwarns << "Not writing cache for handle " << handle << "): Cache is currently in read-only mode." << llendl;
return ;
- }
+ }
HeaderEntryInfo* entry;
handle_entry_map_t::iterator iter = mHandleEntryMap.find(handle) ;
if(iter == mHandleEntryMap.end()) //new entry
- {
- if(mNumEntries >= mCacheSize)
+ {
+ if(mNumEntries >= mCacheSize - 1)
{
- purgeEntries() ;
+ purgeEntries(mCacheSize - 1) ;
}
-
+
entry = new HeaderEntryInfo();
entry->mHandle = handle ;
entry->mTime = time(NULL) ;
- entry->mIndex = mNumEntries++ ;
+ entry->mIndex = mNumEntries++;
mHeaderEntryQueue.insert(entry) ;
mHandleEntryMap[handle] = entry ;
}
else
{
- entry = iter->second ;
- entry->mTime = time(NULL) ;
+ // Update access time.
+ entry = iter->second ;
//resort
mHeaderEntryQueue.erase(entry) ;
+
+ entry->mTime = time(NULL) ;
mHeaderEntryQueue.insert(entry) ;
}
//update cache header
if(!updateEntry(entry))
{
+ llwarns << "Failed to update cache header index " << entry->mIndex << ". handle = " << handle << llendl;
return ; //update failed.
}
if(!dirty_cache)
{
+ llwarns << "Skipping write to cache for handle " << handle << ": cache not dirty" << llendl;
return ; //nothing changed, no need to update.
}
//write to cache file
- std::string filename;
- getObjectCacheFilename(handle, filename);
- LLAPRFile* apr_file = new LLAPRFile(filename, APR_CREATE|APR_WRITE|APR_BINARY, mLocalAPRFilePoolp);
-
- if(!checkWrite(apr_file, (void*)id.mData, UUID_BYTES))
+ bool success = true ;
{
- return ;
- }
+ std::string filename;
+ getObjectCacheFilename(handle, filename);
+ LLAPRFile apr_file(filename, APR_CREATE|APR_WRITE|APR_BINARY, mLocalAPRFilePoolp);
+
+ success = check_write(&apr_file, (void*)id.mData, UUID_BYTES) ;
- S32 num_entries = cache_entry_map.size() ;
- if(!checkWrite(apr_file, &num_entries, sizeof(S32)))
- {
- return ;
+
+ if(success)
+ {
+ S32 num_entries = cache_entry_map.size() ;
+ success = check_write(&apr_file, &num_entries, sizeof(S32));
+
+ for (LLVOCacheEntry::vocache_entry_map_t::const_iterator iter = cache_entry_map.begin(); success && iter != cache_entry_map.end(); ++iter)
+ {
+ success = iter->second->writeToFile(&apr_file) ;
+ }
+ }
}
- for (LLVOCacheEntry::vocache_entry_map_t::const_iterator iter = cache_entry_map.begin(); iter != cache_entry_map.end(); ++iter)
+ if(!success)
{
- if(!iter->second->writeToFile(apr_file))
- {
- //failed
- delete apr_file ;
- removeCache() ;
- return ;
- }
+ removeEntry(entry) ;
+
}
- delete apr_file ;
return ;
}
diff --git a/indra/newview/llvocache.h b/indra/newview/llvocache.h
index ccdff5e96c..14e3b4c793 100644
--- a/indra/newview/llvocache.h
+++ b/indra/newview/llvocache.h
@@ -95,7 +95,12 @@ private:
{
bool operator()(const HeaderEntryInfo* lhs, const HeaderEntryInfo* rhs) const
{
- return lhs->mTime < rhs->mTime; // older entry in front of queue (set)
+ if(lhs->mTime == rhs->mTime)
+ {
+ return lhs < rhs ;
+ }
+
+ return lhs->mTime < rhs->mTime ; // older entry in front of queue (set)
}
};
typedef std::set<HeaderEntryInfo*, header_entry_less> header_entry_queue_t;
@@ -111,6 +116,7 @@ public:
void readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_entry_map_t& cache_entry_map) ;
void writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry::vocache_entry_map_t& cache_entry_map, BOOL dirty_cache) ;
+ void removeEntry(U64 handle) ;
void setReadOnly(BOOL read_only) {mReadOnly = read_only;}
@@ -118,17 +124,17 @@ private:
void setDirNames(ELLPath location);
// determine the cache filename for the region from the region handle
void getObjectCacheFilename(U64 handle, std::string& filename);
- void removeFromCache(U64 handle);
+ void removeFromCache(HeaderEntryInfo* entry);
void readCacheHeader();
void writeCacheHeader();
void clearCacheInMemory();
void removeCache() ;
- void purgeEntries();
+ void removeEntry(HeaderEntryInfo* entry) ;
+ void purgeEntries(U32 size);
BOOL updateEntry(const HeaderEntryInfo* entry);
- BOOL checkRead(LLAPRFile* apr_file, void* src, S32 n_bytes) ;
- BOOL checkWrite(LLAPRFile* apr_file, void* src, S32 n_bytes) ;
private:
+ BOOL mEnabled;
BOOL mInitialized ;
BOOL mReadOnly ;
HeaderMetaInfo mMetaInfo;
@@ -143,7 +149,7 @@ private:
static LLVOCache* sInstance ;
public:
static LLVOCache* getInstance() ;
- static BOOL hasInstance() ;
+ static BOOL hasInstance() ;
static void destroyClass() ;
};
diff --git a/indra/newview/llvograss.cpp b/indra/newview/llvograss.cpp
index f57f7b67ea..32822e1181 100644
--- a/indra/newview/llvograss.cpp
+++ b/indra/newview/llvograss.cpp
@@ -340,7 +340,7 @@ void LLVOGrass::updateTextures()
{
if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_AREA))
{
- setDebugText(llformat("%4.0f", fsqrtf(mPixelArea)));
+ setDebugText(llformat("%4.0f", (F32) sqrt(mPixelArea)));
}
getTEImage(0)->addTextureStats(mPixelArea);
}
@@ -453,7 +453,7 @@ void LLVOGrass::plantBlades()
face->setTexture(getTEImage(0));
face->setState(LLFace::GLOBAL);
face->setSize(mNumBlades * 8, mNumBlades * 12);
- face->mVertexBuffer = NULL;
+ face->setVertexBuffer(NULL);
face->setTEOffset(0);
face->mCenterLocal = mPosition + mRegionp->getOriginAgent();
@@ -640,7 +640,7 @@ BOOL LLVOGrass::lineSegmentIntersect(const LLVector3& start, const LLVector3& en
LLVector2 tc[4];
LLVector3 v[4];
- // LLVector3 n[4]; // unused!
+ //LLVector3 n[4];
F32 closest_t = 1.f;
@@ -686,7 +686,6 @@ BOOL LLVOGrass::lineSegmentIntersect(const LLVector3& start, const LLVector3& en
position.mV[2] += blade_height;
v[3] = v1 = position + mRegionp->getOriginAgent();
-
F32 a,b,t;
BOOL hit = FALSE;
@@ -694,23 +693,23 @@ BOOL LLVOGrass::lineSegmentIntersect(const LLVector3& start, const LLVector3& en
U32 idx0 = 0,idx1 = 0,idx2 = 0;
- if (LLTriangleRayIntersect(v[0], v[1], v[2], start, dir, &a, &b, &t, FALSE))
+ if (LLTriangleRayIntersect(v[0], v[1], v[2], start, dir, a, b, t, FALSE))
{
hit = TRUE;
idx0 = 0; idx1 = 1; idx2 = 2;
}
- else if (LLTriangleRayIntersect(v[1], v[3], v[2], start, dir, &a, &b, &t, FALSE))
+ else if (LLTriangleRayIntersect(v[1], v[3], v[2], start, dir, a, b, t, FALSE))
{
hit = TRUE;
idx0 = 1; idx1 = 3; idx2 = 2;
}
- else if (LLTriangleRayIntersect(v[2], v[1], v[0], start, dir, &a, &b, &t, FALSE))
+ else if (LLTriangleRayIntersect(v[2], v[1], v[0], start, dir, a, b, t, FALSE))
{
normal1 = -normal1;
hit = TRUE;
idx0 = 2; idx1 = 1; idx2 = 0;
}
- else if (LLTriangleRayIntersect(v[2], v[3], v[1], start, dir, &a, &b, &t, FALSE))
+ else if (LLTriangleRayIntersect(v[2], v[3], v[1], start, dir, a, b, t, FALSE))
{
normal1 = -normal1;
hit = TRUE;
diff --git a/indra/newview/llvoground.cpp b/indra/newview/llvoground.cpp
index f032ae8780..ce256fdedf 100644
--- a/indra/newview/llvoground.cpp
+++ b/indra/newview/llvoground.cpp
@@ -97,13 +97,14 @@ BOOL LLVOGround::updateGeometry(LLDrawable *drawable)
drawable->addFace(poolp, NULL);
face = drawable->getFace(0);
- if (face->mVertexBuffer.isNull())
+ if (!face->getVertexBuffer())
{
face->setSize(5, 12);
- face->mVertexBuffer = new LLVertexBuffer(LLDrawPoolGround::VERTEX_DATA_MASK, GL_STREAM_DRAW_ARB);
- face->mVertexBuffer->allocateBuffer(face->getGeomCount(), face->getIndicesCount(), TRUE);
+ LLVertexBuffer* buff = new LLVertexBuffer(LLDrawPoolGround::VERTEX_DATA_MASK, GL_STREAM_DRAW_ARB);
+ buff->allocateBuffer(face->getGeomCount(), face->getIndicesCount(), TRUE);
face->setGeomIndex(0);
face->setIndicesIndex(0);
+ face->setVertexBuffer(buff);
}
index_offset = face->getGeometry(verticesp,normalsp,texCoordsp, indicesp);
@@ -161,7 +162,7 @@ BOOL LLVOGround::updateGeometry(LLDrawable *drawable)
*(texCoordsp++) = LLVector2(0.f, 1.f);
*(texCoordsp++) = LLVector2(0.5f, 0.5f);
- face->mVertexBuffer->setBuffer(0);
+ face->getVertexBuffer()->setBuffer(0);
LLPipeline::sCompiles++;
return TRUE;
}
diff --git a/indra/newview/llvoicecallhandler.cpp b/indra/newview/llvoicecallhandler.cpp
new file mode 100644
index 0000000000..2050dab689
--- /dev/null
+++ b/indra/newview/llvoicecallhandler.cpp
@@ -0,0 +1,69 @@
+ /**
+ * @file llvoicecallhandler.cpp
+ * @brief slapp to handle avatar to avatar voice call.
+ *
+ * $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 "llcommandhandler.h"
+#include "llavataractions.h"
+#include "llnotificationsutil.h"
+#include "llui.h"
+
+class LLVoiceCallAvatarHandler : public LLCommandHandler
+{
+public:
+ // requires trusted browser to trigger
+ LLVoiceCallAvatarHandler() : LLCommandHandler("voicecallavatar", UNTRUSTED_THROTTLE)
+ {
+ }
+
+ bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web)
+ {
+ if (!LLUI::sSettingGroups["config"]->getBOOL("EnableVoiceCall"))
+ {
+ LLNotificationsUtil::add("NoVoiceCall", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit"));
+ return true;
+ }
+
+ //Make sure we have some parameters
+ if (params.size() == 0)
+ {
+ return false;
+ }
+
+ //Get the ID
+ LLUUID id;
+ if (!id.set( params[0], FALSE ))
+ {
+ return false;
+ }
+
+ //instigate call with this avatar
+ LLAvatarActions::startCall( id );
+ return true;
+ }
+};
+
+LLVoiceCallAvatarHandler gVoiceCallAvatarHandler;
+
diff --git a/indra/newview/llvoicechannel.cpp b/indra/newview/llvoicechannel.cpp
index b692093fb9..bd12328a6b 100644
--- a/indra/newview/llvoicechannel.cpp
+++ b/indra/newview/llvoicechannel.cpp
@@ -412,6 +412,7 @@ void LLVoiceChannel::doSetState(const EState& new_state)
{
EState old_state = mState;
mState = new_state;
+
if (!mStateChangedCallback.empty())
mStateChangedCallback(old_state, mState, mCallDirection, mCallEndedByAgent);
}
@@ -846,14 +847,19 @@ void LLVoiceChannelP2P::activate()
// otherwise answering the call
else
{
- LLVoiceClient::getInstance()->answerInvite(mSessionHandle);
-
+ if (!LLVoiceClient::getInstance()->answerInvite(mSessionHandle))
+ {
+ mCallEndedByAgent = false;
+ mSessionHandle.clear();
+ handleError(ERROR_UNKNOWN);
+ return;
+ }
// using the session handle invalidates it. Clear it out here so we can't reuse it by accident.
mSessionHandle.clear();
}
// Add the party to the list of people with which we've recently interacted.
- LLRecentPeople::instance().add(mOtherUserID);
+ addToTheRecentPeopleList();
//Default mic is ON on initiating/joining P2P calls
if (!LLVoiceClient::getInstance()->getUserPTTState() && LLVoiceClient::getInstance()->getPTTIsToggle())
@@ -938,3 +944,25 @@ void LLVoiceChannelP2P::setState(EState state)
LLVoiceChannel::setState(state);
}
+
+void LLVoiceChannelP2P::addToTheRecentPeopleList()
+{
+ bool avaline_call = LLIMModel::getInstance()->findIMSession(mSessionID)->isAvalineSessionType();
+
+ if (avaline_call)
+ {
+ LLSD call_data;
+ std::string call_number = LLVoiceChannel::getSessionName();
+
+ call_data["avaline_call"] = true;
+ call_data["session_id"] = mSessionID;
+ call_data["call_number"] = call_number;
+ call_data["date"] = LLDate::now();
+
+ LLRecentPeople::instance().add(mOtherUserID, call_data);
+ }
+ else
+ {
+ LLRecentPeople::instance().add(mOtherUserID);
+ }
+}
diff --git a/indra/newview/llvoicechannel.h b/indra/newview/llvoicechannel.h
index 7cef3c13d1..b8597ee5cb 100644
--- a/indra/newview/llvoicechannel.h
+++ b/indra/newview/llvoicechannel.h
@@ -191,6 +191,13 @@ protected:
virtual void setState(EState state);
private:
+
+ /**
+ * Add the caller to the list of people with which we've recently interacted
+ *
+ **/
+ void addToTheRecentPeopleList();
+
std::string mSessionHandle;
LLUUID mOtherUserID;
BOOL mReceivedCall;
diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp
index 6c44f639ec..730f022c50 100644
--- a/indra/newview/llvoiceclient.cpp
+++ b/indra/newview/llvoiceclient.cpp
@@ -35,6 +35,7 @@
#include "llnotificationsutil.h"
#include "llsdserialize.h"
#include "llui.h"
+#include "llkeyboard.h"
const F32 LLVoiceClient::OVERDRIVEN_POWER_LEVEL = 0.7f;
@@ -113,8 +114,18 @@ LLVoiceClient::LLVoiceClient()
mVoiceModule(NULL),
m_servicePump(NULL),
mVoiceEffectEnabled(LLCachedControl<bool>(gSavedSettings, "VoiceMorphingEnabled")),
- mVoiceEffectDefault(LLCachedControl<std::string>(gSavedPerAccountSettings, "VoiceEffectDefault"))
+ mVoiceEffectDefault(LLCachedControl<std::string>(gSavedPerAccountSettings, "VoiceEffectDefault")),
+ mPTTDirty(true),
+ mPTT(true),
+ mUsePTT(true),
+ mPTTIsMiddleMouse(false),
+ mPTTKey(0),
+ mPTTIsToggle(false),
+ mUserPTTState(false),
+ mMuteMic(false),
+ mDisableMic(false)
{
+ updateSettings();
}
//---------------------------------------------------
@@ -173,6 +184,14 @@ const LLVoiceVersionInfo LLVoiceClient::getVersion()
void LLVoiceClient::updateSettings()
{
+ setUsePTT(gSavedSettings.getBOOL("PTTCurrentlyEnabled"));
+ std::string keyString = gSavedSettings.getString("PushToTalkButton");
+ setPTTKey(keyString);
+ setPTTIsToggle(gSavedSettings.getBOOL("PushToTalkToggle"));
+ mDisableMic = gSavedSettings.getBOOL("VoiceDisableMic");
+
+ updateMicMuteLogic();
+
if (mVoiceModule) mVoiceModule->updateSettings();
}
@@ -481,6 +500,26 @@ void LLVoiceClient::setVoiceEnabled(bool enabled)
if (mVoiceModule) mVoiceModule->setVoiceEnabled(enabled);
}
+void LLVoiceClient::updateMicMuteLogic()
+{
+ // If not configured to use PTT, the mic should be open (otherwise the user will be unable to speak).
+ bool new_mic_mute = false;
+
+ if(mUsePTT)
+ {
+ // If configured to use PTT, track the user state.
+ new_mic_mute = !mUserPTTState;
+ }
+
+ if(mMuteMic || mDisableMic)
+ {
+ // Either of these always overrides any other PTT setting.
+ new_mic_mute = true;
+ }
+
+ if (mVoiceModule) mVoiceModule->setMuteMic(new_mic_mute);
+}
+
void LLVoiceClient::setLipSyncEnabled(BOOL enabled)
{
if (mVoiceModule) mVoiceModule->setLipSyncEnabled(enabled);
@@ -500,7 +539,8 @@ BOOL LLVoiceClient::lipSyncEnabled()
void LLVoiceClient::setMuteMic(bool muted)
{
- if (mVoiceModule) mVoiceModule->setMuteMic(muted);
+ mMuteMic = muted;
+ updateMicMuteLogic();
}
@@ -509,64 +549,116 @@ void LLVoiceClient::setMuteMic(bool muted)
void LLVoiceClient::setUserPTTState(bool ptt)
{
- if (mVoiceModule) mVoiceModule->setUserPTTState(ptt);
+ mUserPTTState = ptt;
+ updateMicMuteLogic();
}
bool LLVoiceClient::getUserPTTState()
{
- if (mVoiceModule)
- {
- return mVoiceModule->getUserPTTState();
- }
- else
- {
- return false;
- }
+ return mUserPTTState;
}
void LLVoiceClient::setUsePTT(bool usePTT)
{
- if (mVoiceModule) mVoiceModule->setUsePTT(usePTT);
+ if(usePTT && !mUsePTT)
+ {
+ // When the user turns on PTT, reset the current state.
+ mUserPTTState = false;
+ }
+ mUsePTT = usePTT;
+
+ updateMicMuteLogic();
}
void LLVoiceClient::setPTTIsToggle(bool PTTIsToggle)
{
- if (mVoiceModule) mVoiceModule->setPTTIsToggle(PTTIsToggle);
+ if(!PTTIsToggle && mPTTIsToggle)
+ {
+ // When the user turns off toggle, reset the current state.
+ mUserPTTState = false;
+ }
+
+ mPTTIsToggle = PTTIsToggle;
+
+ updateMicMuteLogic();
}
bool LLVoiceClient::getPTTIsToggle()
{
- if (mVoiceModule)
+ return mPTTIsToggle;
+}
+
+void LLVoiceClient::setPTTKey(std::string &key)
+{
+ if(key == "MiddleMouse")
{
- return mVoiceModule->getPTTIsToggle();
+ mPTTIsMiddleMouse = true;
}
- else {
- return false;
+ else
+ {
+ mPTTIsMiddleMouse = false;
+ if(!LLKeyboard::keyFromString(key, &mPTTKey))
+ {
+ // If the call failed, don't match any key.
+ key = KEY_NONE;
+ }
}
-
}
void LLVoiceClient::inputUserControlState(bool down)
{
- if (mVoiceModule) mVoiceModule->inputUserControlState(down);
+ if(mPTTIsToggle)
+ {
+ if(down) // toggle open-mic state on 'down'
+ {
+ toggleUserPTTState();
+ }
+ }
+ else // set open-mic state as an absolute
+ {
+ setUserPTTState(down);
+ }
}
void LLVoiceClient::toggleUserPTTState(void)
{
- if (mVoiceModule) mVoiceModule->toggleUserPTTState();
+ setUserPTTState(!getUserPTTState());
}
void LLVoiceClient::keyDown(KEY key, MASK mask)
{
- if (mVoiceModule) mVoiceModule->keyDown(key, mask);
+ if (gKeyboard->getKeyRepeated(key))
+ {
+ // ignore auto-repeat keys
+ return;
+ }
+
+ if(!mPTTIsMiddleMouse)
+ {
+ bool down = (mPTTKey != KEY_NONE)
+ && gKeyboard->getKeyDown(mPTTKey);
+ inputUserControlState(down);
+ }
+
}
void LLVoiceClient::keyUp(KEY key, MASK mask)
{
- if (mVoiceModule) mVoiceModule->keyUp(key, mask);
+ if(!mPTTIsMiddleMouse)
+ {
+ bool down = (mPTTKey != KEY_NONE)
+ && gKeyboard->getKeyDown(mPTTKey);
+ inputUserControlState(down);
+ }
}
void LLVoiceClient::middleMouseState(bool down)
{
- if (mVoiceModule) mVoiceModule->middleMouseState(down);
+ if(mPTTIsMiddleMouse)
+ {
+ if(mPTTIsMiddleMouse)
+ {
+ inputUserControlState(down);
+ }
+ }
}
diff --git a/indra/newview/llvoiceclient.h b/indra/newview/llvoiceclient.h
index 24d7d7163e..c9aeea35a9 100644
--- a/indra/newview/llvoiceclient.h
+++ b/indra/newview/llvoiceclient.h
@@ -191,25 +191,9 @@ public:
virtual void setVoiceEnabled(bool enabled)=0;
virtual void setLipSyncEnabled(BOOL enabled)=0;
virtual BOOL lipSyncEnabled()=0;
- virtual void setMuteMic(bool muted)=0; // Use this to mute the local mic (for when the client is minimized, etc), ignoring user PTT state.
+ virtual void setMuteMic(bool muted)=0; // Set the mute state of the local mic.
//@}
-
- ////////////////////////
- /// @name PTT
- //@{
- virtual void setUserPTTState(bool ptt)=0;
- virtual bool getUserPTTState()=0;
- virtual void setUsePTT(bool usePTT)=0;
- virtual void setPTTIsToggle(bool PTTIsToggle)=0;
- virtual bool getPTTIsToggle()=0;
- virtual void toggleUserPTTState(void)=0;
- virtual void inputUserControlState(bool down)=0; // interpret any sort of up-down mic-open control input according to ptt-toggle prefs
-
- virtual void keyDown(KEY key, MASK mask)=0;
- virtual void keyUp(KEY key, MASK mask)=0;
- virtual void middleMouseState(bool down)=0;
- //@}
-
+
//////////////////////////
/// @name nearby speaker accessors
//@{
@@ -406,6 +390,9 @@ public:
void setUsePTT(bool usePTT);
void setPTTIsToggle(bool PTTIsToggle);
bool getPTTIsToggle();
+ void setPTTKey(std::string &key);
+
+ void updateMicMuteLogic();
BOOL lipSyncEnabled();
@@ -471,6 +458,17 @@ protected:
LLCachedControl<bool> mVoiceEffectEnabled;
LLCachedControl<std::string> mVoiceEffectDefault;
+
+ bool mPTTDirty;
+ bool mPTT;
+
+ bool mUsePTT;
+ bool mPTTIsMiddleMouse;
+ KEY mPTTKey;
+ bool mPTTIsToggle;
+ bool mUserPTTState;
+ bool mMuteMic;
+ bool mDisableMic;
};
/**
diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp
index 019629084f..6ee6822e2f 100644
--- a/indra/newview/llvoicevivox.cpp
+++ b/indra/newview/llvoicevivox.cpp
@@ -46,7 +46,6 @@
#include "llviewernetwork.h" // for gGridChoice
#include "llbase64.h"
#include "llviewercontrol.h"
-#include "llkeyboard.h"
#include "llappviewer.h" // for gDisconnected, gDisableVoice
// Viewer includes
@@ -326,14 +325,8 @@ LLVivoxVoiceClient::LLVivoxVoiceClient() :
mRenderDeviceDirty(false),
mSpatialCoordsDirty(false),
- mPTTDirty(true),
- mPTT(true),
- mUsePTT(true),
- mPTTIsMiddleMouse(false),
- mPTTKey(0),
- mPTTIsToggle(false),
- mUserPTTState(false),
mMuteMic(false),
+ mMuteMicDirty(false),
mFriendsListDirty(true),
mEarLocation(0),
@@ -435,10 +428,6 @@ const LLVoiceVersionInfo& LLVivoxVoiceClient::getVersion()
void LLVivoxVoiceClient::updateSettings()
{
setVoiceEnabled(gSavedSettings.getBOOL("EnableVoiceChat"));
- setUsePTT(gSavedSettings.getBOOL("PTTCurrentlyEnabled"));
- std::string keyString = gSavedSettings.getString("PushToTalkButton");
- setPTTKey(keyString);
- setPTTIsToggle(gSavedSettings.getBOOL("PushToTalkToggle"));
setEarLocation(gSavedSettings.getS32("VoiceEarLocation"));
std::string inputDevice = gSavedSettings.getString("VoiceInputAudioDevice");
@@ -950,7 +939,7 @@ void LLVivoxVoiceClient::stateMachine()
setState(stateDaemonLaunched);
// Dirty the states we'll need to sync with the daemon when it comes up.
- mPTTDirty = true;
+ mMuteMicDirty = true;
mMicVolumeDirty = true;
mSpeakerVolumeDirty = true;
mSpeakerMuteDirty = true;
@@ -1535,7 +1524,7 @@ void LLVivoxVoiceClient::stateMachine()
if(mAudioSession && mAudioSession->mVoiceEnabled)
{
// Dirty state that may need to be sync'ed with the daemon.
- mPTTDirty = true;
+ mMuteMicDirty = true;
mSpeakerVolumeDirty = true;
mSpatialCoordsDirty = true;
@@ -1576,35 +1565,6 @@ void LLVivoxVoiceClient::stateMachine()
}
else
{
-
- // Figure out whether the PTT state needs to change
- {
- bool newPTT;
- if(mUsePTT)
- {
- // If configured to use PTT, track the user state.
- newPTT = mUserPTTState;
- }
- else
- {
- // If not configured to use PTT, it should always be true (otherwise the user will be unable to speak).
- newPTT = true;
- }
-
- if(mMuteMic)
- {
- // This always overrides any other PTT setting.
- newPTT = false;
- }
-
- // Dirty if state changed.
- if(newPTT != mPTT)
- {
- mPTT = newPTT;
- mPTTDirty = true;
- }
- }
-
if(!inSpatialChannel())
{
// When in a non-spatial channel, never send positional updates.
@@ -1626,7 +1586,7 @@ void LLVivoxVoiceClient::stateMachine()
// Send an update only if the ptt or mute state has changed (which shouldn't be able to happen that often
// -- the user can only click so fast) or every 10hz, whichever is sooner.
// Sending for every volume update causes an excessive flood of messages whenever a volume slider is dragged.
- if((mAudioSession && mAudioSession->mMuteDirty) || mPTTDirty || mUpdateTimer.hasExpired())
+ if((mAudioSession && mAudioSession->mMuteDirty) || mMuteMicDirty || mUpdateTimer.hasExpired())
{
mUpdateTimer.setTimerExpirySec(UPDATE_THROTTLE_SECONDS);
sendPositionalUpdate();
@@ -2749,19 +2709,17 @@ void LLVivoxVoiceClient::buildLocalAudioUpdates(std::ostringstream &stream)
buildSetRenderDevice(stream);
- if(mPTTDirty)
+ if(mMuteMicDirty)
{
- mPTTDirty = false;
+ mMuteMicDirty = false;
// Send a local mute command.
- // NOTE that the state of "PTT" is the inverse of "local mute".
- // (i.e. when PTT is true, we send a mute command with "false", and vice versa)
- LL_DEBUGS("Voice") << "Sending MuteLocalMic command with parameter " << (mPTT?"false":"true") << LL_ENDL;
+ LL_DEBUGS("Voice") << "Sending MuteLocalMic command with parameter " << (mMuteMic?"true":"false") << LL_ENDL;
stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.MuteLocalMic.1\">"
<< "<ConnectorHandle>" << mConnectorHandle << "</ConnectorHandle>"
- << "<Value>" << (mPTT?"false":"true") << "</Value>"
+ << "<Value>" << (mMuteMic?"true":"false") << "</Value>"
<< "</Request>\n\n\n";
}
@@ -5130,7 +5088,7 @@ void LLVivoxVoiceClient::enforceTether(void)
}
}
- if(dist_vec(mCameraPosition, tethered) > 0.1)
+ if(dist_vec_squared(mCameraPosition, tethered) > 0.01)
{
mCameraPosition = tethered;
mSpatialCoordsDirty = true;
@@ -5192,7 +5150,7 @@ void LLVivoxVoiceClient::setCameraPosition(const LLVector3d &position, const LLV
void LLVivoxVoiceClient::setAvatarPosition(const LLVector3d &position, const LLVector3 &velocity, const LLMatrix3 &rot)
{
- if(dist_vec(mAvatarPosition, position) > 0.1)
+ if(dist_vec_squared(mAvatarPosition, position) > 0.01)
{
mAvatarPosition = position;
mSpatialCoordsDirty = true;
@@ -5238,40 +5196,13 @@ void LLVivoxVoiceClient::leaveChannel(void)
void LLVivoxVoiceClient::setMuteMic(bool muted)
{
- mMuteMic = muted;
-}
-
-void LLVivoxVoiceClient::setUserPTTState(bool ptt)
-{
- mUserPTTState = ptt;
-}
-
-bool LLVivoxVoiceClient::getUserPTTState()
-{
- return mUserPTTState;
-}
-
-void LLVivoxVoiceClient::inputUserControlState(bool down)
-{
- if(mPTTIsToggle)
+ if(mMuteMic != muted)
{
- if(down) // toggle open-mic state on 'down'
- {
- toggleUserPTTState();
- }
- }
- else // set open-mic state as an absolute
- {
- setUserPTTState(down);
+ mMuteMic = muted;
+ mMuteMicDirty = true;
}
}
-
-void LLVivoxVoiceClient::toggleUserPTTState(void)
-{
- mUserPTTState = !mUserPTTState;
-}
-
void LLVivoxVoiceClient::setVoiceEnabled(bool enabled)
{
if (enabled != mVoiceEnabled)
@@ -5320,48 +5251,6 @@ BOOL LLVivoxVoiceClient::lipSyncEnabled()
}
}
-void LLVivoxVoiceClient::setUsePTT(bool usePTT)
-{
- if(usePTT && !mUsePTT)
- {
- // When the user turns on PTT, reset the current state.
- mUserPTTState = false;
- }
- mUsePTT = usePTT;
-}
-
-void LLVivoxVoiceClient::setPTTIsToggle(bool PTTIsToggle)
-{
- if(!PTTIsToggle && mPTTIsToggle)
- {
- // When the user turns off toggle, reset the current state.
- mUserPTTState = false;
- }
-
- mPTTIsToggle = PTTIsToggle;
-}
-
-bool LLVivoxVoiceClient::getPTTIsToggle()
-{
- return mPTTIsToggle;
-}
-
-void LLVivoxVoiceClient::setPTTKey(std::string &key)
-{
- if(key == "MiddleMouse")
- {
- mPTTIsMiddleMouse = true;
- }
- else
- {
- mPTTIsMiddleMouse = false;
- if(!LLKeyboard::keyFromString(key, &mPTTKey))
- {
- // If the call failed, don't match any key.
- key = KEY_NONE;
- }
- }
-}
void LLVivoxVoiceClient::setEarLocation(S32 loc)
{
@@ -5402,44 +5291,6 @@ void LLVivoxVoiceClient::setMicGain(F32 volume)
}
}
-void LLVivoxVoiceClient::keyDown(KEY key, MASK mask)
-{
- if (gKeyboard->getKeyRepeated(key))
- {
- // ignore auto-repeat keys
- return;
- }
-
- if(!mPTTIsMiddleMouse)
- {
- bool down = (mPTTKey != KEY_NONE)
- && gKeyboard->getKeyDown(mPTTKey);
- inputUserControlState(down);
- }
-
-
-}
-void LLVivoxVoiceClient::keyUp(KEY key, MASK mask)
-{
- if(!mPTTIsMiddleMouse)
- {
- bool down = (mPTTKey != KEY_NONE)
- && gKeyboard->getKeyDown(mPTTKey);
- inputUserControlState(down);
- }
-
-}
-void LLVivoxVoiceClient::middleMouseState(bool down)
-{
- if(mPTTIsMiddleMouse)
- {
- if(mPTTIsMiddleMouse)
- {
- inputUserControlState(down);
- }
- }
-}
-
/////////////////////////////
// Accessors for data related to nearby speakers
BOOL LLVivoxVoiceClient::getVoiceEnabled(const LLUUID& id)
@@ -7015,8 +6866,8 @@ void LLVivoxVoiceClient::captureBufferRecordStartSendMessage()
<< "<Value>false</Value>"
<< "</Request>\n\n\n";
- // Dirty the PTT state so that it will get reset when we finishing previewing
- mPTTDirty = true;
+ // Dirty the mute mic state so that it will get reset when we finishing previewing
+ mMuteMicDirty = true;
writeString(stream.str());
}
@@ -7030,7 +6881,7 @@ void LLVivoxVoiceClient::captureBufferRecordStopSendMessage()
LL_DEBUGS("Voice") << "Stopping audio capture to buffer." << LL_ENDL;
- // Mute the mic. PTT state was dirtied at recording start, so will be reset when finished previewing.
+ // Mute the mic. Mic mute state was dirtied at recording start, so will be reset when finished previewing.
stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.MuteLocalMic.1\">"
<< "<ConnectorHandle>" << mConnectorHandle << "</ConnectorHandle>"
<< "<Value>true</Value>"
@@ -7128,13 +6979,6 @@ void LLVivoxProtocolParser::reset()
alias.clear();
numberOfAliases = 0;
applicationString.clear();
- id = 0;
- nameString.clear();
- descriptionString.clear();
- expirationDate = LLDate();
- hasExpired = false;
- fontType = 0;
- fontStatus = 0;
}
//virtual
diff --git a/indra/newview/llvoicevivox.h b/indra/newview/llvoicevivox.h
index 3ba517bf36..471545de56 100644
--- a/indra/newview/llvoicevivox.h
+++ b/indra/newview/llvoicevivox.h
@@ -173,25 +173,9 @@ public:
virtual void setVoiceEnabled(bool enabled);
virtual BOOL lipSyncEnabled();
virtual void setLipSyncEnabled(BOOL enabled);
- virtual void setMuteMic(bool muted); // Use this to mute the local mic (for when the client is minimized, etc), ignoring user PTT state.
+ virtual void setMuteMic(bool muted); // Set the mute state of the local mic.
//@}
-
- ////////////////////////
- /// @name PTT
- //@{
- virtual void setUserPTTState(bool ptt);
- virtual bool getUserPTTState();
- virtual void setUsePTT(bool usePTT);
- virtual void setPTTIsToggle(bool PTTIsToggle);
- virtual bool getPTTIsToggle();
- virtual void inputUserControlState(bool down); // interpret any sort of up-down mic-open control input according to ptt-toggle prefs
- virtual void toggleUserPTTState(void);
-
- virtual void keyDown(KEY key, MASK mask);
- virtual void keyUp(KEY key, MASK mask);
- virtual void middleMouseState(bool down);
- //@}
-
+
//////////////////////////
/// @name nearby speaker accessors
//@{
@@ -534,9 +518,6 @@ protected:
// Use this to determine whether to show a "no speech" icon in the menu bar.
- // PTT
- void setPTTKey(std::string &key);
-
/////////////////////////////
// Recording controls
void recordingLoopStart(int seconds = 3600, int deltaFramesPerControlFrame = 200);
@@ -800,15 +781,8 @@ private:
LLVector3 mAvatarVelocity;
LLMatrix3 mAvatarRot;
- bool mPTTDirty;
- bool mPTT;
-
- bool mUsePTT;
- bool mPTTIsMiddleMouse;
- KEY mPTTKey;
- bool mPTTIsToggle;
- bool mUserPTTState;
bool mMuteMic;
+ bool mMuteMicDirty;
// Set to true when the friends list is known to have changed.
bool mFriendsListDirty;
diff --git a/indra/newview/llvopartgroup.cpp b/indra/newview/llvopartgroup.cpp
index 40833ad259..6f354b78b1 100644
--- a/indra/newview/llvopartgroup.cpp
+++ b/indra/newview/llvopartgroup.cpp
@@ -73,12 +73,14 @@ F32 LLVOPartGroup::getBinRadius()
return mScale.mV[0]*2.f;
}
-void LLVOPartGroup::updateSpatialExtents(LLVector3& newMin, LLVector3& newMax)
+void LLVOPartGroup::updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax)
{
const LLVector3& pos_agent = getPositionAgent();
- newMin = pos_agent - mScale;
- newMax = pos_agent + mScale;
- mDrawable->setPositionGroup(pos_agent);
+ newMin.load3( (pos_agent - mScale).mV);
+ newMax.load3( (pos_agent + mScale).mV);
+ LLVector4a pos;
+ pos.load3(pos_agent.mV);
+ mDrawable->setPositionGroup(pos);
}
BOOL LLVOPartGroup::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
@@ -358,7 +360,7 @@ U32 LLVOPartGroup::getPartitionType() const
}
LLParticlePartition::LLParticlePartition()
-: LLSpatialPartition(LLDrawPoolAlpha::VERTEX_DATA_MASK, TRUE, GL_DYNAMIC_DRAW_ARB)
+: LLSpatialPartition(LLDrawPoolAlpha::VERTEX_DATA_MASK, TRUE, GL_STREAM_DRAW_ARB)
{
mRenderPass = LLRenderPass::PASS_ALPHA;
mDrawableType = LLPipeline::RENDER_TYPE_PARTICLES;
@@ -461,7 +463,7 @@ void LLParticlePartition::getGeometry(LLSpatialGroup* group)
LLAlphaObject* object = (LLAlphaObject*) facep->getViewerObject();
facep->setGeomIndex(vertex_count);
facep->setIndicesIndex(index_count);
- facep->mVertexBuffer = buffer;
+ facep->setVertexBuffer(buffer);
facep->setPoolType(LLDrawPool::POOL_ALPHA);
object->getGeometry(facep->getTEOffset(), verticesp, normalsp, texcoordsp, colorsp, indicesp);
diff --git a/indra/newview/llvopartgroup.h b/indra/newview/llvopartgroup.h
index b136f2cbfa..4db893b4ef 100644
--- a/indra/newview/llvopartgroup.h
+++ b/indra/newview/llvopartgroup.h
@@ -51,7 +51,7 @@ public:
BOOL idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time);
virtual F32 getBinRadius();
- virtual void updateSpatialExtents(LLVector3& newMin, LLVector3& newMax);
+ virtual void updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax);
virtual U32 getPartitionType() const;
/*virtual*/ void setPixelAreaAndAngle(LLAgent &agent);
diff --git a/indra/newview/llvosky.cpp b/indra/newview/llvosky.cpp
index 7ae8c2c07d..6396bc042d 100644
--- a/indra/newview/llvosky.cpp
+++ b/indra/newview/llvosky.cpp
@@ -77,9 +77,6 @@ static const LLVector2 TEX11 = LLVector2(1.f, 1.f);
LLUUID gSunTextureID = IMG_SUN;
LLUUID gMoonTextureID = IMG_MOON;
-//static
-LLColor3 LLHaze::sAirScaSeaLevel;
-
class LLFastLn
{
public:
@@ -182,6 +179,23 @@ inline void color_gamma_correct(LLColor3 &col)
}
}
+static LLColor3 calc_air_sca_sea_level()
+{
+ static LLColor3 WAVE_LEN(675, 520, 445);
+ static LLColor3 refr_ind = refr_ind_calc(WAVE_LEN);
+ static LLColor3 n21 = refr_ind * refr_ind - LLColor3(1, 1, 1);
+ static LLColor3 n4 = n21 * n21;
+ static LLColor3 wl2 = WAVE_LEN * WAVE_LEN * 1e-6f;
+ static LLColor3 wl4 = wl2 * wl2;
+ static LLColor3 mult_const = fsigma * 2.0f/ 3.0f * 1e24f * (F_PI * F_PI) * n4;
+ static F32 dens_div_N = F32( ATM_SEA_LEVEL_NDENS / Ndens2);
+ return dens_div_N * color_div ( mult_const, wl4 );
+}
+
+// static constants.
+LLColor3 const LLHaze::sAirScaSeaLevel = calc_air_sca_sea_level();
+F32 const LLHaze::sAirScaIntense = color_intens(LLHaze::sAirScaSeaLevel);
+F32 const LLHaze::sAirScaAvg = LLHaze::sAirScaIntense / 3.f;
/***************************************
@@ -290,7 +304,7 @@ void LLSkyTex::createGLImage(S32 which)
void LLSkyTex::bindTexture(BOOL curr)
{
- gGL.getTexUnit(0)->bind(mTexture[getWhich(curr)]);
+ gGL.getTexUnit(0)->bind(mTexture[getWhich(curr)], true);
}
/***************************************
@@ -394,12 +408,6 @@ LLVOSky::~LLVOSky()
mCubeMap = NULL;
}
-void LLVOSky::initClass()
-{
- LLHaze::initClass();
-}
-
-
void LLVOSky::init()
{
const F32 haze_int = color_intens(mHaze.calcSigSca(0));
@@ -1174,7 +1182,7 @@ BOOL LLVOSky::updateSky()
}
}
- if (mDrawable.notNull() && mDrawable->getFace(0) && mDrawable->getFace(0)->mVertexBuffer.isNull())
+ if (mDrawable.notNull() && mDrawable->getFace(0) && !mDrawable->getFace(0)->getVertexBuffer())
{
gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE);
}
@@ -1225,10 +1233,11 @@ void LLVOSky::createDummyVertexBuffer()
mFace[FACE_DUMMY] = mDrawable->addFace(poolp, NULL);
}
- if(mFace[FACE_DUMMY]->mVertexBuffer.isNull())
+ if(!mFace[FACE_DUMMY]->getVertexBuffer())
{
- mFace[FACE_DUMMY]->mVertexBuffer = new LLVertexBuffer(LLDrawPoolSky::VERTEX_DATA_MASK, GL_DYNAMIC_DRAW_ARB);
- mFace[FACE_DUMMY]->mVertexBuffer->allocateBuffer(1, 1, TRUE);
+ LLVertexBuffer* buff = new LLVertexBuffer(LLDrawPoolSky::VERTEX_DATA_MASK, GL_DYNAMIC_DRAW_ARB);
+ buff->allocateBuffer(1, 1, TRUE);
+ mFace[FACE_DUMMY]->setVertexBuffer(buff);
}
}
@@ -1247,13 +1256,13 @@ void LLVOSky::updateDummyVertexBuffer()
LLFastTimer t(FTM_RENDER_FAKE_VBO_UPDATE) ;
- if(!mFace[FACE_DUMMY] || mFace[FACE_DUMMY]->mVertexBuffer.isNull())
+ if(!mFace[FACE_DUMMY] || !mFace[FACE_DUMMY]->getVertexBuffer())
createDummyVertexBuffer() ;
LLStrider<LLVector3> vertices ;
- mFace[FACE_DUMMY]->mVertexBuffer->getVertexStrider(vertices, 0);
+ mFace[FACE_DUMMY]->getVertexBuffer()->getVertexStrider(vertices, 0);
*vertices = mCameraPosAgent ;
- mFace[FACE_DUMMY]->mVertexBuffer->setBuffer(0) ;
+ mFace[FACE_DUMMY]->getVertexBuffer()->setBuffer(0) ;
}
//----------------------------------
//end of fake vertex buffer updating
@@ -1296,14 +1305,15 @@ BOOL LLVOSky::updateGeometry(LLDrawable *drawable)
{
face = mFace[FACE_SIDE0 + side];
- if (face->mVertexBuffer.isNull())
+ if (!face->getVertexBuffer())
{
face->setSize(4, 6);
face->setGeomIndex(0);
face->setIndicesIndex(0);
- face->mVertexBuffer = new LLVertexBuffer(LLDrawPoolSky::VERTEX_DATA_MASK, GL_STREAM_DRAW_ARB);
- face->mVertexBuffer->allocateBuffer(4, 6, TRUE);
-
+ LLVertexBuffer* buff = new LLVertexBuffer(LLDrawPoolSky::VERTEX_DATA_MASK, GL_STREAM_DRAW_ARB);
+ buff->allocateBuffer(4, 6, TRUE);
+ face->setVertexBuffer(buff);
+
index_offset = face->getGeometry(verticesp,normalsp,texCoordsp, indicesp);
S32 vtx = 0;
@@ -1336,7 +1346,7 @@ BOOL LLVOSky::updateGeometry(LLDrawable *drawable)
*indicesp++ = index_offset + 3;
*indicesp++ = index_offset + 2;
- face->mVertexBuffer->setBuffer(0);
+ buff->setBuffer(0);
}
}
@@ -1463,13 +1473,14 @@ BOOL LLVOSky::updateHeavenlyBodyGeometry(LLDrawable *drawable, const S32 f, cons
facep = mFace[f];
- if (facep->mVertexBuffer.isNull())
+ if (!facep->getVertexBuffer())
{
- facep->setSize(4, 6);
- facep->mVertexBuffer = new LLVertexBuffer(LLDrawPoolSky::VERTEX_DATA_MASK, GL_STREAM_DRAW_ARB);
- facep->mVertexBuffer->allocateBuffer(facep->getGeomCount(), facep->getIndicesCount(), TRUE);
+ facep->setSize(4, 6);
+ LLVertexBuffer* buff = new LLVertexBuffer(LLDrawPoolSky::VERTEX_DATA_MASK, GL_STREAM_DRAW_ARB);
+ buff->allocateBuffer(facep->getGeomCount(), facep->getIndicesCount(), TRUE);
facep->setGeomIndex(0);
facep->setIndicesIndex(0);
+ facep->setVertexBuffer(buff);
}
index_offset = facep->getGeometry(verticesp,normalsp,texCoordsp, indicesp);
@@ -1498,7 +1509,7 @@ BOOL LLVOSky::updateHeavenlyBodyGeometry(LLDrawable *drawable, const S32 f, cons
*indicesp++ = index_offset + 2;
*indicesp++ = index_offset + 3;
- facep->mVertexBuffer->setBuffer(0);
+ facep->getVertexBuffer()->setBuffer(0);
if (is_sun)
{
@@ -1867,13 +1878,14 @@ void LLVOSky::updateReflectionGeometry(LLDrawable *drawable, F32 H,
LLFace *face = mFace[FACE_REFLECTION];
- if (face->mVertexBuffer.isNull() || quads*4 != face->getGeomCount())
+ if (!face->getVertexBuffer() || quads*4 != face->getGeomCount())
{
face->setSize(quads * 4, quads * 6);
- face->mVertexBuffer = new LLVertexBuffer(LLDrawPoolWater::VERTEX_DATA_MASK, GL_STREAM_DRAW_ARB);
- face->mVertexBuffer->allocateBuffer(face->getGeomCount(), face->getIndicesCount(), TRUE);
+ LLVertexBuffer* buff = new LLVertexBuffer(LLDrawPoolWater::VERTEX_DATA_MASK, GL_STREAM_DRAW_ARB);
+ buff->allocateBuffer(face->getGeomCount(), face->getIndicesCount(), TRUE);
face->setIndicesIndex(0);
face->setGeomIndex(0);
+ face->setVertexBuffer(buff);
}
LLStrider<LLVector3> verticesp;
@@ -2011,7 +2023,7 @@ void LLVOSky::updateReflectionGeometry(LLDrawable *drawable, F32 H,
}
}
- face->mVertexBuffer->setBuffer(0);
+ face->getVertexBuffer()->setBuffer(0);
}
@@ -2147,17 +2159,8 @@ void LLVOSky::updateFog(const F32 distance)
stop_glerror();
}
-// static
-void LLHaze::initClass()
-{
- sAirScaSeaLevel = LLHaze::calcAirScaSeaLevel();
-}
-
-
// Functions used a lot.
-
-
F32 color_norm_pow(LLColor3& col, F32 e, BOOL postmultiply)
{
F32 mv = color_max(col);
diff --git a/indra/newview/llvosky.h b/indra/newview/llvosky.h
index 6b3e7873a1..d3a42583ea 100644
--- a/indra/newview/llvosky.h
+++ b/indra/newview/llvosky.h
@@ -292,23 +292,6 @@ LL_FORCE_INLINE LLColor3 refr_ind_calc(const LLColor3 &wave_length)
}
-LL_FORCE_INLINE LLColor3 calc_air_sca_sea_level()
-{
- const static LLColor3 WAVE_LEN(675, 520, 445);
- const static LLColor3 refr_ind = refr_ind_calc(WAVE_LEN);
- const static LLColor3 n21 = refr_ind * refr_ind - LLColor3(1, 1, 1);
- const static LLColor3 n4 = n21 * n21;
- const static LLColor3 wl2 = WAVE_LEN * WAVE_LEN * 1e-6f;
- const static LLColor3 wl4 = wl2 * wl2;
- const static LLColor3 mult_const = fsigma * 2.0f/ 3.0f * 1e24f * (F_PI * F_PI) * n4;
- const static F32 dens_div_N = F32( ATM_SEA_LEVEL_NDENS / Ndens2);
- return dens_div_N * color_div ( mult_const, wl4 );
-}
-
-const LLColor3 gAirScaSeaLevel = calc_air_sca_sea_level();
-const F32 AIR_SCA_INTENS = color_intens(gAirScaSeaLevel);
-const F32 AIR_SCA_AVG = AIR_SCA_INTENS / 3.f;
-
class LLHaze
{
public:
@@ -316,18 +299,15 @@ public:
LLHaze(const F32 g, const LLColor3& sca, const F32 fo = 2.f) :
mG(g), mSigSca(0.25f/F_PI * sca), mFalloff(fo), mAbsCoef(0.f)
{
- mAbsCoef = color_intens(mSigSca) / AIR_SCA_INTENS;
+ mAbsCoef = color_intens(mSigSca) / sAirScaIntense;
}
LLHaze(const F32 g, const F32 sca, const F32 fo = 2.f) : mG(g),
mSigSca(0.25f/F_PI * LLColor3(sca, sca, sca)), mFalloff(fo)
{
- mAbsCoef = 0.01f * sca / AIR_SCA_AVG;
+ mAbsCoef = 0.01f * sca / sAirScaAvg;
}
- static void initClass();
-
-
F32 getG() const { return mG; }
void setG(const F32 g)
@@ -343,12 +323,12 @@ public:
void setSigSca(const LLColor3& s)
{
mSigSca = s;
- mAbsCoef = 0.01f * color_intens(mSigSca) / AIR_SCA_INTENS;
+ mAbsCoef = 0.01f * color_intens(mSigSca) / sAirScaIntense;
}
void setSigSca(const F32 s0, const F32 s1, const F32 s2)
{
- mSigSca = AIR_SCA_AVG * LLColor3 (s0, s1, s2);
+ mSigSca = sAirScaAvg * LLColor3 (s0, s1, s2);
mAbsCoef = 0.01f * (s0 + s1 + s2) / 3;
}
@@ -392,10 +372,11 @@ public:
static inline LLColor3 calcAirSca(const F32 h);
static inline void calcAirSca(const F32 h, LLColor3 &result);
- static LLColor3 calcAirScaSeaLevel() { return gAirScaSeaLevel; }
- static const LLColor3 &getAirScaSeaLevel() { return sAirScaSeaLevel; }
-public:
- static LLColor3 sAirScaSeaLevel;
+
+private:
+ static LLColor3 const sAirScaSeaLevel;
+ static F32 const sAirScaIntense;
+ static F32 const sAirScaAvg;
protected:
F32 mG;
@@ -473,7 +454,6 @@ public:
LLVOSky(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp);
// Initialize/delete data that's only inited once per class.
- static void initClass();
void init();
void initCubeMap();
void initEmpty();
@@ -654,14 +634,12 @@ F32 color_norm_pow(LLColor3& col, F32 e, BOOL postmultiply = FALSE);
inline LLColor3 LLHaze::calcAirSca(const F32 h)
{
- static const LLColor3 air_sca_sea_level = calcAirScaSeaLevel();
- return calcFalloff(h) * air_sca_sea_level;
+ return calcFalloff(h) * sAirScaSeaLevel;
}
inline void LLHaze::calcAirSca(const F32 h, LLColor3 &result)
{
- static const LLColor3 air_sca_sea_level = calcAirScaSeaLevel();
- result = air_sca_sea_level;
+ result = sAirScaSeaLevel;
result *= calcFalloff(h);
}
diff --git a/indra/newview/llvosurfacepatch.cpp b/indra/newview/llvosurfacepatch.cpp
index eba600b50a..dbcd4f50ca 100644
--- a/indra/newview/llvosurfacepatch.cpp
+++ b/indra/newview/llvosurfacepatch.cpp
@@ -54,33 +54,83 @@ public:
LLVertexBuffer(MAP_VERTEX | MAP_NORMAL | MAP_TEXCOORD0 | MAP_TEXCOORD1 | MAP_COLOR, GL_DYNAMIC_DRAW_ARB)
{
//texture coordinates 2 and 3 exist, but use the same data as texture coordinate 1
- mOffsets[TYPE_TEXCOORD3] = mOffsets[TYPE_TEXCOORD2] = mOffsets[TYPE_TEXCOORD1];
- mTypeMask |= MAP_TEXCOORD2 | MAP_TEXCOORD3;
};
- /*// virtual
+ // virtual
void setupVertexBuffer(U32 data_mask) const
- {
- if (LLDrawPoolTerrain::getDetailMode() == 0 || LLPipeline::sShadowRender)
+ {
+ U8* base = useVBOs() ? (U8*) mAlignedOffset : mMappedData;
+
+ //assume tex coords 2 and 3 are present
+ U32 type_mask = mTypeMask | MAP_TEXCOORD2 | MAP_TEXCOORD3;
+
+ if ((data_mask & type_mask) != data_mask)
{
- LLVertexBuffer::setupVertexBuffer(data_mask);
+ llerrs << "LLVertexBuffer::setupVertexBuffer missing required components for supplied data mask." << llendl;
+ }
+
+ if (data_mask & MAP_NORMAL)
+ {
+ glNormalPointer(GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_NORMAL], (void*)(base + mOffsets[TYPE_NORMAL]));
+ }
+ if (data_mask & MAP_TEXCOORD3)
+ { //substitute tex coord 0 for tex coord 3
+ glClientActiveTextureARB(GL_TEXTURE3_ARB);
+ glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], (void*)(base + mOffsets[TYPE_TEXCOORD0]));
+ glClientActiveTextureARB(GL_TEXTURE0_ARB);
+ }
+ if (data_mask & MAP_TEXCOORD2)
+ { //substitute tex coord 0 for tex coord 2
+ glClientActiveTextureARB(GL_TEXTURE2_ARB);
+ glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], (void*)(base + mOffsets[TYPE_TEXCOORD0]));
+ glClientActiveTextureARB(GL_TEXTURE0_ARB);
}
- else if (data_mask & LLVertexBuffer::MAP_TEXCOORD1)
+ if (data_mask & MAP_TEXCOORD1)
{
- LLVertexBuffer::setupVertexBuffer(data_mask);
+ glClientActiveTextureARB(GL_TEXTURE1_ARB);
+ glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], (void*)(base + mOffsets[TYPE_TEXCOORD1]));
+ glClientActiveTextureARB(GL_TEXTURE0_ARB);
}
- else
+ if (data_mask & MAP_BINORMAL)
{
- LLVertexBuffer::setupVertexBuffer(data_mask);
+ glClientActiveTextureARB(GL_TEXTURE2_ARB);
+ glTexCoordPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_BINORMAL], (void*)(base + mOffsets[TYPE_BINORMAL]));
+ glClientActiveTextureARB(GL_TEXTURE0_ARB);
}
- llglassertok();
- }*/
+ if (data_mask & MAP_TEXCOORD0)
+ {
+ glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], (void*)(base + mOffsets[TYPE_TEXCOORD0]));
+ }
+ if (data_mask & MAP_COLOR)
+ {
+ glColorPointer(4, GL_UNSIGNED_BYTE, LLVertexBuffer::sTypeSize[TYPE_COLOR], (void*)(base + mOffsets[TYPE_COLOR]));
+ }
+
+ if (data_mask & MAP_WEIGHT)
+ {
+ glVertexAttribPointerARB(1, 1, GL_FLOAT, FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT], (void*)(base + mOffsets[TYPE_WEIGHT]));
+ }
+
+ if (data_mask & MAP_WEIGHT4 && sWeight4Loc != -1)
+ {
+ glVertexAttribPointerARB(sWeight4Loc, 4, GL_FLOAT, FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT4], (void*)(base+mOffsets[TYPE_WEIGHT4]));
+ }
+
+ if (data_mask & MAP_CLOTHWEIGHT)
+ {
+ glVertexAttribPointerARB(4, 4, GL_FLOAT, TRUE, LLVertexBuffer::sTypeSize[TYPE_CLOTHWEIGHT], (void*)(base + mOffsets[TYPE_CLOTHWEIGHT]));
+ }
+ if (data_mask & MAP_VERTEX)
+ {
+ glVertexPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_VERTEX], (void*)(base + 0));
+ }
+ }
};
//============================================================================
LLVOSurfacePatch::LLVOSurfacePatch(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
- : LLStaticViewerObject(id, LL_VO_SURFACE_PATCH, regionp),
+ : LLStaticViewerObject(id, pcode, regionp),
mDirtiedPatch(FALSE),
mPool(NULL),
mBaseComp(0),
@@ -840,7 +890,7 @@ void LLVOSurfacePatch::dirtyGeom()
if (mDrawable)
{
gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE);
- mDrawable->getFace(0)->mVertexBuffer = NULL;
+ mDrawable->getFace(0)->setVertexBuffer(NULL);
mDrawable->movePartition();
}
}
@@ -939,7 +989,13 @@ BOOL LLVOSurfacePatch::lineSegmentIntersect(const LLVector3& start, const LLVect
//step one meter at a time until intersection point found
- const LLVector3* ext = mDrawable->getSpatialExtents();
+ //VECTORIZE THIS
+ const LLVector4a* exta = mDrawable->getSpatialExtents();
+
+ LLVector3 ext[2];
+ ext[0].set(exta[0].getF32ptr());
+ ext[1].set(exta[1].getF32ptr());
+
F32 rad = (delta*tdelta).magVecSquared();
F32 t = 0.f;
@@ -1001,13 +1057,16 @@ BOOL LLVOSurfacePatch::lineSegmentIntersect(const LLVector3& start, const LLVect
return FALSE;
}
-void LLVOSurfacePatch::updateSpatialExtents(LLVector3& newMin, LLVector3 &newMax)
+void LLVOSurfacePatch::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax)
{
LLVector3 posAgent = getPositionAgent();
LLVector3 scale = getScale();
- newMin = posAgent-scale*0.5f; // Changing to 2.f makes the culling a -little- better, but still wrong
- newMax = posAgent+scale*0.5f;
- mDrawable->setPositionGroup((newMin+newMax)*0.5f);
+ newMin.load3( (posAgent-scale*0.5f).mV); // Changing to 2.f makes the culling a -little- better, but still wrong
+ newMax.load3( (posAgent+scale*0.5f).mV);
+ LLVector4a pos;
+ pos.setAdd(newMin,newMax);
+ pos.mul(0.5f);
+ mDrawable->setPositionGroup(pos);
}
U32 LLVOSurfacePatch::getPartitionType() const
@@ -1060,7 +1119,7 @@ void LLTerrainPartition::getGeometry(LLSpatialGroup* group)
facep->setIndicesIndex(indices_index);
facep->setGeomIndex(index_offset);
- facep->mVertexBuffer = buffer;
+ facep->setVertexBuffer(buffer);
LLVOSurfacePatch* patchp = (LLVOSurfacePatch*) facep->getViewerObject();
patchp->getGeometry(vertices, normals, colors, texcoords, texcoords2, indices);
diff --git a/indra/newview/llvosurfacepatch.h b/indra/newview/llvosurfacepatch.h
index bd80e1dbe6..8e75ff2e6e 100644
--- a/indra/newview/llvosurfacepatch.h
+++ b/indra/newview/llvosurfacepatch.h
@@ -72,7 +72,7 @@ public:
/*virtual*/ void updateTextures();
/*virtual*/ void setPixelAreaAndAngle(LLAgent &agent); // generate accurate apparent angle and area
- /*virtual*/ void updateSpatialExtents(LLVector3& newMin, LLVector3& newMax);
+ /*virtual*/ void updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax);
/*virtual*/ BOOL isActive() const; // Whether this object needs to do an idleUpdate.
void setPatch(LLSurfacePatch *patchp);
diff --git a/indra/newview/llvotextbubble.cpp b/indra/newview/llvotextbubble.cpp
index b61dae53ba..a92172fe23 100644
--- a/indra/newview/llvotextbubble.cpp
+++ b/indra/newview/llvotextbubble.cpp
@@ -39,6 +39,7 @@
#include "llviewertexturelist.h"
#include "llvolume.h"
#include "pipeline.h"
+#include "llvector4a.h"
#include "llviewerregion.h"
LLVOTextBubble::LLVOTextBubble(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
@@ -211,7 +212,7 @@ void LLVOTextBubble::updateFaceSize(S32 idx)
else
{
const LLVolumeFace& vol_face = getVolume()->getVolumeFace(idx);
- face->setSize(vol_face.mVertices.size(), vol_face.mIndices.size());
+ face->setSize(vol_face.mNumVertices, vol_face.mNumIndices);
}
}
@@ -229,19 +230,37 @@ void LLVOTextBubble::getGeometry(S32 idx,
const LLVolumeFace& face = getVolume()->getVolumeFace(idx);
- LLVector3 pos = getPositionAgent();
+ LLVector4a pos;
+ pos.load3(getPositionAgent().mV);
+
+ LLVector4a scale;
+ scale.load3(getScale().mV);
+
LLColor4U color = LLColor4U(getTE(idx)->getColor());
U32 offset = mDrawable->getFace(idx)->getGeomIndex();
- for (U32 i = 0; i < face.mVertices.size(); i++)
+ LLVector4a* dst_pos = (LLVector4a*) verticesp.get();
+ LLVector4a* src_pos = (LLVector4a*) face.mPositions;
+
+ LLVector4a* dst_norm = (LLVector4a*) normalsp.get();
+ LLVector4a* src_norm = (LLVector4a*) face.mNormals;
+
+ LLVector2* dst_tc = (LLVector2*) texcoordsp.get();
+ LLVector2* src_tc = (LLVector2*) face.mTexCoords;
+
+ LLVector4a::memcpyNonAliased16((F32*) dst_norm, (F32*) src_norm, face.mNumVertices*4*sizeof(F32));
+ LLVector4a::memcpyNonAliased16((F32*) dst_tc, (F32*) src_tc, face.mNumVertices*2*sizeof(F32));
+
+
+ for (U32 i = 0; i < face.mNumVertices; i++)
{
- *verticesp++ = face.mVertices[i].mPosition.scaledVec(getScale()) + pos;
- *normalsp++ = face.mVertices[i].mNormal;
- *texcoordsp++ = face.mVertices[i].mTexCoord;
+ LLVector4a t;
+ t.setMul(src_pos[i], scale);
+ dst_pos[i].setAdd(t, pos);
*colorsp++ = color;
}
- for (U32 i = 0; i < face.mIndices.size(); i++)
+ for (U32 i = 0; i < face.mNumIndices; i++)
{
*indicesp++ = face.mIndices[i] + offset;
}
diff --git a/indra/newview/llvotree.cpp b/indra/newview/llvotree.cpp
index 37a974be28..8946d4e0b6 100644
--- a/indra/newview/llvotree.cpp
+++ b/indra/newview/llvotree.cpp
@@ -50,6 +50,7 @@
#include "pipeline.h"
#include "llspatialpartition.h"
#include "llnotificationsutil.h"
+#include "raytrace.h"
extern LLPipeline gPipeline;
@@ -485,7 +486,7 @@ void LLVOTree::updateTextures()
{
if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_AREA))
{
- setDebugText(llformat("%4.0f", fsqrtf(mPixelArea)));
+ setDebugText(llformat("%4.0f", (F32) sqrt(mPixelArea)));
}
mTreeImagep->addTextureStats(mPixelArea);
}
@@ -525,11 +526,11 @@ BOOL LLVOTree::updateGeometry(LLDrawable *drawable)
if(mTrunkLOD >= sMAX_NUM_TREE_LOD_LEVELS) //do not display the tree.
{
mReferenceBuffer = NULL ;
- mDrawable->getFace(0)->mVertexBuffer = NULL ;
+ mDrawable->getFace(0)->setVertexBuffer(NULL);
return TRUE ;
}
- if (mReferenceBuffer.isNull() || mDrawable->getFace(0)->mVertexBuffer.isNull())
+ if (mReferenceBuffer.isNull() || !mDrawable->getFace(0)->getVertexBuffer())
{
const F32 SRR3 = 0.577350269f; // sqrt(1/3)
const F32 SRR2 = 0.707106781f; // sqrt(1/2)
@@ -863,7 +864,7 @@ BOOL LLVOTree::updateGeometry(LLDrawable *drawable)
if (gSavedSettings.getBOOL("RenderAnimateTrees"))
{
- mDrawable->getFace(0)->mVertexBuffer = mReferenceBuffer;
+ mDrawable->getFace(0)->setVertexBuffer(mReferenceBuffer);
}
else
{
@@ -921,8 +922,9 @@ void LLVOTree::updateMesh()
calcNumVerts(vert_count, index_count, mTrunkLOD, stop_depth, mDepth, mTrunkDepth, mBranches);
LLFace* facep = mDrawable->getFace(0);
- facep->mVertexBuffer = new LLVertexBuffer(LLDrawPoolTree::VERTEX_DATA_MASK, GL_STATIC_DRAW_ARB);
- facep->mVertexBuffer->allocateBuffer(vert_count, index_count, TRUE);
+ LLVertexBuffer* buff = new LLVertexBuffer(LLDrawPoolTree::VERTEX_DATA_MASK, GL_STATIC_DRAW_ARB);
+ buff->allocateBuffer(vert_count, index_count, TRUE);
+ facep->setVertexBuffer(buff);
LLStrider<LLVector3> vertices;
LLStrider<LLVector3> normals;
@@ -930,16 +932,15 @@ void LLVOTree::updateMesh()
LLStrider<U16> indices;
U16 idx_offset = 0;
- facep->mVertexBuffer->getVertexStrider(vertices);
- facep->mVertexBuffer->getNormalStrider(normals);
- facep->mVertexBuffer->getTexCoord0Strider(tex_coords);
- facep->mVertexBuffer->getIndexStrider(indices);
+ buff->getVertexStrider(vertices);
+ buff->getNormalStrider(normals);
+ buff->getTexCoord0Strider(tex_coords);
+ buff->getIndexStrider(indices);
genBranchPipeline(vertices, normals, tex_coords, indices, idx_offset, scale_mat, mTrunkLOD, stop_depth, mDepth, mTrunkDepth, 1.0, mTwist, droop, mBranches, alpha);
mReferenceBuffer->setBuffer(0);
- facep->mVertexBuffer->setBuffer(0);
-
+ buff->setBuffer(0);
}
void LLVOTree::appendMesh(LLStrider<LLVector3>& vertices,
@@ -1260,7 +1261,7 @@ void LLVOTree::updateRadius()
mDrawable->setRadius(32.0f);
}
-void LLVOTree::updateSpatialExtents(LLVector3& newMin, LLVector3& newMax)
+void LLVOTree::updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax)
{
F32 radius = getScale().length()*0.05f;
LLVector3 center = getRenderPosition();
@@ -1270,9 +1271,11 @@ void LLVOTree::updateSpatialExtents(LLVector3& newMin, LLVector3& newMax)
center += LLVector3(0, 0, size.mV[2]) * getRotation();
- newMin.set(center-size);
- newMax.set(center+size);
- mDrawable->setPositionGroup(center);
+ newMin.load3((center-size).mV);
+ newMax.load3((center+size).mV);
+ LLVector4a pos;
+ pos.load3(center.mV);
+ mDrawable->setPositionGroup(pos);
}
BOOL LLVOTree::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, S32 face, BOOL pick_transparent, S32 *face_hitp,
@@ -1285,8 +1288,13 @@ BOOL LLVOTree::lineSegmentIntersect(const LLVector3& start, const LLVector3& end
return FALSE;
}
- const LLVector3* ext = mDrawable->getSpatialExtents();
+ const LLVector4a* exta = mDrawable->getSpatialExtents();
+ //VECTORIZE THIS
+ LLVector3 ext[2];
+ ext[0].set(exta[0].getF32ptr());
+ ext[1].set(exta[1].getF32ptr());
+
LLVector3 center = (ext[1]+ext[0])*0.5f;
LLVector3 size = (ext[1]-ext[0]);
@@ -1323,7 +1331,7 @@ U32 LLVOTree::getPartitionType() const
}
LLTreePartition::LLTreePartition()
-: LLSpatialPartition(0, FALSE, 0)
+: LLSpatialPartition(0, FALSE, GL_DYNAMIC_DRAW_ARB)
{
mDrawableType = LLPipeline::RENDER_TYPE_TREE;
mPartitionType = LLViewerRegion::PARTITION_TREE;
diff --git a/indra/newview/llvotree.h b/indra/newview/llvotree.h
index fd0ebdf8e2..1e1deede26 100644
--- a/indra/newview/llvotree.h
+++ b/indra/newview/llvotree.h
@@ -68,7 +68,7 @@ public:
/*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline);
/*virtual*/ BOOL updateGeometry(LLDrawable *drawable);
- /*virtual*/ void updateSpatialExtents(LLVector3 &min, LLVector3 &max);
+ /*virtual*/ void updateSpatialExtents(LLVector4a &min, LLVector4a &max);
virtual U32 getPartitionType() const;
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 761e12020b..e9a8c9b80a 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -30,12 +30,16 @@
#include "llvovolume.h"
+#include <sstream>
+
#include "llviewercontrol.h"
#include "lldir.h"
#include "llflexibleobject.h"
+#include "llfloatertools.h"
#include "llmaterialtable.h"
#include "llprimitive.h"
#include "llvolume.h"
+#include "llvolumeoctree.h"
#include "llvolumemgr.h"
#include "llvolumemessage.h"
#include "material_codes.h"
@@ -44,6 +48,7 @@
#include "object_flags.h"
#include "llagentconstants.h"
#include "lldrawable.h"
+#include "lldrawpoolavatar.h"
#include "lldrawpoolbump.h"
#include "llface.h"
#include "llspatialpartition.h"
@@ -51,18 +56,25 @@
#include "llflexibleobject.h"
#include "llsky.h"
#include "lltexturefetch.h"
+#include "llvector4a.h"
#include "llviewercamera.h"
#include "llviewertexturelist.h"
+#include "llviewerobjectlist.h"
#include "llviewerregion.h"
#include "llviewertextureanim.h"
#include "llworld.h"
#include "llselectmgr.h"
#include "pipeline.h"
#include "llsdutil.h"
+#include "llmatrix4a.h"
#include "llmediaentry.h"
#include "llmediadataclient.h"
+#include "llmeshrepository.h"
#include "llagent.h"
#include "llviewermediafocus.h"
+#include "lldatapacker.h"
+#include "llvoavatar.h"
+#include "llvocache.h"
const S32 MIN_QUIET_FRAMES_COALESCE = 30;
const F32 FORCE_SIMPLE_RENDER_AREA = 512.f;
@@ -82,6 +94,7 @@ LLPointer<LLObjectMediaNavigateClient> LLVOVolume::sObjectMediaNavigateClient =
static LLFastTimer::DeclareTimer FTM_GEN_TRIANGLES("Generate Triangles");
static LLFastTimer::DeclareTimer FTM_GEN_VOLUME("Generate Volumes");
+static LLFastTimer::DeclareTimer FTM_VOLUME_TEXTURES("Volume Textures");
// Implementation class of LLMediaDataClientObject. See llmediadataclient.h
class LLMediaDataClientObjectImpl : public LLMediaDataClientObject
@@ -388,10 +401,12 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys,
// There's something bogus in the data that we're unpacking.
dp->dumpBufferToLog();
llwarns << "Flushing cache files" << llendl;
- std::string mask;
- mask = gDirUtilp->getDirDelimiter() + "*.slc";
- gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""), mask);
-// llerrs << "Bogus TE data in " << getID() << ", crashing!" << llendl;
+
+ if(LLVOCache::hasInstance() && getRegion())
+ {
+ LLVOCache::getInstance()->removeEntry(getRegion()->getHandle()) ;
+ }
+
llwarns << "Bogus TE data in " << getID() << llendl;
}
else
@@ -667,11 +682,33 @@ void LLVOVolume::updateTextures()
}
}
+BOOL LLVOVolume::isVisible() const
+{
+ if(mDrawable.notNull() && mDrawable->isVisible())
+ {
+ return TRUE ;
+ }
+
+ if(isAttachment())
+ {
+ LLViewerObject* objp = (LLViewerObject*)getParent() ;
+ while(objp && !objp->isAvatar())
+ {
+ objp = (LLViewerObject*)objp->getParent() ;
+ }
+
+ return objp && objp->mDrawable.notNull() && objp->mDrawable->isVisible() ;
+ }
+
+ return FALSE ;
+}
+
void LLVOVolume::updateTextureVirtualSize()
{
+ LLFastTimer ftm(FTM_VOLUME_TEXTURES);
// Update the pixel area of all faces
- if(mDrawable.isNull() || !mDrawable->isVisible())
+ if(!isVisible())
{
return ;
}
@@ -702,7 +739,7 @@ void LLVOVolume::updateTextureVirtualSize()
const LLTextureEntry *te = face->getTextureEntry();
LLViewerTexture *imagep = face->getTexture();
if (!imagep || !te ||
- face->mExtents[0] == face->mExtents[1])
+ face->mExtents[0].equals3(face->mExtents[1]))
{
continue;
}
@@ -761,10 +798,12 @@ void LLVOVolume::updateTextureVirtualSize()
if (isSculpted())
{
LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT);
- LLUUID id = sculpt_params->getSculptTexture();
+ LLUUID id = sculpt_params->getSculptTexture();
updateSculptTexture();
+
+
if (mSculptTexture.notNull())
{
mSculptTexture->setBoostLevel(llmax((S32)mSculptTexture->getBoostLevel(),
@@ -805,6 +844,7 @@ void LLVOVolume::updateTextureVirtualSize()
mSculptTexture->getHeight(), mSculptTexture->getWidth()));
}
}
+
}
if (getLightTextureID().notNull())
@@ -820,18 +860,18 @@ void LLVOVolume::updateTextureVirtualSize()
*camera));
}
}
-
+
if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_AREA))
{
- setDebugText(llformat("%.0f:%.0f", fsqrtf(min_vsize),fsqrtf(max_vsize)));
+ setDebugText(llformat("%.0f:%.0f", (F32) sqrt(min_vsize),(F32) sqrt(max_vsize)));
}
else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY))
{
- setDebugText(llformat("%.0f:%.0f", fsqrtf(min_vsize),fsqrtf(max_vsize)));
+ setDebugText(llformat("%.0f:%.0f", (F32) sqrt(min_vsize),(F32) sqrt(max_vsize)));
}
else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_FACE_AREA))
{
- setDebugText(llformat("%.0f:%.0f", fsqrtf(min_vsize),fsqrtf(max_vsize)));
+ setDebugText(llformat("%.0f:%.0f", (F32) sqrt(min_vsize),(F32) sqrt(max_vsize)));
}
if (mPixelArea == 0)
@@ -842,7 +882,8 @@ void LLVOVolume::updateTextureVirtualSize()
BOOL LLVOVolume::isActive() const
{
- return !mStatic || mTextureAnimp || (mVolumeImpl && mVolumeImpl->isActive());
+ return !mStatic || mTextureAnimp || (mVolumeImpl && mVolumeImpl->isActive()) ||
+ (mDrawable.notNull() && mDrawable->isActive());
}
BOOL LLVOVolume::setMaterial(const U8 material)
@@ -916,8 +957,35 @@ LLDrawable *LLVOVolume::createDrawable(LLPipeline *pipeline)
return mDrawable;
}
-BOOL LLVOVolume::setVolume(const LLVolumeParams &volume_params, const S32 detail, bool unique_volume)
+BOOL LLVOVolume::setVolume(const LLVolumeParams &params_in, const S32 detail, bool unique_volume)
{
+ LLVolumeParams volume_params = params_in;
+
+ S32 last_lod = mVolumep.notNull() ? LLVolumeLODGroup::getVolumeDetailFromScale(mVolumep->getDetail()) : -1;
+ S32 lod = mLOD;
+
+ BOOL is404 = FALSE;
+
+ if (isSculpted())
+ {
+ // if it's a mesh
+ if ((volume_params.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH)
+ { //meshes might not have all LODs, get the force detail to best existing LOD
+
+ LLUUID mesh_id = volume_params.getSculptID();
+
+ //profile and path params don't matter for meshes
+ volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
+
+ lod = gMeshRepo.getActualMeshLOD(volume_params, lod);
+ if (lod == -1)
+ {
+ is404 = TRUE;
+ lod = 0;
+ }
+ }
+ }
+
// Check if we need to change implementations
bool is_flexible = (volume_params.getPathParams().getCurveType() == LL_PCODE_PATH_FLEXIBLE);
if (is_flexible)
@@ -945,29 +1013,53 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams &volume_params, const S32 detail
}
}
- if ((LLPrimitive::setVolume(volume_params, mLOD, (mVolumeImpl && mVolumeImpl->isVolumeUnique()))) || mSculptChanged)
+ if (is404)
+ {
+ setIcon(LLViewerTextureManager::getFetchedTextureFromFile("icons/Inv_Mesh.png", TRUE, LLViewerTexture::BOOST_UI));
+ }
+
+ if ((LLPrimitive::setVolume(volume_params, lod, (mVolumeImpl && mVolumeImpl->isVolumeUnique()))) || mSculptChanged)
{
mFaceMappingChanged = TRUE;
if (mVolumeImpl)
{
- mVolumeImpl->onSetVolume(volume_params, detail);
+ mVolumeImpl->onSetVolume(volume_params, mLOD);
}
updateSculptTexture();
+
if (isSculpted())
{
updateSculptTexture();
-
- if (mSculptTexture.notNull())
+ // if it's a mesh
+ if ((volume_params.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH)
{
- sculpt();
+ if (getVolume()->getNumVolumeFaces() == 0 || getVolume()->isTetrahedron())
+ {
+ //load request not yet issued, request pipeline load this mesh
+ LLUUID asset_id = volume_params.getSculptID();
+ S32 available_lod = gMeshRepo.loadMesh(this, volume_params, lod, last_lod);
+ if (available_lod != lod)
+ {
+ LLPrimitive::setVolume(volume_params, available_lod);
+ }
+ }
+
+ }
+ else // otherwise is sculptie
+ {
+ if (mSculptTexture.notNull())
+ {
+ sculpt();
+ }
}
}
return TRUE;
}
+
return FALSE;
}
@@ -975,7 +1067,7 @@ void LLVOVolume::updateSculptTexture()
{
LLPointer<LLViewerFetchedTexture> old_sculpt = mSculptTexture;
- if (isSculpted())
+ if (isSculpted() && !isMesh())
{
LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT);
LLUUID id = sculpt_params->getSculptTexture();
@@ -1003,6 +1095,14 @@ void LLVOVolume::updateSculptTexture()
}
+
+
+void LLVOVolume::notifyMeshLoaded()
+{
+ mSculptChanged = TRUE;
+ gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE);
+}
+
// sculpt replaces generate() for sculpted surfaces
void LLVOVolume::sculpt()
{
@@ -1106,10 +1206,26 @@ BOOL LLVOVolume::calcLOD()
S32 cur_detail = 0;
- F32 radius = getVolume()->mLODScaleBias.scaledVec(getScale()).length();
- F32 distance = mDrawable->mDistanceWRTCamera; //llmin(mDrawable->mDistanceWRTCamera, MAX_LOD_DISTANCE);
+ F32 radius;
+ F32 distance;
+
+ if (mDrawable->isState(LLDrawable::RIGGED))
+ {
+ LLVOAvatar* avatar = getAvatar();
+ distance = avatar->mDrawable->mDistanceWRTCamera;
+ radius = avatar->getBinRadius();
+ }
+ else
+ {
+ distance = mDrawable->mDistanceWRTCamera;
+ radius = getVolume()->mLODScaleBias.scaledVec(getScale()).length();
+ }
+
+ //hold onto unmodified distance for debugging
+ F32 debug_distance = distance;
+
distance *= sDistanceFactor;
-
+
F32 rampDist = LLVOVolume::sLODFactor * 2;
if (distance < rampDist)
@@ -1126,6 +1242,12 @@ BOOL LLVOVolume::calcLOD()
cur_detail = computeLODDetail(llround(distance, 0.01f),
llround(radius, 0.01f));
+
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_LOD_INFO))
+ {
+ setDebugText(llformat("%.2f:%.2f, %d", debug_distance, radius, cur_detail));
+ }
+
if (cur_detail != mLOD)
{
mAppAngle = llround((F32) atan2( mDrawable->getRadius(), mDrawable->mDistanceWRTCamera) * RAD_TO_DEG, 0.01f);
@@ -1153,7 +1275,7 @@ BOOL LLVOVolume::updateLOD()
mLODChanged = TRUE;
}
- lod_changed |= LLViewerObject::updateLOD();
+ lod_changed = lod_changed || LLViewerObject::updateLOD();
return lod_changed;
}
@@ -1189,6 +1311,11 @@ void LLVOVolume::updateFaceFlags()
for (S32 i = 0; i < getVolume()->getNumFaces(); i++)
{
LLFace *face = mDrawable->getFace(i);
+ if (!face)
+ {
+ return;
+ }
+
BOOL fullbright = getTE(i)->getFullbright();
face->clearState(LLFace::FULLBRIGHT | LLFace::HUD_RENDER | LLFace::LIGHT);
@@ -1268,14 +1395,28 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global)
{
BOOL res = TRUE;
- LLVector3 min,max;
+ LLVector4a min,max;
- BOOL rebuild = mDrawable->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION);
+ min.clear();
+ max.clear();
- for (S32 i = 0; i < getVolume()->getNumFaces(); i++)
+ BOOL rebuild = mDrawable->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION | LLDrawable::REBUILD_RIGGED);
+
+// bool rigged = false;
+ LLVolume* volume = mRiggedVolume;
+ if (!volume)
+ {
+ volume = getVolume();
+ }
+
+ for (S32 i = 0; i < getVolume()->getNumVolumeFaces(); i++)
{
LLFace *face = mDrawable->getFace(i);
- res &= face->genVolumeBBoxes(*getVolume(), i,
+ if (!face)
+ {
+ continue;
+ }
+ res &= face->genVolumeBBoxes(*volume, i,
mRelativeXform, mRelativeXformInvTrans,
(mVolumeImpl && mVolumeImpl->isVolumeGlobal()) || force_global);
@@ -1288,17 +1429,8 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global)
}
else
{
- for (U32 i = 0; i < 3; i++)
- {
- if (face->mExtents[0].mV[i] < min.mV[i])
- {
- min.mV[i] = face->mExtents[0].mV[i];
- }
- if (face->mExtents[1].mV[i] > max.mV[i])
- {
- max.mV[i] = face->mExtents[1].mV[i];
- }
- }
+ min.setMin(min, face->mExtents[0]);
+ max.setMax(max, face->mExtents[1]);
}
}
}
@@ -1306,7 +1438,9 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global)
if (rebuild)
{
mDrawable->setSpatialExtents(min,max);
- mDrawable->setPositionGroup((min+max)*0.5f);
+ min.add(max);
+ min.mul(0.5f);
+ mDrawable->setPositionGroup(min);
}
updateRadius();
@@ -1333,7 +1467,21 @@ void LLVOVolume::updateRelativeXform()
LLDrawable* drawable = mDrawable;
- if (drawable->isActive())
+ if (drawable->isState(LLDrawable::RIGGED) && mRiggedVolume.notNull())
+ { //rigged volume (which is in agent space) is used for generating bounding boxes etc
+ //inverse of render matrix should go to partition space
+ mRelativeXform = getRenderMatrix();
+
+ F32* dst = (F32*) mRelativeXformInvTrans.mMatrix;
+ F32* src = (F32*) mRelativeXform.mMatrix;
+ dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2];
+ dst[3] = src[4]; dst[4] = src[5]; dst[5] = src[6];
+ dst[6] = src[8]; dst[7] = src[9]; dst[8] = src[10];
+
+ mRelativeXform.invert();
+ mRelativeXformInvTrans.transpose();
+ }
+ else if (drawable->isActive())
{
// setup relative transforms
LLQuaternion delta_rot;
@@ -1415,11 +1563,22 @@ void LLVOVolume::updateRelativeXform()
static LLFastTimer::DeclareTimer FTM_GEN_FLEX("Generate Flexies");
static LLFastTimer::DeclareTimer FTM_UPDATE_PRIMITIVES("Update Primitives");
+static LLFastTimer::DeclareTimer FTM_UPDATE_RIGGED_VOLUME("Update Rigged");
BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
{
LLFastTimer t(FTM_UPDATE_PRIMITIVES);
+ if (mDrawable->isState(LLDrawable::REBUILD_RIGGED))
+ {
+ {
+ LLFastTimer t(FTM_UPDATE_RIGGED_VOLUME);
+ updateRiggedVolume();
+ }
+ genBBoxes(FALSE);
+ mDrawable->clearState(LLDrawable::REBUILD_RIGGED);
+ }
+
if (mVolumeImpl != NULL)
{
BOOL res;
@@ -1496,6 +1655,17 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
regenFaces();
}
genBBoxes(FALSE);
+
+ if (mSculptChanged)
+ { //changes in sculpt maps can thrash an object bounding box without
+ //triggering a spatial group bounding box update -- force spatial group
+ //to update bounding boxes
+ LLSpatialGroup* group = mDrawable->getSpatialGroup();
+ if (group)
+ {
+ group->unbound();
+ }
+ }
}
}
}
@@ -1515,12 +1685,12 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
{
LLPipeline::sCompiles++;
}
-
+
mVolumeChanged = FALSE;
mLODChanged = FALSE;
mSculptChanged = FALSE;
mFaceMappingChanged = FALSE;
-
+
return LLViewerObject::updateGeometry(drawable);
}
@@ -1529,19 +1699,14 @@ void LLVOVolume::updateFaceSize(S32 idx)
LLFace* facep = mDrawable->getFace(idx);
if (idx >= getVolume()->getNumVolumeFaces())
{
- facep->setSize(0,0);
+ facep->setSize(0,0, true);
}
else
{
const LLVolumeFace& vol_face = getVolume()->getVolumeFace(idx);
- if (LLPipeline::sUseTriStrips)
- {
- facep->setSize(vol_face.mVertices.size(), vol_face.mTriStrip.size());
- }
- else
- {
- facep->setSize(vol_face.mVertices.size(), vol_face.mIndices.size());
- }
+ facep->setSize(vol_face.mNumVertices, vol_face.mNumIndices,
+ true); // <--- volume faces should be padded for 16-byte alignment
+
}
}
@@ -1796,21 +1961,25 @@ bool LLVOVolume::hasMedia() const
LLVector3 LLVOVolume::getApproximateFaceNormal(U8 face_id)
{
LLVolume* volume = getVolume();
- LLVector3 result;
+ LLVector4a result;
+ result.clear();
+
+ LLVector3 ret;
if (volume && face_id < volume->getNumVolumeFaces())
{
const LLVolumeFace& face = volume->getVolumeFace(face_id);
- for (S32 i = 0; i < (S32)face.mVertices.size(); ++i)
+ for (S32 i = 0; i < (S32)face.mNumVertices; ++i)
{
- result += face.mVertices[i].mNormal;
+ result.add(face.mNormals[i]);
}
- result = volumeDirectionToAgent(result);
- result.normVec();
+ LLVector3 ret(result.getF32ptr());
+ ret = volumeDirectionToAgent(ret);
+ ret.normVec();
}
- return result;
+ return ret;
}
void LLVOVolume::requestMediaDataUpdate(bool isNew)
@@ -2142,7 +2311,7 @@ void LLVOVolume::removeMediaImpl(S32 texture_index)
}
//make the face referencing to mMediaImplList[texture_index] to point back to the old texture.
- if(mDrawable)
+ if(mDrawable && texture_index < mDrawable->getNumFaces())
{
LLFace* facep = mDrawable->getFace(texture_index) ;
if(facep)
@@ -2607,6 +2776,23 @@ BOOL LLVOVolume::isSculpted() const
return FALSE;
}
+BOOL LLVOVolume::isMesh() const
+{
+ if (isSculpted())
+ {
+ LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT);
+ U8 sculpt_type = sculpt_params->getSculptType();
+
+ if ((sculpt_type & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH)
+ // mesh is a mesh
+ {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
BOOL LLVOVolume::hasLightTexture() const
{
if (getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE))
@@ -2623,6 +2809,11 @@ BOOL LLVOVolume::isVolumeGlobal() const
{
return mVolumeImpl->isVolumeGlobal() ? TRUE : FALSE;
}
+ else if (mRiggedVolume.notNull())
+ {
+ return TRUE;
+ }
+
return FALSE;
}
@@ -2707,7 +2898,7 @@ void LLVOVolume::generateSilhouette(LLSelectNode* nodep, const LLVector3& view_p
trans_mat.translate(getRegion()->getOriginAgent());
}
- volume->generateSilhouetteVertices(nodep->mSilhouetteVertices, nodep->mSilhouetteNormals, nodep->mSilhouetteSegments, view_vector, trans_mat, mRelativeXformInvTrans, nodep->getTESelectMask());
+ volume->generateSilhouetteVertices(nodep->mSilhouetteVertices, nodep->mSilhouetteNormals, view_vector, trans_mat, mRelativeXformInvTrans, nodep->getTESelectMask());
nodep->mSilhouetteExists = TRUE;
}
@@ -2738,14 +2929,7 @@ void LLVOVolume::updateRadius()
BOOL LLVOVolume::isAttachment() const
{
- if (mState == 0)
- {
- return FALSE;
- }
- else
- {
- return TRUE;
- }
+ return mState != 0 ;
}
BOOL LLVOVolume::isHUDAttachment() const
@@ -2900,6 +3084,62 @@ U32 LLVOVolume::getRenderCost(std::set<LLUUID> &textures) const
}
+F32 LLVOVolume::getStreamingCost(S32* bytes, S32* visible_bytes)
+{
+ if (isMesh())
+ {
+ LLSD& header = gMeshRepo.getMeshHeader(getVolume()->getParams().getSculptID());
+
+ F32 radius = getScale().length();
+
+ return LLMeshRepository::getStreamingCost(header, radius, bytes, visible_bytes, mLOD);
+ }
+
+ return 0.f;
+}
+
+U32 LLVOVolume::getTriangleCount()
+{
+ U32 count = 0;
+ LLVolume* volume = getVolume();
+ if (volume)
+ {
+ count = volume->getNumTriangles();
+ }
+
+ return count;
+}
+
+U32 LLVOVolume::getHighLODTriangleCount()
+{
+ U32 ret = 0;
+
+ LLVolume* volume = getVolume();
+
+ if (!isSculpted())
+ {
+ LLVolume* ref = LLPrimitive::getVolumeManager()->refVolume(volume->getParams(), 3);
+ ret = ref->getNumTriangles();
+ LLPrimitive::getVolumeManager()->unrefVolume(ref);
+ }
+ else if (isMesh())
+ {
+ LLVolume* ref = LLPrimitive::getVolumeManager()->refVolume(volume->getParams(), 3);
+ if (ref->isTetrahedron() || ref->getNumVolumeFaces() == 0)
+ {
+ gMeshRepo.loadMesh(this, volume->getParams(), LLModel::LOD_HIGH);
+ }
+ ret = ref->getNumTriangles();
+ LLPrimitive::getVolumeManager()->unrefVolume(ref);
+ }
+ else
+ { //default sculpts have a constant number of triangles
+ ret = 31*2*31; //31 rows of 31 columns of quads for a 32x32 vertex patch
+ }
+
+ return ret;
+}
+
//static
void LLVOVolume::preUpdateGeom()
{
@@ -2937,7 +3177,7 @@ void LLVOVolume::setSelected(BOOL sel)
}
}
-void LLVOVolume::updateSpatialExtents(LLVector3& newMin, LLVector3& newMax)
+void LLVOVolume::updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax)
{
}
@@ -2945,7 +3185,9 @@ F32 LLVOVolume::getBinRadius()
{
F32 radius;
- const LLVector3* ext = mDrawable->getSpatialExtents();
+ F32 scale = 1.f;
+
+ const LLVector4a* ext = mDrawable->getSpatialExtents();
BOOL shrink_wrap = mDrawable->isAnimating();
BOOL alpha_wrap = FALSE;
@@ -2977,7 +3219,10 @@ F32 LLVOVolume::getBinRadius()
}
else if (shrink_wrap)
{
- radius = (ext[1]-ext[0]).length()*0.5f;
+ LLVector4a rad;
+ rad.setSub(ext[1], ext[0]);
+
+ radius = rad.getLength3().getF32()*0.5f;
}
else if (mDrawable->isStatic())
{
@@ -3001,7 +3246,7 @@ F32 LLVOVolume::getBinRadius()
radius = 8.f;
}
- return llclamp(radius, 0.5f, 256.f);
+ return llclamp(radius*scale, 0.5f, 256.f);
}
const LLVector3 LLVOVolume::getPivotPositionAgent() const
@@ -3013,7 +3258,7 @@ const LLVector3 LLVOVolume::getPivotPositionAgent() const
return LLViewerObject::getPivotPositionAgent();
}
-void LLVOVolume::onShift(const LLVector3 &shift_vector)
+void LLVOVolume::onShift(const LLVector4a &shift_vector)
{
if (mVolumeImpl)
{
@@ -3090,12 +3335,37 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& e
BOOL ret = FALSE;
LLVolume* volume = getVolume();
+
+ bool transform = true;
+
+ if (mDrawable->isState(LLDrawable::RIGGED))
+ {
+ if (LLFloater::isVisible(gFloaterTools) && getAvatar()->isSelf())
+ {
+ gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_RIGGED, TRUE);
+ volume = mRiggedVolume;
+ transform = false;
+ }
+ else
+ { //cannot pick rigged attachments on other avatars or when not in build mode
+ return FALSE;
+ }
+ }
+
if (volume)
{
LLVector3 v_start, v_end, v_dir;
- v_start = agentPositionToVolume(start);
- v_end = agentPositionToVolume(end);
+ if (transform)
+ {
+ v_start = agentPositionToVolume(start);
+ v_end = agentPositionToVolume(end);
+ }
+ else
+ {
+ v_start = start;
+ v_end = end;
+ }
LLVector3 p;
LLVector3 n;
@@ -3136,8 +3406,15 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& e
end_face = face+1;
}
+ bool special_cursor = specialHoverCursor();
for (S32 i = start_face; i < end_face; ++i)
{
+ if (!special_cursor && !pick_transparent && getTE(i)->getColor().mV[3] == 0.f)
+ { //don't attempt to pick completely transparent faces unless
+ //pick_transparent is true
+ continue;
+ }
+
face_hit = volume->lineSegmentIntersect(v_start, v_end, i,
&p, &tc, &n, &bn);
@@ -3155,18 +3432,40 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& e
if (intersection != NULL)
{
- *intersection = volumePositionToAgent(p); // must map back to agent space
+ if (transform)
+ {
+ *intersection = volumePositionToAgent(p); // must map back to agent space
+ }
+ else
+ {
+ *intersection = p;
+ }
}
if (normal != NULL)
{
- *normal = volumeDirectionToAgent(n);
+ if (transform)
+ {
+ *normal = volumeDirectionToAgent(n);
+ }
+ else
+ {
+ *normal = n;
+ }
+
(*normal).normVec();
}
if (bi_normal != NULL)
{
- *bi_normal = volumeDirectionToAgent(bn);
+ if (transform)
+ {
+ *bi_normal = volumeDirectionToAgent(bn);
+ }
+ else
+ {
+ *bi_normal = bn;
+ }
(*bi_normal).normVec();
}
@@ -3184,6 +3483,201 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& e
return ret;
}
+bool LLVOVolume::treatAsRigged()
+{
+ return LLFloater::isVisible(gFloaterTools) &&
+ isAttachment() &&
+ getAvatar() &&
+ getAvatar()->isSelf() &&
+ mDrawable.notNull() &&
+ mDrawable->isState(LLDrawable::RIGGED);
+}
+
+LLRiggedVolume* LLVOVolume::getRiggedVolume()
+{
+ return mRiggedVolume;
+}
+
+void LLVOVolume::clearRiggedVolume()
+{
+ if (mRiggedVolume.notNull())
+ {
+ mRiggedVolume = NULL;
+ updateRelativeXform();
+ }
+}
+
+void LLVOVolume::updateRiggedVolume()
+{
+ //Update mRiggedVolume to match current animation frame of avatar.
+ //Also update position/size in octree.
+
+ if (!treatAsRigged())
+ {
+ clearRiggedVolume();
+
+ return;
+ }
+
+ LLVolume* volume = getVolume();
+
+ const LLMeshSkinInfo* skin = gMeshRepo.getSkinInfo(volume->getParams().getSculptID());
+
+ if (!skin)
+ {
+ clearRiggedVolume();
+ return;
+ }
+
+ LLVOAvatar* avatar = getAvatar();
+
+ if (!avatar)
+ {
+ clearRiggedVolume();
+ return;
+ }
+
+ if (!mRiggedVolume)
+ {
+ LLVolumeParams p;
+ mRiggedVolume = new LLRiggedVolume(p);
+ updateRelativeXform();
+ }
+
+ mRiggedVolume->update(skin, avatar, volume);
+
+}
+
+static LLFastTimer::DeclareTimer FTM_SKIN_RIGGED("Skin");
+static LLFastTimer::DeclareTimer FTM_RIGGED_OCTREE("Octree");
+
+void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, const LLVolume* volume)
+{
+ bool copy = false;
+ if (volume->getNumVolumeFaces() != getNumVolumeFaces())
+ {
+ copy = true;
+ }
+
+ for (S32 i = 0; i < volume->getNumVolumeFaces() && !copy; ++i)
+ {
+ const LLVolumeFace& src_face = volume->getVolumeFace(i);
+ const LLVolumeFace& dst_face = getVolumeFace(i);
+
+ if (src_face.mNumIndices != dst_face.mNumIndices ||
+ src_face.mNumVertices != dst_face.mNumVertices)
+ {
+ copy = true;
+ }
+ }
+
+ if (copy)
+ {
+ copyVolumeFaces(volume);
+ }
+
+ //build matrix palette
+ LLMatrix4a mp[64];
+ LLMatrix4* mat = (LLMatrix4*) mp;
+
+ for (U32 j = 0; j < skin->mJointNames.size(); ++j)
+ {
+ LLJoint* joint = avatar->getJoint(skin->mJointNames[j]);
+ if (joint)
+ {
+ mat[j] = skin->mInvBindMatrix[j];
+ mat[j] *= joint->getWorldMatrix();
+ }
+ }
+
+ for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
+ {
+ const LLVolumeFace& vol_face = volume->getVolumeFace(i);
+
+ LLVolumeFace& dst_face = mVolumeFaces[i];
+
+ LLVector4a* weight = vol_face.mWeights;
+
+ LLMatrix4a bind_shape_matrix;
+ bind_shape_matrix.loadu(skin->mBindShapeMatrix);
+
+ LLVector4a* pos = dst_face.mPositions;
+
+ {
+ LLFastTimer t(FTM_SKIN_RIGGED);
+
+ for (U32 j = 0; j < dst_face.mNumVertices; ++j)
+ {
+ LLMatrix4a final_mat;
+ final_mat.clear();
+
+ S32 idx[4];
+
+ LLVector4 wght;
+
+ F32 scale = 0.f;
+ for (U32 k = 0; k < 4; k++)
+ {
+ F32 w = weight[j][k];
+
+ idx[k] = (S32) floorf(w);
+ wght[k] = w - floorf(w);
+ scale += wght[k];
+ }
+
+ wght *= 1.f/scale;
+
+ for (U32 k = 0; k < 4; k++)
+ {
+ F32 w = wght[k];
+
+ LLMatrix4a src;
+ src.setMul(mp[idx[k]], w);
+
+ final_mat.add(src);
+ }
+
+
+ LLVector4a& v = vol_face.mPositions[j];
+ LLVector4a t;
+ LLVector4a dst;
+ bind_shape_matrix.affineTransform(v, t);
+ final_mat.affineTransform(t, dst);
+ pos[j] = dst;
+ }
+
+ //update bounding box
+ LLVector4a& min = dst_face.mExtents[0];
+ LLVector4a& max = dst_face.mExtents[1];
+
+ min = pos[0];
+ max = pos[1];
+
+ for (U32 j = 1; j < dst_face.mNumVertices; ++j)
+ {
+ min.setMin(min, pos[j]);
+ max.setMax(max, pos[j]);
+ }
+
+ dst_face.mCenter->setAdd(dst_face.mExtents[0], dst_face.mExtents[1]);
+ dst_face.mCenter->mul(0.5f);
+
+ }
+
+ {
+ LLFastTimer t(FTM_RIGGED_OCTREE);
+ delete dst_face.mOctree;
+ dst_face.mOctree = NULL;
+
+ LLVector4a size;
+ size.setSub(dst_face.mExtents[1], dst_face.mExtents[0]);
+ size.splat(size.getLength3().getF32()*0.5f);
+
+ dst_face.createOctree(1.f);
+ }
+ }
+}
+
U32 LLVOVolume::getPartitionType() const
{
if (isHUDAttachment())
@@ -3236,7 +3730,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
(type == LLRenderPass::PASS_INVISIBLE) ||
(type == LLRenderPass::PASS_ALPHA && facep->isState(LLFace::FULLBRIGHT));
- if (!fullbright && type != LLRenderPass::PASS_GLOW && !facep->mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_NORMAL))
+ if (!fullbright && type != LLRenderPass::PASS_GLOW && !facep->getVertexBuffer()->hasDataType(LLVertexBuffer::TYPE_NORMAL))
{
llwarns << "Non fullbright face has no normals!" << llendl;
return;
@@ -3258,22 +3752,20 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
else
{
model_mat = &(drawable->getRegion()->mRenderMatrix);
+ if (model_mat->isIdentity())
+ {
+ model_mat = NULL;
+ }
}
-
U8 bump = (type == LLRenderPass::PASS_BUMP || type == LLRenderPass::PASS_POST_BUMP) ? facep->getTextureEntry()->getBumpmap() : 0;
LLViewerTexture* tex = facep->getTexture();
U8 glow = (U8) (facep->getTextureEntry()->getGlow() * 255);
- if (facep->mVertexBuffer.isNull())
- {
- llerrs << "WTF?" << llendl;
- }
-
if (idx >= 0 &&
- draw_vec[idx]->mVertexBuffer == facep->mVertexBuffer &&
+ draw_vec[idx]->mVertexBuffer == facep->getVertexBuffer() &&
draw_vec[idx]->mEnd == facep->getGeomIndex()-1 &&
(LLPipeline::sTextureBindTest || draw_vec[idx]->mTexture == tex) &&
#if LL_DARWIN
@@ -3289,7 +3781,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
draw_vec[idx]->mCount += facep->getIndicesCount();
draw_vec[idx]->mEnd += facep->getGeomCount();
draw_vec[idx]->mVSize = llmax(draw_vec[idx]->mVSize, facep->getVirtualSize());
- validate_draw_info(*draw_vec[idx]);
+ draw_vec[idx]->validate();
update_min_max(draw_vec[idx]->mExtents[0], draw_vec[idx]->mExtents[1], facep->mExtents[0]);
update_min_max(draw_vec[idx]->mExtents[0], draw_vec[idx]->mExtents[1], facep->mExtents[1]);
}
@@ -3300,7 +3792,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
U32 offset = facep->getIndicesStart();
U32 count = facep->getIndicesCount();
LLPointer<LLDrawInfo> draw_info = new LLDrawInfo(start,end,count,offset, tex,
- facep->mVertexBuffer, fullbright, bump);
+ facep->getVertexBuffer(), fullbright, bump);
draw_info->mGroup = group;
draw_info->mVSize = facep->getVirtualSize();
draw_vec.push_back(draw_info);
@@ -3313,12 +3805,13 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
}
draw_info->mExtents[0] = facep->mExtents[0];
draw_info->mExtents[1] = facep->mExtents[1];
- validate_draw_info(*draw_info);
if (LLPipeline::sUseTriStrips)
{
draw_info->mDrawMode = LLRender::TRIANGLE_STRIP;
}
+
+ draw_info->validate();
}
}
@@ -3330,6 +3823,32 @@ void LLVolumeGeometryManager::getGeometry(LLSpatialGroup* group)
static LLFastTimer::DeclareTimer FTM_REBUILD_VOLUME_VB("Volume");
static LLFastTimer::DeclareTimer FTM_REBUILD_VBO("VBO Rebuilt");
+static LLDrawPoolAvatar* get_avatar_drawpool(LLViewerObject* vobj)
+{
+ LLVOAvatar* avatar = vobj->getAvatar();
+
+ if (avatar)
+ {
+ LLDrawable* drawable = avatar->mDrawable;
+ if (drawable && drawable->getNumFaces() > 0)
+ {
+ LLFace* face = drawable->getFace(0);
+ if (face)
+ {
+ LLDrawPool* drawpool = face->getPool();
+ if (drawpool)
+ {
+ if (drawpool->getType() == LLDrawPool::POOL_AVATAR)
+ {
+ return (LLDrawPoolAvatar*) drawpool;
+ }
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
{
@@ -3368,8 +3887,8 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
std::vector<LLFace*> alpha_faces;
U32 useage = group->mSpatialPartition->mBufferUsage;
- U32 max_vertices = (gSavedSettings.getS32("RenderMaxVBOSize")*1024)/LLVertexBuffer::calcStride(group->mSpatialPartition->mVertexDataMask);
- U32 max_total = (gSavedSettings.getS32("RenderMaxNodeSize")*1024)/LLVertexBuffer::calcStride(group->mSpatialPartition->mVertexDataMask);
+ U32 max_vertices = (gSavedSettings.getS32("RenderMaxVBOSize")*1024)/LLVertexBuffer::calcVertexSize(group->mSpatialPartition->mVertexDataMask);
+ U32 max_total = (gSavedSettings.getS32("RenderMaxNodeSize")*1024)/LLVertexBuffer::calcVertexSize(group->mSpatialPartition->mVertexDataMask);
max_vertices = llmin(max_vertices, (U32) 65535);
U32 cur_total = 0;
@@ -3390,29 +3909,210 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
}
LLVOVolume* vobj = drawablep->getVOVolume();
+
+ if (vobj->getVolume() && vobj->getVolume()->isTetrahedron())
+ {
+ continue;
+ }
+
llassert_always(vobj);
vobj->updateTextureVirtualSize();
vobj->preRebuild();
drawablep->clearState(LLDrawable::HAS_ALPHA);
+ bool rigged = vobj->isAttachment() &&
+ vobj->isMesh() &&
+ gMeshRepo.getSkinInfo(vobj->getVolume()->getParams().getSculptID());
+
+ bool bake_sunlight = LLPipeline::sBakeSunlight && drawablep->isStatic();
+
+ bool is_rigged = false;
+
//for each face
for (S32 i = 0; i < drawablep->getNumFaces(); i++)
{
+ LLFace* facep = drawablep->getFace(i);
+
+ //ALWAYS null out vertex buffer on rebuild -- if the face lands in a render
+ // batch, it will recover its vertex buffer reference from the spatial group
+ facep->setVertexBuffer(NULL);
+
//sum up face verts and indices
drawablep->updateFaceSize(i);
- LLFace* facep = drawablep->getFace(i);
+
+
+
+ if (rigged)
+ {
+ if (!facep->isState(LLFace::RIGGED))
+ { //completely reset vertex buffer
+ facep->clearVertexBuffer();
+ }
+
+ facep->setState(LLFace::RIGGED);
+ is_rigged = true;
+
+ //get drawpool of avatar with rigged face
+ LLDrawPoolAvatar* pool = get_avatar_drawpool(vobj);
+
+ //Determine if we've received skininfo that contains an
+ //alternate bind matrix - if it does then apply the translational component
+ //to the joints of the avatar.
+ LLVOAvatar* pAvatarVO = vobj->getAvatar();
+ bool pelvisGotSet = false;
+
+ if ( pAvatarVO )
+ {
+ LLUUID currentId = vobj->getVolume()->getParams().getSculptID();
+ const LLMeshSkinInfo* pSkinData = gMeshRepo.getSkinInfo( currentId );
+
+ if ( pSkinData )
+ {
+ const int bindCnt = pSkinData->mAlternateBindMatrix.size();
+ if ( bindCnt > 0 )
+ {
+ const int jointCnt = pSkinData->mJointNames.size();
+ const F32 pelvisZOffset = pSkinData->mPelvisOffset;
+ bool fullRig = (jointCnt>=20) ? true : false;
+ if ( fullRig )
+ {
+ for ( int i=0; i<jointCnt; ++i )
+ {
+ std::string lookingForJoint = pSkinData->mJointNames[i].c_str();
+ //llinfos<<"joint name "<<lookingForJoint.c_str()<<llendl;
+ LLJoint* pJoint = pAvatarVO->getJoint( lookingForJoint );
+ if ( pJoint && pJoint->getId() != currentId )
+ {
+ pJoint->setId( currentId );
+ const LLVector3& jointPos = pSkinData->mAlternateBindMatrix[i].getTranslation();
+ //Set the joint position
+ pJoint->storeCurrentXform( jointPos );
+ //If joint is a pelvis then handle old/new pelvis to foot values
+ if ( lookingForJoint == "mPelvis" )
+ {
+ pJoint->storeCurrentXform( jointPos );
+ if ( !pAvatarVO->hasPelvisOffset() )
+ {
+ pAvatarVO->setPelvisOffset( true, jointPos, pelvisZOffset );
+ //Trigger to rebuild viewer AV
+ pelvisGotSet = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ //If we've set the pelvis to a new position we need to also rebuild some information that the
+ //viewer does at launch (e.g. body size etc.)
+ if ( pelvisGotSet )
+ {
+ pAvatarVO->postPelvisSetRecalc();
+ }
+
+ if (pool)
+ {
+ const LLTextureEntry* te = facep->getTextureEntry();
+
+ //remove face from old pool if it exists
+ LLDrawPool* old_pool = facep->getPool();
+ if (old_pool && old_pool->getType() == LLDrawPool::POOL_AVATAR)
+ {
+ ((LLDrawPoolAvatar*) old_pool)->removeRiggedFace(facep);
+ }
+
+ //add face to new pool
+ LLViewerTexture* tex = facep->getTexture();
+ U32 type = gPipeline.getPoolTypeFromTE(te, tex);
+
+ if (type == LLDrawPool::POOL_ALPHA)
+ {
+ if (te->getFullbright())
+ {
+ pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_ALPHA);
+ }
+ else
+ {
+ pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_ALPHA);
+ }
+ }
+ else if (te->getShiny())
+ {
+ if (te->getFullbright())
+ {
+ pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_SHINY);
+ }
+ else
+ {
+ if (LLPipeline::sRenderDeferred)
+ {
+ pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE);
+ }
+ else
+ {
+ pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SHINY);
+ }
+ }
+ }
+ else
+ {
+ if (te->getFullbright())
+ {
+ pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT);
+ }
+ else
+ {
+ pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE);
+ }
+ }
+
+ if (te->getGlow())
+ {
+ pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_GLOW);
+ }
+
+ if (LLPipeline::sRenderDeferred)
+ {
+ if (type != LLDrawPool::POOL_ALPHA && !te->getFullbright())
+ {
+ if (te->getBumpmap())
+ {
+ pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_BUMP);
+ }
+ else
+ {
+ pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_SIMPLE);
+ }
+ }
+ }
+ }
+
+ continue;
+ }
+ else
+ {
+ if (facep->isState(LLFace::RIGGED))
+ { //face is not rigged but used to be, remove from rigged face pool
+ LLDrawPoolAvatar* pool = (LLDrawPoolAvatar*) facep->getPool();
+ if (pool)
+ {
+ pool->removeRiggedFace(facep);
+ }
+ facep->clearState(LLFace::RIGGED);
+ }
+ }
if (cur_total > max_total || facep->getIndicesCount() <= 0 || facep->getGeomCount() <= 0)
{
- facep->mVertexBuffer = NULL;
- facep->mLastVertexBuffer = NULL;
+ facep->clearVertexBuffer();
continue;
}
cur_total += facep->getGeomCount();
- if (facep->hasGeometry() && facep->mPixelArea > FORCE_CULL_AREA)
+ if (facep->hasGeometry() && facep->getPixelArea() > FORCE_CULL_AREA)
{
const LLTextureEntry* te = facep->getTextureEntry();
LLViewerTexture* tex = facep->getTexture();
@@ -3425,7 +4125,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
}
}
- BOOL force_simple = (facep->mPixelArea < FORCE_SIMPLE_RENDER_AREA);
+ BOOL force_simple = (facep->getPixelArea() < FORCE_SIMPLE_RENDER_AREA);
U32 type = gPipeline.getPoolTypeFromTE(te, tex);
if (type != LLDrawPool::POOL_ALPHA && force_simple)
{
@@ -3497,7 +4197,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
bump_faces.push_back(facep);
}
else if ((te->getShiny() && LLPipeline::sRenderBump) ||
- !te->getFullbright())
+ !(te->getFullbright() || bake_sunlight))
{ //needs normal
simple_faces.push_back(facep);
}
@@ -3511,10 +4211,18 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
}
else
{ //face has no renderable geometry
- facep->mVertexBuffer = NULL;
- facep->mLastVertexBuffer = NULL;
+ facep->clearVertexBuffer();
}
}
+
+ if (is_rigged)
+ {
+ drawablep->setState(LLDrawable::RIGGED);
+ }
+ else
+ {
+ drawablep->clearState(LLDrawable::RIGGED);
+ }
}
group->mBufferUsage = useage;
@@ -3529,7 +4237,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
{
bump_mask |= LLVertexBuffer::MAP_BINORMAL;
}
-
+
genDrawInfo(group, simple_mask, simple_faces);
genDrawInfo(group, bump_mask, bump_faces);
genDrawInfo(group, fullbright_mask, fullbright_faces);
@@ -3575,24 +4283,25 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
LLFastTimer t(FTM_VOLUME_GEOM_PARTIAL);
LLDrawable* drawablep = *drawable_iter;
- if (drawablep->isDead() || drawablep->isState(LLDrawable::FORCE_INVISIBLE) )
- {
- continue;
- }
-
- if (drawablep->isState(LLDrawable::REBUILD_ALL))
+ if (!drawablep->isDead() && drawablep->isState(LLDrawable::REBUILD_ALL) )
{
LLVOVolume* vobj = drawablep->getVOVolume();
vobj->preRebuild();
+
LLVolume* volume = vobj->getVolume();
for (S32 i = 0; i < drawablep->getNumFaces(); ++i)
{
LLFace* face = drawablep->getFace(i);
- if (face && face->mVertexBuffer.notNull())
+ if (face && face->getVertexBuffer())
{
face->getGeometryVolume(*volume, face->getTEOffset(),
vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), face->getGeomIndex());
}
+
+ if (!face)
+ {
+ llerrs << "WTF?" << llendl;
+ }
}
drawablep->clearState(LLDrawable::REBUILD_ALL);
@@ -3635,9 +4344,10 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
for (S32 i = 0; i < drawablep->getNumFaces(); ++i)
{
LLFace* face = drawablep->getFace(i);
- if (face && face->mVertexBuffer.notNull() && face->mVertexBuffer->isLocked())
+ LLVertexBuffer* buff = face->getVertexBuffer();
+ if (face && buff && buff->isLocked())
{
- face->mVertexBuffer->setBuffer(0) ;
+ buff->setBuffer(0) ;
}
}
}
@@ -3655,7 +4365,7 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::vector<LLFace*>& faces, BOOL distance_sort)
{
//calculate maximum number of vertices to store in a single buffer
- U32 max_vertices = (gSavedSettings.getS32("RenderMaxVBOSize")*1024)/LLVertexBuffer::calcStride(group->mSpatialPartition->mVertexDataMask);
+ U32 max_vertices = (gSavedSettings.getS32("RenderMaxVBOSize")*1024)/LLVertexBuffer::calcVertexSize(group->mSpatialPartition->mVertexDataMask);
max_vertices = llmin(max_vertices, (U32) 65535);
if (!distance_sort)
@@ -3702,10 +4412,12 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
buffer_index = 0;
}
+ bool bake_sunlight = LLPipeline::sBakeSunlight && facep->getDrawable()->isStatic();
+
U32 index_count = facep->getIndicesCount();
U32 geom_count = facep->getGeomCount();
- //sum up vertices needed for this texture
+ //sum up vertices needed for this render batch
std::vector<LLFace*>::iterator i = face_iter;
++i;
@@ -3715,7 +4427,7 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
facep = *i;
if (geom_count + facep->getGeomCount() > max_vertices)
- { //cut vertex buffers on geom count too big
+ { //cut batches on geom count too big
break;
}
@@ -3743,10 +4455,11 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
buffer->allocateBuffer(geom_count, index_count, TRUE);
}
else
- {
- if (LLVertexBuffer::sEnableVBOs && buffer->getUsage() != group->mBufferUsage)
+ { //resize pre-existing buffer
+ if (LLVertexBuffer::sEnableVBOs && buffer->getUsage() != group->mBufferUsage ||
+ buffer->getTypeMask() != mask)
{
- buffer = createVertexBuffer(group->mSpatialPartition->mVertexDataMask,
+ buffer = createVertexBuffer(mask,
group->mBufferUsage);
buffer->allocateBuffer(geom_count, index_count, TRUE);
}
@@ -3764,15 +4477,18 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
U16 index_offset = 0;
while (face_iter < i)
- {
+ { //update face indices for new buffer
facep = *face_iter;
- facep->mIndicesIndex = indices_index;
- facep->mGeomIndex = index_offset;
- facep->mVertexBuffer = buffer;
+ facep->setIndicesIndex(indices_index);
+ facep->setGeomIndex(index_offset);
+ facep->setVertexBuffer(buffer);
+
{
+ //for debugging, set last time face was updated vs moved
facep->updateRebuildFlags();
+
if (!LLPipeline::sDelayVBUpdate)
- {
+ { //copy face geometry into vertex buffer
LLDrawable* drawablep = facep->getDrawable();
LLVOVolume* vobj = drawablep->getVOVolume();
LLVolume* volume = vobj->getVolume();
@@ -3789,9 +4505,12 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
}
index_offset += facep->getGeomCount();
- indices_index += facep->mIndicesCount;
+ indices_index += facep->getIndicesCount();
+
- BOOL force_simple = facep->mPixelArea < FORCE_SIMPLE_RENDER_AREA;
+ //append face to appropriate render batch
+
+ BOOL force_simple = facep->getPixelArea() < FORCE_SIMPLE_RENDER_AREA;
BOOL fullbright = facep->isState(LLFace::FULLBRIGHT);
if ((mask & LLVertexBuffer::MAP_NORMAL) == 0)
{ //paranoia check to make sure GL doesn't try to read non-existant normals
@@ -3807,7 +4526,7 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
// can we safely treat this as an alpha mask?
if (facep->canRenderAsMask())
{
- if (te->getFullbright())
+ if (te->getFullbright() || LLPipeline::sNoAlpha)
{
registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK);
}
@@ -3871,7 +4590,7 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
{ //invisiprim
registerFace(group, facep, LLRenderPass::PASS_INVISIBLE);
}
- else if (fullbright)
+ else if (fullbright || bake_sunlight)
{ //fullbright
registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT);
if (LLPipeline::sRenderDeferred && LLPipeline::sRenderBump && te->getBumpmap())
@@ -3958,7 +4677,7 @@ void LLGeometryManager::addGeometryCount(LLSpatialGroup* group, U32 &vertex_coun
//sum up face verts and indices
drawablep->updateFaceSize(i);
LLFace* facep = drawablep->getFace(i);
- if (facep->hasGeometry() && facep->mPixelArea > FORCE_CULL_AREA)
+ if (facep->hasGeometry() && facep->getPixelArea() > FORCE_CULL_AREA)
{
vertex_count += facep->getGeomCount();
index_count += facep->getIndicesCount();
@@ -3968,8 +4687,7 @@ void LLGeometryManager::addGeometryCount(LLSpatialGroup* group, U32 &vertex_coun
}
else
{
- facep->mVertexBuffer = NULL;
- facep->mLastVertexBuffer = NULL;
+ facep->clearVertexBuffer();
}
}
}
@@ -3985,7 +4703,7 @@ LLHUDPartition::LLHUDPartition()
mLODPeriod = 1;
}
-void LLHUDPartition::shift(const LLVector3 &offset)
+void LLHUDPartition::shift(const LLVector4a &offset)
{
//HUD objects don't shift with region crossing. That would be silly.
}
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h
index 1e9b9737b1..fc00f0c0d0 100644
--- a/indra/newview/llvovolume.h
+++ b/indra/newview/llvovolume.h
@@ -40,6 +40,8 @@ class LLDrawPool;
class LLSelectNode;
class LLObjectMediaDataClient;
class LLObjectMediaNavigateClient;
+class LLVOAvatar;
+class LLMeshSkinInfo;
typedef std::vector<viewer_media_t> media_list_t;
@@ -48,6 +50,18 @@ enum LLVolumeInterfaceType
INTERFACE_FLEXIBLE = 1,
};
+
+class LLRiggedVolume : public LLVolume
+{
+public:
+ LLRiggedVolume(const LLVolumeParams& params)
+ : LLVolume(params, 0.f)
+ {
+ }
+
+ void update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, const LLVolume* src_volume);
+};
+
// Base class for implementations of the volume - Primitive, Flexible Object, etc.
class LLVolumeInterface
{
@@ -60,7 +74,7 @@ public:
virtual void onSetVolume(const LLVolumeParams &volume_params, const S32 detail) = 0;
virtual void onSetScale(const LLVector3 &scale, BOOL damped) = 0;
virtual void onParameterChanged(U16 param_type, LLNetworkData *data, BOOL in_use, bool local_origin) = 0;
- virtual void onShift(const LLVector3 &shift_vector) = 0;
+ virtual void onShift(const LLVector4a &shift_vector) = 0;
virtual bool isVolumeUnique() const = 0; // Do we need a unique LLVolume instance?
virtual bool isVolumeGlobal() const = 0; // Are we in global space?
virtual bool isActive() const = 0; // Is this object currently active?
@@ -102,6 +116,7 @@ public:
void animateTextures();
/*virtual*/ BOOL idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time);
+ BOOL isVisible() const ;
/*virtual*/ BOOL isActive() const;
/*virtual*/ BOOL isAttachment() const;
/*virtual*/ BOOL isRootEdit() const; // overridden for sake of attachments treating themselves as a root object
@@ -115,7 +130,9 @@ public:
const LLMatrix3& getRelativeXformInvTrans() const { return mRelativeXformInvTrans; }
/*virtual*/ const LLMatrix4 getRenderMatrix() const;
U32 getRenderCost(std::set<LLUUID> &textures) const;
-
+ /*virtual*/ F32 getStreamingCost(S32* bytes = NULL, S32* visible_bytes = NULL);
+ /*virtual*/ U32 getTriangleCount();
+ /*virtual*/ U32 getHighLODTriangleCount();
/*virtual*/ BOOL lineSegmentIntersect(const LLVector3& start, const LLVector3& end,
S32 face = -1, // which face to check, -1 = ALL_SIDES
BOOL pick_transparent = FALSE,
@@ -139,7 +156,7 @@ public:
void markForUpdate(BOOL priority) { LLViewerObject::markForUpdate(priority); mVolumeChanged = TRUE; }
- /*virtual*/ void onShift(const LLVector3 &shift_vector); // Called when the drawable shifts
+ /*virtual*/ void onShift(const LLVector4a &shift_vector); // Called when the drawable shifts
/*virtual*/ void parameterChanged(U16 param_type, bool local_origin);
/*virtual*/ void parameterChanged(U16 param_type, LLNetworkData* data, BOOL in_use, bool local_origin);
@@ -178,6 +195,11 @@ public:
void updateSculptTexture();
void setIndexInTex(S32 index) { mIndexInTex = index ;}
void sculpt();
+ static void rebuildMeshAssetCallback(LLVFS *vfs,
+ const LLUUID& asset_uuid,
+ LLAssetType::EType type,
+ void* user_data, S32 status, LLExtStat ext_status);
+
void updateRelativeXform();
/*virtual*/ BOOL updateGeometry(LLDrawable *drawable);
/*virtual*/ void updateFaceSize(S32 idx);
@@ -190,7 +212,7 @@ public:
void regenFaces();
BOOL genBBoxes(BOOL force_global);
void preRebuild();
- virtual void updateSpatialExtents(LLVector3& min, LLVector3& max);
+ virtual void updateSpatialExtents(LLVector4a& min, LLVector4a& max);
virtual F32 getBinRadius();
virtual U32 getPartitionType() const;
@@ -224,6 +246,7 @@ public:
U32 getVolumeInterfaceID() const;
virtual BOOL isFlexible() const;
virtual BOOL isSculpted() const;
+ virtual BOOL isMesh() const;
virtual BOOL hasLightTexture() const;
BOOL isVolumeGlobal() const;
@@ -248,6 +271,7 @@ public:
void mediaNavigated(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin, std::string new_location);
void mediaEvent(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin, LLViewerMediaObserver::EMediaEvent event);
+
// Sync the given media data with the impl and the given te
void syncMediaData(S32 te, const LLSD &media_data, bool merge, bool ignore_agent);
@@ -263,9 +287,11 @@ public:
LLVector3 getApproximateFaceNormal(U8 face_id);
+ void notifyMeshLoaded();
+
// Returns 'true' iff the media data for this object is in flight
bool isMediaDataBeingFetched() const;
-
+
// Returns the "last fetched" media version, or -1 if not fetched yet
S32 getLastFetchedMediaVersion() const { return mLastFetchedMediaVersion; }
@@ -273,6 +299,21 @@ public:
void removeMDCImpl() { --mMDCImplCount; }
S32 getMDCImplCount() { return mMDCImplCount; }
+
+ //rigged volume update (for raycasting)
+ void updateRiggedVolume();
+ LLRiggedVolume* getRiggedVolume();
+
+ //returns true if volume should be treated as a rigged volume
+ // - Build tools are open
+ // - object is an attachment
+ // - object is attached to self
+ // - object is rendered as rigged
+ bool treatAsRigged();
+
+ //clear out rigged volume and revert back to non-rigged state for picking/LOD/distance updates
+ void clearRiggedVolume();
+
protected:
S32 computeLODDetail(F32 distance, F32 radius);
BOOL calcLOD();
@@ -306,6 +347,9 @@ private:
S32 mLastFetchedMediaVersion; // as fetched from the server, starts as -1
S32 mIndexInTex;
S32 mMDCImplCount;
+
+ LLPointer<LLRiggedVolume> mRiggedVolume;
+
// statics
public:
static F32 sLODSlopDistanceFactor;// Changing this to zero, effectively disables the LOD transition slop
diff --git a/indra/newview/llvowater.cpp b/indra/newview/llvowater.cpp
index 598938b710..69ebad61ac 100644
--- a/indra/newview/llvowater.cpp
+++ b/indra/newview/llvowater.cpp
@@ -60,8 +60,11 @@ const U32 WIDTH = (N_RES * WAVE_STEP); //128.f //64 // width of wave tile, in
const F32 WAVE_STEP_INV = (1. / WAVE_STEP);
-LLVOWater::LLVOWater(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
-: LLStaticViewerObject(id, LL_VO_WATER, regionp)
+LLVOWater::LLVOWater(const LLUUID &id,
+ const LLPCode pcode,
+ LLViewerRegion *regionp) :
+ LLStaticViewerObject(id, pcode, regionp),
+ mRenderType(LLPipeline::RENDER_TYPE_WATER)
{
// Terrain must draw during selection passes so it can block objects behind it.
mbCanSelect = FALSE;
@@ -114,7 +117,7 @@ LLDrawable *LLVOWater::createDrawable(LLPipeline *pipeline)
{
pipeline->allocDrawable(this);
mDrawable->setLit(FALSE);
- mDrawable->setRenderType(LLPipeline::RENDER_TYPE_WATER);
+ mDrawable->setRenderType(mRenderType);
LLDrawPoolWater *pool = (LLDrawPoolWater*) gPipeline.getPool(LLDrawPool::POOL_WATER);
@@ -152,21 +155,29 @@ BOOL LLVOWater::updateGeometry(LLDrawable *drawable)
LLStrider<U16> indicesp;
U16 index_offset;
- S32 size = 16;
- S32 num_quads = size*size;
- face->setSize(4*num_quads, 6*num_quads);
+ // A quad is 4 vertices and 6 indices (making 2 triangles)
+ static const unsigned int vertices_per_quad = 4;
+ static const unsigned int indices_per_quad = 6;
- if (face->mVertexBuffer.isNull())
+ const S32 size = gSavedSettings.getBOOL("RenderTransparentWater") ? 16 : 1;
+
+ const S32 num_quads = size * size;
+ face->setSize(vertices_per_quad * num_quads,
+ indices_per_quad * num_quads);
+
+ LLVertexBuffer* buff = face->getVertexBuffer();
+ if (!buff)
{
- face->mVertexBuffer = new LLVertexBuffer(LLDrawPoolWater::VERTEX_DATA_MASK, GL_DYNAMIC_DRAW_ARB);
- face->mVertexBuffer->allocateBuffer(face->getGeomCount(), face->getIndicesCount(), TRUE);
+ buff = new LLVertexBuffer(LLDrawPoolWater::VERTEX_DATA_MASK, GL_DYNAMIC_DRAW_ARB);
+ buff->allocateBuffer(face->getGeomCount(), face->getIndicesCount(), TRUE);
face->setIndicesIndex(0);
face->setGeomIndex(0);
+ face->setVertexBuffer(buff);
}
else
{
- face->mVertexBuffer->resizeBuffer(face->getGeomCount(), face->getIndicesCount());
+ buff->resizeBuffer(face->getGeomCount(), face->getIndicesCount());
}
index_offset = face->getGeometry(verticesp,normalsp,texCoordsp, indicesp);
@@ -220,7 +231,7 @@ BOOL LLVOWater::updateGeometry(LLDrawable *drawable)
}
}
- face->mVertexBuffer->setBuffer(0);
+ buff->setBuffer(0);
mDrawable->movePartition();
LLPipeline::sCompiles++;
@@ -252,15 +263,21 @@ void LLVOWater::setIsEdgePatch(const BOOL edge_patch)
mIsEdgePatch = edge_patch;
}
-void LLVOWater::updateSpatialExtents(LLVector3 &newMin, LLVector3& newMax)
+void LLVOWater::updateSpatialExtents(LLVector4a &newMin, LLVector4a& newMax)
{
- LLVector3 pos = getPositionAgent();
- LLVector3 scale = getScale();
-
- newMin = pos - scale * 0.5f;
- newMax = pos + scale * 0.5f;
+ LLVector4a pos;
+ pos.load3(getPositionAgent().mV);
+ LLVector4a scale;
+ scale.load3(getScale().mV);
+ scale.mul(0.5f);
+
+ newMin.setSub(pos, scale);
+ newMax.setAdd(pos, scale);
+
+ pos.setAdd(newMin,newMax);
+ pos.mul(0.5f);
- mDrawable->setPositionGroup((newMin + newMax) * 0.5f);
+ mDrawable->setPositionGroup(pos);
}
U32 LLVOWater::getPartitionType() const
@@ -268,10 +285,21 @@ U32 LLVOWater::getPartitionType() const
return LLViewerRegion::PARTITION_WATER;
}
+U32 LLVOVoidWater::getPartitionType() const
+{
+ return LLViewerRegion::PARTITION_VOIDWATER;
+}
+
LLWaterPartition::LLWaterPartition()
-: LLSpatialPartition(0, FALSE, 0)
+: LLSpatialPartition(0, FALSE, GL_DYNAMIC_DRAW_ARB)
{
mInfiniteFarClip = TRUE;
mDrawableType = LLPipeline::RENDER_TYPE_WATER;
mPartitionType = LLViewerRegion::PARTITION_WATER;
}
+
+LLVoidWaterPartition::LLVoidWaterPartition()
+{
+ mDrawableType = LLPipeline::RENDER_TYPE_VOIDWATER;
+ mPartitionType = LLViewerRegion::PARTITION_VOIDWATER;
+}
diff --git a/indra/newview/llvowater.h b/indra/newview/llvowater.h
index beefc3f17f..ed709dd840 100644
--- a/indra/newview/llvowater.h
+++ b/indra/newview/llvowater.h
@@ -29,6 +29,7 @@
#include "llviewerobject.h"
#include "llviewertexture.h"
+#include "pipeline.h"
#include "v2math.h"
const U32 N_RES = 16; //32 // number of subdivisions of wave tile
@@ -60,7 +61,7 @@ public:
/*virtual*/ BOOL idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time);
/*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline);
/*virtual*/ BOOL updateGeometry(LLDrawable *drawable);
- /*virtual*/ void updateSpatialExtents(LLVector3& newMin, LLVector3& newMax);
+ /*virtual*/ void updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax);
/*virtual*/ void updateTextures();
/*virtual*/ void setPixelAreaAndAngle(LLAgent &agent); // generate accurate apparent angle and area
@@ -77,6 +78,19 @@ public:
protected:
BOOL mUseTexture;
BOOL mIsEdgePatch;
+ S32 mRenderType;
};
+class LLVOVoidWater : public LLVOWater
+{
+public:
+ LLVOVoidWater(LLUUID const& id, LLPCode pcode, LLViewerRegion* regionp) : LLVOWater(id, pcode, regionp)
+ {
+ mRenderType = LLPipeline::RENDER_TYPE_VOIDWATER;
+ }
+
+ /*virtual*/ U32 getPartitionType() const;
+};
+
+
#endif // LL_VOSURFACEPATCH_H
diff --git a/indra/newview/llvowlsky.cpp b/indra/newview/llvowlsky.cpp
index ca57c0144b..51664cb31d 100644
--- a/indra/newview/llvowlsky.cpp
+++ b/indra/newview/llvowlsky.cpp
@@ -332,7 +332,7 @@ BOOL LLVOWLSky::updateGeometry(LLDrawable * drawable)
{
const U32 max_buffer_bytes = gSavedSettings.getS32("RenderMaxVBOSize")*1024;
const U32 data_mask = LLDrawPoolWLSky::SKY_VERTEX_DATA_MASK;
- const U32 max_verts = max_buffer_bytes / LLVertexBuffer::calcStride(data_mask);
+ const U32 max_verts = max_buffer_bytes / LLVertexBuffer::calcVertexSize(data_mask);
const U32 total_stacks = getNumStacks();
diff --git a/indra/newview/llwaterparammanager.cpp b/indra/newview/llwaterparammanager.cpp
index 7314894c2e..67bb965f99 100644
--- a/indra/newview/llwaterparammanager.cpp
+++ b/indra/newview/llwaterparammanager.cpp
@@ -33,6 +33,7 @@
#include "pipeline.h"
#include "llsky.h"
+#include "lldiriterator.h"
#include "llfloaterreg.h"
#include "llsliderctrl.h"
#include "llspinctrl.h"
@@ -72,6 +73,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)
{
}
@@ -85,11 +88,12 @@ void LLWaterParamManager::loadAllPresets(const std::string& file_name)
std::string path_name(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight/water", ""));
LL_DEBUGS2("AppInit", "Shaders") << "Loading Default water settings from " << path_name << LL_ENDL;
- bool found = true;
+ bool found = true;
+ LLDirIterator app_settings_iter(path_name, "*.xml");
while(found)
{
std::string name;
- found = gDirUtilp->getNextFileInDir(path_name, "*.xml", name, false);
+ found = app_settings_iter.next(name);
if(found)
{
@@ -111,11 +115,12 @@ void LLWaterParamManager::loadAllPresets(const std::string& file_name)
std::string path_name2(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/water", ""));
LL_DEBUGS2("AppInit", "Shaders") << "Loading User water settings from " << path_name2 << LL_ENDL;
- found = true;
+ found = true;
+ LLDirIterator user_settings_iter(path_name2, "*.xml");
while(found)
{
std::string name;
- found = gDirUtilp->getNextFileInDir(path_name2, "*.xml", name, false);
+ found = user_settings_iter.next(name);
if(found)
{
name=name.erase(name.length()-4);
@@ -265,6 +270,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 +468,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/llwearableitemslist.cpp b/indra/newview/llwearableitemslist.cpp
index a49dc1b59d..92697fb2eb 100644
--- a/indra/newview/llwearableitemslist.cpp
+++ b/indra/newview/llwearableitemslist.cpp
@@ -287,6 +287,9 @@ BOOL LLPanelBodyPartsListItem::postBuild()
addWidgetToRightSide("btn_lock");
addWidgetToRightSide("btn_edit_panel");
+ setWidgetsVisible(false);
+ reshapeWidgets();
+
return TRUE;
}
@@ -443,6 +446,7 @@ clothing_to_string_map_t init_clothing_string_map()
w_map.insert(std::make_pair(LLWearableType::WT_SKIRT, "skirt_not_worn"));
w_map.insert(std::make_pair(LLWearableType::WT_ALPHA, "alpha_not_worn"));
w_map.insert(std::make_pair(LLWearableType::WT_TATTOO, "tattoo_not_worn"));
+ w_map.insert(std::make_pair(LLWearableType::WT_PHYSICS, "physics_not_worn"));
return w_map;
}
@@ -888,6 +892,7 @@ void LLWearableItemsList::ContextMenu::updateItemsVisibility(LLContextMenu* menu
setMenuItemVisible(menu, "edit", !standalone && mask & (MASK_CLOTHING|MASK_BODYPART) && n_worn == n_items && n_worn == 1);
setMenuItemEnabled(menu, "edit", n_editable == 1 && n_worn == 1 && n_items == 1);
setMenuItemVisible(menu, "create_new", mask & (MASK_CLOTHING|MASK_BODYPART) && n_items == 1);
+ setMenuItemEnabled(menu, "create_new", canAddWearables(ids));
setMenuItemVisible(menu, "show_original", !standalone);
setMenuItemEnabled(menu, "show_original", n_items == 1 && n_links == n_items);
setMenuItemVisible(menu, "take_off", mask == MASK_CLOTHING && n_worn == n_items);
@@ -1038,6 +1043,10 @@ bool LLWearableItemsList::ContextMenu::canAddWearables(const uuid_vec_t& item_id
U32 n_clothes = m_it->second;
U32 wearable_count = gAgentWearables.getWearableCount(w_type);
+ if ((wearable_count > 0) && !LLWearableType::getAllowMultiwear(w_type))
+ {
+ return false;
+ }
if ((wearable_count + n_clothes) > LLAgentWearables::MAX_CLOTHING_PER_TYPE)
{
return false;
diff --git a/indra/newview/llwearableitemslist.h b/indra/newview/llwearableitemslist.h
index b060c9f076..a8a5ef3117 100644
--- a/indra/newview/llwearableitemslist.h
+++ b/indra/newview/llwearableitemslist.h
@@ -396,7 +396,6 @@ protected:
*/
class LLWearableItemsList : public LLInventoryItemsList
{
- LOG_CLASS(LLWearableItemsList);
public:
/**
* Context menu.
diff --git a/indra/newview/llwearabletype.cpp b/indra/newview/llwearabletype.cpp
index 0d707d65bf..c090ab5c3d 100644
--- a/indra/newview/llwearabletype.cpp
+++ b/indra/newview/llwearabletype.cpp
@@ -34,25 +34,27 @@ struct WearableEntry : public LLDictionaryEntry
WearableEntry(const std::string &name,
const std::string& default_new_name,
LLAssetType::EType assetType,
- LLInventoryIcon::EIconName iconName);
+ LLInventoryIcon::EIconName iconName,
+ BOOL disable_camera_switch = FALSE,
+ BOOL allow_multiwear = TRUE) :
+ LLDictionaryEntry(name),
+ mAssetType(assetType),
+ mDefaultNewName(default_new_name),
+ mLabel(LLTrans::getString(name)),
+ mIconName(iconName),
+ mDisableCameraSwitch(disable_camera_switch),
+ mAllowMultiwear(allow_multiwear)
+ {
+
+ }
const LLAssetType::EType mAssetType;
const std::string mLabel;
const std::string mDefaultNewName; //keep mLabel for backward compatibility
LLInventoryIcon::EIconName mIconName;
+ BOOL mDisableCameraSwitch;
+ BOOL mAllowMultiwear;
};
-WearableEntry::WearableEntry(const std::string &name,
- const std::string& default_new_name,
- LLAssetType::EType assetType,
- LLInventoryIcon::EIconName iconName) :
- LLDictionaryEntry(name),
- mAssetType(assetType),
- mDefaultNewName(default_new_name),
- mLabel(LLTrans::getString(name)),
- mIconName(iconName)
-{
-}
-
class LLWearableDictionary : public LLSingleton<LLWearableDictionary>,
public LLDictionary<LLWearableType::EType, WearableEntry>
{
@@ -62,23 +64,26 @@ public:
LLWearableDictionary::LLWearableDictionary()
{
- addEntry(LLWearableType::WT_SHAPE, new WearableEntry("shape", "New Shape", LLAssetType::AT_BODYPART, LLInventoryIcon::ICONNAME_BODYPART_SHAPE));
- addEntry(LLWearableType::WT_SKIN, new WearableEntry("skin", "New Skin", LLAssetType::AT_BODYPART, LLInventoryIcon::ICONNAME_BODYPART_SKIN));
- addEntry(LLWearableType::WT_HAIR, new WearableEntry("hair", "New Hair", LLAssetType::AT_BODYPART, LLInventoryIcon::ICONNAME_BODYPART_HAIR));
- addEntry(LLWearableType::WT_EYES, new WearableEntry("eyes", "New Eyes", LLAssetType::AT_BODYPART, LLInventoryIcon::ICONNAME_BODYPART_EYES));
- addEntry(LLWearableType::WT_SHIRT, new WearableEntry("shirt", "New Shirt", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_SHIRT));
- addEntry(LLWearableType::WT_PANTS, new WearableEntry("pants", "New Pants", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_PANTS));
- addEntry(LLWearableType::WT_SHOES, new WearableEntry("shoes", "New Shoes", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_SHOES));
- addEntry(LLWearableType::WT_SOCKS, new WearableEntry("socks", "New Socks", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_SOCKS));
- addEntry(LLWearableType::WT_JACKET, new WearableEntry("jacket", "New Jacket", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_JACKET));
- addEntry(LLWearableType::WT_GLOVES, new WearableEntry("gloves", "New Gloves", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_GLOVES));
- addEntry(LLWearableType::WT_UNDERSHIRT, new WearableEntry("undershirt", "New Undershirt", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_UNDERSHIRT));
- addEntry(LLWearableType::WT_UNDERPANTS, new WearableEntry("underpants", "New Underpants", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_UNDERPANTS));
- addEntry(LLWearableType::WT_SKIRT, new WearableEntry("skirt", "New Skirt", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_SKIRT));
- addEntry(LLWearableType::WT_ALPHA, new WearableEntry("alpha", "New Alpha", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_ALPHA));
- addEntry(LLWearableType::WT_TATTOO, new WearableEntry("tattoo", "New Tattoo", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_TATTOO));
- addEntry(LLWearableType::WT_INVALID, new WearableEntry("invalid", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryIcon::ICONNAME_INVALID));
- addEntry(LLWearableType::WT_NONE, new WearableEntry("none", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryIcon::ICONNAME_INVALID));
+ addEntry(LLWearableType::WT_SHAPE, new WearableEntry("shape", "New Shape", LLAssetType::AT_BODYPART, LLInventoryIcon::ICONNAME_BODYPART_SHAPE, FALSE, FALSE));
+ addEntry(LLWearableType::WT_SKIN, new WearableEntry("skin", "New Skin", LLAssetType::AT_BODYPART, LLInventoryIcon::ICONNAME_BODYPART_SKIN, FALSE, FALSE));
+ addEntry(LLWearableType::WT_HAIR, new WearableEntry("hair", "New Hair", LLAssetType::AT_BODYPART, LLInventoryIcon::ICONNAME_BODYPART_HAIR, FALSE, FALSE));
+ addEntry(LLWearableType::WT_EYES, new WearableEntry("eyes", "New Eyes", LLAssetType::AT_BODYPART, LLInventoryIcon::ICONNAME_BODYPART_EYES, FALSE, FALSE));
+ addEntry(LLWearableType::WT_SHIRT, new WearableEntry("shirt", "New Shirt", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_SHIRT, FALSE, TRUE));
+ addEntry(LLWearableType::WT_PANTS, new WearableEntry("pants", "New Pants", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_PANTS, FALSE, TRUE));
+ addEntry(LLWearableType::WT_SHOES, new WearableEntry("shoes", "New Shoes", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_SHOES, FALSE, TRUE));
+ addEntry(LLWearableType::WT_SOCKS, new WearableEntry("socks", "New Socks", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_SOCKS, FALSE, TRUE));
+ addEntry(LLWearableType::WT_JACKET, new WearableEntry("jacket", "New Jacket", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_JACKET, FALSE, TRUE));
+ addEntry(LLWearableType::WT_GLOVES, new WearableEntry("gloves", "New Gloves", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_GLOVES, FALSE, TRUE));
+ addEntry(LLWearableType::WT_UNDERSHIRT, new WearableEntry("undershirt", "New Undershirt", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_UNDERSHIRT, FALSE, TRUE));
+ addEntry(LLWearableType::WT_UNDERPANTS, new WearableEntry("underpants", "New Underpants", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_UNDERPANTS, FALSE, TRUE));
+ addEntry(LLWearableType::WT_SKIRT, new WearableEntry("skirt", "New Skirt", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_SKIRT, FALSE, TRUE));
+ addEntry(LLWearableType::WT_ALPHA, new WearableEntry("alpha", "New Alpha", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_ALPHA, FALSE, TRUE));
+ addEntry(LLWearableType::WT_TATTOO, new WearableEntry("tattoo", "New Tattoo", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_TATTOO, FALSE, TRUE));
+
+ addEntry(LLWearableType::WT_PHYSICS, new WearableEntry("physics", "New Physics", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_PHYSICS, TRUE, TRUE));
+
+ addEntry(LLWearableType::WT_INVALID, new WearableEntry("invalid", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryIcon::ICONNAME_NONE, FALSE, FALSE));
+ addEntry(LLWearableType::WT_NONE, new WearableEntry("none", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryIcon::ICONNAME_NONE, FALSE, FALSE));
}
// static
@@ -134,3 +139,21 @@ LLInventoryIcon::EIconName LLWearableType::getIconName(LLWearableType::EType typ
return entry->mIconName;
}
+// static
+BOOL LLWearableType::getDisableCameraSwitch(LLWearableType::EType type)
+{
+ const LLWearableDictionary *dict = LLWearableDictionary::getInstance();
+ const WearableEntry *entry = dict->lookup(type);
+ if (!entry) return FALSE;
+ return entry->mDisableCameraSwitch;
+}
+
+// static
+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/llwearabletype.h b/indra/newview/llwearabletype.h
index 3bbf8ba0bd..d633b4807e 100644
--- a/indra/newview/llwearabletype.h
+++ b/indra/newview/llwearabletype.h
@@ -52,7 +52,8 @@ public:
WT_SKIRT = 12,
WT_ALPHA = 13,
WT_TATTOO = 14,
- WT_COUNT = 15,
+ WT_PHYSICS = 15,
+ WT_COUNT = 16,
WT_INVALID = 255,
WT_NONE = -1,
@@ -64,6 +65,8 @@ public:
static LLAssetType::EType getAssetType(EType type);
static EType typeNameToType(const std::string& type_name);
static LLInventoryIcon::EIconName getIconName(EType type);
+ static BOOL getDisableCameraSwitch(EType type);
+ static BOOL getAllowMultiwear(EType type);
protected:
LLWearableType() {}
diff --git a/indra/newview/llweb.cpp b/indra/newview/llweb.cpp
index 73a37a6993..b73017a51a 100644
--- a/indra/newview/llweb.cpp
+++ b/indra/newview/llweb.cpp
@@ -35,6 +35,7 @@
#include "llagent.h"
#include "llappviewer.h"
#include "llfloatermediabrowser.h"
+#include "llfloaterwebcontent.h"
#include "llfloaterreg.h"
#include "lllogininstance.h"
#include "llparcel.h"
@@ -95,6 +96,23 @@ void LLWeb::loadURL(const std::string& url, const std::string& target, const std
}
}
+// static
+void LLWeb::loadWebURL(const std::string& url, const std::string& target, const std::string& uuid)
+{
+ if(target == "_internal")
+ {
+ // Force load in the internal browser, as if with a blank target.
+ loadWebURLInternal(url, "", uuid);
+ }
+ else if (gSavedSettings.getBOOL("UseExternalBrowser") || (target == "_external"))
+ {
+ loadURLExternal(url);
+ }
+ else
+ {
+ loadWebURLInternal(url, target, uuid);
+ }
+}
// static
void LLWeb::loadURLInternal(const std::string &url, const std::string& target, const std::string& uuid)
@@ -102,6 +120,13 @@ void LLWeb::loadURLInternal(const std::string &url, const std::string& target, c
LLFloaterMediaBrowser::create(url, target, uuid);
}
+// static
+// Explicitly open a Web URL using the Web content floater
+void LLWeb::loadWebURLInternal(const std::string &url, const std::string& target, const std::string& uuid)
+{
+ LLFloaterWebContent::create(url, target, uuid);
+}
+
// static
void LLWeb::loadURLExternal(const std::string& url, const std::string& uuid)
@@ -116,6 +141,13 @@ void LLWeb::loadURLExternal(const std::string& url, bool async, const std::strin
// Act like the proxy window was closed, since we won't be able to track targeted windows in the external browser.
LLViewerMedia::proxyWindowClosed(uuid);
+ if(gSavedSettings.getBOOL("DisableExternalBrowser"))
+ {
+ // Don't open an external browser under any circumstances.
+ llwarns << "Blocked attempt to open external browser." << llendl;
+ return;
+ }
+
LLSD payload;
payload["url"] = url;
LLNotificationsUtil::add( "WebLaunchExternalTarget", LLSD(), payload, boost::bind(on_load_url_external_response, _1, _2, async));
diff --git a/indra/newview/llweb.h b/indra/newview/llweb.h
index 2915376583..dc5958e57f 100644
--- a/indra/newview/llweb.h
+++ b/indra/newview/llweb.h
@@ -57,6 +57,11 @@ public:
static void loadURLExternal(const std::string& url, const std::string& uuid);
static void loadURLExternal(const std::string& url, bool async, const std::string& uuid = LLStringUtil::null);
+ // Explicitly open a Web URL using the Web content floater vs. the more general media browser
+ static void loadWebURL(const std::string& url, const std::string& target, const std::string& uuid);
+ static void loadWebURLInternal(const std::string &url, const std::string& target, const std::string& uuid);
+ static void loadWebURLInternal(const std::string &url) { loadWebURLInternal(url, LLStringUtil::null, LLStringUtil::null); }
+
/// Returns escaped url (eg, " " to "%20") - used by all loadURL methods
static std::string escapeURL(const std::string& url);
/// Expands various strings like [LANG], [VERSION], etc. in a URL
diff --git a/indra/newview/llwlparammanager.cpp b/indra/newview/llwlparammanager.cpp
index 9b6047395a..848efcbb49 100644
--- a/indra/newview/llwlparammanager.cpp
+++ b/indra/newview/llwlparammanager.cpp
@@ -31,6 +31,7 @@
#include "pipeline.h"
#include "llsky.h"
+#include "lldiriterator.h"
#include "llfloaterreg.h"
#include "llsliderctrl.h"
#include "llspinctrl.h"
@@ -100,11 +101,12 @@ void LLWLParamManager::loadPresets(const std::string& file_name)
std::string path_name(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight/skies", ""));
LL_DEBUGS2("AppInit", "Shaders") << "Loading Default WindLight settings from " << path_name << LL_ENDL;
- bool found = true;
+ bool found = true;
+ LLDirIterator app_settings_iter(path_name, "*.xml");
while(found)
{
std::string name;
- found = gDirUtilp->getNextFileInDir(path_name, "*.xml", name, false);
+ found = app_settings_iter.next(name);
if(found)
{
@@ -126,11 +128,12 @@ void LLWLParamManager::loadPresets(const std::string& file_name)
std::string path_name2(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/skies", ""));
LL_DEBUGS2("AppInit", "Shaders") << "Loading User WindLight settings from " << path_name2 << LL_ENDL;
- found = true;
+ found = true;
+ LLDirIterator user_settings_iter(path_name2, "*.xml");
while(found)
{
std::string name;
- found = gDirUtilp->getNextFileInDir(path_name2, "*.xml", name, false);
+ found = user_settings_iter.next(name);
if(found)
{
name=name.erase(name.length()-4);
diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp
index 5760d04a08..ec24b02934 100644
--- a/indra/newview/llworld.cpp
+++ b/indra/newview/llworld.cpp
@@ -50,11 +50,17 @@
#include "llviewerstats.h"
#include "llvlcomposition.h"
#include "llvoavatar.h"
+#include "llvocache.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
//
@@ -93,11 +99,6 @@ LLWorld::LLWorld() :
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];
@@ -121,7 +122,10 @@ void LLWorld::destroyClass()
LLViewerRegion* region_to_delete = *region_it++;
removeRegion(region_to_delete->getHost());
}
- LLVOCache::getInstance()->destroyClass() ;
+ if(LLVOCache::hasInstance())
+ {
+ LLVOCache::getInstance()->destroyClass() ;
+ }
LLViewerPartSim::getInstance()->destroyClass();
}
@@ -273,6 +277,10 @@ void LLWorld::removeRegion(const LLHost &host)
delete regionp;
updateWaterObjects();
+
+ //double check all objects of this region are removed.
+ gObjectList.clearAllMapObjectsInRegion(regionp) ;
+ //llassert_always(!gObjectList.hasMapObjectInRegion(regionp)) ;
}
@@ -423,14 +431,15 @@ BOOL LLWorld::positionRegionValidGlobal(const LLVector3d &pos_global)
// Allow objects to go up to their radius underground.
-F32 LLWorld::getMinAllowedZ(LLViewerObject* object)
+F32 LLWorld::getMinAllowedZ(LLViewerObject* object, const LLVector3d &global_pos)
{
- F32 land_height = resolveLandHeightGlobal(object->getPositionGlobal());
+ 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);
@@ -588,7 +597,7 @@ void LLWorld::updateVisibilities()
region_list_t::iterator curiter = iter++;
LLViewerRegion* regionp = *curiter;
F32 height = regionp->getLand().getMaxZ() - regionp->getLand().getMinZ();
- F32 radius = 0.5f*fsqrtf(height * height + diagonal_squared);
+ F32 radius = 0.5f*(F32) sqrt(height * height + diagonal_squared);
if (!regionp->getLand().hasZData()
|| LLViewerCamera::getInstance()->sphereInFrustum(regionp->getCenterAgent(), radius))
{
@@ -609,14 +618,11 @@ void LLWorld::updateVisibilities()
}
F32 height = regionp->getLand().getMaxZ() - regionp->getLand().getMinZ();
- F32 radius = 0.5f*fsqrtf(height * height + diagonal_squared);
+ 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);
- }
+ regionp->getLand().updatePatchVisibilities(gAgent);
}
else
{
@@ -834,9 +840,32 @@ F32 LLWorld::getLandFarClip() const
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()
{
@@ -953,7 +982,7 @@ void LLWorld::updateWaterObjects()
{
// 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_WATER,
+ mEdgeWaterObjects[dir] = (LLVOWater *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_VOID_WATER,
gAgent.getRegion());
waterp = mEdgeWaterObjects[dir];
waterp->setUseTexture(FALSE);
@@ -980,6 +1009,7 @@ void LLWorld::updateWaterObjects()
}
}
+
void LLWorld::shiftRegions(const LLVector3& offset)
{
for (region_list_t::const_iterator i = getRegionList().begin(); i != getRegionList().end(); ++i)
@@ -1237,6 +1267,8 @@ static LLVector3d unpackLocalToGlobalPosition(U32 compact_local, const LLVector3
void LLWorld::getAvatars(uuid_vec_t* avatar_ids, std::vector<LLVector3d>* positions, const LLVector3d& relative_to, F32 radius) const
{
+ F32 radius_squared = radius * radius;
+
if(avatar_ids != NULL)
{
avatar_ids->clear();
@@ -1245,6 +1277,33 @@ void LLWorld::getAvatars(uuid_vec_t* avatar_ids, std::vector<LLVector3d>* positi
{
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_squared(pos_global, relative_to) <= radius_squared)
+ {
+ 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)
{
@@ -1254,15 +1313,17 @@ void LLWorld::getAvatars(uuid_vec_t* avatar_ids, std::vector<LLVector3d>* positi
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(dist_vec_squared(pos_global, relative_to) <= radius_squared)
{
- if(positions != NULL)
- {
- positions->push_back(pos_global);
- }
- if(avatar_ids != NULL)
+ 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())
{
- avatar_ids->push_back(regionp->mMapAvatarIDs.get(i));
+ if(positions != NULL)
+ {
+ positions->push_back(pos_global);
+ }
+ avatar_ids->push_back(uuid);
}
}
}
diff --git a/indra/newview/llworld.h b/indra/newview/llworld.h
index 4465fde210..d8ab4bc508 100644
--- a/indra/newview/llworld.h
+++ b/indra/newview/llworld.h
@@ -89,7 +89,7 @@ public:
// Return the lowest allowed Z point to prevent objects from being moved
// underground.
- F32 getMinAllowedZ(LLViewerObject* object);
+ F32 getMinAllowedZ(LLViewerObject* object, const LLVector3d &global_pos);
// takes a line segment defined by point_a and point_b, then
// determines the closest (to point_a) point of intersection that is
@@ -137,6 +137,7 @@ public:
LLViewerTexture *getDefaultWaterTexture();
void updateWaterObjects();
+ void waterHeightRegionInfo(std::string const& sim_name, F32 water_height);
void shiftRegions(const LLVector3& offset);
void setSpaceTimeUSec(const U64 space_time_usec);
diff --git a/indra/newview/llworldmapview.cpp b/indra/newview/llworldmapview.cpp
index 0c17b5e297..8cdb615686 100644
--- a/indra/newview/llworldmapview.cpp
+++ b/indra/newview/llworldmapview.cpp
@@ -880,8 +880,10 @@ void LLWorldMapView::drawFrustum()
F32 half_width_meters = far_clip_meters * tan( horiz_fov / 2 );
F32 half_width_pixels = half_width_meters * meters_to_pixels;
- F32 ctr_x = getLocalRect().getWidth() * 0.5f + sPanX;
- F32 ctr_y = getLocalRect().getHeight() * 0.5f + sPanY;
+ // Compute the frustum coordinates. Take the UI scale into account.
+ F32 ui_scale_factor = gSavedSettings.getF32("UIScaleFactor");
+ F32 ctr_x = (getLocalRect().getWidth() * 0.5f + sPanX) * ui_scale_factor;
+ F32 ctr_y = (getLocalRect().getHeight() * 0.5f + sPanY) * ui_scale_factor;
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
@@ -1743,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/llworldmipmap.cpp b/indra/newview/llworldmipmap.cpp
index be8298daab..74ed844376 100644
--- a/indra/newview/llworldmipmap.cpp
+++ b/indra/newview/llworldmipmap.cpp
@@ -181,8 +181,7 @@ LLPointer<LLViewerFetchedTexture> LLWorldMipmap::getObjectsTile(U32 grid_x, U32
LLPointer<LLViewerFetchedTexture> LLWorldMipmap::loadObjectsTile(U32 grid_x, U32 grid_y, S32 level)
{
// Get the grid coordinates
- std::string imageurl = gSavedSettings.getString("MapServerURL") + llformat("map-%d-%d-%d-objects.jpg", level, grid_x, grid_y);
-
+ std::string imageurl = gSavedSettings.getString("CurrentMapServerURL") + llformat("map-%d-%d-%d-objects.jpg", level, grid_x, grid_y);
// DO NOT COMMIT!! DEBUG ONLY!!!
// Use a local jpeg for every tile to test map speed without S3 access
diff --git a/indra/newview/llxmlrpclistener.cpp b/indra/newview/llxmlrpclistener.cpp
index 2596f239ca..97a9eb7f5f 100644
--- a/indra/newview/llxmlrpclistener.cpp
+++ b/indra/newview/llxmlrpclistener.cpp
@@ -499,6 +499,13 @@ private:
// 'array' as the value of this 'key'.
responses.insert(key, array);
}
+ else if (xmlrpc_type_struct == type)
+ {
+ LLSD submap = parseValues(status_string,
+ STRINGIZE(key_pfx << key << ':'),
+ current);
+ responses.insert(key, submap);
+ }
else
{
// whoops - unrecognized type
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 03e6e65788..f64eb89866 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -67,6 +67,7 @@
#include "llhudnametag.h"
#include "llhudtext.h"
#include "lllightconstants.h"
+#include "llmeshrepository.h"
#include "llresmgr.h"
#include "llselectmgr.h"
#include "llsky.h"
@@ -74,6 +75,7 @@
#include "lltool.h"
#include "lltoolmgr.h"
#include "llviewercamera.h"
+#include "llviewermediafocus.h"
#include "llviewertexturelist.h"
#include "llviewerobject.h"
#include "llviewerobjectlist.h"
@@ -100,8 +102,29 @@
#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
@@ -130,8 +153,6 @@ static S32 sDelayedVBOEnable = 0;
BOOL gAvatarBacklight = FALSE;
-BOOL gRenderForSelect = FALSE;
-
BOOL gDebugPipeline = FALSE;
LLPipeline gPipeline;
const LLMatrix4* gGLLastMatrix = NULL;
@@ -171,19 +192,20 @@ std::string gPoolNames[] =
// Correspond to LLDrawpool enum render type
"NONE",
"POOL_SIMPLE",
- "POOL_TERRAIN",
+ "POOL_GROUND",
+ "POOL_FULLBRIGHT",
"POOL_BUMP",
- "POOL_TREE",
+ "POOL_TERRAIN,"
"POOL_SKY",
"POOL_WL_SKY",
- "POOL_GROUND",
+ "POOL_TREE",
+ "POOL_GRASS",
"POOL_INVISIBLE",
"POOL_AVATAR",
+ "POOL_VOIDWATER",
"POOL_WATER",
- "POOL_GRASS",
- "POOL_FULLBRIGHT",
"POOL_GLOW",
- "POOL_ALPHA",
+ "POOL_ALPHA"
};
void drawBox(const LLVector3& c, const LLVector3& r);
@@ -218,6 +240,16 @@ 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++)
@@ -255,6 +287,7 @@ 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;
@@ -269,6 +302,8 @@ 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;
@@ -282,7 +317,6 @@ BOOL LLPipeline::sRenderFrameTest = FALSE;
BOOL LLPipeline::sRenderAttachedLights = TRUE;
BOOL LLPipeline::sRenderAttachedParticles = TRUE;
BOOL LLPipeline::sRenderDeferred = FALSE;
-BOOL LLPipeline::sAllowRebuildPriorityGroup = FALSE ;
S32 LLPipeline::sVisibleLightCount = 0;
F32 LLPipeline::sMinRenderSize = 0.f;
@@ -329,6 +363,8 @@ LLPipeline::LLPipeline() :
mRenderDebugFeatureMask(0),
mRenderDebugMask(0),
mOldRenderDebugMask(0),
+ mGroupQ1Locked(false),
+ mGroupQ2Locked(false),
mLastRebuildPool(NULL),
mAlphaPool(NULL),
mSkyPool(NULL),
@@ -360,6 +396,7 @@ void LLPipeline::init()
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");
@@ -394,6 +431,14 @@ void LLPipeline::init()
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;
@@ -527,6 +572,22 @@ void LLPipeline::resizeScreenTexture()
}
}
+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
@@ -535,6 +596,11 @@ void LLPipeline::allocateScreenBuffer(U32 resX, U32 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)
@@ -550,6 +616,10 @@ void LLPipeline::allocateScreenBuffer(U32 resX, U32 resY)
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);
@@ -558,14 +628,40 @@ void LLPipeline::allocateScreenBuffer(U32 resX, U32 resY)
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);
- for (U32 i = 0; i < 3; i++)
+ 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[i].allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE);
+ mDeferredLight[0].release();
}
- for (U32 i = 0; i < 2; i++)
+ if (ssao)
+ { //only need mDeferredLight[1] for ssao
+ mDeferredLight[1].allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE);
+ }
+ else
{
- mGIMapPost[i].allocate(resX,resY, GL_RGB, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE);
+ 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");
@@ -573,18 +669,37 @@ void LLPipeline::allocateScreenBuffer(U32 resX, U32 resY)
//HACK: make alpha masking work on ATI depth shadows (work around for ATI driver bug)
U32 shadow_fmt = gGLManager.mIsATI ? GL_ALPHA : 0;
- for (U32 i = 0; i < 4; i++)
+ 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
{
- mShadow[i].allocate(U32(resX*scale),U32(resY*scale), shadow_fmt, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE);
+ for (U32 i = 0; i < 4; i++)
+ {
+ mShadow[i].release();
+ }
}
-
U32 width = nhpo2(U32(resX*scale))/2;
U32 height = width;
- for (U32 i = 4; i < 6; i++)
+ 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
{
- mShadow[i].allocate(width, height, shadow_fmt, TRUE, FALSE);
+ for (U32 i = 4; i < 6; i++)
+ {
+ mShadow[i].release();
+ }
}
width = nhpo2(resX)/2;
@@ -593,30 +708,55 @@ void LLPipeline::allocateScreenBuffer(U32 resX, U32 resY)
}
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 && gGLManager.mHasFramebufferMultisample && samples > 1)
- {
+ 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
- mDeferredScreen.shareDepthBuffer(mDeferredLight[i]);
+ if (mDeferredLight[i].getTexture(0))
+ {
+ mDeferredScreen.shareDepthBuffer(mDeferredLight[i]);
+ }
}
}
@@ -629,15 +769,34 @@ void LLPipeline::allocateScreenBuffer(U32 resX, U32 resY)
//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;
+ 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;
+ }
+}
+
+//static
+void LLPipeline::refreshRenderDeferred()
+{
+ if(gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_PHYSICS_SHAPES))
+ {
+ //turn the deferred rendering and glow off when draw physics shapes.
+ sRenderDeferred = FALSE ;
+ sRenderGlow = FALSE ;
+ }
+ else
+ {
+ updateRenderDeferred() ;
+ }
}
void LLPipeline::releaseGLBuffers()
@@ -665,8 +824,9 @@ void LLPipeline::releaseGLBuffers()
mWaterRef.release();
mWaterDis.release();
mScreen.release();
+ mPhysicsDisplay.release();
mUIScreen.release();
- mSampleBuffer.releaseSampleBuffer();
+ mSampleBuffer.release();
mDeferredScreen.release();
mDeferredDepth.release();
for (U32 i = 0; i < 3; i++)
@@ -691,6 +851,7 @@ void LLPipeline::releaseGLBuffers()
mGlow[i].release();
}
+ gBumpImageList.destroyGL();
LLVOAvatar::resetImpostors();
}
@@ -729,7 +890,6 @@ void LLPipeline::createGLBuffers()
allocateScreenBuffer(resX,resY);
mScreenWidth = 0;
mScreenHeight = 0;
-
}
if (sRenderDeferred)
@@ -814,6 +974,8 @@ void LLPipeline::createGLBuffers()
addDeferredAttachments(mGIMap);
}
}
+
+ gBumpImageList.restoreGL();
}
void LLPipeline::restoreGL()
@@ -873,7 +1035,7 @@ BOOL LLPipeline::canUseWindLightShadersOnObjects() const
BOOL LLPipeline::canUseAntiAliasing() const
{
- return TRUE; //(gSavedSettings.getBOOL("RenderUseFBO"));
+ return TRUE;
}
void LLPipeline::unloadShaders()
@@ -911,11 +1073,10 @@ S32 LLPipeline::getMaxLightingDetail() const
S32 LLPipeline::setLightingDetail(S32 level)
{
LLMemType mt_ld(LLMemType::MTYPE_PIPELINE_LIGHTING_DETAIL);
- assertInitialized();
if (level < 0)
{
- if (gSavedSettings.getBOOL("VertexShaderEnable"))
+ if (gSavedSettings.getBOOL("RenderLocalLights"))
{
level = 1;
}
@@ -925,15 +1086,8 @@ S32 LLPipeline::setLightingDetail(S32 level)
}
}
level = llclamp(level, 0, getMaxLightingDetail());
- if (level != mLightingDetail)
- {
- mLightingDetail = level;
-
- if (mVertexShadersLoaded == 1)
- {
- LLViewerShaderMgr::instance()->setShaders();
- }
- }
+ mLightingDetail = level;
+
return mLightingDetail;
}
@@ -1159,9 +1313,15 @@ void LLPipeline::allocDrawable(LLViewerObject *vobj)
}
+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_PIPELINE);
+ LLFastTimer t(FTM_UNLINK);
assertInitialized();
@@ -1170,6 +1330,7 @@ void LLPipeline::unlinkDrawable(LLDrawable *drawable)
// 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())
{
@@ -1179,6 +1340,7 @@ void LLPipeline::unlinkDrawable(LLDrawable *drawable)
if (drawablep->getSpatialGroup())
{
+ LLFastTimer t(FTM_REMOVE_FROM_SPATIAL_PARTITION);
if (!drawablep->getSpatialGroup()->mSpatialPartition->remove(drawablep, drawablep->getSpatialGroup()))
{
#ifdef LL_RELEASE_FOR_DOWNLOAD
@@ -1189,18 +1351,23 @@ void LLPipeline::unlinkDrawable(LLDrawable *drawable)
}
}
- mLights.erase(drawablep);
- for (light_set_t::iterator iter = mNearbyLights.begin();
- iter != mNearbyLights.end(); iter++)
{
- if (iter->drawable == drawablep)
+ LLFastTimer t(FTM_REMOVE_FROM_LIGHT_SET);
+ mLights.erase(drawablep);
+
+ for (light_set_t::iterator iter = mNearbyLights.begin();
+ iter != mNearbyLights.end(); iter++)
{
- mNearbyLights.erase(iter);
- break;
+ if (iter->drawable == drawablep)
+ {
+ mNearbyLights.erase(iter);
+ break;
+ }
}
}
{
+ LLFastTimer t(FTM_REMOVE_FROM_HIGHLIGHT_SET);
HighlightItem item(drawablep);
mHighlightSet.erase(item);
@@ -1229,10 +1396,6 @@ void LLPipeline::unlinkDrawable(LLDrawable *drawable)
U32 LLPipeline::addObject(LLViewerObject *vobj)
{
LLMemType mt_ao(LLMemType::MTYPE_PIPELINE_ADD_OBJECT);
- if (gNoRender)
- {
- return 0;
- }
if (gSavedSettings.getBOOL("RenderDelayCreation"))
{
@@ -1497,11 +1660,214 @@ F32 LLPipeline::calcPixelArea(LLVector3 center, LLVector3 size, LLCamera &camera
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();
@@ -1568,7 +1934,7 @@ BOOL LLPipeline::getVisibleExtents(LLCamera& camera, LLVector3& min, LLVector3&
static LLFastTimer::DeclareTimer FTM_CULL("Object Culling");
-void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_clip)
+void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_clip, LLPlane* planep)
{
LLFastTimer t(FTM_CULL);
LLMemType mt_uc(LLMemType::MTYPE_PIPELINE_UPDATE_CULL);
@@ -1588,6 +1954,11 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl
mScreen.bindTarget();
}
+ if (sUseOcclusion > 1)
+ {
+ gGL.setColorMask(false, false);
+ }
+
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadMatrixd(gGLLastProjection);
@@ -1602,10 +1973,37 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl
LLGLDisable test(GL_ALPHA_TEST);
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- if (sUseOcclusion > 1)
+
+ //setup a clip plane in projection matrix for reflection renders (prevents flickering from occlusion culling)
+ LLViewerRegion* region = gAgent.getRegion();
+ LLPlane plane;
+
+ if (planep)
{
- gGL.setColorMask(false, false);
+ 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);
@@ -1638,20 +2036,14 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl
camera.disableUserClipPlane();
- if (gSky.mVOSkyp.notNull() && gSky.mVOSkyp->mDrawable.notNull())
+ if (hasRenderType(LLPipeline::RENDER_TYPE_SKY) &&
+ gSky.mVOSkyp.notNull() &&
+ gSky.mVOSkyp->mDrawable.notNull())
{
- // Hack for sky - always visible.
- if (hasRenderType(LLPipeline::RENDER_TYPE_SKY))
- {
- gSky.mVOSkyp->mDrawable->setVisible(camera);
- sCull->pushDrawable(gSky.mVOSkyp->mDrawable);
- gSky.updateCull();
- stop_glerror();
- }
- }
- else
- {
- llinfos << "No sky drawable!" << llendl;
+ gSky.mVOSkyp->mDrawable->setVisible(camera);
+ sCull->pushDrawable(gSky.mVOSkyp->mDrawable);
+ gSky.updateCull();
+ stop_glerror();
}
if (hasRenderType(LLPipeline::RENDER_TYPE_GROUND) &&
@@ -1703,7 +2095,7 @@ void LLPipeline::markNotCulled(LLSpatialGroup* group, LLCamera& camera)
}
if (sMinRenderSize > 0.f &&
- llmax(llmax(group->mBounds[1].mV[0], group->mBounds[1].mV[1]), group->mBounds[1].mV[2]) < sMinRenderSize)
+ llmax(llmax(group->mBounds[1][0], group->mBounds[1][1]), group->mBounds[1][2]) < sMinRenderSize)
{
return;
}
@@ -1747,33 +2139,34 @@ void LLPipeline::markOccluder(LLSpatialGroup* group)
void LLPipeline::doOcclusion(LLCamera& camera)
{
- LLVertexBuffer::unbind();
-
- if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION))
+ if (LLPipeline::sUseOcclusion > 1 && sCull->hasOcclusionGroups())
{
- 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);
+ LLVertexBuffer::unbind();
- LLGLDisable cull(GL_CULL_FACE);
- if (LLPipeline::sUseOcclusion > 1)
- {
+ 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);
}
-
- gGL.setColorMask(true, false);
}
BOOL LLPipeline::updateDrawableGeom(LLDrawable* drawablep, BOOL priority)
@@ -1800,17 +2193,14 @@ void LLPipeline::updateGL()
void LLPipeline::rebuildPriorityGroups()
{
- if(!sAllowRebuildPriorityGroup)
- {
- return ;
- }
- sAllowRebuildPriorityGroup = FALSE ;
-
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)
@@ -1821,10 +2211,18 @@ void LLPipeline::rebuildPriorityGroups()
}
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);
@@ -1834,33 +2232,30 @@ void LLPipeline::rebuildGroups()
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(); ++iter)
+ iter != mGroupQ2.end() && count <= min_count; ++iter)
{
LLSpatialGroup* group = *iter;
+ last_iter = iter;
- if (group->isDead())
+ if (!group->isDead())
{
- continue;
+ group->rebuildGeom();
+
+ if (group->mSpatialPartition->mRenderByGroup)
+ {
+ count++;
+ }
}
- group->rebuildGeom();
-
- if (group->mSpatialPartition->mRenderByGroup)
- {
- count++;
- }
-
group->clearState(LLSpatialGroup::IN_BUILD_Q2);
-
- if (count > min_count)
- {
- ++iter;
- break;
- }
}
- mGroupQ2.erase(mGroupQ2.begin(), iter);
+ mGroupQ2.erase(mGroupQ2.begin(), ++last_iter);
+
+ mGroupQ2Locked = false;
updateMovedList(mMovedBridge);
}
@@ -1975,12 +2370,12 @@ void LLPipeline::markVisible(LLDrawable *drawablep, LLCamera& camera)
if(drawablep && !drawablep->isDead())
{
- if (drawablep->isSpatialBridge())
- {
+ 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())
+ root->getVObj()->isAttachment())
{
LLDrawable* rootparent = root->getParent();
if (rootparent) // this IS sometimes NULL
@@ -1988,24 +2383,24 @@ void LLPipeline::markVisible(LLDrawable *drawablep, LLCamera& camera)
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;
- }
- }
+ if (av && av->isImpostor())
+ {
+ return;
+ }
+ }
}
}
- sCull->pushBridge((LLSpatialBridge*) drawablep);
- }
- else
- {
- sCull->pushDrawable(drawablep);
- }
+ sCull->pushBridge((LLSpatialBridge*) drawablep);
+ }
+ else
+ {
+ sCull->pushDrawable(drawablep);
+ }
- drawablep->setVisible(camera);
-}
+ drawablep->setVisible(camera);
+ }
}
void LLPipeline::markMoved(LLDrawable *drawablep, BOOL damped_motion)
@@ -2086,6 +2481,9 @@ void LLPipeline::shiftObjects(const LLVector3 &offset)
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++)
{
@@ -2094,7 +2492,7 @@ void LLPipeline::shiftObjects(const LLVector3 &offset)
{
continue;
}
- drawablep->shiftPos(offset);
+ drawablep->shiftPos(offseta);
drawablep->clearState(LLDrawable::ON_SHIFT_LIST);
}
mShiftList.resize(0);
@@ -2108,7 +2506,7 @@ void LLPipeline::shiftObjects(const LLVector3 &offset)
LLSpatialPartition* part = region->getSpatialPartition(i);
if (part)
{
- part->shift(offset);
+ part->shift(offseta);
}
}
}
@@ -2140,8 +2538,7 @@ void LLPipeline::markGLRebuild(LLGLUpdate* glu)
void LLPipeline::markRebuild(LLSpatialGroup* group, BOOL priority)
{
LLMemType mt(LLMemType::MTYPE_PIPELINE);
- //assert_main_thread();
-
+
if (group && !group->isDead() && group->mSpatialPartition)
{
if (group->mSpatialPartition->mPartitionType == LLViewerRegion::PARTITION_HUD)
@@ -2153,6 +2550,8 @@ void LLPipeline::markRebuild(LLSpatialGroup* group, BOOL priority)
{
if (!group->isState(LLSpatialGroup::IN_BUILD_Q1))
{
+ llassert_always(!mGroupQ1Locked);
+
mGroupQ1.push_back(group);
group->setState(LLSpatialGroup::IN_BUILD_Q1);
@@ -2169,11 +2568,7 @@ void LLPipeline::markRebuild(LLSpatialGroup* group, BOOL priority)
}
else if (!group->isState(LLSpatialGroup::IN_BUILD_Q2 | LLSpatialGroup::IN_BUILD_Q1))
{
- //llerrs << "Non-priority updates not yet supported!" << llendl;
- if (std::find(mGroupQ2.begin(), mGroupQ2.end(), group) != mGroupQ2.end())
- {
- llerrs << "WTF?" << llendl;
- }
+ llassert_always(!mGroupQ2Locked);
mGroupQ2.push_back(group);
group->setState(LLSpatialGroup::IN_BUILD_Q2);
@@ -2221,6 +2616,7 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result)
LLPipeline::RENDER_TYPE_TERRAIN,
LLPipeline::RENDER_TYPE_TREE,
LLPipeline::RENDER_TYPE_SKY,
+ LLPipeline::RENDER_TYPE_VOIDWATER,
LLPipeline::RENDER_TYPE_WATER,
LLPipeline::END_RENDER_TYPES))
{
@@ -2252,6 +2648,42 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result)
}
}
}
+
+ 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;
@@ -2267,19 +2699,6 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result)
}
}
- if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD)
- {
- 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 (!bridge->isDead() && group && !group->isOcclusionState(LLSpatialGroup::OCCLUDED))
- {
- stateSort(bridge, camera);
- }
- }
- }
{
LLFastTimer ftm(FTM_STATESORT_DRAWABLE);
for (LLCullResult::drawable_list_t::iterator iter = sCull->beginVisibleList();
@@ -2310,6 +2729,11 @@ void LLPipeline::stateSort(LLSpatialGroup* group, LLCamera& camera)
LLDrawable* drawablep = *i;
stateSort(drawablep, camera);
}
+
+ if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD)
+ { //avoid redundant stateSort calls
+ group->mLastUpdateDistance = group->mDistance;
+ }
}
}
@@ -2317,7 +2741,7 @@ void LLPipeline::stateSort(LLSpatialGroup* group, LLCamera& camera)
void LLPipeline::stateSort(LLSpatialBridge* bridge, LLCamera& camera)
{
LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT);
- if (!sShadowRender && bridge->getSpatialGroup()->changeLOD())
+ if (bridge->getSpatialGroup()->changeLOD())
{
bool force_update = false;
bridge->updateDistance(camera, force_update);
@@ -2376,21 +2800,17 @@ void LLPipeline::stateSort(LLDrawable* drawablep, LLCamera& camera)
if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD)
{
- LLSpatialGroup* group = drawablep->getSpatialGroup();
- if (!group || group->changeLOD())
+ //if (drawablep->isVisible()) isVisible() check here is redundant, if it wasn't visible, it wouldn't be here
{
- if (drawablep->isVisible())
+ if (!drawablep->isActive())
{
- 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()
- }
+ 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()
}
}
}
@@ -2517,6 +2937,42 @@ void renderPhysicalBeacons(LLDrawable* drawablep)
}
}
+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.
@@ -2582,21 +3038,6 @@ void LLPipeline::postSort(LLCamera& camera)
//rebuild groups
sCull->assertDrawMapsEmpty();
- /*LLSpatialGroup::sNoDelete = FALSE;
- for (LLCullResult::sg_list_t::iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i)
- {
- LLSpatialGroup* group = *i;
- if (sUseOcclusion &&
- group->isState(LLSpatialGroup::OCCLUDED))
- {
- continue;
- }
-
- group->rebuildGeom();
- }
- LLSpatialGroup::sNoDelete = TRUE;*/
-
-
rebuildPriorityGroups();
llpushcallstacks ;
@@ -2642,8 +3083,10 @@ void LLPipeline::postSort(LLCamera& camera)
{
if (sMinRenderSize > 0.f)
{
- LLVector3 bounds = (*k)->mExtents[1]-(*k)->mExtents[0];
- if (llmax(llmax(bounds.mV[0], bounds.mV[1]), bounds.mV[2]) > sMinRenderSize)
+ 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);
}
@@ -2722,6 +3165,11 @@ void LLPipeline::postSort(LLCamera& camera)
forAllVisibleDrawables(renderPhysicalBeacons);
}
+ if(sRenderMOAPBeacons)
+ {
+ forAllVisibleDrawables(renderMOAPBeacons);
+ }
+
if (sRenderParticleBeacons)
{
forAllVisibleDrawables(renderParticleBeacons);
@@ -2799,7 +3247,7 @@ void render_hud_elements()
gGL.color4f(1,1,1,1);
if (!LLPipeline::sReflectionRender && gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
{
- LLGLEnable multisample(GL_MULTISAMPLE_ARB);
+ 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
@@ -3013,6 +3461,13 @@ void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate)
}
}
+ S32 stack_depth = 0;
+
+ if (gDebugGL)
+ {
+ glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &stack_depth);
+ }
+
///////////////////////////////////////////
//
// Sync and verify GL state
@@ -3043,7 +3498,7 @@ void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate)
glMatrixMode(GL_MODELVIEW);
LLGLSPipeline gls_pipeline;
- LLGLEnable multisample(GL_MULTISAMPLE_ARB);
+ LLGLEnable multisample(gSavedSettings.getU32("RenderFSAASamples") > 0 ? GL_MULTISAMPLE_ARB : 0);
LLGLState gls_color_material(GL_COLOR_MATERIAL, mLightingDetail < 2);
@@ -3137,18 +3592,9 @@ void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate)
}
poolp->endRenderPass(i);
LLVertexBuffer::unbind();
- if (gDebugGL || gDebugPipeline)
+ if (gDebugGL)
{
- GLint depth;
- glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &depth);
- if (depth > 3)
- {
- if (gDebugSession)
- {
- ll_fail("GL matrix stack corrupted.");
- }
- llerrs << "GL matrix stack corrupted!" << llendl;
- }
+ check_stack_depth(stack_depth);
std::string msg = llformat("%s pass %d", gPoolNames[cur_type].c_str(), i);
LLGLState::checkStates(msg);
LLGLState::checkTextureChannels(msg);
@@ -3171,11 +3617,11 @@ void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate)
iter1 = iter2;
stop_glerror();
}
-
- LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderDrawPoolsEnd");
-
- LLVertexBuffer::unbind();
+ LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderDrawPoolsEnd");
+
+ LLVertexBuffer::unbind();
+
gGLLastMatrix = NULL;
glLoadMatrixd(gGLModelView);
@@ -3222,9 +3668,9 @@ void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate)
{
if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
{
- // Render debugging beacons.
- gObjectList.renderObjectBeacons();
- gObjectList.resetObjectBeacons();
+ // Render debugging beacons.
+ gObjectList.renderObjectBeacons();
+ gObjectList.resetObjectBeacons();
}
else
{
@@ -3283,7 +3729,7 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera)
}
}
- LLGLEnable multisample(GL_MULTISAMPLE_ARB);
+ LLGLEnable multisample(gSavedSettings.getU32("RenderFSAASamples") > 0 ? GL_MULTISAMPLE_ARB : 0);
LLVertexBuffer::unbind();
@@ -3372,7 +3818,7 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera)
LLGLEnable cull(GL_CULL_FACE);
- LLGLEnable multisample(GL_MULTISAMPLE_ARB);
+ LLGLEnable multisample(gSavedSettings.getU32("RenderFSAASamples") > 0 ? GL_MULTISAMPLE_ARB : 0);
calcNearbyLights(camera);
setupHWLights(NULL);
@@ -3557,6 +4003,59 @@ void LLPipeline::addTrianglesDrawn(S32 index_count, U32 render_type)
}
}
+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);
@@ -3569,6 +4068,8 @@ void LLPipeline::renderDebug()
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)
@@ -3579,7 +4080,8 @@ void LLPipeline::renderDebug()
LLSpatialPartition* part = region->getSpatialPartition(i);
if (part)
{
- if (hasRenderType(part->mDrawableType))
+ if ( hud_only && (part->mDrawableType == RENDER_TYPE_HUD || part->mDrawableType == RENDER_TYPE_HUD_PARTICLES) ||
+ !hud_only && hasRenderType(part->mDrawableType) )
{
part->renderDebug();
}
@@ -3599,8 +4101,67 @@ void LLPipeline::renderDebug()
}
}
+ 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);
@@ -3664,7 +4225,7 @@ void LLPipeline::renderDebug()
if (i < 4)
{
- if (i == 0 || !mShadowFrustPoints[i].empty())
+ //if (i == 0 || !mShadowFrustPoints[i].empty())
{
//render visible point cloud
gGL.flush();
@@ -3704,11 +4265,12 @@ void LLPipeline::renderDebug()
gGL.vertex3fv(frust[2].mV); gGL.vertex3fv(frust[6].mV);
gGL.vertex3fv(frust[3].mV); gGL.vertex3fv(frust[7].mV);
gGL.end();
- }
-
+ }
}
- /*for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ /*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;
@@ -3723,7 +4285,9 @@ void LLPipeline::renderDebug()
}
}
}
- }*/
+ }
+ gGL.flush();
+ glLineWidth(1.f);*/
}
}
@@ -3763,13 +4327,19 @@ void LLPipeline::renderDebug()
if (mRenderDebugMask & LLPipeline::RENDER_DEBUG_BUILD_QUEUE)
{
U32 count = 0;
- U32 size = mBuildQ2.size();
+ 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;
@@ -3791,7 +4361,7 @@ void LLPipeline::renderDebug()
glMultMatrixf((F32*)bridge->mDrawable->getRenderMatrix().mMatrix);
}
- F32 alpha = (F32) (size-count)/size;
+ F32 alpha = llclamp((F32) (size-count)/size, 0.f, 1.f);
LLVector2 c(1.f-alpha, alpha);
@@ -3799,7 +4369,7 @@ void LLPipeline::renderDebug()
++count;
- col.set(c.mV[0], c.mV[1], 0, alpha*0.5f+0.1f);
+ col.set(c.mV[0], c.mV[1], 0, alpha*0.5f+0.5f);
group->drawObjectBox(col);
if (bridge)
@@ -3807,188 +4377,13 @@ void LLPipeline::renderDebug()
gGL.popMatrix();
}
}
- }
-
- gGL.flush();
-}
-
-void LLPipeline::renderForSelect(std::set<LLViewerObject*>& objects, BOOL render_transparent, const LLRect& screen_rect)
-{
- assertInitialized();
-
- gGL.setColorMask(true, false);
- gPipeline.resetDrawOrders();
-
- LLViewerCamera* camera = LLViewerCamera::getInstance();
- for (std::set<LLViewerObject*>::iterator iter = objects.begin(); iter != objects.end(); ++iter)
- {
- stateSort((*iter)->mDrawable, *camera);
- }
-
- LLMemType mt(LLMemType::MTYPE_PIPELINE_RENDER_SELECT);
-
-
-
- glMatrixMode(GL_MODELVIEW);
-
- LLGLSDefault gls_default;
- LLGLSObjectSelect gls_object_select;
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- LLGLDepthTest gls_depth(GL_TRUE,GL_TRUE);
- disableLights();
-
- LLVertexBuffer::unbind();
-
- //for each drawpool
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
- LLGLState::checkClientArrays();
- U32 last_type = 0;
-
- // If we don't do this, we crash something on changing graphics settings
- // from Medium -> Low, because we unload all the shaders and the
- // draw pools aren't aware. I don't know if this has to be a separate
- // loop before actual rendering. JC
- for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
- {
- LLDrawPool *poolp = *iter;
- if (poolp->isFacePool() && hasRenderType(poolp->getType()))
- {
- poolp->prerender();
- }
- }
- for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
- {
- LLDrawPool *poolp = *iter;
- if (poolp->isFacePool() && hasRenderType(poolp->getType()))
- {
- LLFacePool* face_pool = (LLFacePool*) poolp;
- face_pool->renderForSelect();
- LLVertexBuffer::unbind();
- gGLLastMatrix = NULL;
- glLoadMatrixd(gGLModelView);
-
- if (poolp->getType() != last_type)
- {
- last_type = poolp->getType();
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
- LLGLState::checkClientArrays();
- }
- }
- }
-
- LLGLEnable alpha_test(GL_ALPHA_TEST);
- if (render_transparent)
- {
- gGL.setAlphaRejectSettings(LLRender::CF_GREATER_EQUAL, 0.f);
- }
- else
- {
- gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.2f);
- }
-
- gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_VERT_COLOR);
- gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_ALPHA, LLTexUnit::TBS_VERT_ALPHA);
-
- U32 prim_mask = LLVertexBuffer::MAP_VERTEX |
- LLVertexBuffer::MAP_TEXCOORD0;
-
- for (std::set<LLViewerObject*>::iterator i = objects.begin(); i != objects.end(); ++i)
- {
- LLViewerObject* vobj = *i;
- LLDrawable* drawable = vobj->mDrawable;
- if (vobj->isDead() ||
- vobj->isHUDAttachment() ||
- (LLSelectMgr::getInstance()->mHideSelectedObjects && vobj->isSelected()) ||
- drawable->isDead() ||
- !hasRenderType(drawable->getRenderType()))
- {
- continue;
- }
- for (S32 j = 0; j < drawable->getNumFaces(); ++j)
- {
- LLFace* facep = drawable->getFace(j);
- if (!facep->getPool())
- {
- facep->renderForSelect(prim_mask);
- }
- }
+ gGL.popMatrix();
}
- // pick HUD objects
- if (isAgentAvatarValid() && sShowHUDAttachments)
- {
- glh::matrix4f save_proj(glh_get_current_projection());
- glh::matrix4f save_model(glh_get_current_modelview());
-
- setup_hud_matrices(screen_rect);
- for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin();
- iter != gAgentAvatarp->mAttachmentPoints.end(); )
- {
- LLVOAvatar::attachment_map_t::iterator curiter = iter++;
- LLViewerJointAttachment* attachment = curiter->second;
- if (attachment->getIsHUDAttachment())
- {
- for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
- attachment_iter != attachment->mAttachedObjects.end();
- ++attachment_iter)
- {
- if (LLViewerObject* attached_object = (*attachment_iter))
- {
- LLDrawable* drawable = attached_object->mDrawable;
- if (drawable->isDead())
- {
- continue;
- }
-
- for (S32 j = 0; j < drawable->getNumFaces(); ++j)
- {
- LLFace* facep = drawable->getFace(j);
- if (!facep->getPool())
- {
- facep->renderForSelect(prim_mask);
- }
- }
-
- //render child faces
- 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++)
- {
- LLViewerObject* child = *iter;
- LLDrawable* child_drawable = child->mDrawable;
- for (S32 l = 0; l < child_drawable->getNumFaces(); ++l)
- {
- LLFace* facep = child_drawable->getFace(l);
- if (!facep->getPool())
- {
- facep->renderForSelect(prim_mask);
- }
- }
- }
- }
- }
- }
- }
-
- glMatrixMode(GL_PROJECTION);
- glLoadMatrixf(save_proj.m);
- glh_set_current_projection(save_proj);
-
- glMatrixMode(GL_MODELVIEW);
- glLoadMatrixf(save_model.m);
- glh_set_current_modelview(save_model);
-
-
- }
+ gGL.flush();
- gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
-
- LLVertexBuffer::unbind();
-
- gGL.setColorMask(true, true);
+ gPipeline.renderPhysicsDisplay();
}
void LLPipeline::rebuildPools()
@@ -4320,16 +4715,19 @@ void LLPipeline::setupAvatarLights(BOOL for_edit)
light_pos.normalize();
+ LLLightState* light = gGL.getLight(1);
+
mHWLightColors[1] = diffuse;
- glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse.mV);
- glLightfv(GL_LIGHT1, GL_AMBIENT, LLColor4::black.mV);
- glLightfv(GL_LIGHT1, GL_SPECULAR, LLColor4::black.mV);
- glLightfv(GL_LIGHT1, GL_POSITION, light_pos.mV);
- glLightf (GL_LIGHT1, GL_CONSTANT_ATTENUATION, 1.0f);
- glLightf (GL_LIGHT1, GL_LINEAR_ATTENUATION, 0.0f);
- glLightf (GL_LIGHT1, GL_QUADRATIC_ATTENUATION, 0.0f);
- glLightf (GL_LIGHT1, GL_SPOT_EXPONENT, 0.0f);
- glLightf (GL_LIGHT1, GL_SPOT_CUTOFF, 180.0f);
+
+ 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)
{
@@ -4360,22 +4758,28 @@ void LLPipeline::setupAvatarLights(BOOL for_edit)
backlight_diffuse *= backlight_mag / max_component;
mHWLightColors[1] = backlight_diffuse;
- glLightfv(GL_LIGHT1, GL_POSITION, backlight_pos.mV); // this is just sun/moon direction
- glLightfv(GL_LIGHT1, GL_DIFFUSE, backlight_diffuse.mV);
- glLightfv(GL_LIGHT1, GL_AMBIENT, LLColor4::black.mV);
- glLightfv(GL_LIGHT1, GL_SPECULAR, LLColor4::black.mV);
- glLightf (GL_LIGHT1, GL_CONSTANT_ATTENUATION, 1.0f);
- glLightf (GL_LIGHT1, GL_LINEAR_ATTENUATION, 0.0f);
- glLightf (GL_LIGHT1, GL_QUADRATIC_ATTENUATION, 0.0f);
- glLightf (GL_LIGHT1, GL_SPOT_EXPONENT, 0.0f);
- glLightf (GL_LIGHT1, GL_SPOT_CUTOFF, 180.0f);
+
+ 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;
- glLightfv(GL_LIGHT1, GL_DIFFUSE, LLColor4::black.mV);
- glLightfv(GL_LIGHT1, GL_AMBIENT, LLColor4::black.mV);
- glLightfv(GL_LIGHT1, GL_SPECULAR, LLColor4::black.mV);
+
+ light->setDiffuse(LLColor4::black);
+ light->setAmbient(LLColor4::black);
+ light->setSpecular(LLColor4::black);
}
}
@@ -4394,7 +4798,7 @@ static F32 calc_light_dist(LLVOVolume* light, const LLVector3& cam_pos, F32 max_
{
return max_dist;
}
- F32 dist = fsqrtf(dist2);
+ F32 dist = (F32) sqrt(dist2);
dist *= 1.f / inten;
dist -= radius;
if (selected)
@@ -4423,7 +4827,7 @@ void LLPipeline::calcNearbyLights(LLCamera& camera)
// 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 = gAgentCamera.getCameraPositionAgent();
+// LLVector3 cam_pos = gAgent.getCameraPositionAgent();
LLVector3 cam_pos = LLViewerJoystick::getInstance()->getOverrideCamera() ?
camera.getOrigin() :
gAgent.getPositionAgent();
@@ -4556,15 +4960,17 @@ void LLPipeline::setupHWLights(LLDrawPool* pool)
LLVector4 light_pos(mSunDir, 0.0f);
LLColor4 light_diffuse = mSunDiffuse;
mHWLightColors[0] = light_diffuse;
- glLightfv(GL_LIGHT0, GL_POSITION, light_pos.mV); // this is just sun/moon direction
- glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse.mV);
- glLightfv(GL_LIGHT0, GL_AMBIENT, LLColor4::black.mV);
- glLightfv(GL_LIGHT0, GL_SPECULAR, LLColor4::black.mV);
- glLightf (GL_LIGHT0, GL_CONSTANT_ATTENUATION, 1.0f);
- glLightf (GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.0f);
- glLightf (GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.0f);
- glLightf (GL_LIGHT0, GL_SPOT_EXPONENT, 0.0f);
- glLightf (GL_LIGHT0, GL_SPOT_CUTOFF, 180.0f);
+
+ 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)
@@ -4622,13 +5028,23 @@ void LLPipeline::setupHWLights(LLDrawPool* pool)
float linatten = x / (light_radius); // % of brightness at radius
mHWLightColors[cur_light] = light_color;
- S32 gllight = GL_LIGHT0+cur_light;
- glLightfv(gllight, GL_POSITION, light_pos_gl.mV);
- glLightfv(gllight, GL_DIFFUSE, light_color.mV);
- glLightfv(gllight, GL_AMBIENT, LLColor4::black.mV);
- glLightf (gllight, GL_CONSTANT_ATTENUATION, 0.0f);
- glLightf (gllight, GL_LINEAR_ATTENUATION, linatten);
- glLightf (gllight, GL_QUADRATIC_ATTENUATION, 0.0f);
+ 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);
+ if (sRenderDeferred)
+ {
+ light_state->setLinearAttenuation(light_radius*1.5f);
+ light_state->setQuadraticAttenuation(light->getLightFalloff()*0.5f+1.f);
+ }
+ else
+ {
+ 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
{
@@ -4636,22 +5052,21 @@ void LLPipeline::setupHWLights(LLDrawPool* pool)
LLQuaternion quat = light->getRenderRotation();
LLVector3 at_axis(0,0,-1); // this matches deferred rendering's object light direction
at_axis *= quat;
- //llinfos << "SPOT!!!!!!! fov: " << spotparams.mV[0] << " focus: " << spotparams.mV[1] << " dir: " << at_axis << llendl;
- glLightfv(gllight, GL_SPOT_DIRECTION, at_axis.mV);
- glLightf (gllight, GL_SPOT_EXPONENT, 2.0f); // 2.0 = good old dot product ^ 2
- glLightf (gllight, GL_SPOT_CUTOFF, 90.0f); // hemisphere
- const float specular[] = {0.f, 0.f, 0.f, 0.f};
- glLightfv(gllight, GL_SPECULAR, specular);
+
+ light_state->setSpotDirection(at_axis);
+ light_state->setSpotCutoff(90.f);
+ light_state->setSpotExponent(2.f);
+
+ light_state->setSpecular(LLColor4::black);
}
else // omnidirectional (point) light
{
- glLightf (gllight, GL_SPOT_EXPONENT, 0.0f);
- glLightf (gllight, GL_SPOT_CUTOFF, 180.0f);
-
+ 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 float specular[] = {0.f, 0.f, 0.f, 1.f};
- glLightfv(gllight, GL_SPECULAR, specular);
- //llinfos << "boring light" << llendl;
+ const LLColor4 specular(0.f, 0.f, 0.f, 1.f);
+ light_state->setSpecular(specular);
}
cur_light++;
if (cur_light >= 8)
@@ -4663,13 +5078,13 @@ void LLPipeline::setupHWLights(LLDrawPool* pool)
for ( ; cur_light < 8 ; cur_light++)
{
mHWLightColors[cur_light] = LLColor4::black;
- S32 gllight = GL_LIGHT0+cur_light;
- glLightfv(gllight, GL_DIFFUSE, LLColor4::black.mV);
- glLightfv(gllight, GL_AMBIENT, LLColor4::black.mV);
- glLightfv(gllight, GL_SPECULAR, LLColor4::black.mV);
- }
+ LLLightState* light = gGL.getLight(cur_light);
- if (isAgentAvatarValid() &&
+ light->setDiffuse(LLColor4::black);
+ light->setAmbient(LLColor4::black);
+ light->setSpecular(LLColor4::black);
+ }
+ if (gAgentAvatarp &&
gAgentAvatarp->mSpecialRenderMode == 3)
{
LLColor4 light_color = LLColor4::white;
@@ -4684,23 +5099,24 @@ void LLPipeline::setupHWLights(LLDrawPool* pool)
float linatten = x / (light_radius); // % of brightness at radius
mHWLightColors[2] = light_color;
- S32 gllight = GL_LIGHT2;
- glLightfv(gllight, GL_POSITION, light_pos_gl.mV);
- glLightfv(gllight, GL_DIFFUSE, light_color.mV);
- glLightfv(gllight, GL_AMBIENT, LLColor4::black.mV);
- glLightfv(gllight, GL_SPECULAR, LLColor4::black.mV);
- glLightf (gllight, GL_CONSTANT_ATTENUATION, 0.0f);
- glLightf (gllight, GL_LINEAR_ATTENUATION, linatten);
- glLightf (gllight, GL_QUADRATIC_ATTENUATION, 0.0f);
- glLightf (gllight, GL_SPOT_EXPONENT, 0.0f);
- glLightf (gllight, GL_SPOT_CUTOFF, 180.0f);
+ 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 gllight=GL_LIGHT0; gllight<=GL_LIGHT7; gllight++)
+ for (S32 i = 0; i < 8; ++i)
{
- glDisable(gllight);
+ gGL.getLight(i)->disable();
}
mLightMask = 0;
}
@@ -4725,15 +5141,16 @@ void LLPipeline::enableLights(U32 mask)
stop_glerror();
for (S32 i=0; i<8; i++)
{
+ LLLightState* light = gGL.getLight(i);
if (mask & (1<<i))
{
- glEnable(GL_LIGHT0 + i);
- glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, mHWLightColors[i].mV);
+ light->enable();
+ light->setDiffuse(mHWLightColors[i]);
}
else
{
- glDisable(GL_LIGHT0 + i);
- glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, LLColor4::black.mV);
+ light->disable();
+ light->setDiffuse(LLColor4::black);
}
}
stop_glerror();
@@ -4757,7 +5174,6 @@ void LLPipeline::enableLightsStatic()
if (mLightingDetail >= 2)
{
mask |= mLightMovingMask; // Hardware moving lights
- glColor4f(0.f, 0.f, 0.f, 1.0f); // no local lighting by default
}
else
{
@@ -4771,11 +5187,7 @@ void LLPipeline::enableLightsDynamic()
assertInitialized();
U32 mask = 0xff & (~2); // Local lights
enableLights(mask);
- if (mLightingDetail >= 2)
- {
- glColor4f(0.f, 0.f, 0.f, 1.f); // no local lighting by default
- }
-
+
if (isAgentAvatarValid() && getLightingDetail() <= 0)
{
if (gAgentAvatarp->mSpecialRenderMode == 0) // normal
@@ -4796,6 +5208,65 @@ void LLPipeline::enableLightsAvatar()
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
@@ -4812,16 +5283,11 @@ void LLPipeline::enableLightsFullbright(const LLColor4& color)
enableLights(mask);
glLightModelfv(GL_LIGHT_MODEL_AMBIENT,color.mV);
- /*if (mLightingDetail >= 2)
- {
- glColor4f(0.f, 0.f, 0.f, 1.f); // no local lighting by default
- }*/
}
void LLPipeline::disableLights()
{
enableLights(0); // no lighting (full bright)
- glColor4f(1.f, 1.f, 1.f, 1.f); // lighting color = white by default
}
//============================================================================
@@ -5012,6 +5478,10 @@ void LLPipeline::setLight(LLDrawable *drawablep, BOOL is_light)
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
@@ -5083,6 +5553,18 @@ BOOL LLPipeline::toggleRenderDebugFeatureControl(void* 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)
{
@@ -5120,6 +5602,24 @@ BOOL LLPipeline::getRenderScriptedTouchBeacons(void*)
}
// 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;
@@ -5415,17 +5915,12 @@ void LLPipeline::resetVertexBuffers(LLDrawable* drawable)
for (S32 i = 0; i < drawable->getNumFaces(); i++)
{
LLFace* facep = drawable->getFace(i);
- facep->mVertexBuffer = NULL;
- facep->mLastVertexBuffer = NULL;
+ facep->clearVertexBuffer();
}
}
void LLPipeline::resetVertexBuffers()
-{
- sRenderBump = gSavedSettings.getBOOL("RenderObjectBump");
- sUseTriStrips = gSavedSettings.getBOOL("RenderUseTriStrips");
- LLVertexBuffer::sUseStreamDraw = gSavedSettings.getBOOL("RenderUseStreamVBO");
-
+{
for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
{
@@ -5465,8 +5960,16 @@ void LLPipeline::resetVertexBuffers()
llwarns << "VBO name pool cleanup failed." << llendl;
}
- LLVertexBuffer::unbind();
-
+ 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");
}
@@ -5481,24 +5984,6 @@ void LLPipeline::renderObjects(U32 type, U32 mask, BOOL texture)
gGLLastMatrix = NULL;
}
-void LLPipeline::setUseVBO(BOOL use_vbo)
-{
- if (use_vbo != LLVertexBuffer::sEnableVBOs)
- {
- if (use_vbo)
- {
- llinfos << "Enabling VBO." << llendl;
- }
- else
- {
- llinfos << "Disabling VBO." << llendl;
- }
-
- resetVertexBuffers();
- LLVertexBuffer::initClass(use_vbo);
- }
-}
-
void apply_cube_face_rotation(U32 face)
{
switch (face)
@@ -5530,21 +6015,21 @@ void apply_cube_face_rotation(U32 face)
void validate_framebuffer_object()
{
GLenum status;
- status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
+ status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
switch(status)
{
- case GL_FRAMEBUFFER_COMPLETE_EXT:
+ case GL_FRAMEBUFFER_COMPLETE:
//framebuffer OK, no error.
break;
- case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
+ case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
// frame buffer not OK: probably means unsupported depth buffer format
- llerrs << "Framebuffer Incomplete Dimensions." << llendl;
+ llerrs << "Framebuffer Incomplete Missing Attachment." << llendl;
break;
- case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
+ 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_EXT:
+ case GL_FRAMEBUFFER_UNSUPPORTED:
/* choose different formats */
llerrs << "Framebuffer unsupported." << llendl;
break;
@@ -5592,8 +6077,6 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield)
tc2 /= (F32) res_mod;
}
- gGL.setColorMask(true, true);
-
LLFastTimer ftm(FTM_RENDER_BLOOM);
gGL.color4f(1,1,1,1);
LLGLDepthTest depth(GL_FALSE);
@@ -5614,7 +6097,7 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield)
gGL.setColorMask(true, true);
glClearColor(0,0,0,0);
- if (for_snapshot)
+ /*if (for_snapshot)
{
gGL.getTexUnit(0)->bind(&mGlow[1]);
{
@@ -5625,14 +6108,21 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield)
// If the snapshot is constructed from tiles, calculate which
// tile we're in.
- const S32 num_horizontal_tiles = llceil(zoom_factor);
- const LLVector2 tile(subfield % num_horizontal_tiles,
- (S32)(subfield / num_horizontal_tiles));
- llassert(zoom_factor > 0.0); // Non-zero, non-negative.
- const F32 tile_size = 1.0/zoom_factor;
-
- tc1 = tile*tile_size; // Top left texture coordinates
- tc2 = (tile+LLVector2(1,1))*tile_size; // Bottom right texture coordinates
+
+ //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);
@@ -5665,7 +6155,7 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield)
glPopMatrix();
return;
- }
+ }*/
{
{
@@ -5782,7 +6272,7 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield)
if (LLRenderTarget::sUseFBO)
{
LLFastTimer ftm(FTM_RENDER_BLOOM_FBO);
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
gGLViewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft;
@@ -5798,16 +6288,149 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield)
LLVertexBuffer::unbind();
- if (LLPipeline::sRenderDeferred && LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) > 2)
+ if (LLPipeline::sRenderDeferred && !LLViewerCamera::getInstance()->cameraUnderWater())
{
+ bool dof_enabled = true;
+
+ LLGLSLShader* shader = &gDeferredPostProgram;
+ if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) > 2)
+ {
+ shader = &gDeferredGIFinalProgram;
+ dof_enabled = false;
+ }
+ else 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
+ shader = &gDeferredPostNoDoFProgram;
+ dof_enabled = false;
+ }
+
+
LLGLDisable blend(GL_BLEND);
- bindDeferredShader(gDeferredGIFinalProgram);
+ bindDeferredShader(*shader);
+
+ if (dof_enabled)
+ {
+ //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())
+ { //focus on selected media object
+ 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 on point under cursor
+ focus_point = gDebugRaycastIntersection;
+ }
+ else if (gAgentCamera.cameraMouselook())
+ { //focus on point under mouselook crosshairs
+ gViewerWindow->cursorIntersect(-1, -1, 512.f, NULL, -1, FALSE,
+ NULL,
+ &focus_point);
+ }
+ else
+ {
+ LLViewerObject* obj = gAgentCamera.getFocusObject();
+ if (obj)
+ { //focus on alt-zoom target
+ focus_point = LLVector3(gAgentCamera.getFocusGlobal()-gAgent.getRegion()->getOriginGlobal());
+ }
+ else
+ { //focus on your avatar
+ focus_point = gAgent.getPositionAgent();
+ }
+ }
+ }
+
+ 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");
+
+ 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
+ //
- S32 channel = gDeferredGIFinalProgram.enableTexture(LLViewerShaderMgr::DEFERRED_DIFFUSE, LLTexUnit::TT_RECT_TEXTURE);
+ 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]);
@@ -5821,11 +6444,10 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield)
gGL.end();
- unbindDeferredShader(gDeferredGIFinalProgram);
+ unbindDeferredShader(*shader);
}
else
{
-
if (res_mod > 1)
{
tc2 /= (F32) res_mod;
@@ -5873,7 +6495,7 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield)
gGL.getTexUnit(1)->bind(&mScreen);
gGL.getTexUnit(1)->activate();
- LLGLEnable multisample(GL_MULTISAMPLE_ARB);
+ LLGLEnable multisample(gSavedSettings.getU32("RenderFSAASamples") > 0 ? GL_MULTISAMPLE_ARB : 0);
buff->setBuffer(mask);
buff->drawArrays(LLRender::TRIANGLE_STRIP, 0, 3);
@@ -5883,16 +6505,41 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield)
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);
- }
+ 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);
@@ -6275,6 +6922,7 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index, LLRen
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)
{
@@ -6312,7 +6960,7 @@ void LLPipeline::renderDeferredLighting()
0, 0, mDeferredDepth.getWidth(), mDeferredDepth.getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST);
}
- LLGLEnable multisample(GL_MULTISAMPLE_ARB);
+ LLGLEnable multisample(gSavedSettings.getU32("RenderFSAASamples") > 0 ? GL_MULTISAMPLE_ARB : 0);
if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
{
@@ -6351,16 +6999,15 @@ void LLPipeline::renderDeferredLighting()
glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], 0);
}
- glPushMatrix();
- glLoadIdentity();
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadIdentity();
-
- mDeferredLight[0].bindTarget();
+ 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);
@@ -6401,16 +7048,9 @@ void LLPipeline::renderDeferredLighting()
unbindDeferredShader(gDeferredSunProgram);
}
- }
- else
- {
- glClearColor(1,1,1,1);
- mDeferredLight[0].clear(GL_COLOR_BUFFER_BIT);
- glClearColor(0,0,0,0);
- }
-
mDeferredLight[0].flush();
-
+ }
+
{ //global illumination specific block (still experimental)
if (gSavedSettings.getBOOL("RenderDeferredBlurLight") &&
gSavedSettings.getBOOL("RenderDeferredGI"))
@@ -6453,7 +7093,7 @@ void LLPipeline::renderDeferredLighting()
mLuminanceMap.flush();
gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mLuminanceMap.getTexture(), true);
gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_TRILINEAR);
- glGenerateMipmapEXT(GL_TEXTURE_2D);
+ glGenerateMipmap(GL_TEXTURE_2D);
}
}
@@ -6516,75 +7156,74 @@ void LLPipeline::renderDeferredLighting()
}
if (gSavedSettings.getBOOL("RenderDeferredSSAO"))
- { //soften direct lighting lightmap
- LLFastTimer ftm(FTM_SOFTEN_SHADOW);
- //blur lightmap
- mDeferredLight[1].bindTarget();
+ { //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);
+ 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");
+ 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;
+ // sample symmetrically with the middle sample falling exactly on 0.0
+ F32 x = 0.f;
- LLVector3 gauss[32]; // xweight, yweight, offset
+ 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;
- }
+ 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[0]", kern_length, gauss[0].mV);
- gDeferredBlurLightProgram.uniform3fv("kern", kern_length, gauss[0].mV);
- gDeferredBlurLightProgram.uniform1f("kern_scale", blur_size * (kern_length/2.f - 0.5f));
+ 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();
+ }
- {
- 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);
+ mDeferredLight[1].flush();
+ unbindDeferredShader(gDeferredBlurLightProgram);
- bindDeferredShader(gDeferredBlurLightProgram, 1);
- mDeferredLight[0].bindTarget();
+ bindDeferredShader(gDeferredBlurLightProgram, 1);
+ mDeferredLight[0].bindTarget();
- gDeferredBlurLightProgram.uniform2f("delta", 0.f, 1.f);
+ 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);
+ {
+ 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();
+ 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(),
@@ -6650,10 +7289,8 @@ void LLPipeline::renderDeferredLighting()
gPipeline.popRenderTypeMask();
}
- BOOL render_local = gSavedSettings.getBOOL("RenderDeferredLocalLights");
- BOOL render_fullscreen = gSavedSettings.getBOOL("RenderDeferredFullscreenLights");
-
-
+ BOOL render_local = gSavedSettings.getBOOL("RenderLocalLights");
+
if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) > 2)
{
mDeferredLight[1].flush();
@@ -6661,7 +7298,7 @@ void LLPipeline::renderDeferredLighting()
mDeferredLight[2].clear(GL_COLOR_BUFFER_BIT);
}
- if (render_local || render_fullscreen)
+ if (render_local)
{
gGL.setSceneBlendType(LLRender::BT_ADD);
std::list<LLVector4> fullscreen_lights;
@@ -6675,10 +7312,11 @@ void LLPipeline::renderDeferredLighting()
std::list<LLVector4> light_colors;
+ LLVertexBuffer::unbind();
+
F32 v[24];
glVertexPointer(3, GL_FLOAT, 0, v);
- BOOL render_local = gSavedSettings.getBOOL("RenderDeferredLocalLights");
-
+
{
bindDeferredShader(gDeferredLightProgram);
LLGLDepthTest depth(GL_TRUE, GL_FALSE);
@@ -6701,8 +7339,9 @@ void LLPipeline::renderDeferredLighting()
}
- LLVector3 center = drawablep->getPositionAgent();
- F32* c = center.mV;
+ LLVector4a center;
+ center.load3(drawablep->getPositionAgent().mV);
+ const F32* c = center.getF32ptr();
F32 s = volume->getLightRadius()*1.5f;
LLColor3 col = volume->getLightColor();
@@ -6718,7 +7357,9 @@ void LLPipeline::renderDeferredLighting()
continue;
}
- if (camera->AABBInFrustumNoFarClip(center, LLVector3(s,s,s)) == 0)
+ LLVector4a sa;
+ sa.splat(s);
+ if (camera->AABBInFrustumNoFarClip(center, sa) == 0)
{
continue;
}
@@ -6762,11 +7403,11 @@ void LLPipeline::renderDeferredLighting()
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(camera, center));
+ GL_UNSIGNED_BYTE, get_box_fan_indices_ptr(camera, center));
stop_glerror();
}
}
- else if (render_fullscreen)
+ else
{
if (volume->isLightSpotlight())
{
@@ -6796,8 +7437,9 @@ void LLPipeline::renderDeferredLighting()
LLVOVolume* volume = drawablep->getVOVolume();
- LLVector3 center = drawablep->getPositionAgent();
- F32* c = center.mV;
+ LLVector4a center;
+ center.load3(drawablep->getPositionAgent().mV);
+ const F32* c = center.getF32ptr();
F32 s = volume->getLightRadius()*1.5f;
sVisibleLightCount++;
@@ -6827,7 +7469,7 @@ void LLPipeline::renderDeferredLighting()
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(camera, center));
+ GL_UNSIGNED_BYTE, get_box_fan_indices_ptr(camera, center));
}
gDeferredSpotLightProgram.disableTexture(LLViewerShaderMgr::DEFERRED_PROJECTION);
unbindDeferredShader(gDeferredSpotLightProgram);
@@ -6869,9 +7511,7 @@ void LLPipeline::renderDeferredLighting()
if (count == max_count || fullscreen_lights.empty())
{
gDeferredMultiLightProgram.uniform1i("light_count", count);
- gDeferredMultiLightProgram.uniform4fv("light[0]", count, (GLfloat*) light);
gDeferredMultiLightProgram.uniform4fv("light", count, (GLfloat*) light);
- gDeferredMultiLightProgram.uniform4fv("light_col[0]", count, (GLfloat*) col);
gDeferredMultiLightProgram.uniform4fv("light_col", count, (GLfloat*) col);
gDeferredMultiLightProgram.uniform1f("far_z", far_z);
far_z = 0.f;
@@ -7008,7 +7648,6 @@ void LLPipeline::renderDeferredLighting()
{
// Render debugging beacons.
gObjectList.renderObjectBeacons();
- LLHUDObject::renderAll();
gObjectList.resetObjectBeacons();
}
}
@@ -7240,11 +7879,6 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
LLCamera camera = camera_in;
camera.setFar(camera.getFar()*0.87654321f);
LLPipeline::sReflectionRender = TRUE;
- S32 occlusion = LLPipeline::sUseOcclusion;
-
- LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
-
- LLPipeline::sUseOcclusion = llmin(occlusion, 1);
gPipeline.pushRenderTypeMask();
@@ -7280,22 +7914,27 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
if (!LLViewerCamera::getInstance()->cameraUnderWater())
{ //generate planar reflection map
+
+ //disable occlusion culling for reflection map for now
+ S32 occlusion = LLPipeline::sUseOcclusion;
+ LLPipeline::sUseOcclusion = 0;
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;
@@ -7315,46 +7954,46 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
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::END_RENDER_TYPES);
+ LLPipeline::RENDER_TYPE_WL_SKY,
+ LLPipeline::RENDER_TYPE_CLOUDS,
+ LLPipeline::END_RENDER_TYPES);
+
static LLCullResult result;
updateCull(camera, result);
stateSort(camera, result);
- andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY,
- LLPipeline::RENDER_TYPE_CLOUDS,
- LLPipeline::RENDER_TYPE_WL_SKY,
- LLPipeline::END_RENDER_TYPES);
renderGeom(camera, TRUE);
+
gPipeline.popRenderTypeMask();
}
gPipeline.pushRenderTypeMask();
clearRenderTypeMask(LLPipeline::RENDER_TYPE_WATER,
- LLPipeline::RENDER_TYPE_GROUND,
- LLPipeline::RENDER_TYPE_SKY,
- LLPipeline::RENDER_TYPE_CLOUDS,
- LLPipeline::END_RENDER_TYPES);
+ 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");
+ 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)
+ if (detail < 3)
{
+ clearRenderTypeMask(LLPipeline::RENDER_TYPE_AVATAR, END_RENDER_TYPES);
+ if (detail < 2)
+ {
clearRenderTypeMask(LLPipeline::RENDER_TYPE_VOLUME, END_RENDER_TYPES);
}
}
@@ -7362,19 +8001,19 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
LLGLUserClipPlane clip_plane(plane, mat, projection);
LLGLDisable cull(GL_CULL_FACE);
- updateCull(camera, ref_result, 1);
+ updateCull(camera, ref_result, -water_clip, &plane);
stateSort(camera, ref_result);
- }
-
- if (LLDrawPoolWater::sNeedsDistortionUpdate)
- {
- if (gSavedSettings.getS32("RenderReflectionDetail") > 0)
+ }
+
+ if (LLDrawPoolWater::sNeedsDistortionUpdate)
{
- gPipeline.grabReferences(ref_result);
- LLGLUserClipPlane clip_plane(plane, mat, projection);
- renderGeom(camera);
- }
- }
+ if (gSavedSettings.getS32("RenderReflectionDetail") > 0)
+ {
+ gPipeline.grabReferences(ref_result);
+ LLGLUserClipPlane clip_plane(plane, mat, projection);
+ renderGeom(camera);
+ }
+ }
gPipeline.popRenderTypeMask();
}
@@ -7382,6 +8021,7 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
glPopMatrix();
mWaterRef.flush();
glh_set_current_modelview(current);
+ LLPipeline::sUseOcclusion = occlusion;
}
camera.setOrigin(camera_in.getOrigin());
@@ -7391,6 +8031,7 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
{
camera.setFar(camera_in.getFar());
clearRenderTypeMask(LLPipeline::RENDER_TYPE_WATER,
+ LLPipeline::RENDER_TYPE_VOIDWATER,
LLPipeline::RENDER_TYPE_GROUND,
END_RENDER_TYPES);
stop_glerror();
@@ -7411,15 +8052,18 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
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();
- LLGLUserClipPlane clip_plane(LLPlane(-pnorm, -(pd+pad)), mat, projection);
+ LLPlane plane(-pnorm, -(pd+pad));
+
+ LLGLUserClipPlane clip_plane(plane, mat, projection);
static LLCullResult result;
- updateCull(camera, result, water_clip);
+ updateCull(camera, result, water_clip, &plane);
stateSort(camera, result);
gGL.setColorMask(true, true);
@@ -7447,8 +8091,8 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
gPipeline.popRenderTypeMask();
LLDrawPoolWater::sNeedsReflectionUpdate = FALSE;
LLDrawPoolWater::sNeedsDistortionUpdate = FALSE;
- LLViewerCamera::getInstance()->setUserClipPlane(LLPlane(-pnorm, -pd));
- LLPipeline::sUseOcclusion = occlusion;
+ LLPlane npnorm(-pnorm, -pd);
+ LLViewerCamera::getInstance()->setUserClipPlane(npnorm);
LLGLState::checkStates();
LLGLState::checkTextureChannels();
@@ -7458,6 +8102,8 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
{
gAgentAvatarp->updateAttachmentVisibility(gAgentCamera.getCameraMode());
}
+
+ LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
}
}
@@ -7560,14 +8206,14 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera
glLoadMatrixf(proj.m);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
- glLoadMatrixf(view.m);
+ glLoadMatrixd(gGLModelView);
stop_glerror();
gGLLastMatrix = NULL;
{
- LLGLDepthTest depth(GL_TRUE);
- glClear(GL_DEPTH_BUFFER_BIT);
+ //LLGLDepthTest depth(GL_TRUE);
+ //glClear(GL_DEPTH_BUFFER_BIT);
}
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
@@ -7580,6 +8226,8 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera
//glCullFace(GL_FRONT);
+ LLVertexBuffer::unbind();
+
{
LLFastTimer ftm(FTM_SHADOW_SIMPLE);
LLGLDisable test(GL_ALPHA_TEST);
@@ -7647,14 +8295,13 @@ BOOL LLPipeline::getVisiblePointCloud(LLCamera& camera, LLVector3& min, LLVector
}
//get set of planes on bounding box
- std::vector<LLPlane> bp;
-
- bp.push_back(LLPlane(min, LLVector3(-1,0,0)));
- bp.push_back(LLPlane(min, LLVector3(0,-1,0)));
- bp.push_back(LLPlane(min, LLVector3(0,0,-1)));
- bp.push_back(LLPlane(max, LLVector3(1,0,0)));
- bp.push_back(LLPlane(max, LLVector3(0,1,0)));
- bp.push_back(LLPlane(max, LLVector3(0,0,1)));
+ 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;
@@ -7702,7 +8349,8 @@ BOOL LLPipeline::getVisiblePointCloud(LLCamera& camera, LLVector3& min, LLVector
const LLPlane& cp = camera.getAgentPlane(j);
const LLVector3& v1 = pp[bs[i*2+0]];
const LLVector3& v2 = pp[bs[i*2+1]];
- const LLVector3 n(cp.mV);
+ LLVector3 n;
+ cp.getVector3(n);
LLVector3 line = v1-v2;
@@ -7716,8 +8364,8 @@ BOOL LLPipeline::getVisiblePointCloud(LLCamera& camera, LLVector3& min, LLVector
LLVector3 intersect = v2+line*t;
pp.push_back(intersect);
}
- }
}
+ }
//camera frustum line segments
const U32 fs[] =
@@ -7725,7 +8373,7 @@ BOOL LLPipeline::getVisiblePointCloud(LLCamera& camera, LLVector3& min, LLVector
0,1,
1,2,
2,3,
- 3,1,
+ 3,0,
4,5,
5,6,
@@ -7748,7 +8396,8 @@ BOOL LLPipeline::getVisiblePointCloud(LLCamera& camera, LLVector3& min, LLVector
const LLVector3& v1 = pp[fs[i*2+0]+8];
const LLVector3& v2 = pp[fs[i*2+1]+8];
const LLPlane& cp = bp[j];
- const LLVector3 n(cp.mV);
+ LLVector3 n;
+ cp.getVector3(n);
LLVector3 line = v1-v2;
@@ -7763,7 +8412,7 @@ BOOL LLPipeline::getVisiblePointCloud(LLCamera& camera, LLVector3& min, LLVector
pp.push_back(intersect);
}
}
- }
+ }
LLVector3 ext[] = { min-LLVector3(0.05f,0.05f,0.05f),
max+LLVector3(0.05f,0.05f,0.05f) };
@@ -7907,6 +8556,7 @@ void LLPipeline::generateGI(LLCamera& camera, LLVector3& lightDir, std::vector<L
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,
@@ -8090,6 +8740,7 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
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,
@@ -8125,6 +8776,14 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
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();
@@ -8199,7 +8858,7 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
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, 128.f);
far_clip = llmin(far_clip, camera.getFar());
F32 range = far_clip-near_clip;
@@ -8489,11 +9148,6 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
fovx = acos(fovx);
fovz = acos(fovz);
- if (fovx > cutoff || llround(fovz, 0.01f) > cutoff)
- {
- // llerrs << "WTF?" << llendl;
- }
-
mShadowFOV.mV[j] = cutoff;
}
@@ -8549,7 +9203,7 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
}
}
- shadow_cam.setFar(128.f);
+ //shadow_cam.setFar(128.f);
shadow_cam.setOriginAndLookAt(eye, up, center);
shadow_cam.setOrigin(0,0,0);
@@ -8559,7 +9213,8 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE);
- shadow_cam.ignoreAgentFrustumPlane(LLCamera::AGENT_PLANE_NEAR);
+ //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,
@@ -8586,7 +9241,8 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
mShadow[j].bindTarget();
mShadow[j].getViewport(gGLViewport);
-
+ mShadow[j].clear();
+
{
static LLCullResult result[4];
@@ -8605,152 +9261,138 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
//hack to disable projector shadows
- static bool clear = true;
bool gen_shadow = gSavedSettings.getS32("RenderShadowDetail") > 1;
if (gen_shadow)
{
- clear = true;
- F32 fade_amt = gFrameIntervalSeconds * llmax(LLViewerCamera::getInstance()->getVelocityStat()->getCurrentPerSec(), 1.f);
+ 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];
+ //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())
+ for (S32 i = 0; i < 2; i++)
{
- continue;
- }
+ glh_set_current_modelview(saved_view);
+ glh_set_current_projection(saved_proj);
- LLVOVolume* volume = mShadowSpotLight[i]->getVOVolume();
+ if (mShadowSpotLight[i].isNull())
+ {
+ continue;
+ }
- if (!volume)
- {
- mShadowSpotLight[i] = NULL;
- continue;
- }
+ LLVOVolume* volume = mShadowSpotLight[i]->getVOVolume();
- LLDrawable* drawable = mShadowSpotLight[i];
+ if (!volume)
+ {
+ mShadowSpotLight[i] = NULL;
+ continue;
+ }
- LLVector3 params = volume->getSpotLightParams();
- F32 fov = params.mV[0];
+ LLDrawable* drawable = mShadowSpotLight[i];
- //get agent->light space matrix (modelview)
- LLVector3 center = drawable->getPositionAgent();
- LLQuaternion quat = volume->getRenderRotation();
+ LLVector3 params = volume->getSpotLightParams();
+ F32 fov = params.mV[0];
- //get near clip plane
- LLVector3 scale = volume->getScale();
- LLVector3 at_axis(0,0,-scale.mV[2]*0.5f);
- at_axis *= quat;
+ //get agent->light space matrix (modelview)
+ LLVector3 center = drawable->getPositionAgent();
+ LLQuaternion quat = volume->getRenderRotation();
- LLVector3 np = center+at_axis;
- at_axis.normVec();
+ //get near clip plane
+ LLVector3 scale = volume->getScale();
+ LLVector3 at_axis(0,0,-scale.mV[2]*0.5f);
+ at_axis *= quat;
- //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 np = center+at_axis;
+ at_axis.normVec();
- LLVector3 origin = np - at_axis*dist;
+ //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);
- LLMatrix4 mat(quat, LLVector4(origin, 1.f));
+ LLVector3 origin = np - at_axis*dist;
- view[i+4] = glh::matrix4f((F32*) mat.mMatrix);
+ LLMatrix4 mat(quat, LLVector4(origin, 1.f));
- view[i+4] = view[i+4].inverse();
+ view[i+4] = glh::matrix4f((F32*) mat.mMatrix);
- //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;
+ view[i+4] = view[i+4].inverse();
- F32 fovy = fov * RAD_TO_DEG;
- F32 aspect = width/height;
-
- proj[i+4] = gl_perspective(fovy, aspect, near_clip, far_clip);
+ //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;
- //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);
+ F32 fovy = fov * RAD_TO_DEG;
+ F32 aspect = width/height;
+
+ proj[i+4] = gl_perspective(fovy, aspect, near_clip, far_clip);
- glh_set_current_modelview(view[i+4]);
- glh_set_current_projection(proj[i+4]);
+ //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);
- 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];
- }
+ glh_set_current_modelview(view[i+4]);
+ glh_set_current_projection(proj[i+4]);
- mShadowModelview[i+4] = view[i+4];
- mShadowProjection[i+4] = 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];
+ }
- LLCamera shadow_cam = camera;
- shadow_cam.setFar(far_clip);
- shadow_cam.setOrigin(origin);
+ mShadowModelview[i+4] = view[i+4];
+ mShadowProjection[i+4] = proj[i+4];
- LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE);
+ LLCamera shadow_cam = camera;
+ shadow_cam.setFar(far_clip);
+ shadow_cam.setOrigin(origin);
- stop_glerror();
+ LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE);
- mShadow[i+4].bindTarget();
- mShadow[i+4].getViewport(gGLViewport);
+ stop_glerror();
- static LLCullResult result[2];
+ mShadow[i+4].bindTarget();
+ mShadow[i+4].getViewport(gGLViewport);
+ mShadow[i+4].clear();
- LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_SHADOW0+i+4;
+ static LLCullResult result[2];
- renderShadow(view[i+4], proj[i+4], shadow_cam, result[i], FALSE, FALSE);
+ LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_SHADOW0+i+4;
- mShadow[i+4].flush();
- }
- }
- else
- {
- if (clear)
- {
- clear = false;
- for (U32 i = 4; i < 6; i++)
- {
- mShadow[i].bindTarget();
- mShadow[i].clear();
- mShadow[i].flush();
- }
- }
+ renderShadow(view[i+4], proj[i+4], shadow_cam, result[i], FALSE, FALSE);
+
+ mShadow[i+4].flush();
+ }
}
if (!gSavedSettings.getBOOL("CameraOffset"))
@@ -8870,7 +9512,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
stateSort(*LLViewerCamera::getInstance(), result);
- const LLVector3* ext = avatar->mDrawable->getSpatialExtents();
+ const LLVector4a* ext = avatar->mDrawable->getSpatialExtents();
LLVector3 pos(avatar->getRenderPosition()+avatar->getImpostorOffset());
LLCamera camera = *viewer_camera;
@@ -8879,25 +9521,30 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
LLVector2 tdim;
- LLVector3 half_height = (ext[1]-ext[0])*0.5f;
- LLVector3 left = camera.getLeftAxis();
- left *= left;
- left.normalize();
+ 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();
- LLVector3 up = camera.getUpAxis();
- up *= up;
- up.normalize();
+ LLVector4a up;
+ up.load3(camera.getUpAxis().mV);
+ up.mul(up);
+ up.normalize3fast();
- tdim.mV[0] = fabsf(half_height * left);
- tdim.mV[1] = fabsf(half_height * up);
+ tdim.mV[0] = fabsf(half_height.dot3(left).getF32());
+ tdim.mV[1] = fabsf(half_height.dot3(up).getF32());
glMatrixMode(GL_PROJECTION);
glPushMatrix();
- //glh::matrix4f ortho = gl_ortho(-tdim.mV[0], tdim.mV[0], -tdim.mV[1], tdim.mV[1], 1.0, 256.0);
+
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]; //128.f/256.f;
+ 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);
@@ -8914,9 +9561,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
glClearColor(0.0f,0.0f,0.0f,0.0f);
gGL.setColorMask(true, true);
- glStencilMask(0xFFFFFFFF);
- glClearStencil(0);
-
+
// get the number of pixels per angle
F32 pa = gViewerWindow->getWindowHeightRaw() / (RAD_TO_DEG * viewer_camera->getView());
@@ -8927,7 +9572,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
if (!avatar->mImpostor.isComplete() || resX != avatar->mImpostor.getWidth() ||
resY != avatar->mImpostor.getHeight())
{
- avatar->mImpostor.allocate(resX,resY,GL_RGBA,TRUE,TRUE);
+ avatar->mImpostor.allocate(resX,resY,GL_RGBA,TRUE,FALSE);
if (LLPipeline::sRenderDeferred)
{
@@ -8939,43 +9584,30 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
}
- LLGLEnable stencil(GL_STENCIL_TEST);
- glStencilMask(0xFFFFFFFF);
- glStencilFunc(GL_ALWAYS, 1, 0xFFFFFFFF);
- glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
+ avatar->mImpostor.bindTarget();
- {
- LLGLEnable scissor(GL_SCISSOR_TEST);
- glScissor(0, 0, resX, resY);
- avatar->mImpostor.bindTarget();
- avatar->mImpostor.clear();
- }
-
if (LLPipeline::sRenderDeferred)
{
- stop_glerror();
+ avatar->mImpostor.clear();
renderGeomDeferred(camera);
renderGeomPostDeferred(camera);
}
else
{
+ LLGLEnable scissor(GL_SCISSOR_TEST);
+ glScissor(0, 0, resX, resY);
+ avatar->mImpostor.clear();
renderGeom(camera);
}
- glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
- glStencilFunc(GL_EQUAL, 1, 0xFFFFFF);
-
- { //create alpha mask based on stencil buffer (grey out if muted)
- LLVector3 left = camera.getLeftAxis()*tdim.mV[0]*2.f;
- LLVector3 up = camera.getUpAxis()*tdim.mV[1]*2.f;
-
+ { //create alpha mask based on depth buffer (grey out if muted)
if (LLPipeline::sRenderDeferred)
{
- GLuint buff = GL_COLOR_ATTACHMENT0_EXT;
+ GLuint buff = GL_COLOR_ATTACHMENT0;
glDrawBuffersARB(1, &buff);
}
- LLGLEnable blend(muted ? 0 : GL_BLEND);
+ LLGLDisable blend(GL_BLEND);
if (muted)
{
@@ -8986,25 +9618,34 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
gGL.setColorMask(false, true);
}
- gGL.setSceneBlendType(LLRender::BT_ADD);
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- LLGLDepthTest depth(GL_FALSE, GL_FALSE);
+ 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.color4f(1,1,1,1);
gGL.color4ub(64,64,64,255);
gGL.begin(LLRender::QUADS);
- gGL.vertex3fv((pos+left-up).mV);
- gGL.vertex3fv((pos-left-up).mV);
- gGL.vertex3fv((pos-left+up).mV);
- gGL.vertex3fv((pos+left+up).mV);
+ 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();
- gGL.setSceneBlendType(LLRender::BT_ALPHA);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
}
-
avatar->mImpostor.flush();
avatar->setImpostorDim(tdim);
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index b80765dac6..e9a250cd6d 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -42,6 +42,10 @@
#include <stack>
+#include <stack>
+
+#include <stack>
+
class LLViewerTexture;
class LLEdge;
class LLFace;
@@ -54,6 +58,9 @@ class LLCubeMap;
class LLCullResult;
class LLVOAvatar;
class LLGLSLShader;
+class LLCurlRequest;
+
+class LLMeshResponder;
typedef enum e_avatar_skinning_method
{
@@ -107,10 +114,11 @@ public:
void resizeScreenTexture();
void releaseGLBuffers();
void createGLBuffers();
- void allocateScreenBuffer(U32 resX, U32 resY);
+ void allocateScreenBuffer(U32 resX, U32 resY);
+ void allocatePhysicsBuffer();
+
void resetVertexBuffers(LLDrawable* drawable);
- void setUseVBO(BOOL use_vbo);
void generateImpostor(LLVOAvatar* avatar);
void bindScreenToTexture();
void renderBloom(BOOL for_snapshot, F32 zoom_factor = 1.f, int subfield = 0);
@@ -200,7 +208,7 @@ public:
BOOL visibleObjectsInFrustum(LLCamera& camera);
BOOL getVisibleExtents(LLCamera& camera, LLVector3 &min, LLVector3& max);
BOOL getVisiblePointCloud(LLCamera& camera, LLVector3 &min, LLVector3& max, std::vector<LLVector3>& fp, LLVector3 light_dir = LLVector3(0,0,0));
- void updateCull(LLCamera& camera, LLCullResult& result, S32 water_clip = 0); //if water_clip is 0, ignore water plane, 1, cull to above plane, -1, cull to below plane
+ void updateCull(LLCamera& camera, LLCullResult& result, S32 water_clip = 0, LLPlane* plane = NULL); //if water_clip is 0, ignore water plane, 1, cull to above plane, -1, cull to below plane
void createObjects(F32 max_dtime);
void createObject(LLViewerObject* vobj);
void updateGeom(F32 max_dtime);
@@ -210,6 +218,7 @@ public:
//calculate pixel area of given box from vantage point of given camera
static F32 calcPixelArea(LLVector3 center, LLVector3 size, LLCamera& camera);
+ static F32 calcPixelArea(const LLVector4a& center, const LLVector4a& size, LLCamera &camera);
void stateSort(LLCamera& camera, LLCullResult& result);
void stateSort(LLSpatialGroup* group, LLCamera& camera);
@@ -222,6 +231,14 @@ public:
void renderGroups(LLRenderPass* pass, U32 type, U32 mask, BOOL texture);
void grabReferences(LLCullResult& result);
+ void clearReferences();
+
+ //check references will assert that there are no references in sCullResult to the provided data
+ void checkReferences(LLFace* face);
+ void checkReferences(LLDrawable* drawable);
+ void checkReferences(LLDrawInfo* draw_info);
+ void checkReferences(LLSpatialGroup* group);
+
void renderGeom(LLCamera& camera, BOOL forceVBOUpdate = FALSE);
void renderGeomDeferred(LLCamera& camera);
@@ -244,8 +261,8 @@ public:
void generateGI(LLCamera& camera, LLVector3& lightDir, std::vector<LLVector3>& vpc);
void renderHighlights();
void renderDebug();
+ void renderPhysicsDisplay();
- void renderForSelect(std::set<LLViewerObject*>& objects, BOOL render_transparent, const LLRect& screen_rect);
void rebuildPools(); // Rebuild pools
void findReferences(LLDrawable *drawablep); // Find the lists which have references to this object
@@ -260,6 +277,7 @@ public:
void enableLightsStatic();
void enableLightsDynamic();
void enableLightsAvatar();
+ void enableLightsPreview();
void enableLightsAvatarEdit(const LLColor4& color);
void enableLightsFullbright(const LLColor4& color);
void disableLights();
@@ -303,6 +321,7 @@ public:
static BOOL toggleRenderTypeControlNegated(void* data);
static BOOL toggleRenderDebugControl(void* data);
static BOOL toggleRenderDebugFeatureControl(void* data);
+ static void setRenderDebugFeatureControl(U32 bit, bool value);
static void setRenderParticleBeacons(BOOL val);
static void toggleRenderParticleBeacons(void* data);
@@ -312,6 +331,10 @@ public:
static void toggleRenderSoundBeacons(void* data);
static BOOL getRenderSoundBeacons(void* data);
+ static void setRenderMOAPBeacons(BOOL val);
+ static void toggleRenderMOAPBeacons(void * data);
+ static BOOL getRenderMOAPBeacons(void * data);
+
static void setRenderPhysicalBeacons(BOOL val);
static void toggleRenderPhysicalBeacons(void* data);
static BOOL getRenderPhysicalBeacons(void* data);
@@ -333,6 +356,7 @@ public:
static BOOL getRenderHighlights(void* data);
static void updateRenderDeferred();
+ static void refreshRenderDeferred();
private:
void unloadShaders();
@@ -359,6 +383,7 @@ public:
RENDER_TYPE_AVATAR = LLDrawPool::POOL_AVATAR,
RENDER_TYPE_TREE = LLDrawPool::POOL_TREE,
RENDER_TYPE_INVISIBLE = LLDrawPool::POOL_INVISIBLE,
+ RENDER_TYPE_VOIDWATER = LLDrawPool::POOL_VOIDWATER,
RENDER_TYPE_WATER = LLDrawPool::POOL_WATER,
RENDER_TYPE_ALPHA = LLDrawPool::POOL_ALPHA,
RENDER_TYPE_GLOW = LLDrawPool::POOL_GLOW,
@@ -424,6 +449,10 @@ public:
RENDER_DEBUG_AVATAR_VOLUME = 0x0100000,
RENDER_DEBUG_BUILD_QUEUE = 0x0200000,
RENDER_DEBUG_AGENT_TARGET = 0x0400000,
+ RENDER_DEBUG_UPDATE_TYPE = 0x0800000,
+ RENDER_DEBUG_PHYSICS_SHAPES = 0x1000000,
+ RENDER_DEBUG_NORMALS = 0x2000000,
+ RENDER_DEBUG_LOD_INFO = 0x4000000,
};
public:
@@ -446,6 +475,10 @@ public:
S32 mNumVisibleNodes;
S32 mVerticesRelit;
+ S32 mDebugTextureUploadCost;
+ S32 mDebugSculptUploadCost;
+ S32 mDebugMeshUploadCost;
+
S32 mLightingChanges;
S32 mGeometryChanges;
@@ -461,6 +494,8 @@ public:
static BOOL sAutoMaskAlphaNonDeferred;
static BOOL sDisableShaders; // if TRUE, rendering will be done without shaders
static BOOL sRenderBump;
+ static BOOL sBakeSunlight;
+ static BOOL sNoAlpha;
static BOOL sUseTriStrips;
static BOOL sUseFarClip;
static BOOL sShadowRender;
@@ -476,7 +511,6 @@ public:
static BOOL sRenderAttachedLights;
static BOOL sRenderAttachedParticles;
static BOOL sRenderDeferred;
- static BOOL sAllowRebuildPriorityGroup;
static S32 sVisibleLightCount;
static F32 sMinRenderSize;
@@ -495,6 +529,7 @@ public:
LLRenderTarget mGIMapPost[2];
LLRenderTarget mLuminanceMap;
LLRenderTarget mHighlight;
+ LLRenderTarget mPhysicsDisplay;
//sun shadow map
LLRenderTarget mShadow[6];
@@ -602,6 +637,8 @@ protected:
LLDrawable::drawable_list_t mBuildQ2; // non-priority
LLSpatialGroup::sg_vector_t mGroupQ1; //priority
LLSpatialGroup::sg_vector_t mGroupQ2; // non-priority
+ bool mGroupQ2Locked;
+ bool mGroupQ1Locked;
LLViewerObject::vobj_list_t mCreateQ;
@@ -696,6 +733,7 @@ protected:
S32 mLightingDetail;
static BOOL sRenderPhysicalBeacons;
+ static BOOL sRenderMOAPBeacons;
static BOOL sRenderScriptedTouchBeacons;
static BOOL sRenderScriptedBeacons;
static BOOL sRenderParticleBeacons;
@@ -712,7 +750,6 @@ void render_bbox(const LLVector3 &min, const LLVector3 &max);
void render_hud_elements();
extern LLPipeline gPipeline;
-extern BOOL gRenderForSelect;
extern BOOL gDebugPipeline;
extern const LLMatrix4* gGLLastMatrix;
diff --git a/indra/newview/res/resource.h b/indra/newview/res/resource.h
index 28813be896..01d90da971 100644
--- a/indra/newview/res/resource.h
+++ b/indra/newview/res/resource.h
@@ -38,6 +38,7 @@
#define IDC_CURSOR5 154
#define IDI_LCD_LL_ICON 157
#define IDC_CURSOR6 158
+#define IDC_STATIC 1000
#define IDC_RADIO_56 1000
#define IDC_RADIO_128 1001
#define IDC_RADIO_256 1002
diff --git a/indra/newview/res/toolbuy.cur b/indra/newview/res/toolbuy.cur
index a1bc278116..65bbf01d45 100644
--- a/indra/newview/res/toolbuy.cur
+++ b/indra/newview/res/toolbuy.cur
Binary files differ
diff --git a/indra/newview/res/toolopen.cur b/indra/newview/res/toolopen.cur
index a72cdfe4c0..22ecbd5228 100644
--- a/indra/newview/res/toolopen.cur
+++ b/indra/newview/res/toolopen.cur
Binary files differ
diff --git a/indra/newview/res/toolsit.cur b/indra/newview/res/toolsit.cur
index 6327bdb281..d26b6f8638 100644
--- a/indra/newview/res/toolsit.cur
+++ b/indra/newview/res/toolsit.cur
Binary files differ
diff --git a/indra/newview/res/viewerRes.rc b/indra/newview/res/viewerRes.rc
index 5e8cee1f5f..38d04b4b5c 100644
--- a/indra/newview/res/viewerRes.rc
+++ b/indra/newview/res/viewerRes.rc
@@ -7,7 +7,7 @@
//
// Generated from the TEXTINCLUDE 2 resource.
//
-#include "winres.h"
+#include "windows.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
@@ -34,7 +34,7 @@ END
2 TEXTINCLUDE
BEGIN
- "#include ""winres.h""\r\n"
+ "#include ""windows.h""\r\n"
"\0"
END
diff --git a/indra/newview/skins/default/colors.xml b/indra/newview/skins/default/colors.xml
index ddd2ff196b..d02662681b 100644
--- a/indra/newview/skins/default/colors.xml
+++ b/indra/newview/skins/default/colors.xml
@@ -115,12 +115,6 @@
name="AlertCautionTextColor"
reference="LtYellow" />
<color
- name="AgentLinkColor"
- reference="EmphasisColor" />
- <color
- name="AlertTextColor"
- value="0.58 0.66 0.84 1" />
- <color
name="AvatarListItemIconDefaultColor"
reference="White" />
<color
@@ -139,9 +133,6 @@
name="AvatarListItemIconVoiceLeftColor"
reference="AvatarListItemIconOfflineColor" />
<color
- name="BackgroundChatColor"
- reference="DkGray_66" />
- <color
name="ButtonBorderColor"
reference="Unused?" />
<color
@@ -352,9 +343,6 @@
name="GridlineShadowColor"
value="0 0 0 0.31" />
<color
- name="GroupLinkColor"
- reference="White" />
- <color
name="GroupNotifyBoxColor"
value="0.3344 0.5456 0.5159 1" />
<color
@@ -400,9 +388,6 @@
name="HighlightParentColor"
value="0.67 0.83 0.96 1" />
<color
- name="IMChatColor"
- reference="LtGray" />
- <color
name="IMHistoryBgColor"
reference="Unused?" />
<color
@@ -767,9 +752,6 @@
name="SysWellItemSelected"
value="0.3 0.3 0.3 1.0" />
<color
- name="ChatToastAgentNameColor"
- reference="EmphasisColor" />
- <color
name="ColorSwatchBorderColor"
value="0.45098 0.517647 0.607843 1"/>
<color
@@ -778,4 +760,29 @@
<color
name="MenuBarProjectBgColor"
reference="MdBlue" />
+
+ <color
+ name="MeshImportTableNormalColor"
+ value="1 1 1 1"/>
+ <color
+ name="MeshImportTableHighlightColor"
+ value="0.2 0.8 1 1"/>
+
+
+ <!-- Generic color names (legacy) -->
+ <color
+ name="white"
+ value="1 1 1 1"/>
+ <color
+ name="black"
+ value="0 0 0 1"/>
+ <color
+ name="red"
+ value="1 0 0 1"/>
+ <color
+ name="green"
+ value="0 1 0 1"/>
+ <color
+ name="blue"
+ value="0 0 1 1"/>
</colors>
diff --git a/indra/newview/skins/default/textures/arrow_keys.png b/indra/newview/skins/default/textures/arrow_keys.png
new file mode 100644
index 0000000000..f19af59251
--- /dev/null
+++ b/indra/newview/skins/default/textures/arrow_keys.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/bottomtray/ChatBarHandle.png b/indra/newview/skins/default/textures/bottomtray/ChatBarHandle.png
new file mode 100644
index 0000000000..8b58db0cba
--- /dev/null
+++ b/indra/newview/skins/default/textures/bottomtray/ChatBarHandle.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Edit_Wrench.png b/indra/newview/skins/default/textures/icons/Edit_Wrench.png
index 250697b4b1..edb40b9c96 100644
--- a/indra/newview/skins/default/textures/icons/Edit_Wrench.png
+++ b/indra/newview/skins/default/textures/icons/Edit_Wrench.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Inv_Mesh.png b/indra/newview/skins/default/textures/icons/Inv_Mesh.png
new file mode 100644
index 0000000000..f1f21f7941
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Inv_Mesh.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Inv_Physics.png b/indra/newview/skins/default/textures/icons/Inv_Physics.png
new file mode 100644
index 0000000000..360baec46d
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Inv_Physics.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Web_Profile_Off.png b/indra/newview/skins/default/textures/icons/Web_Profile_Off.png
new file mode 100644
index 0000000000..f5fb774a6f
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Web_Profile_Off.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/check_mark.png b/indra/newview/skins/default/textures/icons/check_mark.png
new file mode 100644
index 0000000000..2c05297f4f
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/check_mark.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/model_wizard/divider_line.png b/indra/newview/skins/default/textures/model_wizard/divider_line.png
new file mode 100644
index 0000000000..76c9e68767
--- /dev/null
+++ b/indra/newview/skins/default/textures/model_wizard/divider_line.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/model_wizard/progress_bar_bg.png b/indra/newview/skins/default/textures/model_wizard/progress_bar_bg.png
new file mode 100644
index 0000000000..d0b213cdc5
--- /dev/null
+++ b/indra/newview/skins/default/textures/model_wizard/progress_bar_bg.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/model_wizard/progress_light.png b/indra/newview/skins/default/textures/model_wizard/progress_light.png
new file mode 100644
index 0000000000..019344f812
--- /dev/null
+++ b/indra/newview/skins/default/textures/model_wizard/progress_light.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml
index b2658d2525..cc7cce99c9 100644
--- a/indra/newview/skins/default/textures/textures.xml
+++ b/indra/newview/skins/default/textures/textures.xml
@@ -73,7 +73,22 @@ with the same filename but different name
<texture name="BackButton_Press" file_name="icons/back_arrow_press.png" preload="false" scale.left="22" scale.top="12" scale.right="25" scale.bottom="12" />
<texture name="Blank" file_name="Blank.png" preload="false" />
-
+
+ <texture name="BreadCrumbBtn_Left_Disabled" file_name="widgets/BreadCrumbBtn_Left_Disabled.png" preload="false"/>
+ <texture name="BreadCrumbBtn_Left_Off" file_name="widgets/BreadCrumbBtn_Left_Off.png" preload="false"/>
+ <texture name="BreadCrumbBtn_Left_Over" file_name="widgets/BreadCrumbBtn_Left_Over.png" preload="false"/>
+ <texture name="BreadCrumbBtn_Left_Press" file_name="widgets/BreadCrumbBtn_Left_Press.png" preload="false"/>
+
+ <texture name="BreadCrumbBtn_Middle_Disabled" file_name="widgets/BreadCrumbBtn_Middle_Disabled.png" preload="false"/>
+ <texture name="BreadCrumbBtn_Middle_Off" file_name="widgets/BreadCrumbBtn_Middle_Off.png" preload="false"/>
+ <texture name="BreadCrumbBtn_Middle_Over" file_name="widgets/BreadCrumbBtn_Middle_Over.png" preload="false"/>
+ <texture name="BreadCrumbBtn_Middle_Press" file_name="widgets/BreadCrumbBtn_Middle_Press.png" preload="false"/>
+
+ <texture name="BreadCrumbBtn_Right_Disabled" file_name="widgets/BreadCrumbBtn_Right_Disabled.png" preload="false"/>
+ <texture name="BreadCrumbBtn_Right_Off" file_name="widgets/BreadCrumbBtn_Right_Off.png" preload="false"/>
+ <texture name="BreadCrumbBtn_Right_Over" file_name="widgets/BreadCrumbBtn_Right_Over.png" preload="false"/>
+ <texture name="BreadCrumbBtn_Right_Press" file_name="widgets/BreadCrumbBtn_Right_Press.png" preload="false"/>
+
<texture name="BuyArrow_Over" file_name="navbar/BuyArrow_Over.png" preload="true" scale.left="0" scale.top="1" scale.right="0" scale.bottom="0" />
<texture name="BuyArrow_Press" file_name="navbar/BuyArrow_Press.png" preload="true" scale.left="1" scale.top="1" scale.right="0" scale.bottom="0" />
@@ -102,11 +117,13 @@ with the same filename but different name
<texture name="Checkbox_On" file_name="widgets/Checkbox_On.png" preload="true" />
<texture name="Checkbox_On_Press" file_name="widgets/Checkbox_On_Press.png" preload="true" />
<texture name="Checkbox_Press" file_name="widgets/Checkbox_Press.png" preload="true" />
+ <texture name="Check_Mark" file_name="icons/check_mark" preload="true" />
<texture name="ComboButton_Disabled" file_name="widgets/ComboButton_Disabled.png" preload="true" scale.left="2" scale.top="19" scale.right="18" scale.bottom="2" />
<texture name="ComboButton_Selected" file_name="widgets/ComboButton_Selected.png" preload="true" scale.left="2" scale.top="19" scale.right="18" scale.bottom="2" />
<texture name="ComboButton_UpSelected" file_name="widgets/ComboButton_UpSelected.png" preload="true" scale.left="2" scale.top="19" scale.right="18" scale.bottom="2" />
<texture name="ComboButton_Up_On_Selected" file_name="widgets/ComboButton_Up_On_Selected.png" preload="true" scale.left="2" scale.top="19" scale.right="18" scale.bottom="2" />
+ <texture name="ComboButton_On" file_name="widgets/ComboButton_On.png" preload="true" scale.left="2" scale.top="19" scale.right="18" scale.bottom="2" />
<texture name="ComboButton_Off" file_name="widgets/ComboButton_Off.png" preload="true" scale.left="2" scale.top="19" scale.right="18" scale.bottom="2" />
<texture name="ComboButton_UpOff" file_name="widgets/ComboButton_UpOff.png" preload="true" scale.left="2" scale.top="19" scale.right="18" scale.bottom="2" />
<texture name="Container" file_name="containers/Container.png" preload="false" />
@@ -114,6 +131,7 @@ with the same filename but different name
<texture name="DisclosureArrow_Opened_Off" file_name="widgets/DisclosureArrow_Opened_Off.png" preload="true" />
+ <texture name="ChatBarHandle" file_name="bottomtray/ChatBarHandle.png" preload="false" />
<texture name="DownArrow" file_name="bottomtray/DownArrow.png" preload="false" />
<texture name="DownArrow_Off" file_name="icons/DownArrow_Off.png" preload="false" />
<texture name="Dragbar" file_name="windows/Dragbar.png" preload="false" scale.left="35" scale.top="5" scale.right="29" scale.bottom="5" />
@@ -209,6 +227,7 @@ with the same filename but different name
<texture name="Inv_LostClosed" file_name="icons/Inv_LostClosed.png" preload="false" />
<texture name="Inv_LostOpen" file_name="icons/Inv_LostOpen.png" preload="false" />
<texture name="Inv_Landmark" file_name="icons/Inv_Landmark.png" preload="false" />
+ <texture name="Inv_Mesh" file_name="icons/Inv_Mesh.png" preload="false" />
<texture name="Inv_Notecard" file_name="icons/Inv_Notecard.png" preload="false" />
<texture name="Inv_Object" file_name="icons/Inv_Object.png" preload="false" />
<texture name="Inv_Object_Multi" file_name="icons/Inv_Object_Multi.png" preload="false" />
@@ -224,6 +243,7 @@ with the same filename but different name
<texture name="Inv_SysClosed" file_name="icons/Inv_SysClosed.png" preload="false" />
<texture name="Inv_SysOpen" file_name="icons/Inv_SysOpen.png" preload="false" />
<texture name="Inv_Tattoo" file_name="icons/Inv_Tattoo.png" preload="false" />
+ <texture name="Inv_Physics" file_name="icons/Inv_Physics.png" preload="false" />
<texture name="Inv_Texture" file_name="icons/Inv_Texture.png" preload="false" />
<texture name="Inv_TrashClosed" file_name="icons/Inv_TrashClosed.png" preload="false" />
<texture name="Inv_TrashOpen" file_name="icons/Inv_TrashOpen.png" preload="false" />
@@ -255,6 +275,10 @@ with the same filename but different name
<texture name="menu_separator" file_name="navbar/FileMenu_Divider.png" scale.left="4" scale.top="166" scale.right="0" scale.bottom="0" />
+ <texture name="ModelImport_Status_Good" file_name="lag_status_good.tga" preload="false"/>
+ <texture name="ModelImport_Status_Warning" file_name="lag_status_warning.tga" preload="false"/>
+ <texture name="ModelImport_Status_Error" file_name="lag_status_critical.tga" preload="false"/>
+
<texture name="MouseLook_View_Off" file_name="bottomtray/MouseLook_view_off.png" preload="false" />
<texture name="MouseLook_View_On" file_name="bottomtray/MouseLook_view_on.png" preload="false" />
@@ -371,8 +395,8 @@ with the same filename but different name
<texture name="Play_Off" file_name="icons/Play_Off.png" preload="false" />
<texture name="Play_Over" file_name="icons/Play_Over.png" preload="false" />
<texture name="Play_Press" file_name="icons/Play_Press.png" preload="false" />
-
- <texture name="ProgressBar" file_name="widgets/ProgressBar.png" preload="true" scale.left="4" scale.top="10" scale.right="48" scale.bottom="2" />
+
+ <texture name="ProgressBar" file_name="widgets/ProgressBar.png" preload="true" scale.left="4" scale.top="11" scale.right="48" scale.bottom="3" />
<texture name="ProgressTrack" file_name="widgets/ProgressTrack.png" preload="true" scale.left="4" scale.top="13" scale.right="148" scale.bottom="2" />
<texture name="PushButton_Disabled" file_name="widgets/PushButton_Disabled.png" preload="true" scale.left="4" scale.top="19" scale.right="28" scale.bottom="4" />
@@ -392,7 +416,7 @@ with the same filename but different name
<texture name="RadioButton_On_Disabled" file_name="widgets/RadioButton_On_Disabled.png" preload="true" />
- <texture name="Refresh_Off" file_name="icons/Refresh_Off.png" preload="false" />
+ <texture name="Refresh_Off" file_name="icons/Refresh_Off.png" preload="true" />
<texture name="Resize_Corner" file_name="windows/Resize_Corner.png" preload="true" />
@@ -468,7 +492,7 @@ with the same filename but different name
<texture name="Stepper_Up_Off" file_name="widgets/Stepper_Up_Off.png" preload="false" />
<texture name="Stepper_Up_Press" file_name="widgets/Stepper_Up_Press.png" preload="false" />
- <texture name="Stop_Off" file_name="icons/Stop_Off.png" preload="false" />
+ <texture name="Stop_Off" file_name="icons/Stop_Off.png" preload="true" />
<texture name="StopReload_Off" file_name="icons/StopReload_Off.png" preload="false" />
<texture name="StopReload_Over" file_name="icons/StopReload_Over.png" preload="false" />
@@ -553,11 +577,11 @@ with the same filename but different name
<texture name="Wearables_Divider" file_name="windows/Wearables_Divider.png" preload="false" />
+ <texture name="Web_Profile_Off" file_name="icons/Web_Profile_Off.png" preload="false" />
+
<texture name="WellButton_Lit" file_name="bottomtray/WellButton_Lit.png" preload="true" scale.left="4" scale.top="19" scale.right="28" scale.bottom="4" />
<texture name="WellButton_Lit_Selected" file_name="bottomtray/WellButton_Lit_Selected.png" preload="true" scale.left="4" scale.top="19" scale.right="28" scale.bottom="4" />
-
-
<texture name="Window_Background" file_name="windows/Window_Background.png" preload="true"
scale.left="4" scale.top="24" scale.right="26" scale.bottom="4" />
<texture name="Window_Foreground" file_name="windows/Window_Foreground.png" preload="true"
@@ -623,6 +647,8 @@ with the same filename but different name
<texture name="icon_for_sale.tga" file_name="icons/Icon_For_Sale.png" />
<texture name="icon_top_pick.tga" />
+ <texture name="inv_folder_mesh.tga"/>
+ <texture name="inv_item_mesh.tga"/>
<texture name="lag_status_critical.tga" />
<texture name="lag_status_good.tga" />
<texture name="lag_status_warning.tga" />
@@ -671,4 +697,5 @@ with the same filename but different name
<texture name="Yellow_Gradient" file_name="windows/yellow_gradient.png"/>
<texture name="Popup_Caution" file_name="icons/pop_up_caution.png"/>
+ <texture name="Camera_Drag_Dot" file_name="world/CameraDragDot.png"/>
</textures>
diff --git a/indra/newview/skins/default/textures/widgets/BreadCrumbBtn_Left_Disabled.png b/indra/newview/skins/default/textures/widgets/BreadCrumbBtn_Left_Disabled.png
new file mode 100644
index 0000000000..c7c0eaa96b
--- /dev/null
+++ b/indra/newview/skins/default/textures/widgets/BreadCrumbBtn_Left_Disabled.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/BreadCrumbBtn_Left_Off.png b/indra/newview/skins/default/textures/widgets/BreadCrumbBtn_Left_Off.png
new file mode 100644
index 0000000000..4a73c254fc
--- /dev/null
+++ b/indra/newview/skins/default/textures/widgets/BreadCrumbBtn_Left_Off.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/BreadCrumbBtn_Left_Over.png b/indra/newview/skins/default/textures/widgets/BreadCrumbBtn_Left_Over.png
new file mode 100644
index 0000000000..6fb5c432de
--- /dev/null
+++ b/indra/newview/skins/default/textures/widgets/BreadCrumbBtn_Left_Over.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/BreadCrumbBtn_Left_Press.png b/indra/newview/skins/default/textures/widgets/BreadCrumbBtn_Left_Press.png
new file mode 100644
index 0000000000..fa18517933
--- /dev/null
+++ b/indra/newview/skins/default/textures/widgets/BreadCrumbBtn_Left_Press.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/BreadCrumbBtn_Middle_Disabled.png b/indra/newview/skins/default/textures/widgets/BreadCrumbBtn_Middle_Disabled.png
new file mode 100644
index 0000000000..bed1a701bd
--- /dev/null
+++ b/indra/newview/skins/default/textures/widgets/BreadCrumbBtn_Middle_Disabled.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/BreadCrumbBtn_Middle_Off.png b/indra/newview/skins/default/textures/widgets/BreadCrumbBtn_Middle_Off.png
new file mode 100644
index 0000000000..57ce9af574
--- /dev/null
+++ b/indra/newview/skins/default/textures/widgets/BreadCrumbBtn_Middle_Off.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/BreadCrumbBtn_Middle_Over.png b/indra/newview/skins/default/textures/widgets/BreadCrumbBtn_Middle_Over.png
new file mode 100644
index 0000000000..2c43022f0e
--- /dev/null
+++ b/indra/newview/skins/default/textures/widgets/BreadCrumbBtn_Middle_Over.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/BreadCrumbBtn_Middle_Press.png b/indra/newview/skins/default/textures/widgets/BreadCrumbBtn_Middle_Press.png
new file mode 100644
index 0000000000..6b8c1baca4
--- /dev/null
+++ b/indra/newview/skins/default/textures/widgets/BreadCrumbBtn_Middle_Press.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/BreadCrumbBtn_Right_Disabled.png b/indra/newview/skins/default/textures/widgets/BreadCrumbBtn_Right_Disabled.png
new file mode 100644
index 0000000000..51505e80c5
--- /dev/null
+++ b/indra/newview/skins/default/textures/widgets/BreadCrumbBtn_Right_Disabled.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/BreadCrumbBtn_Right_Off.png b/indra/newview/skins/default/textures/widgets/BreadCrumbBtn_Right_Off.png
new file mode 100644
index 0000000000..9f93efbd93
--- /dev/null
+++ b/indra/newview/skins/default/textures/widgets/BreadCrumbBtn_Right_Off.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/BreadCrumbBtn_Right_Over.png b/indra/newview/skins/default/textures/widgets/BreadCrumbBtn_Right_Over.png
new file mode 100644
index 0000000000..3a4ec1a315
--- /dev/null
+++ b/indra/newview/skins/default/textures/widgets/BreadCrumbBtn_Right_Over.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/BreadCrumbBtn_Right_Press.png b/indra/newview/skins/default/textures/widgets/BreadCrumbBtn_Right_Press.png
new file mode 100644
index 0000000000..1f1b4c2ed5
--- /dev/null
+++ b/indra/newview/skins/default/textures/widgets/BreadCrumbBtn_Right_Press.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/ProgressBar.png b/indra/newview/skins/default/textures/widgets/ProgressBar.png
index edf11ac1f5..3f0e4eba28 100644
--- a/indra/newview/skins/default/textures/widgets/ProgressBar.png
+++ b/indra/newview/skins/default/textures/widgets/ProgressBar.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/world/CameraDragDot.png b/indra/newview/skins/default/textures/world/CameraDragDot.png
new file mode 100644
index 0000000000..57698e1956
--- /dev/null
+++ b/indra/newview/skins/default/textures/world/CameraDragDot.png
Binary files differ
diff --git a/indra/newview/skins/default/xui/en/floater_about.xml b/indra/newview/skins/default/xui/en/floater_about.xml
index 6a1a600696..a8b3ce9c28 100644
--- a/indra/newview/skins/default/xui/en/floater_about.xml
+++ b/indra/newview/skins/default/xui/en/floater_about.xml
@@ -139,27 +139,32 @@ Thank you to the following Residents for helping to ensure that this is the best
word_wrap="true">
3Dconnexion SDK Copyright (C) 1992-2007 3Dconnexion
APR Copyright (C) 2000-2004 The Apache Software Foundation
+Collada DOM Copyright 2005 Sony Computer Entertainment Inc.
cURL Copyright (C) 1996-2002, Daniel Stenberg, (daniel@haxx.se)
DBus/dbus-glib Copyright (C) 2002, 2003 CodeFactory AB / Copyright (C) 2003, 2004 Red Hat, Inc.
expat Copyright (C) 1998, 1999, 2000 Thai Open Source Software Center Ltd.
FreeType Copyright (C) 1996-2002, The FreeType Project (www.freetype.org).
GL Copyright (C) 1999-2004 Brian Paul.
+GLOD Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns Hopkins University and David Luebke, Brenden Schubert, University of Virginia.
google-perftools Copyright (c) 2005, Google Inc.
Havok.com(TM) Copyright (C) 1999-2001, Telekinesys Research Limited.
jpeg2000 Copyright (C) 2001, David Taubman, The University of New South Wales (UNSW)
jpeglib Copyright (C) 1991-1998, Thomas G. Lane.
ogg/vorbis Copyright (C) 2001, Xiphophorus
OpenSSL Copyright (C) 1998-2002 The OpenSSL Project.
+PCRE Copyright (c) 1997-2008 University of Cambridge
SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
xmlrpc-epi Copyright (C) 2000 Epinions, Inc.
zlib Copyright (C) 1995-2002 Jean-loup Gailly and Mark Adler.
google-perftools Copyright (c) 2005, Google Inc.
+Second Life Viewer uses Havok (TM) Physics. (c)Copyright 1999-2010 Havok.com Inc. (and its Licensors). All Rights Reserved. See www.havok.com for details.
+
All rights reserved. See licenses.txt for details.
Voice chat Audio coding: Polycom(R) Siren14(TM) (ITU-T Rec. G.722.1 Annex C)
- </text_editor>
+ </text_editor>
</panel>
</tab_container>
</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_import_collada.xml b/indra/newview/skins/default/xui/en/floater_import_collada.xml
new file mode 100644
index 0000000000..441ab6a2de
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_import_collada.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater can_close="false" can_drag_on_left="false" can_minimize="false"
+ can_resize="false" height="160" min_height="160" width="300" min_width="300"
+ name="Import Collada" title="Import Scene">
+
+ <text bottom_delta="40" left="20" name="mesh count" height="15" follows="top|left">
+ Meshes: [COUNT]
+ </text>
+
+ <text bottom_delta="20" left="20" name="texture count" height="15" follows="top|left">
+ Textures: [COUNT]
+ </text>
+
+ <text bottom_delta="40" left="10" name="status" height="15" follows="top|left">
+ Status: [STATUS]
+ </text>
+
+ <button
+ bottom_delta="40"
+ name="cancel"
+ label="Cancel"
+ enabled="true"
+ height="20"
+ layout="topleft"
+ left="125"
+ width="75" />
+
+ <button
+ bottom_delta="0"
+ name="ok"
+ label="OK"
+ enabled="true"
+ height="20"
+ layout="topleft"
+ left="210"
+ width="75" />
+
+ <string name="status_idle">Idle</string>
+ <string name="status_uploading">Uploading [NAME]</string>
+ <string name="status_creating">Creating object [NAME]</string>
+
+ </floater>
diff --git a/indra/newview/skins/default/xui/en/floater_inventory_view_finder.xml b/indra/newview/skins/default/xui/en/floater_inventory_view_finder.xml
index 90fee857fb..c86ed595a7 100644
--- a/indra/newview/skins/default/xui/en/floater_inventory_view_finder.xml
+++ b/indra/newview/skins/default/xui/en/floater_inventory_view_finder.xml
@@ -95,6 +95,23 @@
width="126" />
<icon
height="16"
+ image_name="Inv_Mesh"
+ layout="topleft"
+ left="8"
+ mouse_opaque="true"
+ name="icon_mesh"
+ top="142"
+ width="16" />
+ <check_box
+ height="16"
+ label="Meshes"
+ layout="topleft"
+ left_pad="2"
+ name="check_mesh"
+ top_delta="0"
+ width="126" />
+ <icon
+ height="16"
image_name="Inv_Notecard"
layout="topleft"
left="8"
@@ -117,7 +134,7 @@
left="8"
mouse_opaque="true"
name="icon_object"
- top="142"
+ top="162"
width="16" />
<check_box
height="16"
@@ -134,7 +151,7 @@
left="8"
mouse_opaque="true"
name="icon_script"
- top="162"
+ top="182"
width="16" />
<check_box
height="16"
@@ -151,7 +168,7 @@
left="8"
mouse_opaque="true"
name="icon_sound"
- top="182"
+ top="202"
width="16" />
<check_box
height="16"
@@ -168,7 +185,7 @@
left="8"
mouse_opaque="true"
name="icon_texture"
- top="202"
+ top="222"
width="16" />
<check_box
height="16"
@@ -185,7 +202,7 @@
left="8"
mouse_opaque="true"
name="icon_snapshot"
- top="222"
+ top="242"
width="16" />
<check_box
height="16"
@@ -203,7 +220,7 @@
layout="topleft"
left="8"
name="All"
- top="242"
+ top="262"
width="100" />
<button
follows="left|top"
diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml
new file mode 100644
index 0000000000..d08c3e7078
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml
@@ -0,0 +1,547 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater can_close="true" can_drag_on_left="false" can_minimize="false"
+ can_resize="true" height="550" min_height="550" min_width="620"
+ name="Model Preview" title="Upload Model" width="620">
+
+ <string name="status_idle">Idle</string>
+ <string name="status_reading_file">Loading...</string>
+ <string name="status_generating_meshes">Generating Meshes...</string>
+ <string name="status_vertex_number_overflow">Error: Vertex number is more than 65534, aborted!</string>
+ <string name="high">High</string>
+ <string name="medium">Medium</string>
+ <string name="low">Low</string>
+ <string name="lowest">Lowest</string>
+ <string name="mesh_status_good">Ship it!</string>
+ <string name="mesh_status_na">N/A</string>
+ <string name="mesh_status_none">None</string>
+ <string name="mesh_status_submesh_mismatch">Levels of detail have a different number of textureable faces.</string>
+ <string name="mesh_status_mesh_mismatch">Levels of detail have a different number of mesh instances.</string>
+ <string name="mesh_status_too_many_vertices">Level of detail has too many vertices.</string>
+ <string name="mesh_status_missing_lod">Missing required level of detail.</string>
+ <string name="layer_all">All</string> <!-- Text to display in physics layer combo box for "all layers" -->
+ <string name="decomposing">Analyzing...</string>
+ <string name="simplifying">Simplifying...</string>
+
+
+ <text left="15" bottom="25" follows="top|left" height="15" name="name_label">
+ Name:
+ </text>
+ <line_editor bottom_delta="20" follows="top|left|right" height="19"
+ name="description_form" prevalidate_callback="ascii" width="290" />
+
+ <text bottom_delta="20" left="15" follows="left|top" height="15" name="lod_label">
+ Preview:
+ </text>
+ <combo_box bottom_delta="20" follows="left|top" height="18"
+ name="preview_lod_combo" width="240" tool_tip="LOD to view in preview render">
+ <combo_item name="high">
+ Level of Detail: High
+ </combo_item>
+ <combo_item name="medium">
+ Level of Detail: Medium
+ </combo_item>
+ <combo_item name="low">
+ Level of Detail: Low
+ </combo_item>
+ <combo_item name="lowest">
+ Level of Detail: Lowest
+ </combo_item>
+ </combo_box>
+
+ <menu_button follows="top|left"
+ image_hover_unselected="Toolbar_Left_Over"
+ image_overlay="OptionsMenu_Off"
+ image_selected="Toolbar_Left_Selected"
+ image_unselected="Toolbar_Left_Off"
+ layout="topleft"
+ left_pad="5"
+ name="options_gear_btn"
+ width="31"
+ height="25"/>
+ <!-- Placeholder panel for 3D preview render -->
+ <panel
+ name="preview_panel"
+ left="15"
+ bevel_style="none"
+ border_style="line"
+ border="true"
+ width="290"
+ height="290"
+ follows="all"/>
+
+ <text bottom_delta="25" left="25" width="100" follows="bottom|left">Upload Details</text>
+ <panel top_pad="5" border="true" left="15" width="290" height="70" follows="bottom|left"
+ bevel_style="none" bg_alpha_color="0 0 0 0" bg_opaque_color="0 0 0 0.3">
+ <text left="25" follows="bottom|left" width="140" height="15" name="streaming cost">
+ Resource Cost: [COST]
+ </text>
+ <text left="25" top_pad="5" width="140" follows="bottom|left" height="15" name="physics cost">
+ Physics Cost: [COST]
+ </text>
+ <text left="25" top_pad="5" follows="bottom|left" height="15" name="upload fee">
+ Upload Fee: N/A
+ </text>
+ </panel>
+
+ <text left="10" bottom="540" width="290" height="15" follows="bottom|left|right" name="status">[STATUS]</text>
+
+
+ <button bottom="540" left="300" follows="bottom|right" height="20" label="Defaults"
+ width="80" name="reset_btn" tool_tip="Reset to defaults"/>
+ <button bottom="540" left="430" follows="bottom|right" height="20" label="Upload"
+ width="80" name="ok_btn" tool_tip="Upload to simulator"/>
+ <button left_pad="10" follows="right|bottom" height="20" width="80" label="Cancel" name="cancel_btn"/>
+
+ <tab_container
+ follows="right|top|bottom"
+ top="15"
+ left="310"
+ height="470"
+ width="300"
+ name="import_tab"
+ border="true"
+ tab_position="top">
+
+ <!-- LOD PANEL -->
+ <panel
+ border="true"
+ label="Level of Detail"
+ name="lod_panel">
+
+ <text left="10" width="240" bottom="20" height="15" follows="left|top" name="lod_table_header">
+ Select Level of Detail:
+ </text>
+
+ <text valign="center" halign="center" bg_visible="true" bottom_delta="16" left="75" width="65" height="18" follows="left|top" value="Triangles"/>
+ <text valign="center" halign="center" bg_visible="true" left_pad="0" width="65" height="18" follows="left|top" value="Vertices"/>
+ <text valign="center" halign="center" left_pad="0" width="65" bg_visible="true" height="18" follows="left|top" value="Status"/>
+
+ <text valign="center" halign="center" bg_visible="true" name="high_label" left="10" top_pad="0" width="65" height="18" follows="left|top" value="High"/>
+ <text valign="center" halign="center" bg_visible="true" name="high_triangles" left_pad="0" width="65" height="18" follows="left|top" value="0"/>
+ <text valign="center" halign="center" bg_visible="true" name="high_vertices" left_pad="0" width="65" height="18" follows="left|top" value="0"/>
+ <text valign="center" halign="center" bg_visible="true" name="high_status" left_pad="0" width="65" height="18" follows="left|top" value=""/>
+ <icon height="16" width="16" image_name="lag_status_critical.tga" mouse_opaque="true" name="status_icon_high" left_delta="20" top_delta="0" />
+
+ <text valign="center" halign="center" bg_visible="true" name="medium_label" left="10" top_pad="0" width="65" height="18" follows="left|top" value="Medium"/>
+ <text valign="center" halign="center" bg_visible="true" name="medium_triangles" left_pad="0" width="65" height="18" follows="left|top" value="0"/>
+ <text valign="center" halign="center" bg_visible="true" name="medium_vertices" left_pad="0" width="65" height="18" follows="left|top" value="0"/>
+ <text valign="center" halign="center" bg_visible="true" name="medium_status" left_pad="0" width="65" height="18" follows="left|top" value=""/>
+ <icon height="16" width="16" image_name="lag_status_critical.tga" mouse_opaque="true" name="status_icon_medium" left_delta="20" top_delta="0" />
+
+ <text valign="center" halign="center" bg_visible="true" name="low_label" left="10" top_pad="0" width="65" height="18" follows="left|top" value="Low"/>
+ <text valign="center" halign="center" bg_visible="true" name="low_triangles" left_pad="0" width="65" height="18" follows="left|top" value="0"/>
+ <text valign="center" halign="center" bg_visible="true" name="low_vertices" left_pad="0" width="65" height="18" follows="left|top" value="0"/>
+ <text valign="center" halign="center" bg_visible="true" name="low_status" left_pad="0" width="65" height="18" follows="left|top" value=""/>
+ <icon height="16" width="16" image_name="lag_status_critical.tga" mouse_opaque="true" name="status_icon_low" left_delta="20" top_delta="0" />
+
+ <text valign="center" halign="center" bg_visible="true" name="lowest_label" left="10" top_pad="0" width="65" height="18" follows="left|top" value="Lowest"/>
+ <text valign="center" halign="center" bg_visible="true" name="lowest_triangles" left_pad="0" width="65" height="18" follows="left|top" value="0"/>
+ <text valign="center" halign="center" bg_visible="true" name="lowest_vertices" left_pad="0" width="65" height="18" follows="left|top" value="0"/>
+ <text valign="center" halign="center" bg_visible="true" name="lowest_status" left_pad="0" width="65" height="18" follows="left|top" value=""/>
+ <icon height="16" width="16" image_name="lag_status_critical.tga" mouse_opaque="true" name="status_icon_lowest" left_delta="20" top_delta="0" />
+
+ <text left="10" width="240" height="15" top_pad="15" follows="left|top" name="lod_table_footer">
+ Level of Detail: [DETAIL]
+ </text>
+
+ <icon height="16" width="16" left="20" follows="left|top" name="lod_status_message_icon"/>
+ <text left_pad="5" width="200" height="28" follows="left|top" top_pad="-15" wrap="true" name="lod_status_message_text"/>
+
+ <text top_pad="-3" left="10" height="15" follows="left|top">
+ Mesh
+ </text>
+
+ <radio_group follows="top|left" height="210" left="30" name="lod_file_or_limit" width="240" value="lod_from_file">
+ <radio_item bottom="195" label="Load from file" name="lod_from_file"/>
+ <radio_item bottom="150" label="Auto generate" name="lod_auto_generate"/>
+ <radio_item bottom="0" label="None" name="lod_none"/>
+ </radio_group>
+
+ <line_editor follows="left|top" bottom_delta="-170" width="140" left="45" value="" name="lod_file" height="20"/>
+ <button bottom_delta="3" name="lod_browse" label="Browse..." left_pad="5" follows="left|top" width="70" height="25"/>
+
+ <combo_box follows="top|left" name="lod_mode" top_pad="22" width="100" left="45" height="20">
+ <combo_item name="triangle_limit">
+ Triangle Limit
+ </combo_item>
+ <combo_item name="error_threshold">
+ Error Threshold
+ </combo_item>
+ </combo_box>
+ <spinner follows="top|left" name="lod_triangle_limit" increment="10" left_pad="5" height="20" width="100" decimal_digits="0" enabled="true"/>
+ <spinner left_delta="0" bottom_delta="0" increment="0.01" follows="top|left" name="lod_error_threshold" min_val="0" max_val="100" height="20" width="100" decimal_digits="3" visible="false" enabled="true"/>
+
+ <text follows="top|left" name="build_operator_text" left="45" top_pad="10" width="100" height="15">
+ Build Operator:
+ </text>
+ <text follows="top|left" name="queue_mode_text" left_pad="5" width="100" height="15">
+ Queue Mode:
+ </text>
+ <combo_box follows="top|left" name="build_operator" top_pad="5" left="45" width="100" height="20">
+ <combo_item name="edge_collapse">
+ Edge Collapse
+ </combo_item>
+ <combo_item name="half_edge_collapse">
+ Half Edge Collapse
+ </combo_item>
+ </combo_box>
+
+ <combo_box follows="top|left" name="queue_mode" left_pad="5" width="100" height="20">
+ <combo_item name="greedy">
+ Greedy
+ </combo_item>
+ <combo_item name="lazy">
+ Lazy
+ </combo_item>
+ <combo_item name="independent">
+ Independent
+ </combo_item>
+ </combo_box>
+
+ <text top_pad="10" name="border_mode_text" left="45" follows="left|top" width="100" height="15">
+ Border Mode:
+ </text>
+
+ <text left_pad="5" name="share_tolderance_text" follows="left|top" width="100" height="15">
+ Share Tolerance:
+ </text>
+
+ <combo_box follows="left|top" left="45" height="20" name="border_mode" width="100">
+ <combo_item name="border_unlock">
+ Unlock
+ </combo_item>
+ <combo_item name="border_lock">
+ Lock
+ </combo_item>
+ </combo_box>
+ <spinner follows="left|top" name="share_tolerance" left_pad="5" width="100" decimal_digits="5" initial_value="0.00001" height="20"/>
+
+ <text left="10" top_pad="35" follows="top|left" width="240" height="15">
+ Generate Normals
+ </text>
+ <text left="35" top_pad="5" follows="top|left" width="100" height="15">
+ Crease Angle:
+ </text>
+ <spinner follows="top|left" left_pad="5" min_val="0" max_val="180" value="75" width="60" height="20" name="crease_angle"/>
+ </panel>
+
+ <!-- PANEL -->
+ <panel
+ border="true"
+ label="Physics"
+ name="physics_panel">
+
+ <!-- PHYSICS GEOMETRY-->
+ <panel
+ follows="top|left"
+ name="physics geometry"
+ left="0"
+ top="0"
+ width="300"
+ height="65"
+ visible="true"
+ border="true"
+ bevel_style="none" bg_alpha_color="0 0 0 0" bg_opaque_color="0 0 0 0.3">
+
+ <radio_group follows="top|left" top="10" width="240" height="40" name="physics_load_radio" value="physics_load_from_file">
+ <radio_item bottom="0" name="physics_load_from_file" label="File:"/>
+ <radio_item bottom="23" name="physics_use_lod" label="Use Level of Detail:"/>
+ </radio_group>
+
+ <combo_box left="180" top="10" follows="left|top" height="18"
+ name="physics_lod_combo" width="110" tool_tip="LOD to use for physics shape">
+ <combo_item name="physics_lowest">
+ Lowest
+ </combo_item>
+ <combo_item name="physics_low">
+ Low
+ </combo_item>
+ <combo_item name="physics_medium">
+ Medium
+ </combo_item>
+ <combo_item name="physics_high">
+ High
+ </combo_item>
+ </combo_box>
+
+ <line_editor follows="left|top" top_pad="5" width="140" left="60" value="" name="physics_file" height="20"/>
+ <button left_pad="10" name="physics_browse" label="Browse..." follows="left|top" width="70" height="20"/>
+
+ <!--
+ <check_box name="physics_optimize" follows="left|top" width="130" left="10" top_pad="5" height="20" label="Optimize"/>
+ <check_box name="physics_use_hull" follows="left|top" width="130" left_pad="5" height="20" label="Use Convex Hull"/>
+ -->
+ </panel>
+
+
+ <!-- PHYSICS ANALYSIS-->
+ <panel
+ follows="top|left"
+ name="physics analysis"
+ top_pad="0"
+ left="0"
+ width="300"
+ height="130"
+ visible="true"
+ border="true"
+ bevel_style="none" bg_alpha_color="0 0 0 0" bg_opaque_color="0 0 0 0.3">
+
+ <text follows="left|top" bottom="40" height="30" left="10" font="SansSerifBig">
+ Step 1: Analysis
+ </text>
+
+ <text top_pad="5" width="50" follows="top|left" height="15">
+ Method:
+ </text>
+ <combo_box name="Method" follows="top|left" left_pad="5" bottom_delta="2" height="20" width="80"/>
+ <text left="160" bottom_delta="-2" width="50" follows="top|left" height="15">
+ Quality:
+ </text>
+ <combo_box name="Decompose Quality" bottom_delta="2" follows="top|left" left_pad="5" height="20" width="80"/>
+
+ <slider name="Smooth" left="10" width="280" follows="top|left" top_pad="10" height="20" label="Smooth:"/>
+
+ <check_box name="Close Holes (Slow)" follows="top|left" top_pad="10" height="15" label="Close Holes (slow)"/>
+
+ <button left="200" bottom_delta="0" width="90" follows="top|left" label="Analyze" name="Decompose" height="20"/>
+ <button left="200" bottom_delta="0" width="90" follows="top|left" label="Cancel" name="decompose_cancel" visble="false" height="20"/>
+ </panel>
+
+
+ <!-- PHYSICS SIMPLIFICATION -->
+ <panel
+ follows="top|left"
+ name="physics simplification"
+ left="0"
+ top_pad="0"
+ width="300"
+ height="150"
+ visible="true"
+ border="true"
+ bevel_style="none" bg_alpha_color="0 0 0 0" bg_opaque_color="0 0 0 0.3">
+
+ <text follows="left|top" bottom="40" height="30" left="10" font="SansSerifBig">
+ Step 2: Simplification
+ </text>
+
+ <text left="10" top_pad="5" height="15" width="140" follows="top|left">
+ Method:
+ </text>
+
+ <combo_box left_pad="5" height="20" width="120" follows="top|left" name="Simplify Method"/>
+
+ <slider left="10" name="Combine Quality" label="Passes:" label_width="120" width="270" follows="top|left" top_pad="10" height="20"/>
+ <slider name="Detail Scale" label="Detail Scale:" label_width="120" width="270" follows="top|left" top_pad="10" height="20"/>
+ <slider name="Retain%" label="Retain:" label_width="120" width="270" follows="top|left" bottom_delta="0" left_delta="0" visible="false" height="20"/>
+ <button left="190" width="90" follows="top|left" label="Simplify" name="Simplify" height="20"/>
+ <button left="190" bottom_delta="0" width="90" follows="top|left" label="Cancel" name="simplify_cancel" height="20"/>
+
+ </panel>
+
+ <!-- INFO PANEL -->
+ <panel
+ left="0"
+ top_pad="0"
+ width="300"
+ height="100"
+ follows="left|top"
+ name="physics info"
+ visible="true"
+ border="true"
+ bevel_style="none" bg_alpha_color="0 0 0 0" bg_opaque_color="0 0 0 0.3">
+
+ <slider name="physics_explode" follows="top|left" top="10" left="10" label="Preview Spread:" min_val="0.0" max_val="3.0" height="20" width="280"/>
+
+ <text follows="top|left" name="physics_triangles" top_pad="10" height="15" left="10">
+ Triangles: [TRIANGLES]
+ </text>
+ <text follows="top|left" name="physics_points" top_pad="5" height="15">
+ Vertices: [POINTS]
+ </text>
+ <text follows="top|left" name="physics_hulls" top_pad="5" height="15">
+ Hulls: [HULLS]
+ </text>
+
+
+ </panel>
+ </panel>
+
+ <!-- MODIFIERS PANEL -->
+ <panel
+ border="true"
+ label="Modifiers"
+ name="modifiers_panel">
+ <text left="10" width="90" bottom="30" follows="top|left" height="15">
+ Scale:
+ </text>
+ <text left_pad="5" width="140" follows="top|left" height="15">
+ Dimensions:
+ </text>
+
+ <spinner left="10" height="20" follows="top|left" width="80" top_pad="5" value="1.0" min_val="0.01" max_val="64.0" name="import_scale"/>
+
+ <text left_pad="20" height="15" name="import_dimensions" follows="top|left">
+ [X] x [Y] x [Z] m
+ </text>
+
+ <text left="10" top_pad="20" follows="top|left" height="15">
+ Include:
+ </text>
+
+ <check_box top_pad="5" name="upload_textures" height="15" follows="top|left" label="Textures"/>
+ <check_box top_pad="5" name="upload_skin" height="15" follows="top|left" label="Skin weight"/>
+ <check_box top_pad="5" left="20" name="upload_joints" height="15" follows="top|left" label="Joint positions"/>
+
+ <text left="10" top_pad="4" width="90" bottom="30" follows="top|left" height="15">
+ Pelvis Z Offset:
+ </text>
+
+ <spinner left="10" top_pad="4" height="20" follows="top|left" width="80" value="0.0" min_val="-3.00" max_val="3.0" name="pelvis_offset"/>
+
+ </panel>
+ </tab_container>
+
+ <!--
+ <button bottom_delta="0" left="10" width="120" name="auto fill" label="Generate LOD" tool_tip="Automatically generate levels of detail"/>
+ <button bottom_delta="0" left="140" width="120" name="smooth normals" label="Generate Normals" tool_tip="Regenerate normals based on mesh shape"/>
+ <button bottom_delta="0" left="260" width="120" name="consolidate" label="Consolidate" tool_tip="Combine similar submeshes (reduces number of submeshes)"/>
+ <button bottom_delta="30" left="260" width="120" name="scrub materials" label="Scrub Materials" tool_tip="Remove all material information (clear textures, set all colors to white)."/>
+
+ <spinner bottom_delta="0" left="140" width="120" height="16" initial_value="75" label_width="60" name="edge threshold" decimal_digits="0" min_val="0" max_val="180" increment="5" label="Hard Angle" tool_tip="Maximum angle that will be smoothed between triangles when using Generate Normals"/>
+
+ <text bottom_delta="30" follows="top|left" height="15" left="10" name="high_lod_label">
+ High LOD:
+ </text>
+ <combo_box bottom_delta="0" left="97" follows="left|top" height="18"
+ name="high detail combo" width="100" tool_tip="Specify mesh for this level of detail">
+ <combo_item name="high none" value="none">
+ None
+ </combo_item>
+ <combo_item name="high choose file" value="file">
+ Choose File...
+ </combo_item>
+ <combo_item name="high triangle limit" value="limit">
+ Triangle Limit
+ </combo_item>
+ </combo_box>
+ <spinner bottom_delta="-5" left="200" width="120" name="high limit" decimal_digits="0" increment="1" min_val="0" max_val="100" tool_tip="Triangle budget for this LOD"/>
+ <text bottom_delta="25" follows="top|left" height="15" left="10" name="high info" width="300">
+ [TRIANGLES] Triangles, [VERTICES] Vertices, [SUBMESHES] Submeshes.
+ [MESSAGE]
+ </text>
+
+ <text bottom_delta="35" follows="top|left" height="15" left="10" name="medium_lod_label">
+ Medium LOD:
+ </text>
+ <combo_box bottom_delta="0" left="97" follows="left|top" height="18"
+ name="medium detail combo" width="100" tool_tip="Specify mesh for this level of detail">
+ <combo_item name="medium none" value="none">
+ None
+ </combo_item>
+ <combo_item name="medium choose file" value="file">
+ Choose File...
+ </combo_item>
+ <combo_item name="medium triangle limit" value="limit">
+ Triangle Limit
+ </combo_item>
+ </combo_box>
+ <spinner bottom_delta="-5" left="200" width="120" name="medium limit" decimal_digits="0" increment="1" min_val="0" max_val="100" tool_tip="Triangle budget for this LOD"/>
+ <text bottom_delta="25" follows="top|left" height="15" left="10" name="medium info" width="300">
+ [TRIANGLES] Triangles, [VERTICES] Vertices, [SUBMESHES] Submeshes.
+ [MESSAGE]
+ </text>
+
+ <text bottom_delta="35" follows="top|left" height="15" left="10" name="low_lod_label">
+ Low LOD:
+ </text>
+ <combo_box bottom_delta="0" left="97" follows="left|top" height="18"
+ name="low detail combo" width="100" tool_tip="Specify mesh for this level of detail">
+ <combo_item name="low none" value="none">
+ None
+ </combo_item>
+ <combo_item name="low choose file" value="file">
+ Choose File...
+ </combo_item>
+ <combo_item name="low triangle limit" value="limit">
+ Triangle Limit
+ </combo_item>
+ </combo_box>
+ <spinner bottom_delta="-5" left="200" width="120" name="low limit" decimal_digits="0" increment="1" min_val="0" max_val="100" tool_tip="Triangle budget for this LOD"/>
+ <text bottom_delta="25" follows="top|left" height="15" left="10" name="low info" width="300">
+ [TRIANGLES] Triangles, [VERTICES] Vertices, [SUBMESHES] Submeshes
+ [MESSAGE]
+ </text>
+
+ <text bottom_delta="35" follows="top|left" height="15" left="10" name="lowest_lod_label">
+ Lowest LOD:
+ </text>
+ <combo_box bottom_delta="0" left="97" follows="left|top" height="18"
+ name="lowest detail combo" width="100" tool_tip="Specify mesh for this level of detail">
+ <combo_item name="lowest none" value="none">
+ None
+ </combo_item>
+ <combo_item name="lowest choose file" value="file">
+ Choose File...
+ </combo_item>
+ <combo_item name="lowest triangle limit" value="limit">
+ Triangle Limit
+ </combo_item>
+ </combo_box>
+ <spinner bottom_delta="-5" left="200" width="120" name="lowest limit" decimal_digits="0" increment="1" min_val="0" max_val="100" tool_tip="Triangle budget for this LOD"/>
+ <text bottom_delta="25" follows="top|left" height="15" left="10" name="lowest info" width="300">
+ [TRIANGLES] Triangles, [VERTICES] Vertices, [SUBMESHES] Submeshes
+ [MESSAGE]
+ </text>
+
+ <text bottom_delta="35" follows="top|left" height="15" left="10" name="physics_lod_label">
+ Physical Shape:
+ </text>
+ <combo_box bottom_delta="0" left="97" follows="left|top" height="18"
+ name="physics detail combo" width="100">
+ <combo_item name="physics none" value="none">
+ None
+ </combo_item>
+ <combo_item name="physics choose file" value="file">
+ Choose File...
+ </combo_item>
+ <combo_item name="physics triangle limit" value="limit">
+ Triangle Limit...
+ </combo_item>
+ </combo_box>
+ <spinner bottom_delta="-5" left="200" width="90" name="physics limit" decimal_digits="0" increment="1" min_val="0" max_val="100" tool_tip="Triangle budget for this LOD"/>
+ <button bottom_delta="0" left="290" width="30" follows="left|top" height="20" label=">>"
+ name="decompose_btn" tool_tip="Create convex decomposition."/>
+ <text bottom_delta="25" follows="top|left" height="15" left="10" name="physics info" width="300">
+ [TRIANGLES] Triangles, [HULLS] Hulls, [POINTS] Points
+ </text>
+
+ <text bottom_delta="25" follows="top|left" height="15" left="10" name="include label" width="300">
+ Include:
+ </text>
+
+ <check_box bottom_delta="20" follow="bottom|left" height="20" label="Textures"
+ left="15" width="125" name="upload_textures" tool_tip="Upload associated textures "/>
+
+ <check_box bottom_delta="20" follow="bottom|left" height="20" label="Skin Weights"
+ left="15" width="125" name="upload_skin" tool_tip="Upload vertex skin weighting information."/>
+
+ <check_box bottom_delta="20" follow="bottom|left" height="20" label="Joint Positions"
+ left="15" width="125" name="upload_joints" tool_tip="Upload joint position information (will override avatar joint positions when mesh is worn)."/>
+
+
+ <button bottom_delta="25" follows="bottom|left" height="20" label="Upload"
+ left="15" name="ok_btn" width="125" tool_tip="Upload to simulator"/>
+
+ <text bottom_delta="20" left="15" width="280" follows="top|left" height="15" name="description_label" text_color="1 0.82 0.46 1">
+ (No charge for upload during First Look)
+ </text>
+ <text bottom_delta="20" left="15" width="280" follows="top|left" height="15" name="upload_message">
+ [MESSAGE]
+ </text>
+
+ <spinner bottom_delta="20" label="Scale" left="15" width="120" name="debug scale" decimal_digits="3" increment="0.1" min_val="0" max_val="64" initial_value="1" tool_tip="Multiplier for incoming object scale. If incoming dimensions are very small or very large, modify this value to get dimensions into an acceptable range."/>
+ <text bottom_delta="30" left="15" width="280" follows="top|left" height="15" name="dimensions">
+ Model Dimensions: [X]m x [Y]m x [Z]m
+ </text>
+ -->
+</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_model_wizard.xml b/indra/newview/skins/default/xui/en/floater_model_wizard.xml
new file mode 100644
index 0000000000..92d57b20be
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_model_wizard.xml
@@ -0,0 +1,1039 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+ legacy_header_height="18"
+ layout="topleft"
+ name="Model Wizard"
+ help_topic="model_wizard"
+ bg_opaque_image_overlay="0.5 0.5 0.5 1"
+ height="480"
+ save_rect="true"
+ title="UPLOAD MODEL WIZARD"
+ width="535">
+ <button
+ top="32"
+ tab_stop="false"
+ left="410"
+ height="32"
+ name="upload_btn"
+ enabled="false"
+ label="5. Upload"
+ border="false"
+ image_unselected="BreadCrumbBtn_Right_Off"
+ image_selected="BreadCrumbBtn_Right_Press"
+ image_hover_unselected="BreadCrumbBtn_Right_Over"
+ image_disabled="BreadCrumbBtn_Right_Disabled"
+ image_disabled_selected="BreadCrumbBtn_Right_Disabled"
+ width="110">
+ <button.commit_callback
+ function="Wizard.Upload"/>
+ </button>
+ <button
+ top="32"
+ left="310"
+ height="32"
+ tab_stop="false"
+ name="review_btn"
+ label="4. Review"
+ enabled="false"
+ border="false"
+ image_unselected="BreadCrumbBtn_Middle_Off"
+ image_selected="BreadCrumbBtn_Middle_Press"
+ image_hover_unselected="BreadCrumbBtn_Middle_Over"
+ image_disabled="BreadCrumbBtn_Middle_Disabled"
+ image_disabled_selected="BreadCrumbBtn_Middle_Disabled"
+ width="110">
+ <button.commit_callback
+ function="Wizard.Review"/>
+ </button>
+ <button
+ top="32"
+ left="210"
+ height="32"
+ name="physics2_btn"
+ label="3. Physics"
+ tab_stop="false"
+ enabled="false"
+ border="false"
+ image_unselected="BreadCrumbBtn_Middle_Off"
+ image_selected="BreadCrumbBtn_Middle_Press"
+ image_hover_unselected="BreadCrumbBtn_Middle_Over"
+ image_disabled="BreadCrumbBtn_Middle_Disabled"
+ image_disabled_selected="BreadCrumbBtn_Middle_Disabled"
+ width="110">
+ <button.commit_callback
+ function="Wizard.Physics2"/>
+ </button>
+ <button
+ top="32"
+ left="210"
+ height="32"
+ name="physics_btn"
+ label="3. Physics"
+ tab_stop="false"
+ enabled="false"
+ border="false"
+ image_unselected="BreadCrumbBtn_Middle_Off"
+ image_selected="BreadCrumbBtn_Middle_Press"
+ image_hover_unselected="BreadCrumbBtn_Middle_Over"
+ image_disabled="BreadCrumbBtn_Middle_Disabled"
+ image_disabled_selected="BreadCrumbBtn_Middle_Disabled"
+ width="110">
+ <button.commit_callback
+ function="Wizard.Physics"/>
+ </button>
+ <button
+ top="32"
+ left="115"
+ name="optimize_btn"
+ label="2. Optimize"
+ tab_stop="false"
+ height="32"
+ border="false"
+ image_unselected="BreadCrumbBtn_Middle_Off"
+ image_selected="BreadCrumbBtn_Middle_Press"
+ image_hover_unselected="BreadCrumbBtn_Middle_Over"
+ image_disabled="BreadCrumbBtn_Middle_Disabled"
+ image_disabled_selected="BreadCrumbBtn_Middle_Disabled"
+ width="110">
+ <button.commit_callback
+ function="Wizard.Optimize"/>
+ </button>
+ <button
+ top="32"
+ left="15"
+ name="choose_file_btn"
+ tab_stop="false"
+ enabled="false"
+ label="1. Choose File"
+ height="32"
+ image_unselected="BreadCrumbBtn_Left_Off"
+ image_selected="BreadCrumbBtn_Left_Press"
+ image_hover_unselected="BreadCrumbBtn_Left_Over"
+ image_disabled="BreadCrumbBtn_Left_Disabled"
+ image_disabled_selected="BreadCrumbBtn_Left_Disabled"
+ width="110">
+ <button.commit_callback
+ function="Wizard.Choose"/>
+ </button>
+ <panel
+ height="388"
+ top_pad="0"
+ name="choose_file_panel"
+ visible="false"
+ width="535"
+ left="0">
+ <panel
+ height="22"
+ top_pad="15"
+ width="505"
+ name="header_panel"
+ bg_opaque_color="DkGray2"
+ background_visible="true"
+ background_opaque="true"
+ left="15">
+ <text
+ width="200"
+ left="10"
+ top="3"
+ name="header_text"
+ text_color="White"
+ height="10"
+ font="SansSerifBig"
+ layout="topleft">
+ Upload Model
+ </text>
+ </panel>
+ <text
+ top_pad="14"
+ width="460"
+ height="20"
+ name="description"
+ font="SansSerifSmall"
+ layout="topleft"
+ word_wrap="true"
+ left_delta="5">
+ This wizard will help you import mesh models to Second Life. First specify a file containing the model you wish to import. Second Life supports COLLADA (.dae) files.
+ </text>
+ <panel
+ top_delta="40"
+ left="15"
+ height="270"
+ width="505"
+ name="content"
+ bg_opaque_color="DkGray2"
+ background_visible="true"
+ background_opaque="true">
+ <text
+ type="string"
+ length="1"
+ text_color="White"
+ follows="left|top"
+ top="10"
+ height="10"
+ layout="topleft"
+ left_delta="10"
+ name="Cache location"
+ width="300">
+ Filename:
+ </text>
+ <line_editor
+ border_style="line"
+ border_thickness="1"
+ follows="left|top"
+ font="SansSerifSmall"
+ height="20"
+ layout="topleft"
+ left_delta="0"
+ max_length="4096"
+ name="lod_file"
+ top_pad="5"
+ width="220" />
+ <button
+ follows="left|top"
+ height="23"
+ label="Browse..."
+ label_selected="Browse..."
+ layout="topleft"
+ left_pad="5"
+ name="browse"
+ top_delta="-1"
+ width="85">
+ </button>
+ <text
+ top_delta="-15"
+ width="200"
+ height="15"
+ font="SansSerifSmall"
+ layout="topleft"
+ text_color="White"
+ left_pad="19">
+ Model Preview:
+ </text>
+ <!-- Placeholder panel for 3D preview render -->
+ <panel
+ left_delta="0"
+ top_pad="0"
+ name="preview_panel"
+ bevel_style="none"
+ highlight_light_color="0.09 0.09 0.09 1"
+ border="true"
+ height="150"
+ follows="all"
+ width="150">
+ </panel>
+ <text
+ top_pad="10"
+ width="130"
+ height="14"
+ left="340"
+ text_color="White"
+ word_wrap="true">
+ Dimensions (meters):
+ </text>
+ <text
+ top_pad="0"
+ width="160"
+ height="15"
+ font="SansSerifSmallBold"
+ text_color="White"
+ name="dimensions"
+ left_delta="0">
+ X: Y: Z:
+ </text>
+ <text
+ top_delta="0"
+ width="160"
+ height="15"
+ name="dimension_dividers"
+ left_delta="41">
+ | |
+ </text>
+ <text
+ top_delta="0"
+ width="160"
+ height="15"
+ name="dimension_x"
+ left="356"/>
+ <text
+ top_delta="0"
+ width="160"
+ height="15"
+ name="dimension_y"
+ left="403"/>
+ <text
+ top_delta="0"
+ width="160"
+ height="15"
+ name="dimension_z"
+ left="450"/>
+ <text
+ top="100"
+ width="320"
+ height="15"
+ left="10"
+ text_color="White"
+ word_wrap="true">
+ Note:
+ </text>
+ <text
+ top_pad="0"
+ width="320"
+ height="40"
+ left="10"
+ word_wrap="true">
+Advanced users familiar with 3d content creation tools may prefer to use the [secondlife:///app/floater/upload_model Advanced Mesh Import Window] .
+ </text>
+ </panel>
+ </panel>
+
+
+ <panel
+ height="388"
+ top_delta="0"
+ name="optimize_panel"
+ visible="false"
+ width="535"
+ left="0">
+ <panel
+ height="22"
+ top_pad="15"
+ name="header_panel"
+ width="505"
+ bg_opaque_color="DkGray2"
+ background_visible="true"
+ background_opaque="true"
+ left="15">
+ <text
+ width="200"
+ left="10"
+ name="header_text"
+ top="3"
+ text_color="White"
+ height="10"
+ font="SansSerifBig"
+ layout="topleft">
+ Optimize
+ </text>
+ </panel>
+ <text
+ top_pad="14"
+ width="460"
+ height="20"
+ font="SansSerifSmall"
+ layout="topleft"
+ name="description"
+ word_wrap="true"
+ left_delta="5">
+ This wizard has optimized your model to improve performance. You may adjust the results of the optimization process bellow or click Next to continue.
+ </text>
+ <panel
+ top_delta="40"
+ visible="false"
+ left="15"
+ height="270"
+ width="505"
+ name="content"
+ bg_opaque_color="DkGray2"
+ background_visible="true"
+ background_opaque="true">
+ <text
+ top="20"
+ width="300"
+ height="12"
+ font="SansSerifBold"
+ left="112">Generating Level of Detail</text>
+ <progress_bar
+ name="optimize_progress_bar"
+ image_fill="model_wizard\progress_light.png"
+ color_bg="1 1 1 1"
+ color_bar="1 1 1 0.96"
+ follows="left|right|top"
+ width="260"
+ height="16"
+ image_bar="model_wizard\progress_bar_bg.png"
+ top_pad="14"
+ left="110"/>
+ <icon
+ top_pad="10"
+ left_delta="0"
+ width="13"
+ height="12"
+ image_name="model_wizard\check_mark.png"/>
+ <text
+ top_delta="0"
+ left_delta="18"
+ name="high_detail_text"
+ width="200"
+ height="14">Generate Level of Detail: High</text>
+ <icon
+ top_pad="10"
+ left_delta="-18"
+ width="13"
+ height="12"
+ image_name="model_wizard\check_mark.png"/>
+ <text
+ top_delta="0"
+ left_delta="18"
+ name="medium_detail_text"
+ width="200"
+ height="14">Generate Level of Detail: Medium</text>
+ <icon
+ top_pad="10"
+ left_delta="-18"
+ width="13"
+ height="12"
+ image_name="model_wizard\check_mark.png"/>
+ <text
+ top_delta="0"
+ left_delta="18"
+ name="low_detail_text"
+ width="200"
+ height="14">Generate Level of Detail: Low</text>
+ <icon
+ top_pad="10"
+ left_delta="-18"
+ width="13"
+ height="12"
+ image_name="model_wizard\check_mark.png"/>
+ <text
+ top_delta="0"
+ left_delta="18"
+ name="lowest_detail_text"
+ width="200"
+ height="14">Generate Level of Detail: Lowest</text>
+ </panel>
+ <panel
+ top_delta="0"
+ left_delta="0"
+ height="270"
+ width="505"
+ name="content2"
+ bg_opaque_color="DkGray2"
+ background_visible="true"
+ background_opaque="true">
+ <text top="10" left="10" width="85" text_color="White" follows="left|top" height="15" name="lod_label">
+ Model Preview:
+ </text>
+ <combo_box left_pad="5" top_delta="-5" follows="left|top" list_position="below" height="22"
+ name="preview_lod_combo2" width="90" tool_tip="LOD to view in preview render">
+ <combo_item name="high">
+ High
+ </combo_item>
+ <combo_item name="medium">
+ Medium
+ </combo_item>
+ <combo_item name="low">
+ Low
+ </combo_item>
+ <combo_item name="lowest">
+ Lowest
+ </combo_item>
+ </combo_box>
+ <panel
+ left="10"
+ top_pad="5"
+ name="preview_panel"
+ bevel_style="none"
+ highlight_light_color="0.09 0.09 0.09 1"
+ border_style="line"
+ border="true"
+ height="185"
+ follows="all"
+ width="185">
+ </panel>
+ <text top="45" left="214" text_color="White" font="SansSerifSmallBold" halign="center" width="110" height="30" wrap="true">Higher Performance</text>
+ <text top="75" left="204" halign="center" width="130" word_wrap="true" font="SansSerifSmall" height="80">Faster rendering but less detailed; lowers Resource (prim) cost.</text>
+ <text top="45" left="378" text_color="White" font="SansSerifSmallBold" halign="center" width="90" height="30" wrap="true">Higher Accuracy</text>
+ <text top="75" left="364" halign="center" width="130" word_wrap="true" font="SansSerifSmall" height="80">More detailed model but slower; increases Resource (prim) cost.</text>
+
+ <slider
+ follows="left|top"
+ height="20"
+ increment="1"
+ layout="topleft"
+ left="204"
+ max_val="3"
+ initial_value="2"
+ min_val="0"
+ name="accuracy_slider"
+ show_text="false"
+ top="130"
+ width="290" />
+ <text
+ font="SansSerifSmall"
+ top_pad="0"
+ width="300"
+ left_delta="6"
+ height="4">'
+ </text>
+
+
+ <icon
+ top_pad="14"
+ left_delta="0"
+ width="280"
+ height="2"
+ image_name="model_wizard\divider_line.png"/>
+
+ <text top_delta="20" width="200" text_color="White" left_delta="50" name="streaming cost" height="20">Resource Cost: [COST]</text>
+ <text
+ top_pad="15"
+ width="130"
+ height="14"
+ left="10"
+ text_color="White"
+ word_wrap="true">
+ Dimensions (meters):
+ </text>
+ <text
+ top_pad="0"
+ width="160"
+ height="15"
+ font="SansSerifSmallBold"
+ text_color="White"
+ name="dimensions"
+ left_delta="0">
+ X: Y: Z:
+ </text>
+ <text
+ top_delta="0"
+ width="160"
+ height="15"
+ name="dimension_dividers"
+ left_delta="41">
+ | |
+ </text>
+ <text
+ top_delta="0"
+ width="160"
+ height="15"
+ name="dimension_x"
+ left_delta="-25"/>
+ <text
+ top_delta="0"
+ width="160"
+ height="15"
+ name="dimension_y"
+ left_delta="46"/>
+ <text
+ top_delta="0"
+ width="160"
+ height="15"
+ name="dimension_z"
+ left_delta="46"/>
+ </panel>
+ </panel>
+
+ <panel
+ height="388"
+ top_delta="0"
+ name="physics_panel"
+ visible="false"
+ width="535"
+ left="0">
+ <panel
+ height="22"
+ top_pad="15"
+ name="header_panel"
+ width="505"
+ bg_opaque_color="DkGray2"
+ background_visible="true"
+ background_opaque="true"
+ left="15">
+ <text
+ width="200"
+ left="10"
+ name="header_text"
+ top="3"
+ height="10"
+ font="SansSerifBig"
+ text_color="White"
+ layout="topleft">
+ Physics
+ </text>
+ </panel>
+ <text
+ top_pad="10"
+ width="474"
+ height="50"
+ font="SansSerifSmall"
+ layout="topleft"
+ name="description"
+ word_wrap="true"
+ left_delta="5">
+ The wizard will create a physical shape, which determines how the object interacts with other objects and avatars. Set the slider to the detail level most appropriate for how your object will be used:
+ </text>
+ <panel
+ top_delta="44"
+ left="15"
+ height="270"
+ width="505"
+ name="content"
+ bg_opaque_color="DkGray2"
+ background_visible="true"
+ background_opaque="true">
+ <text top="25" left="30" text_color="White" font="SansSerifSmallBold" width="300" height="4">Performance</text>
+ <text top="45" left="10" halign="center" width="130" word_wrap="true" font="SansSerifSmall" height="80">Faster rendering but less detailed; lowers Resource (prim) cost.</text>
+ <text top="25" left="390" text_color="White" font="SansSerifSmallBold" width="300" height="4">Accuracy</text>
+ <text top="45" left="360" halign="center" width="130" word_wrap="true" font="SansSerifSmall" height="80">More detailed model but slower; increases Resource (prim) cost.</text>
+
+ <slider
+ follows="left|top"
+ height="22"
+ increment=".1"
+ layout="topleft"
+ left="20"
+ max_val="1"
+ initial_value="0.5"
+ min_val="0"
+ name="physics_slider"
+ show_text="false"
+ top="90"
+ width="440" />
+ <text
+ font="SansSerifSmall"
+ top_pad="0"
+ width="500"
+ left_delta="6"
+ height="4">' ' ' ' ' ' ' ' ' ' '</text>
+ <text top_pad="10" width="110" halign="center" word_wrap="true" left="25" height="40">Recommended for solid objects</text>
+ <text top_delta="0" width="110" halign="center" word_wrap="true" left="190" height="40">Recommended for buildings</text>
+ <text top_delta="0" width="110" halign="center" word_wrap="true" left="350" height="40">Recommended for vehicles</text>
+
+
+ <icon
+ top_pad="5"
+ left="15"
+ width="470"
+ height="2"
+ image_name="model_wizard\divider_line.png"/>
+
+ <text top_delta="30" width="180" text_color="White" left="160" name="streaming cost" height="20">Resource Cost: [COST]</text>
+
+ </panel>
+ </panel>
+
+ <panel
+ height="388"
+ top_delta="0"
+ name="physics2_panel"
+ visible="true"
+ width="535"
+ left="0">
+ <panel
+ height="22"
+ top_pad="15"
+ name="header_panel"
+ width="505"
+ bg_opaque_color="DkGray2"
+ background_visible="true"
+ background_opaque="true"
+ left="15">
+ <text
+ width="200"
+ left="10"
+ name="header_text"
+ text_color="White"
+ top="3"
+ height="10"
+ font="SansSerifBig"
+ layout="topleft">
+ Physics
+ </text>
+ </panel>
+ <text
+ top_pad="14"
+ width="475"
+ height="50"
+ font="SansSerifSmall"
+ layout="topleft"
+ name="description"
+ word_wrap="true"
+ left_delta="5">
+ Preview the physics shape below then click Next to continue. To modify the physics shape, click the Back button.
+ </text>
+ <panel
+ top_delta="40"
+ left="15"
+ height="270"
+ width="505"
+ name="content"
+ bg_opaque_color="DkGray2"
+ background_visible="true"
+ background_opaque="true">
+ <text top="10" left="10" width="85" text_color="White" follows="left|top" height="15" name="lod_label">
+ Model Preview:
+ </text>
+ <combo_box left_pad="5" top_delta="-5" follows="left|top" list_position="below" height="22"
+ name="preview_lod_combo3" width="90" tool_tip="LOD to view in preview render">
+ <combo_item name="high">
+ High
+ </combo_item>
+ <combo_item name="medium">
+ Medium
+ </combo_item>
+ <combo_item name="low">
+ Low
+ </combo_item>
+ <combo_item name="lowest">
+ Lowest
+ </combo_item>
+ </combo_box>
+ <panel
+ left="10"
+ top_pad="10"
+ name="preview_panel"
+ bevel_style="none"
+ highlight_light_color="0.09 0.09 0.09 1"
+ border_style="line"
+ border="true"
+ height="190"
+ follows="all"
+ width="190">
+ </panel>
+ <text
+ top_pad="8"
+ width="130"
+ height="14"
+ left="10"
+ text_color="White"
+ word_wrap="true">
+ Dimensions (meters):
+ </text>
+ <text
+ top_pad="0"
+ width="160"
+ height="15"
+ font="SansSerifSmallBold"
+ text_color="White"
+ name="dimensions"
+ left_delta="0">
+ X: Y: Z:
+ </text>
+ <text
+ top_delta="0"
+ width="160"
+ height="15"
+ name="dimension_dividers"
+ left_delta="41">
+ | |
+ </text>
+ <text
+ top_delta="0"
+ width="160"
+ height="15"
+ name="dimension_x"
+ left_delta="-25"/>
+ <text
+ top_delta="0"
+ width="160"
+ height="15"
+ name="dimension_y"
+ left_delta="46"/>
+ <text
+ top_delta="0"
+ width="160"
+ height="15"
+ name="dimension_z"
+ left_delta="46"/>
+ <text top="60" width="180" text_color="White" left="225" name="streaming cost" height="20">Resource Cost: [COST]</text>
+ </panel>
+ </panel>
+
+ <panel
+ height="388"
+ top_delta="0"
+ name="review_panel"
+ visible="false"
+ width="535"
+ left="0">
+ <panel
+ height="22"
+ top_pad="15"
+ name="header_panel"
+ width="505"
+ bg_opaque_color="DkGray2"
+ background_visible="true"
+ background_opaque="true"
+ left="15">
+ <text
+ width="200"
+ left="10"
+ name="header_text"
+ text_color="White"
+ top="3"
+ height="10"
+ font="SansSerifBig"
+ layout="topleft">
+ Review
+ </text>
+ </panel>
+ <text
+ top_pad="14"
+ width="470"
+ height="24"
+ font="SansSerifSmall"
+ layout="topleft"
+ name="description"
+ word_wrap="true"
+ left_delta="5">
+ Review the details below then click. Upload to upload your model. Your L$ balance will be charged when you click Upload.
+ </text>
+ <icon
+ top_pad="10"
+ left="20"
+ width="495"
+ height="2"
+ image_name="model_wizard\divider_line.png"/>
+ <panel
+ top_pad="5"
+ left="15"
+ height="270"
+ width="505"
+ name="content">
+ <text top="10" left="10" width="85" text_color="White" follows="left|top" height="15" name="lod_label">
+ Model Preview:
+ </text>
+ <combo_box left_pad="5" top_delta="-5" follows="left|top" list_position="below" height="22"
+ name="preview_lod_combo" width="90" tool_tip="LOD to view in preview render">
+ <combo_item name="high">
+ High
+ </combo_item>
+ <combo_item name="medium">
+ Medium
+ </combo_item>
+ <combo_item name="low">
+ Low
+ </combo_item>
+ <combo_item name="lowest">
+ Lowest
+ </combo_item>
+ </combo_box>
+ <panel
+ left="10"
+ top_pad="10"
+ name="preview_panel"
+ bevel_style="none"
+ highlight_light_color="0.09 0.09 0.09 1"
+ border_style="line"
+ border="true"
+ height="190"
+ follows="all"
+ width="190">
+ </panel>
+ <text
+ top_pad="8"
+ width="130"
+ height="14"
+ left="10"
+ text_color="White"
+ word_wrap="true">
+ Dimensions (meters):
+ </text>
+ <text
+ top_pad="0"
+ width="160"
+ height="15"
+ font="SansSerifSmallBold"
+ text_color="White"
+ name="dimensions"
+ left_delta="0">
+ X: Y: Z:
+ </text>
+ <text
+ top_delta="0"
+ width="160"
+ height="15"
+ name="dimension_dividers"
+ left_delta="41">
+ | |
+ </text>
+ <text
+ top_delta="0"
+ width="160"
+ height="15"
+ name="dimension_x"
+ left_delta="-25"/>
+ <text
+ top_delta="0"
+ width="160"
+ height="15"
+ name="dimension_y"
+ left_delta="46"/>
+ <text
+ top_delta="0"
+ width="160"
+ height="15"
+ name="dimension_z"
+ left_delta="46"/>
+ </panel>
+ <text
+ width="300"
+ height="12"
+ top="125"
+ name="streaming cost"
+ left="230"
+ font="SansSerifSmallBold"
+ text_color="White">Resource Cost: [COST]</text>
+ <text
+ width="285"
+ height="30"
+ top_pad="0"
+ left_delta="0"
+ word_wrap="true"
+ font="SansSerifItalic">This is the cost to your Region's prim/object limit, at default scale</text>
+ <text
+ width="300"
+ height="12"
+ name="physics cost"
+ top_pad="10"
+ left_delta="0"
+ font="SansSerifSmallBold"
+ text_color="White">Physics Cost: [COST]</text>
+ <text
+ width="285"
+ height="30"
+ top_pad="0"
+ left_delta="0"
+ word_wrap="true"
+ font="SansSerifItalic">This is the cost to your Region's prim/object limit, at default scale</text>
+ <text
+ width="200"
+ height="12"
+ top_pad="10"
+ left_delta="0"
+ font="SansSerifSmallBold"
+ text_color="White">Upload Fee:</text>
+ <text
+ width="285"
+ height="26"
+ top_pad="0"
+ left_delta="0"
+ word_wrap="true"
+ font="SansSerifItalic">This is the amount the upload will cost.</text>
+ <check_box
+ height="16"
+ layout="topleft"
+ left_delta="0"
+ name="confirm_checkbox"
+ top_pad="15"
+ width="16" />
+ <text
+ height="100"
+ width="240"
+ word_wrap="true"
+ left_delta="25"
+ top_delta="0">I confirm that I have the appropriate rights to the material contained in this model. [secondlife:///app/floater/learn_more Learn more]</text>
+ </panel>
+
+
+
+
+ <panel
+ height="388"
+ top_delta="0"
+ name="upload_panel"
+ visible="false"
+ width="535"
+ left="0">
+ <panel
+ height="22"
+ top_pad="15"
+ name="header_panel"
+ width="505"
+ bg_opaque_color="DkGray2"
+ background_visible="true"
+ background_opaque="true"
+ left="15">
+ <text
+ width="200"
+ left="10"
+ name="header_text"
+ top="3"
+ text_color="White"
+ height="10"
+ font="SansSerifBig"
+ layout="topleft">
+ Upload Complete!
+ </text>
+ </panel>
+ <text
+ top_pad="14"
+ width="474"
+ height="20"
+ font="SansSerifSmall"
+ layout="topleft"
+ name="description"
+ word_wrap="true"
+ left_delta="5">
+ Congratulations! Your model has been sucessfully uploaded. You will find the model in the Objects folder in your inventory.
+ </text>
+ <icon
+ top_pad="15"
+ left_delta="0"
+ width="495"
+ height="2"
+ image_name="model_wizard\divider_line.png"/>
+ </panel>
+
+
+
+ <button
+ top="440"
+ right="-245"
+ width="90"
+ height="22"
+ name="back"
+ label="&lt;&lt; Back" />
+ <button
+ top_delta="0"
+ right="-150"
+ width="90"
+ height="22"
+ name="next"
+ label="Next &gt;&gt; " />
+ <button
+ top_delta="0"
+ right="-150"
+ width="90"
+ height="22"
+ visible="false"
+ name="upload"
+ tool_tip="Upload to simulator"
+ label="Upload" />
+ <button
+ top_delta="0"
+ right="-15"
+ width="90"
+ height="22"
+ name="cancel"
+ label="Cancel" />
+ <button
+ top_delta="0"
+ right="-15"
+ width="90"
+ height="22"
+ name="close"
+ visible="false"
+ label="Close" />
+ <spinner visible="false" left="10" height="20" follows="top|left" width="80" top_pad="-50" value="1.0" min_val="0.01" max_val="64.0" name="import_scale"/>
+
+ <string name="status_idle">Idle</string>
+ <string name="status_reading_file">Loading...</string>
+ <string name="status_generating_meshes">Generating Meshes...</string>
+ <string name="status_vertex_number_overflow">Error: Vertex number is more than 65534, aborted!</string>
+ <string name="high">High</string>
+ <string name="medium">Medium</string>
+ <string name="low">Low</string>
+ <string name="lowest">Lowest</string>
+ <string name="mesh_status_good">Ship it!</string>
+ <string name="mesh_status_na">N/A</string>
+ <string name="mesh_status_none">None</string>
+ <string name="mesh_status_submesh_mismatch">Levels of detail have a different number of textureable faces.</string>
+ <string name="mesh_status_mesh_mismatch">Levels of detail have a different number of mesh instances.</string>
+ <string name="mesh_status_too_many_vertices">Level of detail has too many vertices.</string>
+ <string name="mesh_status_missing_lod">Missing required level of detail.</string>
+ <string name="layer_all">All</string>
+ <!-- Text to display in physics layer combo box for "all layers" -->
+
+</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_postcard.xml b/indra/newview/skins/default/xui/en/floater_postcard.xml
index b4ecedd981..8da35e9d7f 100644
--- a/indra/newview/skins/default/xui/en/floater_postcard.xml
+++ b/indra/newview/skins/default/xui/en/floater_postcard.xml
@@ -36,6 +36,7 @@
Recipient&apos;s Email:
</text>
<line_editor
+ control_name="LastPostcardRecipient"
follows="left|top"
height="20"
layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/floater_price_for_listing.xml b/indra/newview/skins/default/xui/en/floater_price_for_listing.xml
new file mode 100644
index 0000000000..6312366b86
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_price_for_listing.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+ legacy_header_height="18"
+ can_minimize="false"
+ height="240"
+ layout="topleft"
+ name="price_for_listing"
+ help_topic="price_for_listing"
+ title="PUBLISH CLASSIFIED AD"
+ width="320">
+ <text
+ type="string"
+ length="1"
+ bottom="200"
+ follows="top|left"
+ font="SansSerif"
+ height="165"
+ layout="topleft"
+ left="15"
+ word_wrap="true"
+ name="explanation_text">
+ Your classified ad will run for one week from the day it is published.
+
+Your ad&apos;s position in the classified listings is determined by how much you choose to pay.
+
+The highest paid ads go to the top of the list, and appear higher in searches.
+ </text>
+ <text
+ type="string"
+ length="1"
+ follows="top|right"
+ font="SansSerif"
+ height="20"
+ layout="topleft"
+ left="140"
+ name="price_text"
+ top_delta="135"
+ width="85">
+ Price for Ad:
+ </text>
+ <text
+ type="string"
+ length="1"
+ follows="top|right"
+ font="SansSerif"
+ height="20"
+ layout="topleft"
+ left_pad="4"
+ name="price_symbol"
+ top_delta="0"
+ width="20">
+ L$
+ </text>
+ <line_editor
+ follows="top|left"
+ height="20"
+ layout="topleft"
+ left_pad="0"
+ max_length="6"
+ top_delta="-4"
+ name="price_edit"
+ width="60" />
+ <button
+ follows="top|left"
+ height="22"
+ label="OK"
+ layout="topleft"
+ left="105"
+ name="set_price_btn"
+ top_pad="22"
+ width="100" />
+ <button
+ follows="top|left"
+ height="22"
+ label="Cancel"
+ layout="topleft"
+ left_pad="5"
+ name="cancel_btn"
+ width="100" />
+
+</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_script_debug_panel.xml b/indra/newview/skins/default/xui/en/floater_script_debug_panel.xml
index d1db5c17ba..ce96ea232e 100644
--- a/indra/newview/skins/default/xui/en/floater_script_debug_panel.xml
+++ b/indra/newview/skins/default/xui/en/floater_script_debug_panel.xml
@@ -20,5 +20,6 @@
parse_highlights="true"
read_only="true"
width="420"
+ track_bottom="true"
word_wrap="true" />
</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_sound_devices.xml b/indra/newview/skins/default/xui/en/floater_sound_devices.xml
index c7c7a05af2..304987c3d5 100644
--- a/indra/newview/skins/default/xui/en/floater_sound_devices.xml
+++ b/indra/newview/skins/default/xui/en/floater_sound_devices.xml
@@ -11,7 +11,7 @@
save_rect="true"
single_instance="true"
bevel_style="in"
- height="140"
+ height="164"
layout="topleft"
name="floater_sound_devices"
title="Sound Devices"
@@ -25,4 +25,23 @@
left="2"
top="26"
class="panel_voice_device_settings"/>
+ <text
+ name="voice_label"
+ top="136"
+ left="12"
+ height="14"
+ width="80"
+ layout="topleft"
+ >Voice Chat</text>
+ <check_box
+ layout="topleft"
+ control_name="EnableVoiceChat"
+ follows="bottom|left"
+ top="138"
+ left="80"
+ name="enable_voice"
+ width="100"
+ height="14"
+ label="Enabled"
+ />
</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml
index d0603cb30e..05d47506db 100644
--- a/indra/newview/skins/default/xui/en/floater_tools.xml
+++ b/indra/newview/skins/default/xui/en/floater_tools.xml
@@ -295,22 +295,24 @@
width="100">
þ: [COUNT]
</text>
- <check_box
+ <check_box
control_name="ScaleUniform"
height="19"
label=""
layout="topleft"
left="143"
name="checkbox uniform"
- top="50"
+ top="50"
width="20" />
<text
height="19"
label="Stretch Both Sides"
- left="163"
+ left_delta="20"
name="checkbox uniform label"
- top="55"
+ top_delta="2"
width="120"
+ layout="topleft"
+ follows="top|left"
wrap="true">
Stretch Both Sides
</text>
@@ -323,6 +325,7 @@
left="143"
name="checkbox stretch textures"
top_pad="-6"
+ follows="left|top"
width="134" />
<check_box
control_name="SnapEnabled"
@@ -361,9 +364,10 @@
image_selected="ForwardArrow_Press"
image_unselected="ForwardArrow_Off"
layout="topleft"
+ follows="top|left"
name="Options..."
tool_tip="See more grid options"
- top_delta="0"
+ top_pad="-22"
right="-10"
width="18"
height="23" >
@@ -745,18 +749,73 @@
<button.commit_callback
function="BuildTool.applyToSelection"/>
</button>
- <text
+ <text
+ text_color="LtGray_50"
+ type="string"
+ length="1"
+ height="10"
+ follows="left|top"
+ halign="right"
+ layout="topleft"
+ right="-10"
+ name="obj_count"
+ top_pad="5"
+ width="143">
+ Objects: [COUNT]
+ </text>
+ <text
text_color="LtGray_50"
type="string"
length="1"
- height="10"
+ height="10"
follows="left|top"
halign="right"
layout="topleft"
right="-10"
- name="obj_count"
- top_pad="7"
+ name="prim_count"
width="143">
+ Prims: [COUNT]
+ </text>
+ <text
+ text_color="LtGray_50"
+ type="string"
+ length="1"
+ height="10"
+ follows="left|top"
+ halign="right"
+ layout="topleft"
+ right="-120"
+ name="linked_set_count"
+ top="144"
+ width="80">
+ Linked Sets: [COUNT]
+ </text>
+ <text
+ text_color="LtGray_50"
+ type="string"
+ length="1"
+ height="10"
+ follows="left|top"
+ halign="right"
+ layout="topleft"
+ top_delta="0"
+ right="-8"
+ name="linked_set_cost"
+ tool_tip="Cost of currently selected linked sets as [prims],[physics complexity]"
+ width="80">
+ Cost: [COST] / [PHYSICS]
+ </text>
+ <text
+ text_color="LtGray_50"
+ type="string"
+ length="1"
+ follows="left|top"
+ halign="right"
+ layout="topleft"
+ top_pad="5"
+ right="-120"
+ name="object_count"
+ width="80">
Objects: [COUNT]
</text>
<text
@@ -766,11 +825,39 @@
follows="left|top"
halign="right"
layout="topleft"
- right="-10"
- name="prim_count"
- width="143">
- Prims: [COUNT]
+ top_delta="0"
+ right="-8"
+ name="object_cost"
+ tool_tip="Cost of currently selected objects as [prims] / [physics complexity]"
+ width="80">
+ Cost: [COST] / [PHYSICS]
</text>
+ <!-- <text -->
+ <!-- text_color="LtGray_50" -->
+ <!-- type="string" -->
+ <!-- length="1" -->
+ <!-- height="10" -->
+ <!-- follows="left|top" -->
+ <!-- halign="right" -->
+ <!-- layout="topleft" -->
+ <!-- right="-10" -->
+ <!-- name="obj_count" -->
+ <!-- top_pad="5" -->
+ <!-- width="143"> -->
+ <!-- Objects: [COUNT] -->
+ <!-- </text> -->
+ <!-- <text -->
+ <!-- text_color="LtGray_50" -->
+ <!-- type="string" -->
+ <!-- length="1" -->
+ <!-- follows="left|top" -->
+ <!-- halign="right" -->
+ <!-- layout="topleft" -->
+ <!-- right="-10" -->
+ <!-- name="prim_count" -->
+ <!-- width="143"> -->
+ <!-- Prims: [COUNT] -->
+ <!-- </text> -->
<tab_container
follows="left|top"
height="410"
@@ -783,7 +870,8 @@
tab_height="25"
top="173"
width="295">
- <panel
+
+<panel
border="false"
follows="all"
label="General"
@@ -1253,7 +1341,7 @@ even though the user gets a free copy.
<panel
border="false"
follows="all"
- height="367"
+ height="567"
label="Object"
layout="topleft"
left_delta="0"
@@ -1372,7 +1460,7 @@ even though the user gets a free copy.
label_width="10"
layout="topleft"
left_delta="0"
- max_val="10"
+ max_val="64"
min_val="0.01"
name="Scale X"
text_enabled_color="1 1 1 1"
@@ -1387,7 +1475,7 @@ even though the user gets a free copy.
label_width="10"
layout="topleft"
left_delta="0"
- max_val="10"
+ max_val="64"
min_val="0.01"
name="Scale Y"
text_enabled_color="1 1 1 1"
@@ -1402,7 +1490,7 @@ even though the user gets a free copy.
label_width="10"
layout="topleft"
left_delta="0"
- max_val="10"
+ max_val="64"
min_val="0.01"
name="Scale Z"
text_enabled_color="1 1 1 1"
@@ -1468,7 +1556,6 @@ even though the user gets a free copy.
text_enabled_color="1 1 1 1"
top_pad="3"
width="87" />
-
<!-- <text
type="string"
length="1"
@@ -2046,6 +2133,10 @@ even though the user gets a free copy.
label="Cylinder"
name="Cylinder"
value="Cylinder" />
+ <combo_box.item
+ label="Mesh"
+ name="Mesh"
+ value="Mesh" />
</combo_box>
</panel>
<panel
@@ -2060,6 +2151,9 @@ even though the user gets a free copy.
name="Features"
top_delta="0"
width="295">
+ <panel.string name="None">None</panel.string>
+ <panel.string name="Prim">Prim</panel.string>
+ <panel.string name="Convex Hull">Convex Hull</panel.string>
<text
type="string"
length="1"
@@ -2202,6 +2296,7 @@ even though the user gets a free copy.
name="FlexForceZ"
top_pad="4"
width="128" />
+
<check_box
height="16"
label="Light"
@@ -2312,6 +2407,94 @@ even though the user gets a free copy.
mouse_opaque="true"
name="Light Ambiance"
width="120" />
+ <text
+ type="string"
+ length="1"
+ follows="left|top"
+ height="10"
+ layout="topleft"
+ name="label physicsshapetype"
+ top="38"
+ width="121">
+ Physics Shape Type:
+ </text>
+ <combo_box
+ height="19"
+ top_delta="15"
+ layout="topleft"
+ follows="left|top"
+ name="Physics Shape Type Combo Ctrl"
+ tool_tip="Choose the physics shape type"
+ width="108"/>
+
+ <spinner
+ follows="left|top"
+ height="19"
+ increment="1"
+ initial_value="1"
+ label="Gravity"
+ label_width="70"
+ layout="topleft"
+ min_val="-1"
+ max_val="28"
+ name="Physics Gravity"
+ top_pad="10"
+ width="132" />
+
+ <check_box
+ height="19"
+ label="Override material"
+ layout="topleft"
+ left_delta="0"
+ name="Physics Material Override"
+ tool_tip="Override Material"
+ top_pad="10"
+ width="132" />
+
+ <spinner
+ follows="left|top"
+ height="19"
+ increment="0.1"
+ initial_value="0"
+ label="Friction"
+ label_width="70"
+ layout="topleft"
+ left_delta="0"
+ max_val="255"
+ min_val="0"
+ name="Physics Friction"
+ top_pad="4"
+ width="132" />
+
+ <spinner
+ follows="left|top"
+ height="19"
+ increment="0.1"
+ initial_value="0"
+ label="Density"
+ label_width="70"
+ layout="topleft"
+ left_delta="0"
+ max_val="22587"
+ min_val="1"
+ name="Physics Density"
+ top_pad="4"
+ width="132" />
+
+ <spinner
+ follows="left|top"
+ height="19"
+ increment="0.01"
+ initial_value="0"
+ label="Restitution"
+ label_width="70"
+ layout="topleft"
+ left_delta="0"
+ max_val="1"
+ min_val="0"
+ name="Physics Restitution"
+ top_pad="4"
+ width="132" />
</panel>
<panel
border="false"
@@ -2378,7 +2561,7 @@ even though the user gets a free copy.
initial_value="0"
layout="topleft"
left_delta="0"
- max_val="90"
+ max_val="100"
name="ColorTrans"
top_pad="4"
width="80" />
diff --git a/indra/newview/skins/default/xui/en/menu_inventory_add.xml b/indra/newview/skins/default/xui/en/menu_inventory_add.xml
index 90e8db3709..484af63097 100644
--- a/indra/newview/skins/default/xui/en/menu_inventory_add.xml
+++ b/indra/newview/skins/default/xui/en/menu_inventory_add.xml
@@ -42,6 +42,18 @@
<menu_item_call.on_enable
function="File.EnableUpload" />
</menu_item_call>
+ <menu_item_call
+ label="Model..."
+ layout="topleft"
+ name="Upload Model">
+ <menu_item_call.on_click
+ function="File.UploadModel"
+ parameter="" />
+ <menu_item_call.on_enable
+ function="File.EnableUploadModel" />
+ <menu_item_call.on_visible
+ function="File.VisibleUploadModel"/>
+ </menu_item_call>
<menu_item_call
label="Bulk (L$[COST] per file)..."
layout="topleft"
@@ -239,4 +251,4 @@
parameter="eyes" />
</menu_item_call>
</menu>
-</menu> \ No newline at end of file
+</menu>
diff --git a/indra/newview/skins/default/xui/en/menu_model_import_gear_default.xml b/indra/newview/skins/default/xui/en/menu_model_import_gear_default.xml
new file mode 100644
index 0000000000..2650903f88
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_model_import_gear_default.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu
+ bottom="806"
+ layout="topleft"
+ left="0"
+ mouse_opaque="false"
+ name="model_menu_gear_default"
+ visible="false">
+ <menu_item_check
+ label="Show edges"
+ layout="topleft"
+ name="show_edges">
+ <on_click
+ function="ModelImport.ViewOption.Action"
+ parameter="show_edges" />
+ <on_check
+ function="ModelImport.ViewOption.Check"
+ parameter="show_edges" />
+ <on_enable
+ function="ModelImport.ViewOption.Enabled"
+ parameter="show_edges" />
+ </menu_item_check>
+ <menu_item_check
+ label="Show physics"
+ layout="topleft"
+ name="show_physics">
+ <on_click
+ function="ModelImport.ViewOption.Action"
+ parameter="show_physics" />
+ <on_check
+ function="ModelImport.ViewOption.Check"
+ parameter="show_physics" />
+ <on_enable
+ function="ModelImport.ViewOption.Enabled"
+ parameter="show_physics" />
+ </menu_item_check>
+ <menu_item_check
+ label="Show textures"
+ layout="topleft"
+ name="show_textures">
+ <on_click
+ function="ModelImport.ViewOption.Action"
+ parameter="show_textures" />
+ <on_check
+ function="ModelImport.ViewOption.Check"
+ parameter="show_textures" />
+ <on_enable
+ function="ModelImport.ViewOption.Enabled"
+ parameter="show_textures" />
+ </menu_item_check>
+ <menu_item_check
+ label="Show skin weight"
+ layout="topleft"
+ name="show_skin_weight">
+ <on_click
+ function="ModelImport.ViewOption.Action"
+ parameter="show_skin_weight" />
+ <on_check
+ function="ModelImport.ViewOption.Check"
+ parameter="show_skin_weight" />
+ <on_enable
+ function="ModelImport.ViewOption.Enabled"
+ parameter="show_skin_weight" />
+ </menu_item_check>
+ <menu_item_check
+ label="Show joint positions"
+ layout="topleft"
+ name="show_joint_positions">
+ <on_click
+ function="ModelImport.ViewOption.Action"
+ parameter="show_joint_positions" />
+ <on_check
+ function="ModelImport.ViewOption.Check"
+ parameter="show_joint_positions" />
+ <on_enable
+ function="ModelImport.ViewOption.Enabled"
+ parameter="show_joint_positions" />
+ </menu_item_check>
+</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index 8a85a331e5..81046e99a0 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -89,7 +89,7 @@
visibility_control="VoiceMorphingEnabled">
<menu_item_check.on_check
function="Floater.Visible"
- parameter="voice_effect" />
+ Parameter="voice_effect" />
<menu_item_check.on_click
function="Floater.Toggle"
parameter="voice_effect" />
@@ -972,6 +972,30 @@
parameter="Upload Animation" />
</menu_item_call>
<menu_item_call
+ label="Model..."
+ layout="topleft"
+ name="Upload Model">
+ <menu_item_call.on_click
+ function="File.UploadModel"
+ parameter="" />
+ <menu_item_call.on_enable
+ function="File.EnableUploadModel" />
+ <menu_item_call.on_visible
+ function="File.VisibleUploadModel"/>
+ </menu_item_call>
+ <menu_item_call
+ label="Model Wizard..."
+ layout="topleft"
+ name="Upload Model Wizard">
+ <menu_item_call.on_click
+ function="Floater.Show"
+ parameter="upload_model_wizard" />
+ <menu_item_call.on_enable
+ function="File.EnableUploadModel" />
+ <menu_item_call.on_visible
+ function="File.VisibleUploadModel"/>
+ </menu_item_call>
+ <menu_item_call
label="Bulk (L$[COST] per file)..."
layout="topleft"
name="Bulk Upload">
@@ -1342,15 +1366,15 @@
parameter="character" />
</menu_item_check>
<menu_item_check
- label="SurfacePath"
- name="SurfacePath"
+ label="Surface Patch"
+ name="Surface Patch"
shortcut="control|alt|shift|5">
<menu_item_check.on_check
function="Advanced.CheckRenderType"
- parameter="surfacePath" />
+ parameter="surfacePatch" />
<menu_item_check.on_click
function="Advanced.ToggleRenderType"
- parameter="surfacePath" />
+ parameter="surfacePatch" />
</menu_item_check>
<menu_item_check
label="Sky"
@@ -1877,6 +1901,16 @@
function="Advanced.ToggleConsole"
parameter="memory view" />
</menu_item_check>
+ <menu_item_check
+ label="Scene Statistics"
+ name="Scene Statistics">
+ <menu_item_check.on_check
+ function="Advanced.CheckConsole"
+ parameter="scene view" />
+ <menu_item_check.on_click
+ function="Advanced.ToggleConsole"
+ parameter="scene view" />
+ </menu_item_check>
<menu_item_separator/>
@@ -1961,6 +1995,17 @@
function="ToggleControl"
parameter="DebugShowTime" />
</menu_item_check>
+ <menu_item_check
+ label="Show Upload Cost"
+ layout="topleft"
+ name="Show Upload Cost">
+ <menu_item_check.on_check
+ function="CheckControl"
+ parameter="DebugShowUploadCost" />
+ <menu_item_check.on_click
+ function="ToggleControl"
+ parameter="DebugShowUploadCost" />
+ </menu_item_check>
<menu_item_check
label="Show Render Info"
name="Show Render Info">
@@ -2144,6 +2189,16 @@
parameter="bboxes" />
</menu_item_check>
<menu_item_check
+ label="Normals"
+ name="Normals">
+ <menu_item_check.on_check
+ function="Advanced.CheckInfoDisplay"
+ parameter="normals" />
+ <menu_item_check.on_click
+ function="Advanced.ToggleInfoDisplay"
+ parameter="normals" />
+ </menu_item_check>
+ <menu_item_check
label="Octree"
name="Octree">
<menu_item_check.on_check
@@ -2164,6 +2219,16 @@
parameter="shadow frusta" />
</menu_item_check>
<menu_item_check
+ label="Physics Shapes"
+ name="Physics Shapes">
+ <menu_item_check.on_check
+ function="Advanced.CheckInfoDisplay"
+ parameter="physics shapes" />
+ <menu_item_check.on_click
+ function="Advanced.ToggleInfoDisplay"
+ parameter="physics shapes" />
+ </menu_item_check>
+ <menu_item_check
label="Occlusion"
name="Occlusion">
<menu_item_check.on_check
@@ -2234,6 +2299,26 @@
parameter="face area" />
</menu_item_check>
<menu_item_check
+ label="LOD Info"
+ name="LOD Info">
+ <menu_item_check.on_check
+ function="Advanced.CheckInfoDisplay"
+ parameter="lod info" />
+ <menu_item_check.on_click
+ function="Advanced.ToggleInfoDisplay"
+ parameter="lod info" />
+ </menu_item_check>
+ <menu_item_check
+ label="Build Queue"
+ name="Build Queue">
+ <menu_item_check.on_check
+ function="Advanced.CheckInfoDisplay"
+ parameter="build queue" />
+ <menu_item_check.on_click
+ function="Advanced.ToggleInfoDisplay"
+ parameter="build queue" />
+ </menu_item_check>
+ <menu_item_check
label="Lights"
name="Lights">
<menu_item_check.on_check
@@ -2263,6 +2348,16 @@
function="Advanced.ToggleInfoDisplay"
parameter="raycast" />
</menu_item_check>
+ <menu_item_check
+ label="Sculpt"
+ name="Sculpt">
+ <menu_item_check.on_check
+ function="Advanced.CheckInfoDisplay"
+ parameter="sculpt" />
+ <menu_item_check.on_click
+ function="Advanced.ToggleInfoDisplay"
+ parameter="sculpt" />
+ </menu_item_check>
</menu>
<menu
create_jump_keys="true"
@@ -2319,19 +2414,6 @@
<menu_item_check.on_enable
function="Advanced.EnableObjectObjectOcclusion" />
</menu_item_check>
- <menu_item_check
- label="Framebuffer Objects"
- name="Framebuffer Objects">
- <menu_item_check.on_check
- function="CheckControl"
- parameter="RenderUseFBO" />
- <menu_item_check.on_click
- function="ToggleControl"
- parameter="RenderUseFBO" />
- <menu_item_check.on_enable
- function="Advanced.EnableRenderFBO" />
- </menu_item_check>
-
<menu_item_separator />
<menu_item_check
@@ -2758,7 +2840,6 @@
function="Floater.Toggle"
parameter="region_debug_console" />
</menu_item_check>
-
<menu_item_separator />
<menu_item_check
@@ -3166,7 +3247,7 @@
<menu_item_call.on_click
function="Advanced.LeaveAdminStatus" />
</menu_item_call>
- <menu_item_check
+ <menu_item_check
label="Show Admin Menu"
name="View Admin Options">
<menu_item_check.on_enable
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index d0dd639249..ebfed990ec 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -6721,7 +6721,7 @@ Unable to find the help topic for this element.
<tag>fail</tag>
</notification>
- <notification
+ <notification
icon="alertmodal.tga"
name="ObjectMediaFailure"
type="alertmodal">
@@ -6753,6 +6753,17 @@ Your voice has been muted by moderator.
name="okbutton"
yestext="OK"/>
</notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="UploadCostConfirmation"
+ type="alertmodal">
+This upload will cost L$[PRICE], do you wish to continue with the upload?
+ <usetemplate
+ name="okcancelbuttons"
+ notext="Cancel"
+ yestext="Upload"/>
+ </notification>
<notification
icon="alertmodal.tga"
@@ -6781,6 +6792,14 @@ The button will be shown when there is enough space for it.
type="notifytip">
Select residents to share with.
</notification>
+
+ <notification
+ name="MeshUploadError"
+ icon="alert.tga"
+ type="alert">
+ [LABEL] failed to upload: [MESSAGE] [IDENTIFIER] [INVALIDITY_IDENTIFIER]
+ </notification>
+
<notification
icon="notifytip.tga"
name="ShareItemsConfirmation"
@@ -6995,7 +7014,6 @@ Mute everyone?
notext="Cancel"
unique="true"/>
</notification>
-
<notification
name="HintChat"
label="Chat"
@@ -7299,10 +7317,6 @@ The site at &apos;&lt;nolink&gt;[HOST_NAME]&lt;/nolink&gt;&apos; in realm &apos;
notext="Don't Quit"/>
</notification>
- <global name="UnsupportedCPU">
-- Your CPU speed does not meet the minimum requirements.
- </global>
-
<global name="UnsupportedGLRequirements">
You do not appear to have the proper hardware requirements for [APP_NAME]. [APP_NAME] requires an OpenGL graphics card that has multitexture support. If this is the case, you may want to make sure that you have the latest drivers for your graphics card, and service packs and patches for your operating system.
diff --git a/indra/newview/skins/default/xui/en/panel_place_profile.xml b/indra/newview/skins/default/xui/en/panel_place_profile.xml
index 7e89860c60..774a9e8bbf 100644
--- a/indra/newview/skins/default/xui/en/panel_place_profile.xml
+++ b/indra/newview/skins/default/xui/en/panel_place_profile.xml
@@ -191,7 +191,7 @@
width="310">
<panel
bg_alpha_color="DkGray2"
- follows="left|top|right"
+ follows="left|top|right|bottom"
height="580"
layout="topleft"
left="0"
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml
index d74197d965..f20ce52125 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml
@@ -193,8 +193,18 @@
left_delta="0"
name="BumpShiny"
top_pad="1"
+ width="256" />
+ <check_box
+ control_name="RenderLocalLights"
+ height="16"
+ initial_value="true"
+ label="Local Lights"
+ layout="topleft"
+ left_delta="0"
+ name="LocalLights"
+ top_pad="1"
width="256" />
- <check_box
+ <check_box
control_name="VertexShaderEnable"
height="16"
initial_value="true"
@@ -221,7 +231,6 @@
<check_box.commit_callback
function="Pref.VertexShaderEnable" />
</check_box>
-<!-- DISABLED UNTIL WE REALLY WANT TO SUPPORT THIS
<check_box
control_name="RenderDeferred"
height="16"
@@ -248,6 +257,19 @@
<check_box.commit_callback
function="Pref.VertexShaderEnable" />
</check_box>
+ <check_box
+ control_name="RenderDepthOfField"
+ height="16"
+ initial_value="true"
+ label="Depth of Field"
+ layout="topleft"
+ left_delta="0"
+ name="UseDoF"
+ top_pad="1"
+ width="256">
+ <check_box.commit_callback
+ function="Pref.VertexShaderEnable" />
+ </check_box>
<text
type="string"
@@ -283,7 +305,7 @@
name="2"
value="2"/>
</combo_box>
--->
+
<text
type="string"
length="1"
diff --git a/indra/newview/skins/default/xui/en/panel_region_general.xml b/indra/newview/skins/default/xui/en/panel_region_general.xml
index ca9579284b..e0d9f3f714 100644
--- a/indra/newview/skins/default/xui/en/panel_region_general.xml
+++ b/indra/newview/skins/default/xui/en/panel_region_general.xml
@@ -114,7 +114,7 @@
layout="topleft"
left="10"
name="allow_land_resell_check"
- top="160"
+ top="150"
width="80" />
<check_box
height="20"
@@ -122,7 +122,7 @@
layout="topleft"
left="10"
name="allow_parcel_changes_check"
- top="180"
+ top="170"
width="80" />
<check_box
height="20"
@@ -131,7 +131,16 @@
left="10"
name="block_parcel_search_check"
tool_tip="Let people see this region and its parcels in search results"
- top="200"
+ top="190"
+ width="80" />
+ <check_box
+ height="20"
+ label="Allow Mesh Objects"
+ layout="topleft"
+ left="10"
+ name="mesh_rez_enabled_check"
+ tool_tip="Let people rez mesh objects on this region"
+ top="210"
width="80" />
<spinner
decimal_digits="0"
diff --git a/indra/newview/skins/default/xui/en/panel_sound_devices.xml b/indra/newview/skins/default/xui/en/panel_sound_devices.xml
index 9812281323..ccae7c5350 100644
--- a/indra/newview/skins/default/xui/en/panel_sound_devices.xml
+++ b/indra/newview/skins/default/xui/en/panel_sound_devices.xml
@@ -11,14 +11,6 @@
name="default_text">
Default
</panel.string>
- <panel.string
- name="default system device">
- Default system device
- </panel.string>
- <panel.string
- name="no device">
- No device
- </panel.string>
<icon
height="18"
image_name="Microphone_On"
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index b0ede60fa0..2a6af23d3a 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -58,6 +58,83 @@
<string name="Quit">Quit</string>
<string name="create_account_url">http://join.secondlife.com/</string>
+ <string name="LoginFailedViewerNotPermitted">
+The viewer you are using can no longer access Second Life. Please visit the following page to download a new viewer:
+http://secondlife.com/download
+
+For more information, see our FAQ below:
+http://secondlife.com/viewer-access-faq</string>
+ <string name="LoginIntermediateOptionalUpdateAvailable">Optional viewer update available: [VERSION]</string>
+ <string name="LoginFailedRequiredUpdate">Required viewer update: [VERSION]</string>
+ <string name="LoginFailedAlreadyLoggedIn">This agent is already logged in.
+</string>
+ <string name="LoginFailedAuthenticationFailed">Sorry! We couldn't log you in.
+Please check to make sure you entered the right
+ * Username (like bobsmith12 or steller.sunshine)
+ * Password
+Also, please make sure your Caps Lock key is off.</string>
+ <string name="LoginFailedPasswordChanged">As a security precaution your password has been changed.
+Please go to your account page at http://secondlife.com/password
+and answer the security question to reset your password.
+We are very sorry for the inconvenience.</string>
+ <string name="LoginFailedPasswordReset">We made some changes to our system and you will need to reset your password.
+Please go to your account page at http://secondlife.com/password
+and answer the security question to reset your password.
+We are very sorry for the inconvenience.</string>
+ <string name="LoginFailedEmployeesOnly">Second Life is temporarily closed for maintenance.
+Logins are currently restricted to employees only.
+Check www.secondlife.com/status for updates.</string>
+ <string name="LoginFailedPremiumOnly">Second Life logins are temporarily restricted in order to make sure that those in-world have the best possible experience.
+
+People with free accounts will not be able to access Second Life during this time, to make room for those who have paid for Second Life.</string>
+ <string name="LoginFailedComputerProhibited">Second Life cannot be accessed from this computer.
+If you feel this is an error, please contact
+support@secondlife.com.</string>
+ <string name="LoginFailedAcountSuspended">Your account is not accessible until
+[TIME] Pacific Time.</string>
+ <string name="LoginFailedAccountDisabled">We are unable to complete your request at this time.
+Please contact Second Life support for assistance at http://secondlife.com/support.
+If you are unable to change your password, please call (866) 476-9763.</string>
+ <string name="LoginFailedTransformError">Data inconsistency found during login.
+Please contact support@secondlife.com.</string>
+ <string name="LoginFailedAccountMaintenance">Your account is undergoing minor maintenance.
+Your account is not accessible until
+[TIME] Pacific Time.
+If you feel this is an error, please contact support@secondlife.com.</string>
+ <string name="LoginFailedPendingLogoutFault">Request for logout responded with a fault from simulator.</string>
+ <string name="LoginFailedPendingLogout">The system is logging you out right now.
+Your Account will not be available until
+[TIME] Pacific Time.</string>
+ <string name="LoginFailedUnableToCreateSession">Unable to create valid session.</string>
+ <string name="LoginFailedUnableToConnectToSimulator">Unable to connect to a simulator.</string>
+ <string name="LoginFailedRestrictedHours">Your account can only access Second Life
+between [START] and [END] Pacific Time.
+Please come back during those hours.
+If you feel this is an error, please contact support@secondlife.com.</string>
+ <string name="LoginFailedIncorrectParameters">Incorrect parameters.
+If you feel this is an error, please contact support@secondlife.com.</string>
+ <string name="LoginFailedFirstNameNotAlphanumeric">First name parameter must be alphanumeric.
+If you feel this is an error, please contact support@secondlife.com.</string>
+ <string name="LoginFailedLastNameNotAlphanumeric">Last name parameter must be alphanumeric.
+If you feel this is an error, please contact support@secondlife.com.</string>
+ <string name="LogoutFailedRegionGoingOffline">Region is going offline.
+Please try logging in again in a minute.</string>
+ <string name="LogoutFailedAgentNotInRegion">Agent not in region.
+Please try logging in again in a minute.</string>
+ <string name="LogoutFailedPendingLogin">The region was logging in another session.
+Please try logging in again in a minute.</string>
+ <string name="LogoutFailedLoggingOut">The region was logging out the previous session.
+Please try logging in again in a minute.</string>
+ <string name="LogoutFailedStillLoggingOut">The region is still logging out the previous session.
+Please try logging in again in a minute.</string>
+ <string name="LogoutSucceeded">Region has logged out last session.
+Please try logging in again in a minute.</string>
+ <string name="LogoutFailedLogoutBegun">Region has begun the logout process.
+Please try logging in again in a minute.</string>
+ <string name="LoginFailedLoggingOutSession">The system has begun logging out your last session.
+Please try logging in again in a minute.</string>
+
+
<!-- Disconnection -->
<string name="AgentLostConnection">This region may be experiencing trouble. Please check your connection to the Internet.</string>
<string name="SavingSettings">Saving your settings...</string>
@@ -198,6 +275,7 @@
<string name="favorite">favorite</string>
<string name="symbolic link">link</string>
<string name="symbolic folder link">folder link</string>
+ <string name="mesh">mesh</string>
<!-- llvoavatar. Displayed in the avatar chat bubble -->
<string name="AvatarEditingAppearance">(Editing Appearance)</string>
@@ -2008,6 +2086,7 @@ Requests name of an avatar. When data is available the dataserver event will be
<string name="InvFolder Initial Outfits">Initial Outfits</string>
<string name="InvFolder My Outfits">My Outfits</string>
<string name="InvFolder Accessories">Accessories</string>
+ <string name="InvFolder Meshes">Meshes</string>
<!-- are used for Friends and Friends/All folders in Inventory "Calling cards" folder. See EXT-694-->
<string name="InvFolder Friends">Friends</string>
diff --git a/indra/newview/skins/minimal/colors.xml b/indra/newview/skins/minimal/colors.xml
new file mode 100644
index 0000000000..097a298ce5
--- /dev/null
+++ b/indra/newview/skins/minimal/colors.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<colors>
+ <color
+ name="MenuBarBgColor"
+ value="0 0 0 0" />
+</colors>
diff --git a/indra/newview/skins/minimal/textures/arrow_keys.png b/indra/newview/skins/minimal/textures/arrow_keys.png
new file mode 100644
index 0000000000..f19af59251
--- /dev/null
+++ b/indra/newview/skins/minimal/textures/arrow_keys.png
Binary files differ
diff --git a/indra/newview/skins/minimal/textures/bottomtray/Speak_Btn_Off.png b/indra/newview/skins/minimal/textures/bottomtray/Speak_Btn_Off.png
new file mode 100644
index 0000000000..b6e9eef891
--- /dev/null
+++ b/indra/newview/skins/minimal/textures/bottomtray/Speak_Btn_Off.png
Binary files differ
diff --git a/indra/newview/skins/minimal/textures/bottomtray/Speak_Btn_Selected_Press.png b/indra/newview/skins/minimal/textures/bottomtray/Speak_Btn_Selected_Press.png
new file mode 100644
index 0000000000..687cb7fb53
--- /dev/null
+++ b/indra/newview/skins/minimal/textures/bottomtray/Speak_Btn_Selected_Press.png
Binary files differ
diff --git a/indra/newview/skins/minimal/textures/bottomtray/button_separator.png b/indra/newview/skins/minimal/textures/bottomtray/button_separator.png
new file mode 100644
index 0000000000..71ed25f931
--- /dev/null
+++ b/indra/newview/skins/minimal/textures/bottomtray/button_separator.png
Binary files differ
diff --git a/indra/newview/skins/minimal/textures/bottomtray/close_off.png b/indra/newview/skins/minimal/textures/bottomtray/close_off.png
new file mode 100644
index 0000000000..241a24bde9
--- /dev/null
+++ b/indra/newview/skins/minimal/textures/bottomtray/close_off.png
Binary files differ
diff --git a/indra/newview/skins/minimal/textures/bottomtray/close_over.png b/indra/newview/skins/minimal/textures/bottomtray/close_over.png
new file mode 100644
index 0000000000..4630cb6dd6
--- /dev/null
+++ b/indra/newview/skins/minimal/textures/bottomtray/close_over.png
Binary files differ
diff --git a/indra/newview/skins/minimal/textures/bottomtray/close_press.png b/indra/newview/skins/minimal/textures/bottomtray/close_press.png
new file mode 100644
index 0000000000..3ed9c99a26
--- /dev/null
+++ b/indra/newview/skins/minimal/textures/bottomtray/close_press.png
Binary files differ
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
new file mode 100644
index 0000000000..e3ed01721a
--- /dev/null
+++ b/indra/newview/skins/minimal/textures/textures.xml
@@ -0,0 +1,11 @@
+
+<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" />
+ <texture name="Speak_Btn_Off" file_name="bottomtray/Speak_Btn_Off.png" preload="true" scale.left="4" scale.top="16" scale.right="8" scale.bottom="4" />
+ <texture name="Speak_Btn_Selected_Press" file_name="bottomtray/Speak_Btn_Selected_Press.png" preload="true" scale.left="4" scale.top="16" scale.right="8" scale.bottom="4" />
+ </textures>
diff --git a/indra/newview/skins/minimal/xui/en/main_view.xml b/indra/newview/skins/minimal/xui/en/main_view.xml
index 45ba785c1f..6e8ad9adaf 100644
--- a/indra/newview/skins/minimal/xui/en/main_view.xml
+++ b/indra/newview/skins/minimal/xui/en/main_view.xml
@@ -8,13 +8,13 @@
tab_stop="false"
name="main_view"
width="1024">
- <panel top="0"
- follows="all"
- height="768"
- mouse_opaque="false"
- name="login_panel_holder"
- width="1024"/>
-
+ <panel top="0"
+ follows="all"
+ height="768"
+ mouse_opaque="false"
+ name="login_panel_holder"
+ width="1024"/>
+
<layout_stack border_size="0"
follows="all"
mouse_opaque="false"
@@ -96,6 +96,7 @@
name="stand_stop_flying_container"
visible="false"
width="500"/>
+
<panel follows="all"
height="500"
left="0"
diff --git a/indra/newview/skins/minimal/xui/en/menu_attachment_other.xml b/indra/newview/skins/minimal/xui/en/menu_attachment_other.xml
index b55e677276..80cf365c46 100644
--- a/indra/newview/skins/minimal/xui/en/menu_attachment_other.xml
+++ b/indra/newview/skins/minimal/xui/en/menu_attachment_other.xml
@@ -25,6 +25,14 @@
<menu_item_call.on_click
function="Avatar.SendIM" />
</menu_item_call>
+ <menu_item_call
+ label="Call"
+ name="Call">
+ <menu_item_call.on_click
+ function="Avatar.Call" />
+ <menu_item_call.on_enable
+ function="Avatar.EnableCall" />
+ </menu_item_call>
<menu_item_separator />
<menu_item_call
enabled="false"
diff --git a/indra/newview/skins/minimal/xui/en/menu_avatar_other.xml b/indra/newview/skins/minimal/xui/en/menu_avatar_other.xml
index b76629f401..2c81b5a778 100644
--- a/indra/newview/skins/minimal/xui/en/menu_avatar_other.xml
+++ b/indra/newview/skins/minimal/xui/en/menu_avatar_other.xml
@@ -25,6 +25,14 @@
<menu_item_call.on_click
function="Avatar.SendIM" />
</menu_item_call>
+ <menu_item_call
+ label="Call"
+ name="Call">
+ <menu_item_call.on_click
+ function="Avatar.Call" />
+ <menu_item_call.on_enable
+ function="Avatar.EnableCall" />
+ </menu_item_call>
<menu_item_separator />
<menu_item_call
enabled="false"
diff --git a/indra/newview/skins/minimal/xui/en/menu_inspect_avatar_gear.xml b/indra/newview/skins/minimal/xui/en/menu_inspect_avatar_gear.xml
index 5a4a059781..a11e367d66 100644
--- a/indra/newview/skins/minimal/xui/en/menu_inspect_avatar_gear.xml
+++ b/indra/newview/skins/minimal/xui/en/menu_inspect_avatar_gear.xml
@@ -27,6 +27,15 @@
function="InspectAvatar.IM"/>
</menu_item_call>
<menu_item_call
+ label="Call"
+ enabled="true"
+ name="call">
+ <menu_item_call.on_click
+ function="InspectAvatar.Call"/>
+ <menu_item_call.on_enable
+ function="InspectAvatar.Gear.EnableCall"/>
+ </menu_item_call>
+ <menu_item_call
label="Teleport"
name="teleport">
<menu_item_call.on_click
diff --git a/indra/newview/skins/minimal/xui/en/menu_people_nearby.xml b/indra/newview/skins/minimal/xui/en/menu_people_nearby.xml
index 3d64133f54..1840ebd491 100644
--- a/indra/newview/skins/minimal/xui/en/menu_people_nearby.xml
+++ b/indra/newview/skins/minimal/xui/en/menu_people_nearby.xml
@@ -36,6 +36,16 @@
<menu_item_call.on_click
function="Avatar.IM" />
</menu_item_call>
+ <menu_item_call
+ label="Call"
+ layout="topleft"
+ name="Call">
+ <menu_item_call.on_click
+ function="Avatar.Call" />
+ <menu_item_call.on_enable
+ function="Avatar.EnableItem"
+ parameter="can_call" />
+ </menu_item_call>
<menu_item_check
label="Block/Unblock"
layout="topleft"
diff --git a/indra/newview/skins/minimal/xui/en/notification_visibility.xml b/indra/newview/skins/minimal/xui/en/notification_visibility.xml
index 616b544847..bdd3c3d4a4 100644
--- a/indra/newview/skins/minimal/xui/en/notification_visibility.xml
+++ b/indra/newview/skins/minimal/xui/en/notification_visibility.xml
@@ -1,12 +1,9 @@
<?xml version="1.0" ?>
<notification_visibility>
- <respond name="VoiceInviteP2P" response="Decline"/>
- <respond name="VoiceInviteAdHoc" response="Decline"/>
<respond name="VoiceInviteGroup" response="Decline"/>
<!-- group and voice are disabled features -->
<hide tag="group"/>
- <hide tag="voice"/>
<!-- no spammy scripts -->
<!-- <hide name="ScriptDialog"/> -->
@@ -16,6 +13,7 @@
<hide name="FirstInventory"/>
<hide name="HintSidePanel"/>
<hide name="HintMove"/>
+ <hide name="HintSpeak"/>
<hide name="HintDisplayName"/>
<hide name="HintInventory"/>
<hide name="HintLindenDollar"/>
diff --git a/indra/newview/skins/minimal/xui/en/panel_adhoc_control_panel.xml b/indra/newview/skins/minimal/xui/en/panel_adhoc_control_panel.xml
index 5730adab8a..39d1a90850 100644
--- a/indra/newview/skins/minimal/xui/en/panel_adhoc_control_panel.xml
+++ b/indra/newview/skins/minimal/xui/en/panel_adhoc_control_panel.xml
@@ -42,5 +42,40 @@
show_speaking_indicator="false"
width="147" />
</layout_panel>
+ <layout_panel
+ auto_resize="false"
+ follows="top|left|right"
+ height="25"
+ layout="topleft"
+ min_height="25"
+ width="130"
+ name="call_btn_panel"
+ user_resize="false"
+ visible="false">
+ <button
+ follows="all"
+ height="20"
+ label="Call"
+ name="call_btn"
+ width="130"
+ top="5" />
+ </layout_panel>
+ <layout_panel
+ auto_resize="false"
+ follows="top|left|right"
+ height="25"
+ layout="topleft"
+ min_height="25"
+ width="130"
+ name="end_call_btn_panel"
+ user_resize="false"
+ visible="false">
+ <button
+ follows="all"
+ height="20"
+ label="Leave Call"
+ name="end_call_btn"
+ top="5"/>
+ </layout_panel>
</layout_stack>
</panel>
diff --git a/indra/newview/skins/minimal/xui/en/panel_bottomtray.xml b/indra/newview/skins/minimal/xui/en/panel_bottomtray.xml
index e0c0bd13d9..d722c54081 100644
--- a/indra/newview/skins/minimal/xui/en/panel_bottomtray.xml
+++ b/indra/newview/skins/minimal/xui/en/panel_bottomtray.xml
@@ -47,7 +47,7 @@
mouse_opaque="false"
name="chat_bar_layout_panel"
user_resize="true"
- width="308" >
+ width="312" >
<panel
name="chat_bar"
filename="panel_nearby_chat_bar.xml"
@@ -61,6 +61,79 @@
</layout_panel>
<layout_panel
auto_resize="false"
+ follows="left|right"
+ height="28"
+ layout="topleft"
+ min_height="28"
+ min_width="35"
+ mouse_opaque="false"
+ name="speak_panel"
+ top_delta="0"
+ user_resize="false"
+ width="85">
+ <button
+ follows="left|right"
+ height="23"
+ layout="topleft"
+ label="Speak"
+ left="0"
+ name="speak_btn"
+ tool_tip="Turn your microphone on and off"
+ pad_right="30"
+ halign="center"
+ use_ellipses="true"
+ tab_stop="true"
+ is_toggle="true"
+ image_selected="Speak_Btn_Selected_Press"
+ image_unselected="Speak_Btn_Off"
+ image_pressed="Speak_Btn_Selected_Press"
+ image_pressed_selected="Speak_Btn_Selected_Press"
+ top="5"
+ width="85">
+
+ <commit_callback
+ function="ToggleSpeak"
+ parameter="f1_help" />
+ </button>
+ </layout_panel>
+
+ <layout_panel
+ auto_resize="false"
+ follows="left|right"
+ height="28"
+ layout="topleft"
+ min_height="28"
+ min_width="20"
+ mouse_opaque="false"
+ name="speak_flyout_panel"
+ top_delta="0"
+ user_resize="false"
+ width="26">
+ <button
+ follows="left|right"
+ width="20"
+ top="5"
+ left="0"
+ height="23"
+ name="flyout_btn"
+ label=""
+ tab_stop="false"
+ tool_tip="Change your sound preferences"
+ is_toggle="true"
+ image_disabled="ComboButton_UpOff"
+ image_unselected="ComboButton_UpOff"
+ image_selected="ComboButton_On"
+ image_pressed="ComboButton_UpSelected"
+ image_pressed_selected="ComboButton_Selected">
+ <init_callback
+ function="Button.SetDockableFloaterToggle"
+ parameter="sound_devices" />
+ </button>
+
+ </layout_panel>
+
+ <layout_panel
+ auto_resize="false"
follows="right"
height="28"
layout="topleft"
@@ -70,7 +143,7 @@
name="gesture_panel"
top_delta="0"
user_resize="false"
- width="85">
+ width="88">
<gesture_combo_list
follows="left|right"
height="23"
@@ -80,7 +153,7 @@
view_all="false"
left="0"
name="Gesture"
- tool_tip="Shows/hides gestures"
+ tool_tip="Make your avatar do things"
top="5"
width="82">
<combo_button
@@ -101,7 +174,7 @@
mouse_opaque="false"
name="cam_panel"
user_resize="false"
- width="83">
+ width="86">
<bottomtray_button
can_drag="false"
follows="left|right"
@@ -114,7 +187,7 @@
layout="topleft"
left="0"
name="camera_btn"
- tool_tip="Shows/hides camera controls"
+ tool_tip="Control your camera angle"
top="5"
use_ellipses="true"
width="80">
@@ -128,15 +201,15 @@
follows="left|right"
height="28"
layout="topleft"
- min_width="17"
- name="splitter_panel"
+ min_width="8"
+ name="splitter_panel_1"
user_resize="false"
- width="17">
+ width="8">
<icon
follows="left|bottom"
height="18"
width="2"
- left="6"
+ left="0"
image_name="Button_Separator"
name="separator"
top="7"/>
@@ -149,9 +222,9 @@
min_height="28"
min_width="83"
mouse_opaque="false"
- name="avatar_and_destinations_panel"
+ name="destinations_panel"
user_resize="false"
- width="103">
+ width="106">
<bottomtray_button
can_drag="false"
follows="left|right"
@@ -163,7 +236,7 @@
layout="topleft"
left="0"
name="destination_btn"
- tool_tip="Shows destinations window"
+ tool_tip="Travel through Second Life"
top="5"
is_toggle="true"
use_ellipses="true"
@@ -180,9 +253,9 @@
min_height="28"
min_width="73"
mouse_opaque="false"
- name="avatar_and_destinations_panel"
+ name="avatar_panel"
user_resize="false"
- width="103">
+ width="106">
<bottomtray_button
can_drag="false"
follows="left|right"
@@ -196,6 +269,7 @@
name="avatar_btn"
top="5"
is_toggle="true"
+ tool_tip="Change your appearance"
use_ellipses="true"
width="100">
<bottomtray_button.commit_callback
@@ -207,15 +281,15 @@
follows="left|right"
height="28"
layout="topleft"
- min_width="17"
- name="splitter_panel"
+ min_width="8"
+ name="splitter_panel_2"
user_resize="false"
- width="17">
+ width="8">
<icon
follows="left|bottom"
height="18"
width="2"
- left="6"
+ left="0"
image_name="Button_Separator"
name="separator"
top="7"/>
@@ -231,7 +305,7 @@
name="people_panel"
top_delta="0"
user_resize="false"
- width="105">
+ width="106">
<bottomtray_button
can_drag="false"
follows="left|right"
@@ -243,7 +317,7 @@
layout="topleft"
left="0"
name="show_people_button"
- tool_tip="Shows people window"
+ tool_tip="Find people in Second Life"
top="5"
is_toggle="true"
use_ellipses="true"
@@ -264,7 +338,7 @@
name="profile_panel"
top_delta="0"
user_resize="false"
- width="105">
+ width="106">
<bottomtray_button
can_drag="false"
follows="left|right"
@@ -276,7 +350,7 @@
layout="topleft"
left="0"
name="show_profile_btn"
- tool_tip="Shows profile window"
+ tool_tip="View and edit your Profile"
is_toggle="true"
top="5"
use_ellipses="true"
@@ -297,7 +371,7 @@
name="howto_panel"
top_delta="0"
user_resize="false"
- width="105">
+ width="106">
<bottomtray_button
can_drag="false"
follows="left|right"
@@ -309,7 +383,7 @@
layout="topleft"
left="0"
name="show_help_btn"
- tool_tip="Open Second Life How To topics"
+ tool_tip="View Second Life help info"
is_toggle="true"
top="5"
use_ellipses="true"
diff --git a/indra/newview/skins/minimal/xui/en/panel_im_control_panel.xml b/indra/newview/skins/minimal/xui/en/panel_im_control_panel.xml
index c3f46f11e0..be13bc1bb7 100644
--- a/indra/newview/skins/minimal/xui/en/panel_im_control_panel.xml
+++ b/indra/newview/skins/minimal/xui/en/panel_im_control_panel.xml
@@ -78,6 +78,39 @@
width="140" />
</layout_panel>
<layout_panel
+ auto_resize="false"
+ follows="top|left|right"
+ height="25"
+ layout="topleft"
+ min_height="25"
+ width="140"
+ name="call_btn_panel"
+ user_resize="false">
+ <button
+ follows="left|top|right"
+ height="23"
+ label="Call"
+ name="call_btn"
+ width="140" />
+ </layout_panel>
+ <layout_panel
+ auto_resize="false"
+ follows="top|left|right"
+ height="25"
+ layout="topleft"
+ min_height="25"
+ width="140"
+ name="end_call_btn_panel"
+ user_resize="false"
+ visible="false">
+ <button
+ follows="left|top|right"
+ height="23"
+ label="End Call"
+ name="end_call_btn"
+ width="140" />
+ </layout_panel>
+ <layout_panel
mouse_opaque="false"
auto_resize="true"
follows="top|left"
diff --git a/indra/newview/skins/minimal/xui/en/panel_people.xml b/indra/newview/skins/minimal/xui/en/panel_people.xml
index 4a72653d76..76baacb091 100644
--- a/indra/newview/skins/minimal/xui/en/panel_people.xml
+++ b/indra/newview/skins/minimal/xui/en/panel_people.xml
@@ -452,6 +452,27 @@ Looking for people to hang out with? Try the Destinations button below.
name="chat_btn_lp"
user_resize="false"
auto_resize="true"
+ width="52">
+ <button
+ follows="bottom|left|right"
+ left="1"
+ height="23"
+ label="Call"
+ layout="topleft"
+ name="call_btn"
+ tool_tip="Call this Resident"
+ top="0"
+ width="51" />
+ </layout_panel>
+
+ <layout_panel
+ follows="bottom|left|right"
+ height="23"
+ layout="bottomleft"
+ left_pad="3"
+ name="chat_btn_lp"
+ user_resize="false"
+ auto_resize="true"
width="77">
<button
follows="bottom|left|right"
diff --git a/indra/newview/tests/gpus_results.txt b/indra/newview/tests/gpus_results.txt
new file mode 100644
index 0000000000..7e9a064921
--- /dev/null
+++ b/indra/newview/tests/gpus_results.txt
@@ -0,0 +1,1595 @@
+GPU String Supported? Class Recognizer
+------------------------------------------------------------------------------------------------------ ----------- ----- ------------------------------------
+ATI UNRECOGNIZED
+ATI 3D-Analyze unsupported 0 ATI 3D-Analyze
+ATI ASUS A9xxx supported 1 ATI ASUS A9xxx
+ATI ASUS AH24xx supported 1 ATI ASUS AH24xx
+ATI ASUS AH26xx supported 3 ATI ASUS AH26xx
+ATI ASUS AH34xx supported 1 ATI ASUS AH34xx
+ATI ASUS AH36xx supported 3 ATI ASUS AH36xx
+ATI ASUS AH46xx supported 3 ATI ASUS AH46xx
+ATI ASUS AX3xx supported 1 ATI ASUS AX3xx
+ATI ASUS AX5xx supported 1 ATI ASUS AX5xx
+ATI ASUS AX8xx supported 2 ATI ASUS AX8xx
+ATI ASUS EAH38xx supported 3 ATI ASUS EAH38xx
+ATI ASUS EAH43xx supported 1 ATI ASUS EAH43xx
+ATI ASUS EAH45xx supported 1 ATI ASUS EAH45xx
+ATI ASUS EAH48xx supported 3 ATI ASUS EAH48xx
+ATI ASUS EAH57xx supported 3 ATI ASUS EAH57xx
+ATI ASUS EAH58xx supported 3 ATI ASUS EAH58xx
+ATI ASUS X1xxx supported 3 ATI ASUS Radeon X1xxx
+ATI All-in-Wonder 9xxx supported 1 ATI All-in-Wonder 9xxx
+ATI All-in-Wonder HD supported 1 ATI All-in-Wonder HD
+ATI All-in-Wonder PCI-E supported 1 ATI All-in-Wonder PCI-E
+ATI All-in-Wonder X1800 supported 3 ATI All-in-Wonder X1800
+ATI All-in-Wonder X1900 supported 3 ATI All-in-Wonder X1900
+ATI All-in-Wonder X600 supported 1 ATI All-in-Wonder X600
+ATI All-in-Wonder X800 supported 2 ATI All-in-Wonder X800
+ATI Diamond X1xxx supported 0 ATI Radeon X1xxx
+ATI Display Adapter UNRECOGNIZED
+ATI FireGL supported 0 ATI FireGL
+ATI FireGL 5200 supported 0 ATI FireGL
+ATI FireGL 5xxx supported 0 ATI FireGL
+ATI FireMV supported 0 ATI FireMV
+ATI Generic unsupported 0 ATI Generic
+ATI Hercules 9800 supported 1 ATI Hercules 9800
+ATI IGP 340M unsupported 0 ATI IGP 340M
+ATI M52 supported 1 ATI M52
+ATI M54 supported 1 ATI M54
+ATI M56 supported 1 ATI M56
+ATI M71 supported 1 ATI M71
+ATI M72 supported 1 ATI M72
+ATI M76 supported 3 ATI M76
+ATI Mobility Radeon supported 0 ATI Mobility Radeon
+ATI Mobility Radeon 7xxx supported 0 ATI Mobility Radeon 7xxx
+ATI Mobility Radeon 9600 supported 0 ATI Mobility Radeon 9600
+ATI Mobility Radeon 9700 supported 1 ATI Mobility Radeon 9700
+ATI Mobility Radeon 9800 supported 1 ATI Mobility Radeon 9800
+ATI Mobility Radeon HD 2300 supported 1 ATI Mobility Radeon HD 2300
+ATI Mobility Radeon HD 2400 supported 1 ATI Mobility Radeon HD 2400
+ATI Mobility Radeon HD 2600 supported 3 ATI Mobility Radeon HD 2600
+ATI Mobility Radeon HD 2700 supported 3 ATI Mobility Radeon HD 2700
+ATI Mobility Radeon HD 3400 supported 2 ATI Mobility Radeon HD 3400
+ATI Mobility Radeon HD 3600 supported 3 ATI Mobility Radeon HD 3600
+ATI Mobility Radeon HD 3800 supported 3 ATI Mobility Radeon HD 3800
+ATI Mobility Radeon HD 4200 supported 2 ATI Mobility Radeon HD 4200
+ATI Mobility Radeon HD 4300 supported 2 ATI Mobility Radeon HD 4300
+ATI Mobility Radeon HD 4500 supported 3 ATI Mobility Radeon HD 4500
+ATI Mobility Radeon HD 4600 supported 3 ATI Mobility Radeon HD 4600
+ATI Mobility Radeon HD 4800 supported 3 ATI Mobility Radeon HD 4800
+ATI Mobility Radeon HD 5400 supported 2 ATI Mobility Radeon HD 5400
+ATI Mobility Radeon HD 5600 supported 2 ATI Mobility Radeon HD 5600
+ATI Mobility Radeon X1xxx supported 0 ATI Radeon X1xxx
+ATI Mobility Radeon X2xxx supported 0 ATI Mobility Radeon X2xxx
+ATI Mobility Radeon X3xx supported 1 ATI Mobility Radeon X3xx
+ATI Mobility Radeon X6xx supported 1 ATI Mobility Radeon X6xx
+ATI Mobility Radeon X7xx supported 1 ATI Mobility Radeon X7xx
+ATI Mobility Radeon Xxxx supported 0 ATI Mobility Radeon Xxxx
+ATI RV380 supported 0 ATI RV380
+ATI RV530 supported 1 ATI RV530
+ATI Radeon 2100 supported 0 ATI Radeon 2100
+ATI Radeon 3000 supported 0 ATI Radeon 3000
+ATI Radeon 3100 supported 1 ATI Radeon 3100
+ATI Radeon 7000 supported 0 ATI Radeon 7xxx
+ATI Radeon 7xxx supported 0 ATI Radeon 7xxx
+ATI Radeon 8xxx supported 0 ATI Radeon 8xxx
+ATI Radeon 9000 supported 0 ATI Radeon 9000
+ATI Radeon 9100 supported 0 ATI Radeon 9100
+ATI Radeon 9200 supported 0 ATI Radeon 9200
+ATI Radeon 9500 supported 0 ATI Radeon 9500
+ATI Radeon 9600 supported 0 ATI Radeon 9600
+ATI Radeon 9700 supported 1 ATI Radeon 9700
+ATI Radeon 9800 supported 1 ATI Radeon 9800
+ATI Radeon HD 2300 supported 0 ATI Radeon HD 2300
+ATI Radeon HD 2400 supported 1 ATI Radeon HD 2400
+ATI Radeon HD 2600 supported 2 ATI Radeon HD 2600
+ATI Radeon HD 2900 supported 3 ATI Radeon HD 2900
+ATI Radeon HD 3000 supported 0 ATI Radeon HD 3000
+ATI Radeon HD 3100 supported 1 ATI Radeon HD 3100
+ATI Radeon HD 3200 supported 0 ATI Radeon HD 3200
+ATI Radeon HD 3300 supported 1 ATI Radeon HD 3300
+ATI Radeon HD 3400 supported 1 ATI Radeon HD 3400
+ATI Radeon HD 3600 supported 3 ATI Radeon HD 3600
+ATI Radeon HD 3800 supported 3 ATI Radeon HD 3800
+ATI Radeon HD 4200 supported 1 ATI Radeon HD 4200
+ATI Radeon HD 4300 supported 1 ATI Radeon HD 4300
+ATI Radeon HD 4500 supported 3 ATI Radeon HD 4500
+ATI Radeon HD 4600 supported 3 ATI Radeon HD 4600
+ATI Radeon HD 4700 supported 3 ATI Radeon HD 4700
+ATI Radeon HD 4800 supported 3 ATI Radeon HD 4800
+ATI Radeon HD 5400 supported 3 ATI Radeon HD 5400
+ATI Radeon HD 5500 supported 3 ATI Radeon HD 5500
+ATI Radeon HD 5600 supported 3 ATI Radeon HD 5600
+ATI Radeon HD 5700 supported 3 ATI Radeon HD 5700
+ATI Radeon HD 5800 supported 3 ATI Radeon HD 5800
+ATI Radeon HD 5900 supported 3 ATI Radeon HD 5900
+ATI Radeon HD 6200 supported 2 ATI Radeon HD 6200
+ATI Radeon HD 6300 supported 2 ATI Radeon HD 6300
+ATI Radeon HD 6500 supported 3 ATI Radeon HD 6500
+ATI Radeon HD 6800 supported 3 ATI Radeon HD 6800
+ATI Radeon HD 6900 supported 3 ATI Radeon HD 6900
+ATI Radeon OpenGL supported 0 ATI Radeon
+ATI Radeon RV250 supported 0 ATI Radeon RV250
+ATI Radeon RV600 supported 1 ATI Radeon RV600
+ATI Radeon RX9550 supported 1 ATI Radeon RX9550
+ATI Radeon VE unsupported 0 ATI Radeon VE
+ATI Radeon X1000 supported 0 ATI Radeon X1xxx
+ATI Radeon X1200 supported 0 ATI Radeon X1xxx
+ATI Radeon X1300 supported 0 ATI Radeon X1xxx
+ATI Radeon X13xx supported 0 ATI Radeon X1xxx
+ATI Radeon X1400 supported 0 ATI Radeon X1xxx
+ATI Radeon X1500 supported 0 ATI Radeon X1xxx
+ATI Radeon X1600 supported 0 ATI Radeon X1xxx
+ATI Radeon X16xx supported 0 ATI Radeon X1xxx
+ATI Radeon X1700 supported 0 ATI Radeon X1xxx
+ATI Radeon X1800 supported 0 ATI Radeon X1xxx
+ATI Radeon X1900 supported 0 ATI Radeon X1xxx
+ATI Radeon X19xx supported 0 ATI Radeon X1xxx
+ATI Radeon X1xxx supported 0 ATI Radeon X1xxx
+ATI Radeon X300 supported 0 ATI Radeon X300
+ATI Radeon X500 supported 0 ATI Radeon X500
+ATI Radeon X600 supported 1 ATI Radeon X600
+ATI Radeon X700 supported 1 ATI Radeon X700
+ATI Radeon X7xx supported 1 ATI Radeon X700
+ATI Radeon X800 supported 2 ATI Radeon X800
+ATI Radeon Xpress supported 0 ATI Radeon Xpress
+ATI Rage 128 supported 0 ATI Rage 128
+ATI Technologies Inc. supported 0 ATI Technologies
+ATI Technologies Inc. x86 supported 0 ATI Technologies
+ATI Technologies Inc. x86/SSE2 supported 0 ATI Technologies
+ATI Technologies Inc. (Vista) ATI Mobility Radeon HD 5730 supported 3 ATI Mobility Radeon HD 5700
+ATI Technologies Inc. 256MB ATI Radeon X1300PRO x86/SSE2 supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. AMD 760G supported 1 ATI 760G/Radeon 3000
+ATI Technologies Inc. AMD 760G (Microsoft WDDM 1.1) supported 1 ATI 760G/Radeon 3000
+ATI Technologies Inc. AMD 780L supported 1 ATI 780L/Radeon 3000
+ATI Technologies Inc. AMD FirePro 2270 supported 1 ATI FirePro 2000
+ATI Technologies Inc. AMD M860G with ATI Mobility Radeon 4100 supported 0 ATI Mobility Radeon 4100
+ATI Technologies Inc. AMD M880G with ATI Mobility Radeon HD 4200 supported 2 ATI Mobility Radeon HD 4200
+ATI Technologies Inc. AMD M880G with ATI Mobility Radeon HD 4250 supported 2 ATI Mobility Radeon HD 4200
+ATI Technologies Inc. AMD RADEON HD 6450 supported 3 ATI Radeon HD 6400
+ATI Technologies Inc. AMD Radeon HD 6200 series Graphics supported 2 ATI Radeon HD 6200
+ATI Technologies Inc. AMD Radeon HD 6250 Graphics supported 2 ATI Radeon HD 6200
+ATI Technologies Inc. AMD Radeon HD 6300 series Graphics supported 2 ATI Radeon HD 6300
+ATI Technologies Inc. AMD Radeon HD 6300M Series supported 2 ATI Radeon HD 6300
+ATI Technologies Inc. AMD Radeon HD 6310 Graphics supported 2 ATI Radeon HD 6300
+ATI Technologies Inc. AMD Radeon HD 6310M supported 2 ATI Radeon HD 6300
+ATI Technologies Inc. AMD Radeon HD 6330M supported 2 ATI Radeon HD 6300
+ATI Technologies Inc. AMD Radeon HD 6350 supported 2 ATI Radeon HD 6300
+ATI Technologies Inc. AMD Radeon HD 6370M supported 2 ATI Radeon HD 6300
+ATI Technologies Inc. AMD Radeon HD 6400M Series supported 3 ATI Radeon HD 6400
+ATI Technologies Inc. AMD Radeon HD 6450 supported 3 ATI Radeon HD 6400
+ATI Technologies Inc. AMD Radeon HD 6470M supported 3 ATI Radeon HD 6400
+ATI Technologies Inc. AMD Radeon HD 6490M supported 3 ATI Radeon HD 6400
+ATI Technologies Inc. AMD Radeon HD 6500M/5600/5700 Series supported 3 ATI Radeon HD 6500
+ATI Technologies Inc. AMD Radeon HD 6530M supported 3 ATI Radeon HD 6500
+ATI Technologies Inc. AMD Radeon HD 6550M supported 3 ATI Radeon HD 6500
+ATI Technologies Inc. AMD Radeon HD 6570 supported 3 ATI Radeon HD 6500
+ATI Technologies Inc. AMD Radeon HD 6570M supported 3 ATI Radeon HD 6500
+ATI Technologies Inc. AMD Radeon HD 6570M/5700 Series supported 3 ATI Radeon HD 6500
+ATI Technologies Inc. AMD Radeon HD 6600M Series supported 3 ATI Radeon HD 66xx
+ATI Technologies Inc. AMD Radeon HD 6650M supported 3 ATI Radeon HD 66xx
+ATI Technologies Inc. AMD Radeon HD 6670 supported 3 ATI Radeon HD 66xx
+ATI Technologies Inc. AMD Radeon HD 6700 Series supported 3 ATI Radeon HD 6700
+ATI Technologies Inc. AMD Radeon HD 6750 supported 3 ATI Radeon HD 6700
+ATI Technologies Inc. AMD Radeon HD 6750M supported 3 ATI Radeon HD 6700
+ATI Technologies Inc. AMD Radeon HD 6770 supported 3 ATI Radeon HD 6700
+ATI Technologies Inc. AMD Radeon HD 6800 Series supported 3 ATI Radeon HD 6800
+ATI Technologies Inc. AMD Radeon HD 6850M supported 3 ATI Radeon HD 6800
+ATI Technologies Inc. AMD Radeon HD 6870 supported 3 ATI Radeon HD 6800
+ATI Technologies Inc. AMD Radeon HD 6870M supported 3 ATI Radeon HD 6800
+ATI Technologies Inc. AMD Radeon HD 6900 Series supported 3 ATI Radeon HD 6900
+ATI Technologies Inc. AMD Radeon HD 6970M supported 3 ATI Radeon HD 6900
+ATI Technologies Inc. AMD Radeon HD 6990 supported 3 ATI Radeon HD 6900
+ATI Technologies Inc. AMD Radeon(TM) HD 6470M supported 0 ATI Technologies
+ATI Technologies Inc. ASUS 5870 Eyefinity 6 supported 0 ATI Technologies
+ATI Technologies Inc. ASUS AH2600 Series supported 3 ATI ASUS AH26xx
+ATI Technologies Inc. ASUS AH3450 Series supported 1 ATI ASUS AH34xx
+ATI Technologies Inc. ASUS AH3650 Series supported 3 ATI ASUS AH36xx
+ATI Technologies Inc. ASUS AH4650 Series supported 3 ATI ASUS AH46xx
+ATI Technologies Inc. ASUS ARES supported 0 ATI Technologies
+ATI Technologies Inc. ASUS EAH2900 Series supported 0 ATI Technologies
+ATI Technologies Inc. ASUS EAH3450 Series supported 1 ATI ASUS AH34xx
+ATI Technologies Inc. ASUS EAH3650 Series supported 3 ATI ASUS AH36xx
+ATI Technologies Inc. ASUS EAH4350 series supported 1 ATI ASUS EAH43xx
+ATI Technologies Inc. ASUS EAH4550 series supported 1 ATI ASUS EAH45xx
+ATI Technologies Inc. ASUS EAH4650 series supported 3 ATI ASUS AH46xx
+ATI Technologies Inc. ASUS EAH4670 series supported 3 ATI ASUS AH46xx
+ATI Technologies Inc. ASUS EAH4750 Series supported 0 ATI Technologies
+ATI Technologies Inc. ASUS EAH4770 Series supported 0 ATI Technologies
+ATI Technologies Inc. ASUS EAH4770 series supported 0 ATI Technologies
+ATI Technologies Inc. ASUS EAH4850 series supported 3 ATI ASUS EAH48xx
+ATI Technologies Inc. ASUS EAH5450 Series supported 0 ATI Technologies
+ATI Technologies Inc. ASUS EAH5550 Series supported 0 ATI Technologies
+ATI Technologies Inc. ASUS EAH5570 series supported 0 ATI Technologies
+ATI Technologies Inc. ASUS EAH5670 Series supported 0 ATI Technologies
+ATI Technologies Inc. ASUS EAH5750 Series supported 3 ATI ASUS EAH57xx
+ATI Technologies Inc. ASUS EAH5770 Series supported 3 ATI ASUS EAH57xx
+ATI Technologies Inc. ASUS EAH5830 Series supported 3 ATI ASUS EAH58xx
+ATI Technologies Inc. ASUS EAH5850 Series supported 3 ATI ASUS EAH58xx
+ATI Technologies Inc. ASUS EAH5870 Series supported 3 ATI ASUS EAH58xx
+ATI Technologies Inc. ASUS EAH5970 Series supported 0 ATI Technologies
+ATI Technologies Inc. ASUS EAH6850 Series supported 0 ATI Technologies
+ATI Technologies Inc. ASUS EAH6870 Series supported 0 ATI Technologies
+ATI Technologies Inc. ASUS EAH6950 Series supported 0 ATI Technologies
+ATI Technologies Inc. ASUS EAH6970 Series supported 0 ATI Technologies
+ATI Technologies Inc. ASUS EAHG4670 series supported 0 ATI Technologies
+ATI Technologies Inc. ASUS Extreme AX600 Series supported 0 ATI Technologies
+ATI Technologies Inc. ASUS Extreme AX600XT-TD supported 0 ATI Technologies
+ATI Technologies Inc. ASUS X1300 Series x86/SSE2 supported 3 ATI ASUS Radeon X1xxx
+ATI Technologies Inc. ASUS X1550 Series supported 3 ATI ASUS Radeon X1xxx
+ATI Technologies Inc. ASUS X1950 Series x86/SSE2 supported 3 ATI ASUS Radeon X1xxx
+ATI Technologies Inc. ASUS X800 Series supported 0 ATI Technologies
+ATI Technologies Inc. ASUS X850 Series supported 0 ATI Technologies
+ATI Technologies Inc. ATI All-in-Wonder HD supported 1 ATI All-in-Wonder HD
+ATI Technologies Inc. ATI FirePro 2260 supported 1 ATI FirePro 2000
+ATI Technologies Inc. ATI FirePro 2450 supported 1 ATI FirePro 2000
+ATI Technologies Inc. ATI FirePro M5800 supported 3 ATI FirePro M5800
+ATI Technologies Inc. ATI FirePro M7740 supported 3 ATI FirePro M7740
+ATI Technologies Inc. ATI FirePro M7820 supported 3 ATI FirePro M7820
+ATI Technologies Inc. ATI FirePro V3700 (FireGL) supported 0 ATI FireGL
+ATI Technologies Inc. ATI FirePro V3800 supported 1 ATI FirePro 3000
+ATI Technologies Inc. ATI FirePro V4800 supported 2 ATI FirePro 4000
+ATI Technologies Inc. ATI FirePro V4800 (FireGL) supported 0 ATI FireGL
+ATI Technologies Inc. ATI FirePro V5800 supported 3 ATI FirePro 5000
+ATI Technologies Inc. ATI FirePro V7800 supported 3 ATI FirePro 7000
+ATI Technologies Inc. ATI MOBILITY RADEON 9XXX x86/SSE2 supported 0 ATI Mobility Radeon Xxxx
+ATI Technologies Inc. ATI MOBILITY RADEON HD 3450 supported 2 ATI Mobility Radeon HD 3400
+ATI Technologies Inc. ATI MOBILITY RADEON X1600 supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. ATI MOBILITY RADEON X2300 supported 0 ATI Mobility Radeon X2xxx
+ATI Technologies Inc. ATI MOBILITY RADEON X2300 HD x86/SSE2 supported 0 ATI Mobility Radeon X2xxx
+ATI Technologies Inc. ATI MOBILITY RADEON X2300 x86/MMX/3DNow!/SSE2 supported 0 ATI Mobility Radeon X2xxx
+ATI Technologies Inc. ATI MOBILITY RADEON X2300 x86/SSE2 supported 0 ATI Mobility Radeon X2xxx
+ATI Technologies Inc. ATI MOBILITY RADEON X300 supported 1 ATI Mobility Radeon X3xx
+ATI Technologies Inc. ATI MOBILITY RADEON X600 supported 1 ATI Mobility Radeon X6xx
+ATI Technologies Inc. ATI MOBILITY RADEON XPRESS 200 supported 0 ATI Mobility Radeon Xxxx
+ATI Technologies Inc. ATI Mobility FireGL V5700 supported 1 ATI FireGL 5xxx
+ATI Technologies Inc. ATI Mobility Radeon 4100 supported 0 ATI Mobility Radeon 4100
+ATI Technologies Inc. ATI Mobility Radeon Graphics supported 0 ATI Mobility Radeon
+ATI Technologies Inc. ATI Mobility Radeon HD 2300 supported 1 ATI Mobility Radeon HD 2300
+ATI Technologies Inc. ATI Mobility Radeon HD 2400 supported 1 ATI Mobility Radeon HD 2400
+ATI Technologies Inc. ATI Mobility Radeon HD 2400 XT supported 1 ATI Mobility Radeon HD 2400
+ATI Technologies Inc. ATI Mobility Radeon HD 2600 supported 3 ATI Mobility Radeon HD 2600
+ATI Technologies Inc. ATI Mobility Radeon HD 2600 XT supported 3 ATI Mobility Radeon HD 2600
+ATI Technologies Inc. ATI Mobility Radeon HD 2700 supported 3 ATI Mobility Radeon HD 2700
+ATI Technologies Inc. ATI Mobility Radeon HD 3400 Series supported 2 ATI Mobility Radeon HD 3400
+ATI Technologies Inc. ATI Mobility Radeon HD 3430 supported 2 ATI Mobility Radeon HD 3400
+ATI Technologies Inc. ATI Mobility Radeon HD 3450 supported 2 ATI Mobility Radeon HD 3400
+ATI Technologies Inc. ATI Mobility Radeon HD 3470 supported 2 ATI Mobility Radeon HD 3400
+ATI Technologies Inc. ATI Mobility Radeon HD 3470 Hybrid X2 supported 2 ATI Mobility Radeon HD 3400
+ATI Technologies Inc. ATI Mobility Radeon HD 3650 supported 3 ATI Mobility Radeon HD 3600
+ATI Technologies Inc. ATI Mobility Radeon HD 4200 supported 2 ATI Mobility Radeon HD 4200
+ATI Technologies Inc. ATI Mobility Radeon HD 4200 Series supported 2 ATI Mobility Radeon HD 4200
+ATI Technologies Inc. ATI Mobility Radeon HD 4225 supported 2 ATI Mobility Radeon HD 4200
+ATI Technologies Inc. ATI Mobility Radeon HD 4225 Series supported 2 ATI Mobility Radeon HD 4200
+ATI Technologies Inc. ATI Mobility Radeon HD 4250 supported 2 ATI Mobility Radeon HD 4200
+ATI Technologies Inc. ATI Mobility Radeon HD 4250 Graphics supported 2 ATI Mobility Radeon HD 4200
+ATI Technologies Inc. ATI Mobility Radeon HD 4270 supported 2 ATI Mobility Radeon HD 4200
+ATI Technologies Inc. ATI Mobility Radeon HD 4300 Series supported 2 ATI Mobility Radeon HD 4300
+ATI Technologies Inc. ATI Mobility Radeon HD 4300/4500 Series supported 2 ATI Mobility Radeon HD 4300
+ATI Technologies Inc. ATI Mobility Radeon HD 4330 supported 2 ATI Mobility Radeon HD 4300
+ATI Technologies Inc. ATI Mobility Radeon HD 4330 Series supported 2 ATI Mobility Radeon HD 4300
+ATI Technologies Inc. ATI Mobility Radeon HD 4350 supported 2 ATI Mobility Radeon HD 4300
+ATI Technologies Inc. ATI Mobility Radeon HD 4350 Series supported 2 ATI Mobility Radeon HD 4300
+ATI Technologies Inc. ATI Mobility Radeon HD 4500 Series supported 3 ATI Mobility Radeon HD 4500
+ATI Technologies Inc. ATI Mobility Radeon HD 4500/5100 Series supported 3 ATI Mobility Radeon HD 4500
+ATI Technologies Inc. ATI Mobility Radeon HD 4530 supported 3 ATI Mobility Radeon HD 4500
+ATI Technologies Inc. ATI Mobility Radeon HD 4530 Series supported 3 ATI Mobility Radeon HD 4500
+ATI Technologies Inc. ATI Mobility Radeon HD 4550 supported 3 ATI Mobility Radeon HD 4500
+ATI Technologies Inc. ATI Mobility Radeon HD 4570 supported 3 ATI Mobility Radeon HD 4500
+ATI Technologies Inc. ATI Mobility Radeon HD 4600 Series supported 3 ATI Mobility Radeon HD 4600
+ATI Technologies Inc. ATI Mobility Radeon HD 4650 supported 3 ATI Mobility Radeon HD 4600
+ATI Technologies Inc. ATI Mobility Radeon HD 4650 Series supported 3 ATI Mobility Radeon HD 4600
+ATI Technologies Inc. ATI Mobility Radeon HD 4670 supported 3 ATI Mobility Radeon HD 4600
+ATI Technologies Inc. ATI Mobility Radeon HD 4830 Series supported 3 ATI Mobility Radeon HD 4800
+ATI Technologies Inc. ATI Mobility Radeon HD 4850 supported 3 ATI Mobility Radeon HD 4800
+ATI Technologies Inc. ATI Mobility Radeon HD 4870 supported 3 ATI Mobility Radeon HD 4800
+ATI Technologies Inc. ATI Mobility Radeon HD 5000 supported 0 ATI Mobility Radeon
+ATI Technologies Inc. ATI Mobility Radeon HD 5000 Series supported 0 ATI Mobility Radeon
+ATI Technologies Inc. ATI Mobility Radeon HD 5145 supported 2 ATI Mobility Radeon HD 5100
+ATI Technologies Inc. ATI Mobility Radeon HD 5165 supported 2 ATI Mobility Radeon HD 5100
+ATI Technologies Inc. ATI Mobility Radeon HD 530v supported 1 ATI Mobility Radeon HD 530v
+ATI Technologies Inc. ATI Mobility Radeon HD 5400 Series supported 2 ATI Mobility Radeon HD 5400
+ATI Technologies Inc. ATI Mobility Radeon HD 540v supported 2 ATI Mobility Radeon HD 540v
+ATI Technologies Inc. ATI Mobility Radeon HD 5430 supported 2 ATI Mobility Radeon HD 5400
+ATI Technologies Inc. ATI Mobility Radeon HD 5450 supported 2 ATI Mobility Radeon HD 5400
+ATI Technologies Inc. ATI Mobility Radeon HD 5450 Series supported 2 ATI Mobility Radeon HD 5400
+ATI Technologies Inc. ATI Mobility Radeon HD 545v supported 2 ATI Mobility Radeon HD 545v
+ATI Technologies Inc. ATI Mobility Radeon HD 5470 supported 2 ATI Mobility Radeon HD 5400
+ATI Technologies Inc. ATI Mobility Radeon HD 550v supported 2 ATI Mobility Radeon HD 550v
+ATI Technologies Inc. ATI Mobility Radeon HD 5600/5700 Series supported 2 ATI Mobility Radeon HD 5600
+ATI Technologies Inc. ATI Mobility Radeon HD 560v supported 2 ATI Mobility Radeon HD 560v
+ATI Technologies Inc. ATI Mobility Radeon HD 5650 supported 2 ATI Mobility Radeon HD 5600
+ATI Technologies Inc. ATI Mobility Radeon HD 5700 Series supported 3 ATI Mobility Radeon HD 5700
+ATI Technologies Inc. ATI Mobility Radeon HD 5730 supported 3 ATI Mobility Radeon HD 5700
+ATI Technologies Inc. ATI Mobility Radeon HD 5800 Series supported 0 ATI Mobility Radeon
+ATI Technologies Inc. ATI Mobility Radeon HD 5850 supported 0 ATI Mobility Radeon
+ATI Technologies Inc. ATI Mobility Radeon HD 5870 supported 0 ATI Mobility Radeon
+ATI Technologies Inc. ATI Mobility Radeon HD 6300 series supported 2 ATI Mobility Radeon HD 6300
+ATI Technologies Inc. ATI Mobility Radeon HD 6370 supported 2 ATI Mobility Radeon HD 6300
+ATI Technologies Inc. ATI Mobility Radeon HD 6470M supported 3 ATI Mobility Radeon HD 6400M
+ATI Technologies Inc. ATI Mobility Radeon HD 6550 supported 3 ATI Mobility Radeon HD 6500M
+ATI Technologies Inc. ATI Mobility Radeon HD 6570 supported 3 ATI Mobility Radeon HD 6500M
+ATI Technologies Inc. ATI Mobility Radeon X1300 supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. ATI Mobility Radeon X1300 x86/MMX/3DNow!/SSE2 supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. ATI Mobility Radeon X1300 x86/SSE2 supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. ATI Mobility Radeon X1350 supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. ATI Mobility Radeon X1350 x86/SSE2 supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. ATI Mobility Radeon X1400 supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. ATI Mobility Radeon X1400 x86/SSE2 supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. ATI Mobility Radeon X1600 supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. ATI Mobility Radeon X1600 x86/SSE2 supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. ATI Mobility Radeon X1700 x86/SSE2 supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. ATI Mobility Radeon X2300 supported 0 ATI Mobility Radeon X2xxx
+ATI Technologies Inc. ATI Mobility Radeon X2300 (Omega 3.8.442) supported 0 ATI Mobility Radeon X2xxx
+ATI Technologies Inc. ATI Mobility Radeon X2300 x86 supported 0 ATI Mobility Radeon X2xxx
+ATI Technologies Inc. ATI Mobility Radeon X2300 x86/MMX/3DNow!/SSE2 supported 0 ATI Mobility Radeon X2xxx
+ATI Technologies Inc. ATI Mobility Radeon X2300 x86/SSE2 supported 0 ATI Mobility Radeon X2xxx
+ATI Technologies Inc. ATI Mobility Radeon X2500 supported 0 ATI Mobility Radeon X2xxx
+ATI Technologies Inc. ATI Mobility Radeon X2500 x86/SSE2 supported 0 ATI Mobility Radeon X2xxx
+ATI Technologies Inc. ATI Mobility Radeon. HD 530v supported 1 ATI Mobility Radeon HD 530v
+ATI Technologies Inc. ATI Mobility Radeon. HD 5470 supported 2 ATI Mobility Radeon HD 5400
+ATI Technologies Inc. ATI RADEON HD 3200 T25XX by CAMILO supported 0 ATI Radeon HD 3200
+ATI Technologies Inc. ATI RADEON XPRESS 1100 supported 0 ATI Radeon Xpress
+ATI Technologies Inc. ATI RADEON XPRESS 200 Series supported 0 ATI Radeon Xpress
+ATI Technologies Inc. ATI RADEON XPRESS 200 Series x86/SSE2 supported 0 ATI Radeon Xpress
+ATI Technologies Inc. ATI RADEON XPRESS 200M SERIES supported 0 ATI Radeon Xpress
+ATI Technologies Inc. ATI Radeon supported 0 ATI Technologies
+ATI Technologies Inc. ATI Radeon 2100 supported 0 ATI Radeon 2100
+ATI Technologies Inc. ATI Radeon 2100 (Microsoft - WDDM) supported 0 ATI Radeon 2100
+ATI Technologies Inc. ATI Radeon 2100 Graphics supported 0 ATI Radeon 2100
+ATI Technologies Inc. ATI Radeon 3000 supported 0 ATI Radeon 3000
+ATI Technologies Inc. ATI Radeon 3000 Graphics supported 0 ATI Radeon 3000
+ATI Technologies Inc. ATI Radeon 3100 Graphics supported 1 ATI Radeon 3100
+ATI Technologies Inc. ATI Radeon 5xxx series supported 3 ATI Radeon 5xxx
+ATI Technologies Inc. ATI Radeon 9550 / X1050 Series supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. ATI Radeon 9550 / X1050 Series x86/MMX/3DNow!/SSE supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. ATI Radeon 9550 / X1050 Series x86/SSE2 supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. ATI Radeon 9550 / X1050 Series(Microsoft - WDDM) supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. ATI Radeon 9600 / X1050 Series supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. ATI Radeon 9600/9550/X1050 Series supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. ATI Radeon BA Prototype OpenGL Engine supported 0 ATI Technologies
+ATI Technologies Inc. ATI Radeon BB Prototype OpenGL Engine supported 0 ATI Technologies
+ATI Technologies Inc. ATI Radeon Cedar PRO Prototype OpenGL Engine supported 2 AMD CEDAR (HD 5450)
+ATI Technologies Inc. ATI Radeon Cypress PRO Prototype OpenGL Engine supported 3 AMD CYPRESS (HD 5800)
+ATI Technologies Inc. ATI Radeon Graphics Processor supported 0 ATI Technologies
+ATI Technologies Inc. ATI Radeon HD 2200 Graphics supported 0 ATI Technologies
+ATI Technologies Inc. ATI Radeon HD 2350 supported 0 ATI Radeon HD 2300
+ATI Technologies Inc. ATI Radeon HD 2400 supported 1 ATI Radeon HD 2400
+ATI Technologies Inc. ATI Radeon HD 2400 OpenGL Engine supported 1 ATI Radeon HD 2400
+ATI Technologies Inc. ATI Radeon HD 2400 PRO supported 1 ATI Radeon HD 2400
+ATI Technologies Inc. ATI Radeon HD 2400 PRO AGP supported 1 ATI Radeon HD 2400
+ATI Technologies Inc. ATI Radeon HD 2400 Pro supported 1 ATI Radeon HD 2400
+ATI Technologies Inc. ATI Radeon HD 2400 Series supported 1 ATI Radeon HD 2400
+ATI Technologies Inc. ATI Radeon HD 2400 XT supported 1 ATI Radeon HD 2400
+ATI Technologies Inc. ATI Radeon HD 2400 XT OpenGL Engine supported 1 ATI Radeon HD 2400
+ATI Technologies Inc. ATI Radeon HD 2600 OpenGL Engine supported 2 ATI Radeon HD 2600
+ATI Technologies Inc. ATI Radeon HD 2600 PRO supported 2 ATI Radeon HD 2600
+ATI Technologies Inc. ATI Radeon HD 2600 PRO OpenGL Engine supported 2 ATI Radeon HD 2600
+ATI Technologies Inc. ATI Radeon HD 2600 Pro supported 2 ATI Radeon HD 2600
+ATI Technologies Inc. ATI Radeon HD 2600 Series supported 2 ATI Radeon HD 2600
+ATI Technologies Inc. ATI Radeon HD 2600 XT supported 2 ATI Radeon HD 2600
+ATI Technologies Inc. ATI Radeon HD 2900 GT supported 3 ATI Radeon HD 2900
+ATI Technologies Inc. ATI Radeon HD 2900 XT supported 3 ATI Radeon HD 2900
+ATI Technologies Inc. ATI Radeon HD 3200 Graphics supported 0 ATI Radeon HD 3200
+ATI Technologies Inc. ATI Radeon HD 3300 Graphics supported 1 ATI Radeon HD 3300
+ATI Technologies Inc. ATI Radeon HD 3400 Series supported 1 ATI Radeon HD 3400
+ATI Technologies Inc. ATI Radeon HD 3450 supported 1 ATI Radeon HD 3400
+ATI Technologies Inc. ATI Radeon HD 3450 - Dell Optiplex supported 1 ATI Radeon HD 3400
+ATI Technologies Inc. ATI Radeon HD 3470 supported 1 ATI Radeon HD 3400
+ATI Technologies Inc. ATI Radeon HD 3470 - Dell Optiplex supported 1 ATI Radeon HD 3400
+ATI Technologies Inc. ATI Radeon HD 3550 supported 1 ATI Radeon HD 3500
+ATI Technologies Inc. ATI Radeon HD 3600 Series supported 3 ATI Radeon HD 3600
+ATI Technologies Inc. ATI Radeon HD 3650 supported 3 ATI Radeon HD 3600
+ATI Technologies Inc. ATI Radeon HD 3650 AGP supported 3 ATI Radeon HD 3600
+ATI Technologies Inc. ATI Radeon HD 3730 supported 3 ATI Radeon HD 3700
+ATI Technologies Inc. ATI Radeon HD 3800 Series supported 3 ATI Radeon HD 3800
+ATI Technologies Inc. ATI Radeon HD 3850 supported 3 ATI Radeon HD 3800
+ATI Technologies Inc. ATI Radeon HD 3850 AGP supported 3 ATI Radeon HD 3800
+ATI Technologies Inc. ATI Radeon HD 3870 supported 3 ATI Radeon HD 3800
+ATI Technologies Inc. ATI Radeon HD 3870 X2 supported 3 ATI Radeon HD 3800
+ATI Technologies Inc. ATI Radeon HD 4200 supported 1 ATI Radeon HD 4200
+ATI Technologies Inc. ATI Radeon HD 4250 supported 1 ATI Radeon HD 4200
+ATI Technologies Inc. ATI Radeon HD 4250 Graphics supported 1 ATI Radeon HD 4200
+ATI Technologies Inc. ATI Radeon HD 4270 supported 1 ATI Radeon HD 4200
+ATI Technologies Inc. ATI Radeon HD 4290 supported 1 ATI Radeon HD 4200
+ATI Technologies Inc. ATI Radeon HD 4300 Series supported 1 ATI Radeon HD 4300
+ATI Technologies Inc. ATI Radeon HD 4300/4500 Series supported 1 ATI Radeon HD 4300
+ATI Technologies Inc. ATI Radeon HD 4350 supported 1 ATI Radeon HD 4300
+ATI Technologies Inc. ATI Radeon HD 4350 (Microsoft WDDM 1.1) supported 1 ATI Radeon HD 4300
+ATI Technologies Inc. ATI Radeon HD 4450 supported 1 ATI Radeon HD 4400
+ATI Technologies Inc. ATI Radeon HD 4500 Series supported 3 ATI Radeon HD 4500
+ATI Technologies Inc. ATI Radeon HD 4550 supported 3 ATI Radeon HD 4500
+ATI Technologies Inc. ATI Radeon HD 4600 Series supported 3 ATI Radeon HD 4600
+ATI Technologies Inc. ATI Radeon HD 4650 supported 3 ATI Radeon HD 4600
+ATI Technologies Inc. ATI Radeon HD 4670 supported 3 ATI Radeon HD 4600
+ATI Technologies Inc. ATI Radeon HD 4670 OpenGL Engine supported 3 ATI Radeon HD 4600
+ATI Technologies Inc. ATI Radeon HD 4700 Series supported 3 ATI Radeon HD 4700
+ATI Technologies Inc. ATI Radeon HD 4720 supported 3 ATI Radeon HD 4700
+ATI Technologies Inc. ATI Radeon HD 4730 supported 3 ATI Radeon HD 4700
+ATI Technologies Inc. ATI Radeon HD 4730 Series supported 3 ATI Radeon HD 4700
+ATI Technologies Inc. ATI Radeon HD 4750 supported 3 ATI Radeon HD 4700
+ATI Technologies Inc. ATI Radeon HD 4770 supported 3 ATI Radeon HD 4700
+ATI Technologies Inc. ATI Radeon HD 4800 Series supported 3 ATI Radeon HD 4800
+ATI Technologies Inc. ATI Radeon HD 4850 supported 3 ATI Radeon HD 4800
+ATI Technologies Inc. ATI Radeon HD 4850 OpenGL Engine supported 3 ATI Radeon HD 4800
+ATI Technologies Inc. ATI Radeon HD 4850 Series supported 3 ATI Radeon HD 4800
+ATI Technologies Inc. ATI Radeon HD 4870 supported 3 ATI Radeon HD 4800
+ATI Technologies Inc. ATI Radeon HD 4870 OpenGL Engine supported 3 ATI Radeon HD 4800
+ATI Technologies Inc. ATI Radeon HD 4870 X2 supported 3 ATI Radeon HD 4800
+ATI Technologies Inc. ATI Radeon HD 5400 Series supported 3 ATI Radeon HD 5400
+ATI Technologies Inc. ATI Radeon HD 5450 supported 3 ATI Radeon HD 5400
+ATI Technologies Inc. ATI Radeon HD 5500 Series supported 3 ATI Radeon HD 5500
+ATI Technologies Inc. ATI Radeon HD 5570 supported 3 ATI Radeon HD 5500
+ATI Technologies Inc. ATI Radeon HD 5600 Series supported 3 ATI Radeon HD 5600
+ATI Technologies Inc. ATI Radeon HD 5630 supported 3 ATI Radeon HD 5600
+ATI Technologies Inc. ATI Radeon HD 5670 supported 3 ATI Radeon HD 5600
+ATI Technologies Inc. ATI Radeon HD 5670 OpenGL Engine supported 3 ATI Radeon HD 5600
+ATI Technologies Inc. ATI Radeon HD 5700 Series supported 3 ATI Radeon HD 5700
+ATI Technologies Inc. ATI Radeon HD 5750 supported 3 ATI Radeon HD 5700
+ATI Technologies Inc. ATI Radeon HD 5750 OpenGL Engine supported 3 ATI Radeon HD 5700
+ATI Technologies Inc. ATI Radeon HD 5770 supported 3 ATI Radeon HD 5700
+ATI Technologies Inc. ATI Radeon HD 5770 OpenGL Engine supported 3 ATI Radeon HD 5700
+ATI Technologies Inc. ATI Radeon HD 5800 Series supported 3 ATI Radeon HD 5800
+ATI Technologies Inc. ATI Radeon HD 5850 supported 3 ATI Radeon HD 5800
+ATI Technologies Inc. ATI Radeon HD 5870 supported 3 ATI Radeon HD 5800
+ATI Technologies Inc. ATI Radeon HD 5870 OpenGL Engine supported 3 ATI Radeon HD 5800
+ATI Technologies Inc. ATI Radeon HD 5900 Series supported 3 ATI Radeon HD 5900
+ATI Technologies Inc. ATI Radeon HD 5970 supported 3 ATI Radeon HD 5900
+ATI Technologies Inc. ATI Radeon HD 6230 supported 2 ATI Radeon HD 6200
+ATI Technologies Inc. ATI Radeon HD 6250 supported 2 ATI Radeon HD 6200
+ATI Technologies Inc. ATI Radeon HD 6350 supported 2 ATI Radeon HD 6300
+ATI Technologies Inc. ATI Radeon HD 6390 supported 2 ATI Radeon HD 6300
+ATI Technologies Inc. ATI Radeon HD 6490M OpenGL Engine supported 3 ATI Radeon HD 6400
+ATI Technologies Inc. ATI Radeon HD 6510 supported 3 ATI Radeon HD 6500
+ATI Technologies Inc. ATI Radeon HD 6570M supported 3 ATI Radeon HD 6500
+ATI Technologies Inc. ATI Radeon HD 6750 supported 3 ATI Radeon HD 6700
+ATI Technologies Inc. ATI Radeon HD 6750M OpenGL Engine supported 3 ATI Radeon HD 6700
+ATI Technologies Inc. ATI Radeon HD 6770 supported 3 ATI Radeon HD 6700
+ATI Technologies Inc. ATI Radeon HD 6770M OpenGL Engine supported 3 ATI Radeon HD 6700
+ATI Technologies Inc. ATI Radeon HD 6800 Series supported 3 ATI Radeon HD 6800
+ATI Technologies Inc. ATI Radeon HD 6970M OpenGL Engine supported 3 ATI Radeon HD 6900
+ATI Technologies Inc. ATI Radeon HD3750 supported 3 ATI Radeon HD 3700
+ATI Technologies Inc. ATI Radeon HD4300/HD4500 series supported 1 ATI Radeon HD 4300
+ATI Technologies Inc. ATI Radeon HD4670 supported 3 ATI Radeon HD 4600
+ATI Technologies Inc. ATI Radeon Juniper LE Prototype OpenGL Engine supported 3 AMD JUNIPER (HD 5700)
+ATI Technologies Inc. ATI Radeon RV710 Prototype OpenGL Engine supported 1 AMD RV710 (HD 4300)
+ATI Technologies Inc. ATI Radeon RV730 Prototype OpenGL Engine supported 3 AMD RV730 (HD 4600)
+ATI Technologies Inc. ATI Radeon RV770 Prototype OpenGL Engine supported 3 AMD RV770 (HD 4800)
+ATI Technologies Inc. ATI Radeon RV790 Prototype OpenGL Engine supported 3 AMD RV790 (HD 4800)
+ATI Technologies Inc. ATI Radeon Redwood PRO Prototype OpenGL Engine supported 3 AMD REDWOOD (HD 5500/5600)
+ATI Technologies Inc. ATI Radeon Redwood XT Prototype OpenGL Engine supported 3 AMD REDWOOD (HD 5500/5600)
+ATI Technologies Inc. ATI Radeon Whistler PRO/LP Prototype OpenGL Engine supported 0 ATI Technologies
+ATI Technologies Inc. ATI Radeon X1050 supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. ATI Radeon X1050 Series supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. ATI Radeon X1200 supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. ATI Radeon X1200 Series supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. ATI Radeon X1200 Series x86/MMX/3DNow!/SSE2 supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. ATI Radeon X1250 supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. ATI Radeon X1250 x86/MMX/3DNow!/SSE2 supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. ATI Radeon X1270 supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. ATI Radeon X1270 x86/MMX/3DNow!/SSE2 supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. ATI Radeon X1300/X1550 Series supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. ATI Radeon X1550 Series supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. ATI Radeon X1600 OpenGL Engine supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. ATI Radeon X1900 OpenGL Engine supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. ATI Radeon X1950 GT supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. ATI Radeon X300/X550/X1050 Series supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. ATI Radeon Xpress 1100 supported 0 ATI Radeon Xpress
+ATI Technologies Inc. ATI Radeon Xpress 1150 supported 0 ATI Radeon Xpress
+ATI Technologies Inc. ATI Radeon Xpress 1150 x86/MMX/3DNow!/SSE2 supported 0 ATI Radeon Xpress
+ATI Technologies Inc. ATI Radeon Xpress 1200 supported 0 ATI Radeon Xpress
+ATI Technologies Inc. ATI Radeon Xpress 1200 Series supported 0 ATI Radeon Xpress
+ATI Technologies Inc. ATI Radeon Xpress 1200 Series x86/MMX/3DNow!/SSE2 supported 0 ATI Radeon Xpress
+ATI Technologies Inc. ATI Radeon Xpress 1200 x86/MMX/3DNow!/SSE2 supported 0 ATI Radeon Xpress
+ATI Technologies Inc. ATI Radeon Xpress 1250 supported 0 ATI Radeon Xpress
+ATI Technologies Inc. ATI Radeon Xpress 1250 x86/SSE2 supported 0 ATI Radeon Xpress
+ATI Technologies Inc. ATI Radeon Xpress Series supported 0 ATI Radeon Xpress
+ATI Technologies Inc. ATI Yamaha HD 9000 supported 0 ATI Technologies
+ATI Technologies Inc. ATi RS880M supported 1 ATI RS880M
+ATI Technologies Inc. Carte graphique VGA standard supported 0 ATI Technologies
+ATI Technologies Inc. Diamond Radeon X1550 Series supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. EG JUNIPER supported 3 AMD JUNIPER (HD 5700)
+ATI Technologies Inc. EG PARK supported 3 AMD PARK
+ATI Technologies Inc. FireGL V3100 Pentium 4 (SSE2) supported 0 ATI FireGL
+ATI Technologies Inc. FireMV 2400 PCI DDR x86 supported 0 ATI FireMV
+ATI Technologies Inc. FireMV 2400 PCI DDR x86/SSE2 supported 0 ATI FireMV
+ATI Technologies Inc. GeCube Radeon X1550 supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. Geforce 9500 GT supported 2 ATI Geforce 9500 GT
+ATI Technologies Inc. Geforce 9500GT supported 2 ATI Geforce 9500 GT
+ATI Technologies Inc. Geforce 9800 GT supported 2 ATI Geforce 9800 GT
+ATI Technologies Inc. HD3730 supported 0 ATI Technologies
+ATI Technologies Inc. HIGHTECH EXCALIBUR RADEON 9550SE Series supported 0 ATI Radeon 9500
+ATI Technologies Inc. HIGHTECH EXCALIBUR X700 PRO supported 0 ATI Technologies
+ATI Technologies Inc. M21 x86/MMX/3DNow!/SSE2 supported 0 ATI Technologies
+ATI Technologies Inc. M76M supported 3 ATI M76
+ATI Technologies Inc. MOBILITY RADEON 7500 DDR x86/SSE2 supported 0 ATI Mobility Radeon
+ATI Technologies Inc. MOBILITY RADEON 9000 DDR x86/SSE2 supported 0 ATI Mobility Radeon
+ATI Technologies Inc. MOBILITY RADEON 9000 IGPRADEON 9100 IGP DDR x86/SSE2 supported 0 ATI Mobility Radeon
+ATI Technologies Inc. MOBILITY RADEON 9600 x86/SSE2 supported 0 ATI Mobility Radeon 9600
+ATI Technologies Inc. MOBILITY RADEON 9700 x86/SSE2 supported 1 ATI Mobility Radeon 9700
+ATI Technologies Inc. MOBILITY RADEON X300 x86/SSE2 supported 1 ATI Mobility Radeon X3xx
+ATI Technologies Inc. MOBILITY RADEON X600 x86/SSE2 supported 1 ATI Mobility Radeon X6xx
+ATI Technologies Inc. MOBILITY RADEON X700 SE x86 supported 1 ATI Mobility Radeon X7xx
+ATI Technologies Inc. MOBILITY RADEON X700 x86/SSE2 supported 1 ATI Mobility Radeon X7xx
+ATI Technologies Inc. MSI RX9550SE supported 1 ATI Radeon RX9550
+ATI Technologies Inc. Mobility Radeon X2300 HD supported 0 ATI Mobility Radeon X2xxx
+ATI Technologies Inc. Mobility Radeon X2300 HD x86/SSE2 supported 0 ATI Mobility Radeon X2xxx
+ATI Technologies Inc. RADEON 7000 DDR x86/MMX/3DNow!/SSE supported 0 ATI Radeon 7xxx
+ATI Technologies Inc. RADEON 7000 DDR x86/SSE2 supported 0 ATI Radeon 7xxx
+ATI Technologies Inc. RADEON 7500 DDR x86/MMX/3DNow!/SSE2 supported 0 ATI Radeon 7xxx
+ATI Technologies Inc. RADEON 7500 DDR x86/SSE2 supported 0 ATI Radeon 7xxx
+ATI Technologies Inc. RADEON 9100 IGP DDR x86/SSE2 supported 0 ATI Radeon 9100
+ATI Technologies Inc. RADEON 9200 DDR x86/MMX/3DNow!/SSE supported 0 ATI Radeon 9200
+ATI Technologies Inc. RADEON 9200 DDR x86/SSE2 supported 0 ATI Radeon 9200
+ATI Technologies Inc. RADEON 9200 PRO DDR x86/MMX/3DNow!/SSE supported 0 ATI Radeon 9200
+ATI Technologies Inc. RADEON 9200 Series DDR x86/MMX/3DNow!/SSE supported 0 ATI Radeon 9200
+ATI Technologies Inc. RADEON 9200 Series DDR x86/MMX/3DNow!/SSE2 supported 0 ATI Radeon 9200
+ATI Technologies Inc. RADEON 9200 Series DDR x86/SSE supported 0 ATI Radeon 9200
+ATI Technologies Inc. RADEON 9200 Series DDR x86/SSE2 supported 0 ATI Radeon 9200
+ATI Technologies Inc. RADEON 9200SE DDR x86/MMX/3DNow!/SSE2 supported 0 ATI Radeon 9200
+ATI Technologies Inc. RADEON 9200SE DDR x86/SSE2 supported 0 ATI Radeon 9200
+ATI Technologies Inc. RADEON 9250/9200 Series DDR x86/MMX/3DNow!/SSE supported 0 ATI Radeon 9200
+ATI Technologies Inc. RADEON 9250/9200 Series DDR x86/MMX/3DNow!/SSE2 supported 0 ATI Radeon 9200
+ATI Technologies Inc. RADEON 9250/9200 Series DDR x86/SSE2 supported 0 ATI Radeon 9200
+ATI Technologies Inc. RADEON 9500 supported 0 ATI Radeon 9500
+ATI Technologies Inc. RADEON 9550 x86/SSE2 supported 0 ATI Radeon 9500
+ATI Technologies Inc. RADEON 9600 SERIES supported 0 ATI Radeon 9600
+ATI Technologies Inc. RADEON 9600 SERIES x86/MMX/3DNow!/SSE2 supported 0 ATI Radeon 9600
+ATI Technologies Inc. RADEON 9600 TX x86/SSE2 supported 0 ATI Radeon 9600
+ATI Technologies Inc. RADEON 9600 x86/MMX/3DNow!/SSE2 supported 0 ATI Radeon 9600
+ATI Technologies Inc. RADEON 9600 x86/SSE2 supported 0 ATI Radeon 9600
+ATI Technologies Inc. RADEON 9700 PRO x86/MMX/3DNow!/SSE supported 1 ATI Radeon 9700
+ATI Technologies Inc. RADEON 9800 PRO supported 1 ATI Radeon 9800
+ATI Technologies Inc. RADEON 9800 x86/SSE2 supported 1 ATI Radeon 9800
+ATI Technologies Inc. RADEON IGP 340M DDR x86/SSE2 unsupported 0 ATI IGP 340M
+ATI Technologies Inc. RADEON X300 Series x86/SSE2 supported 0 ATI Radeon X300
+ATI Technologies Inc. RADEON X300 x86/SSE2 supported 0 ATI Radeon X300
+ATI Technologies Inc. RADEON X300/X550 Series x86/SSE2 supported 0 ATI Radeon X300
+ATI Technologies Inc. RADEON X550 x86/MMX/3DNow!/SSE2 supported 0 ATI Radeon X500
+ATI Technologies Inc. RADEON X550 x86/SSE2 supported 0 ATI Radeon X500
+ATI Technologies Inc. RADEON X600 Series supported 1 ATI Radeon X600
+ATI Technologies Inc. RADEON X600 x86/SSE2 supported 1 ATI Radeon X600
+ATI Technologies Inc. RADEON X700 PRO x86/SSE2 supported 1 ATI Radeon X700
+ATI Technologies Inc. RADEON X800 SE x86/MMX/3DNow!/SSE2 supported 2 ATI Radeon X800
+ATI Technologies Inc. RADEON X800GT supported 2 ATI Radeon X800
+ATI Technologies Inc. RADEON XPRESS 200 Series SW TCL x86/MMX/3DNow!/SSE2 supported 0 ATI Radeon Xpress
+ATI Technologies Inc. RADEON XPRESS 200 Series SW TCL x86/SSE2 supported 0 ATI Radeon Xpress
+ATI Technologies Inc. RADEON XPRESS 200 Series x86/SSE2 supported 0 ATI Radeon Xpress
+ATI Technologies Inc. RADEON XPRESS 200M Series SW TCL x86/MMX/3DNow!/SSE2 supported 0 ATI Radeon Xpress
+ATI Technologies Inc. RADEON XPRESS 200M Series SW TCL x86/SSE2 supported 0 ATI Radeon Xpress
+ATI Technologies Inc. RADEON XPRESS 200M Series x86/MMX/3DNow!/SSE2 supported 0 ATI Radeon Xpress
+ATI Technologies Inc. RADEON XPRESS 200M Series x86/SSE2 supported 0 ATI Radeon Xpress
+ATI Technologies Inc. RADEON XPRESS Series x86/MMX/3DNow!/SSE2 supported 0 ATI Radeon Xpress
+ATI Technologies Inc. RADEON XPRESS Series x86/SSE2 supported 0 ATI Radeon Xpress
+ATI Technologies Inc. RS740 supported 0 ATI Technologies
+ATI Technologies Inc. RS780C supported 0 AMD RS780 (HD 3200)
+ATI Technologies Inc. RS780M supported 0 AMD RS780 (HD 3200)
+ATI Technologies Inc. RS880 supported 1 AMD RS880 (HD 4200)
+ATI Technologies Inc. RV410 Pro x86/SSE2 supported 1 ATI RV410 (X700)
+ATI Technologies Inc. RV790 supported 3 AMD RV790 (HD 4800)
+ATI Technologies Inc. Radeon (TM) HD 6470M supported 0 ATI Technologies
+ATI Technologies Inc. Radeon (TM) HD 6490M supported 0 ATI Technologies
+ATI Technologies Inc. Radeon (TM) HD 6770M supported 0 ATI Technologies
+ATI Technologies Inc. Radeon 7000 DDR x86/SSE2 supported 0 ATI Radeon 7xxx
+ATI Technologies Inc. Radeon 7000 SDR x86/SSE2 supported 0 ATI Radeon 7xxx
+ATI Technologies Inc. Radeon 7500 DDR x86/SSE2 supported 0 ATI Radeon 7xxx
+ATI Technologies Inc. Radeon 9000 DDR x86/SSE2 supported 0 ATI Radeon 9000
+ATI Technologies Inc. Radeon DDR x86/MMX/3DNow!/SSE2 supported 0 ATI Radeon DDR
+ATI Technologies Inc. Radeon DDR x86/SSE supported 0 ATI Radeon DDR
+ATI Technologies Inc. Radeon DDR x86/SSE2 supported 0 ATI Radeon DDR
+ATI Technologies Inc. Radeon HD 6310 supported 2 ATI Radeon HD 6300
+ATI Technologies Inc. Radeon HD 6800 Series supported 3 ATI Radeon HD 6800
+ATI Technologies Inc. Radeon SDR x86/SSE2 supported 0 ATI Technologies
+ATI Technologies Inc. Radeon X1300 Series supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. Radeon X1300 Series x86/MMX/3DNow!/SSE2 supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. Radeon X1300 Series x86/SSE2 supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. Radeon X1300/X1550 Series supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. Radeon X1300/X1550 Series x86/SSE2 supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. Radeon X1550 64-bit (Microsoft - WDDM) supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. Radeon X1550 Series supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. Radeon X1550 Series x86/SSE2 supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. Radeon X1600 supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. Radeon X1600 Pro / X1300XT x86/MMX/3DNow!/SSE2 supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. Radeon X1600 Series x86/SSE2 supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. Radeon X1600/X1650 Series supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. Radeon X1650 Series supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. Radeon X1650 Series x86/MMX/3DNow!/SSE2 supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. Radeon X1650 Series x86/SSE2 supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. Radeon X1900 Series x86/MMX/3DNow!/SSE2 supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. Radeon X1950 Pro supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. Radeon X1950 Pro x86/MMX/3DNow!/SSE2 supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. Radeon X1950 Series supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. Radeon X1950 Series (Microsoft - WDDM) supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. Radeon X300/X550/X1050 Series supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. Radeon X550/X700 Series supported 0 ATI Radeon X500
+ATI Technologies Inc. Radeon X550XTX x86/MMX/3DNow!/SSE2 supported 0 ATI Radeon X500
+ATI Technologies Inc. SAPPHIRE RADEON X300SE supported 0 ATI Radeon X300
+ATI Technologies Inc. SAPPHIRE RADEON X300SE x86/MMX/3DNow!/SSE2 supported 0 ATI Radeon X300
+ATI Technologies Inc. SAPPHIRE RADEON X300SE x86/SSE2 supported 0 ATI Radeon X300
+ATI Technologies Inc. SAPPHIRE Radeon X1550 Series supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. SAPPHIRE Radeon X1550 Series x86/MMX/3DNow!/SSE2 supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. Sapphire Radeon HD 3730 supported 3 ATI Radeon HD 3700
+ATI Technologies Inc. Sapphire Radeon HD 3750 supported 3 ATI Radeon HD 3700
+ATI Technologies Inc. Standard VGA Graphics Adapter supported 0 ATI Technologies
+ATI Technologies Inc. Tul, RADEON X600 PRO supported 0 ATI Technologies
+ATI Technologies Inc. Tul, RADEON X600 PRO x86/SSE2 supported 0 ATI Technologies
+ATI Technologies Inc. Tul, RADEON X700 PRO supported 0 ATI Technologies
+ATI Technologies Inc. Tul, RADEON X700 PRO x86/MMX/3DNow!/SSE2 supported 0 ATI Technologies
+ATI Technologies Inc. VisionTek Radeon 4350 supported 0 ATI Technologies
+ATI Technologies Inc. VisionTek Radeon X1550 Series supported 0 ATI Radeon X1xxx
+ATI Technologies Inc. WRESTLER 9802 supported 0 ATI Technologies
+ATI Technologies Inc. WRESTLER 9803 supported 0 ATI Technologies
+ATI Technologies Inc. XFX Radeon HD 4570 supported 3 ATI Radeon HD 4500
+ATI Technologies Inc. Yamaha ATI HD 9000da/s supported 0 ATI Technologies
+ATI Technologies Inc. Yamaha ATI HD 9000da/s 2048 supported 0 ATI Technologies
+Advanced Micro Devices, Inc. Mesa DRI R600 (RS780 9612) 20090101 x86/MMX+/3DNow!+/SSE2 TCL DRI2 supported 0 AMD RS780 (HD 3200)
+Advanced Micro Devices, Inc. Mesa DRI R600 (RS880 9710) 20090101 x86/MMX+/3DNow!+/SSE2 TCL DRI2 supported 1 AMD RS880 (HD 4200)
+Advanced Micro Devices, Inc. Mesa DRI R600 (RS880 9712) 20090101 TCL supported 1 AMD RS880 (HD 4200)
+Advanced Micro Devices, Inc. Mesa DRI R600 (RV610 94C1) 20090101 x86/MMX+/3DNow!+/SSE2 TCL DRI2 supported 1 AMD RV610 (HD 2400)
+Advanced Micro Devices, Inc. Mesa DRI R600 (RV610 94C9) 20090101 x86/MMX/SSE2 TCL DRI2 supported 1 AMD RV610 (HD 2400)
+Advanced Micro Devices, Inc. Mesa DRI R600 (RV620 95C4) 20090101 x86/MMX/SSE2 TCL DRI2 supported 1 AMD RV620 (HD 3400)
+Advanced Micro Devices, Inc. Mesa DRI R600 (RV620 95C5) 20090101 x86/MMX+/3DNow!+/SSE2 TCL DRI2 supported 1 AMD RV620 (HD 3400)
+Advanced Micro Devices, Inc. Mesa DRI R600 (RV620 95C5) 20090101 x86/MMX/SSE2 TCL DRI2 supported 1 AMD RV620 (HD 3400)
+Advanced Micro Devices, Inc. Mesa DRI R600 (RV635 9596) 20090101 x86/MMX+/3DNow!+/SSE TCL DRI2 supported 3 AMD RV635 (HD 3600)
+Advanced Micro Devices, Inc. Mesa DRI R600 (RV670 9505) 20090101 x86/MMX+/3DNow!+/SSE2 TCL DRI2 supported 3 AMD RV670 (HD 3800)
+Advanced Micro Devices, Inc. Mesa DRI R600 (RV710 9552) 20090101 x86/MMX/SSE2 TCL DRI2 supported 1 AMD RV710 (HD 4300)
+Advanced Micro Devices, Inc. Mesa DRI R600 (RV730 9490) 20090101 x86/MMX+/3DNow!+/SSE2 TCL DRI2 supported 3 AMD RV730 (HD 4600)
+Advanced Micro Devices, Inc. Mesa DRI R600 (RV730 9490) 20090101 x86/MMX/SSE2 TCL DRI2 supported 3 AMD RV730 (HD 4600)
+Advanced Micro Devices, Inc. Mesa DRI R600 (RV730 9498) 20090101 TCL DRI2 supported 3 AMD RV730 (HD 4600)
+Advanced Micro Devices, Inc. Mesa DRI R600 (RV770 9440) 20090101 x86/MMX+/3DNow!+/SSE2 TCL DRI2 supported 3 AMD RV770 (HD 4800)
+Advanced Micro Devices, Inc. Mesa DRI R600 (RV770 9442) 20090101 x86/MMX/SSE2 TCL DRI2 supported 3 AMD RV770 (HD 4800)
+Alex Mohr GL Hijacker! UNRECOGNIZED
+Apple Software Renderer unsupported 0 Apple Software Renderer
+DRI R300 Project Mesa DRI R300 (RS400 5954) 20090101 x86/MMX+/3DNow!+/SSE2 NO-TCL DRI2 supported 1 ATI R300 (9700)
+DRI R300 Project Mesa DRI R300 (RS400 5975) 20090101 x86/MMX+/3DNow!+/SSE2 NO-TCL DRI2 supported 1 ATI R300 (9700)
+DRI R300 Project Mesa DRI R300 (RS400 5A62) 20090101 x86/MMX/SSE2 NO-TCL DRI2 supported 1 ATI R300 (9700)
+DRI R300 Project Mesa DRI R300 (RS600 7941) 20090101 x86/MMX/SSE2 NO-TCL unsupported 0 ATI RS600 (Xpress 3200)
+DRI R300 Project Mesa DRI R300 (RS690 791F) 20090101 x86/MMX+/3DNow!+/SSE2 NO-TCL DRI2 supported 1 ATI R300 (9700)
+DRI R300 Project Mesa DRI R300 (RV350 4151) 20090101 AGP 4x x86/MMX+/3DNow!+/SSE TCL supported 0 ATI RV350 (9600)
+DRI R300 Project Mesa DRI R300 (RV350 4153) 20090101 AGP 8x x86/MMX+/3DNow!+/SSE TCL supported 0 ATI RV350 (9600)
+DRI R300 Project Mesa DRI R300 (RV380 3150) 20090101 x86/MMX+/3DNow!+/SSE2 TCL DRI2 supported 0 ATI RV380
+DRI R300 Project Mesa DRI R300 (RV380 3150) 20090101 x86/MMX/SSE2 TCL DRI2 supported 0 ATI RV380
+DRI R300 Project Mesa DRI R300 (RV380 5B60) 20090101 x86/MMX/SSE2 TCL DRI2 supported 0 ATI RV380
+DRI R300 Project Mesa DRI R300 (RV380 5B62) 20090101 x86/MMX+/3DNow!+/SSE2 TCL DRI2 supported 0 ATI RV380
+DRI R300 Project Mesa DRI R300 (RV515 7145) 20090101 x86/MMX/SSE2 TCL DRI2 supported 1 ATI RV515
+DRI R300 Project Mesa DRI R300 (RV515 7146) 20090101 x86/MMX+/3DNow!+/SSE2 TCL DRI2 supported 1 ATI RV515
+DRI R300 Project Mesa DRI R300 (RV515 7146) 20090101 x86/MMX/SSE2 TCL DRI2 supported 1 ATI RV515
+DRI R300 Project Mesa DRI R300 (RV515 7149) 20090101 x86/MMX/SSE2 TCL DRI2 supported 1 ATI RV515
+DRI R300 Project Mesa DRI R300 (RV515 714A) 20090101 x86/MMX/SSE2 TCL supported 1 ATI RV515
+DRI R300 Project Mesa DRI R300 (RV515 714A) 20090101 x86/MMX/SSE2 TCL DRI2 supported 1 ATI RV515
+DRI R300 Project Mesa DRI R300 (RV530 71C4) 20090101 x86/MMX/SSE2 TCL DRI2 supported 1 ATI RV530
+GPU_CLASS_UNKNOWN UNRECOGNIZED
+Humper Chromium UNRECOGNIZED
+Intel UNRECOGNIZED
+Intel HD Graphics Family supported 2 Intel HD Graphics
+Intel 3D-Analyze v2.2 - http://www.tommti-systems.com UNRECOGNIZED
+Intel 3D-Analyze v2.3 - http://www.tommti-systems.com UNRECOGNIZED
+Intel 4 Series Internal Chipset UNRECOGNIZED
+Intel 830M unsupported 0 Intel 830M
+Intel 845G unsupported 0 Intel 845G
+Intel 855GM unsupported 0 Intel 855GM
+Intel 865G unsupported 0 Intel 865G
+Intel 915G unsupported 0 Intel 915G
+Intel 915GM unsupported 0 Intel 915GM
+Intel 945G supported 0 Intel 945G
+Intel 945GM supported 0 Intel 945GM
+Intel 950 supported 0 Intel 950
+Intel 965 supported 0 Intel 965
+Intel B43 Express Chipset UNRECOGNIZED
+Intel Bear Lake unsupported 0 Intel Bear Lake
+Intel Broadwater unsupported 0 Intel Broadwater
+Intel Brookdale unsupported 0 Intel Brookdale
+Intel Cantiga unsupported 0 Intel Cantiga
+Intel Eaglelake supported 0 Intel Eaglelake
+Intel Familia Mobile 45 Express Chipset (Microsoft Corporation - WDDM 1.1) UNRECOGNIZED
+Intel G33 unsupported 0 Intel G33
+Intel G41 supported 0 Intel G41
+Intel G41 Express Chipset supported 0 Intel G41
+Intel G45 supported 0 Intel G45
+Intel G45/G43 Express Chipset supported 0 Intel G45
+Intel Graphics Media Accelerator HD supported 0 Intel Graphics Media HD
+Intel HD Graphics supported 2 Intel HD Graphics
+Intel HD Graphics 100 supported 2 Intel HD Graphics
+Intel HD Graphics 200 supported 2 Intel HD Graphics
+Intel HD Graphics 200 BR-1101-00SH supported 2 Intel HD Graphics
+Intel HD Graphics 200 BR-1101-00SJ supported 2 Intel HD Graphics
+Intel HD Graphics 200 BR-1101-00SK supported 2 Intel HD Graphics
+Intel HD Graphics 200 BR-1101-01M5 supported 2 Intel HD Graphics
+Intel HD Graphics 200 BR-1101-01M6 supported 2 Intel HD Graphics
+Intel HD Graphics BR-1004-01Y1 supported 2 Intel HD Graphics
+Intel HD Graphics BR-1006-0364 supported 2 Intel HD Graphics
+Intel HD Graphics BR-1006-0365 supported 2 Intel HD Graphics
+Intel HD Graphics BR-1006-0366 supported 2 Intel HD Graphics
+Intel HD Graphics BR-1007-02G4 supported 2 Intel HD Graphics
+Intel HD Graphics BR-1101-04SY supported 2 Intel HD Graphics
+Intel HD Graphics BR-1101-04SZ supported 2 Intel HD Graphics
+Intel HD Graphics BR-1101-04T0 supported 2 Intel HD Graphics
+Intel HD Graphics BR-1101-04T9 supported 2 Intel HD Graphics
+Intel HD Graphics Family supported 2 Intel HD Graphics
+Intel HD Graphics Family BR-1012-00Y8 supported 2 Intel HD Graphics
+Intel HD Graphics Family BR-1012-00YF supported 2 Intel HD Graphics
+Intel HD Graphics Family BR-1012-00ZD supported 2 Intel HD Graphics
+Intel HD Graphics Family BR-1102-00ML supported 2 Intel HD Graphics
+Intel Inc. Intel GMA 900 OpenGL Engine UNRECOGNIZED
+Intel Inc. Intel GMA 950 OpenGL Engine supported 0 Intel 950
+Intel Inc. Intel GMA X3100 OpenGL Engine supported 0 Intel X3100
+Intel Inc. Intel HD Graphics 3000 OpenGL Engine supported 2 Intel HD Graphics
+Intel Inc. Intel HD Graphics OpenGL Engine supported 2 Intel HD Graphics
+Intel Inc. Intel HD xxxx OpenGL Engine UNRECOGNIZED
+Intel Intel 845G unsupported 0 Intel 845G
+Intel Intel 855GM unsupported 0 Intel 855GM
+Intel Intel 865G unsupported 0 Intel 865G
+Intel Intel 915G unsupported 0 Intel 915G
+Intel Intel 915GM unsupported 0 Intel 915GM
+Intel Intel 945G supported 0 Intel 945G
+Intel Intel 945GM supported 0 Intel 945GM
+Intel Intel 965/963 Graphics Media Accelerator supported 0 Intel 965
+Intel Intel Bear Lake B unsupported 0 Intel Bear Lake
+Intel Intel Broadwater G unsupported 0 Intel Broadwater
+Intel Intel Brookdale-G unsupported 0 Intel Brookdale
+Intel Intel Calistoga UNRECOGNIZED
+Intel Intel Cantiga unsupported 0 Intel Cantiga
+Intel Intel Eaglelake supported 0 Intel Eaglelake
+Intel Intel Grantsdale-G UNRECOGNIZED
+Intel Intel HD Graphics 3000 supported 2 Intel HD Graphics
+Intel Intel Lakeport UNRECOGNIZED
+Intel Intel Montara-GM unsupported 0 Intel Montara
+Intel Intel Pineview Platform supported 0 Intel Pineview
+Intel Intel Springdale-G unsupported 0 Intel Springdale
+Intel Mobile - famiglia Express Chipset 45 (Microsoft Corporation - WDDM 1.1) UNRECOGNIZED
+Intel Mobile 4 Series supported 0 Intel Mobile 4 Series
+Intel Mobile 4 Series Express Chipset Family supported 0 Intel Mobile 4 Series
+Intel Mobile 45 Express Chipset Family (Microsoft Corporation - WDDM 1.1) UNRECOGNIZED
+Intel Mobile HD Graphics supported 2 Intel HD Graphics
+Intel Mobile SandyBridge HD Graphics supported 2 Intel HD Graphics
+Intel Montara unsupported 0 Intel Montara
+Intel Pineview supported 0 Intel Pineview
+Intel Q45/Q43 Express Chipset UNRECOGNIZED
+Intel Royal BNA Driver UNRECOGNIZED
+Intel SandyBridge HD Graphics supported 2 Intel HD Graphics
+Intel SandyBridge HD Graphics BR-1006-00V8 supported 2 Intel HD Graphics
+Intel Springdale unsupported 0 Intel Springdale
+Intel X3100 supported 0 Intel X3100
+Intergraph wcgdrv 06.05.06.18 UNRECOGNIZED
+Intergraph wcgdrv 06.06.00.35 UNRECOGNIZED
+LegendgrafiX Mobile 945 Express C/TitaniumGL/GAC/D3D ACCELERATION/6x86/1 THREADs | http://Legendgra... UNRECOGNIZED
+LegendgrafiX NVIDIA GeForce GT 430/TitaniumGL/GAC/D3D ACCELERATION/6x86/1 THREADs | http://Legendgr... supported 3 NVIDIA GT 430M
+Linden Lab Headless UNRECOGNIZED
+Matrox unsupported 0 Matrox
+Mesa unsupported 0 Mesa
+Mesa Project Software Rasterizer unsupported 0 Mesa
+NVIDIA /PCI/SSE2 UNRECOGNIZED
+NVIDIA /PCI/SSE2/3DNOW! UNRECOGNIZED
+NVIDIA 205 supported 0 NVIDIA G 205M
+NVIDIA 210 supported 1 NVIDIA G 210
+NVIDIA 310 supported 2 NVIDIA G 310M
+NVIDIA 310M supported 2 NVIDIA G 310M
+NVIDIA 315 supported 2 NVIDIA G 315
+NVIDIA 315M supported 2 NVIDIA G 315
+NVIDIA 320M supported 2 NVIDIA G 320M
+NVIDIA C51 supported 0 NVIDIA C51
+NVIDIA D10M2-20/PCI/SSE2 UNRECOGNIZED
+NVIDIA D10P1-25/PCI/SSE2 UNRECOGNIZED
+NVIDIA D10P1-30/PCI/SSE2 UNRECOGNIZED
+NVIDIA D10P2-50/PCI/SSE2 UNRECOGNIZED
+NVIDIA D11M2-30/PCI/SSE2 UNRECOGNIZED
+NVIDIA D12-P1-35/PCI/SSE2 UNRECOGNIZED
+NVIDIA D12U-15/PCI/SSE2 UNRECOGNIZED
+NVIDIA D13M1-40/PCI/SSE2 UNRECOGNIZED
+NVIDIA D13P1-40/PCI/SSE2 UNRECOGNIZED
+NVIDIA D13U-10/PCI/SSE2 UNRECOGNIZED
+NVIDIA D13U/PCI/SSE2 UNRECOGNIZED
+NVIDIA D9M supported 1 NVIDIA D9M
+NVIDIA D9M-20/PCI/SSE2 supported 1 NVIDIA D9M
+NVIDIA Entry Graphics/PCI/SSE2 UNRECOGNIZED
+NVIDIA Entry Graphics/PCI/SSE2/3DNOW! UNRECOGNIZED
+NVIDIA G 102M supported 0 NVIDIA G102M
+NVIDIA G 103M supported 0 NVIDIA G103M
+NVIDIA G 105M supported 0 NVIDIA G105M
+NVIDIA G 110M supported 0 NVIDIA G 110M
+NVIDIA G100 supported 0 NVIDIA G100
+NVIDIA G102M supported 0 NVIDIA G102M
+NVIDIA G103M supported 0 NVIDIA G103M
+NVIDIA G105M supported 0 NVIDIA G105M
+NVIDIA G210 supported 1 NVIDIA G 210
+NVIDIA G210M supported 1 NVIDIA G 210
+NVIDIA G70/PCI/SSE2 UNRECOGNIZED
+NVIDIA G72 supported 1 NVIDIA G72
+NVIDIA G73 supported 1 NVIDIA G73
+NVIDIA G84 supported 2 NVIDIA G84
+NVIDIA G86 supported 3 NVIDIA G86
+NVIDIA G92 supported 3 NVIDIA G92
+NVIDIA G92-200/PCI/SSE2 supported 3 NVIDIA G92
+NVIDIA G94 supported 3 NVIDIA G94
+NVIDIA G96/PCI/SSE2 UNRECOGNIZED
+NVIDIA G98/PCI/SSE2 UNRECOGNIZED
+NVIDIA GT 120 supported 2 NVIDIA GT 120M
+NVIDIA GT 130 supported 2 NVIDIA GT 130M
+NVIDIA GT 130M supported 2 NVIDIA GT 130M
+NVIDIA GT 140 supported 2 NVIDIA GT 140M
+NVIDIA GT 150 supported 2 NVIDIA GT 150M
+NVIDIA GT 160M supported 2 NVIDIA GT 160M
+NVIDIA GT 220 supported 2 NVIDIA GT 220M
+NVIDIA GT 220/PCI/SSE2 supported 2 NVIDIA GT 220M
+NVIDIA GT 220/PCI/SSE2/3DNOW! supported 2 NVIDIA GT 220M
+NVIDIA GT 230 supported 2 NVIDIA GT 230M
+NVIDIA GT 230M supported 2 NVIDIA GT 230M
+NVIDIA GT 240 supported 2 NVIDIA GT 240M
+NVIDIA GT 240M supported 2 NVIDIA GT 240M
+NVIDIA GT 250M supported 2 NVIDIA GT 250M
+NVIDIA GT 260M supported 2 NVIDIA GT 260M
+NVIDIA GT 320 supported 2 NVIDIA GT 320M
+NVIDIA GT 320M supported 2 NVIDIA GT 320M
+NVIDIA GT 330 supported 3 NVIDIA GT 330M
+NVIDIA GT 330M supported 3 NVIDIA GT 330M
+NVIDIA GT 340 supported 2 NVIDIA GT 340M
+NVIDIA GT 420 supported 2 NVIDIA GT 420M
+NVIDIA GT 430 supported 3 NVIDIA GT 430M
+NVIDIA GT 440 supported 3 NVIDIA GT 440M
+NVIDIA GT 450 supported 3 NVIDIA GT 450M
+NVIDIA GT 520 supported 3 NVIDIA GT 520M
+NVIDIA GT 540 supported 3 NVIDIA GT 540M
+NVIDIA GT 540M supported 3 NVIDIA GT 540M
+NVIDIA GT-120 supported 2 NVIDIA GT 120
+NVIDIA GT200/PCI/SSE2 UNRECOGNIZED
+NVIDIA GTS 150 supported 2 NVIDIA GT 150M
+NVIDIA GTS 240 supported 3 NVIDIA GTS 240
+NVIDIA GTS 250 supported 3 NVIDIA GTS 250
+NVIDIA GTS 350M supported 3 NVIDIA GTS 350M
+NVIDIA GTS 360 supported 3 NVIDIA GTS 360
+NVIDIA GTS 360M supported 3 NVIDIA GTS 360M
+NVIDIA GTS 450 supported 3 NVIDIA GTS 450
+NVIDIA GTX 260 supported 3 NVIDIA GTX 260
+NVIDIA GTX 260M supported 3 NVIDIA GTX 260
+NVIDIA GTX 270 supported 3 NVIDIA GTX 270
+NVIDIA GTX 280 supported 3 NVIDIA GTX 280
+NVIDIA GTX 285 supported 3 NVIDIA GTX 285
+NVIDIA GTX 290 supported 3 NVIDIA GTX 290
+NVIDIA GTX 460 supported 3 NVIDIA GTX 460
+NVIDIA GTX 460M supported 3 NVIDIA GTX 460M
+NVIDIA GTX 465 supported 3 NVIDIA GTX 465
+NVIDIA GTX 470 supported 3 NVIDIA GTX 470
+NVIDIA GTX 470M supported 3 NVIDIA GTX 470M
+NVIDIA GTX 480 supported 3 NVIDIA GTX 480
+NVIDIA GTX 480M supported 3 NVIDIA GTX 480M
+NVIDIA GTX 550 Ti supported 3 NVIDIA GTX 550
+NVIDIA GTX 560 supported 3 NVIDIA GTX 560
+NVIDIA GTX 560 Ti supported 3 NVIDIA GTX 560
+NVIDIA GTX 570 supported 3 NVIDIA GTX 570
+NVIDIA GTX 580 supported 3 NVIDIA GTX 580
+NVIDIA GTX 590 supported 3 NVIDIA GTX 590
+NVIDIA GeForce UNRECOGNIZED
+NVIDIA GeForce 2 supported 0 NVIDIA GeForce 2
+NVIDIA GeForce 205/PCI/SSE2 supported 2 NVIDIA 205
+NVIDIA GeForce 210 supported 2 NVIDIA 210
+NVIDIA GeForce 210/PCI/SSE2 supported 2 NVIDIA 210
+NVIDIA GeForce 210/PCI/SSE2/3DNOW! supported 2 NVIDIA 210
+NVIDIA GeForce 3 supported 0 NVIDIA GeForce 3
+NVIDIA GeForce 305M/PCI/SSE2 supported 1 NVIDIA 305M
+NVIDIA GeForce 310/PCI/SSE2 supported 3 NVIDIA 310
+NVIDIA GeForce 310/PCI/SSE2/3DNOW! supported 3 NVIDIA 310
+NVIDIA GeForce 310M/PCI/SSE2 supported 1 NVIDIA 310M
+NVIDIA GeForce 315/PCI/SSE2 supported 3 NVIDIA 315
+NVIDIA GeForce 315/PCI/SSE2/3DNOW! supported 3 NVIDIA 315
+NVIDIA GeForce 315M/PCI/SSE2 supported 2 NVIDIA 315M
+NVIDIA GeForce 320M/PCI/SSE2 supported 2 NVIDIA 320M
+NVIDIA GeForce 4 Go supported 0 NVIDIA GeForce 4
+NVIDIA GeForce 4 MX supported 0 NVIDIA GeForce 4
+NVIDIA GeForce 4 Ti supported 0 NVIDIA GeForce 4
+NVIDIA GeForce 405/PCI/SSE2 supported 1 NVIDIA G 405
+NVIDIA GeForce 6100 supported 0 NVIDIA GeForce 6100
+NVIDIA GeForce 6100 nForce 400/PCI/SSE2/3DNOW! supported 0 NVIDIA GeForce 6100
+NVIDIA GeForce 6100 nForce 405/PCI/SSE2 supported 0 NVIDIA GeForce 6100
+NVIDIA GeForce 6100 nForce 405/PCI/SSE2/3DNOW! supported 0 NVIDIA GeForce 6100
+NVIDIA GeForce 6100 nForce 420/PCI/SSE2/3DNOW! supported 0 NVIDIA GeForce 6100
+NVIDIA GeForce 6100 nForce 430/PCI/SSE2/3DNOW! supported 0 NVIDIA GeForce 6100
+NVIDIA GeForce 6100/PCI/SSE2/3DNOW! supported 0 NVIDIA GeForce 6100
+NVIDIA GeForce 6150 LE/PCI/SSE2/3DNOW! supported 0 NVIDIA GeForce 6100
+NVIDIA GeForce 6150/PCI/SSE2 supported 0 NVIDIA GeForce 6100
+NVIDIA GeForce 6150/PCI/SSE2/3DNOW! supported 0 NVIDIA GeForce 6100
+NVIDIA GeForce 6150SE nForce 430/PCI/SSE2 supported 0 NVIDIA GeForce 6100
+NVIDIA GeForce 6150SE nForce 430/PCI/SSE2/3DNOW! supported 0 NVIDIA GeForce 6100
+NVIDIA GeForce 6150SE/PCI/SSE2/3DNOW! supported 0 NVIDIA GeForce 6100
+NVIDIA GeForce 6200 supported 0 NVIDIA GeForce 6200
+NVIDIA GeForce 6200 A-LE/AGP/SSE/3DNOW! supported 0 NVIDIA GeForce 6200
+NVIDIA GeForce 6200 A-LE/AGP/SSE2 supported 0 NVIDIA GeForce 6200
+NVIDIA GeForce 6200 A-LE/AGP/SSE2/3DNOW! supported 0 NVIDIA GeForce 6200
+NVIDIA GeForce 6200 LE/PCI/SSE2 supported 0 NVIDIA GeForce 6200
+NVIDIA GeForce 6200 LE/PCI/SSE2/3DNOW! supported 0 NVIDIA GeForce 6200
+NVIDIA GeForce 6200 TurboCache(TM)/PCI/SSE2 supported 0 NVIDIA GeForce 6200
+NVIDIA GeForce 6200 TurboCache(TM)/PCI/SSE2/3DNOW! supported 0 NVIDIA GeForce 6200
+NVIDIA GeForce 6200/AGP/SSE/3DNOW! supported 0 NVIDIA GeForce 6200
+NVIDIA GeForce 6200/AGP/SSE2 supported 0 NVIDIA GeForce 6200
+NVIDIA GeForce 6200/AGP/SSE2/3DNOW! supported 0 NVIDIA GeForce 6200
+NVIDIA GeForce 6200/PCI/SSE/3DNOW! supported 0 NVIDIA GeForce 6200
+NVIDIA GeForce 6200/PCI/SSE2 supported 0 NVIDIA GeForce 6200
+NVIDIA GeForce 6200/PCI/SSE2/3DNOW! supported 0 NVIDIA GeForce 6200
+NVIDIA GeForce 6200SE TurboCache(TM)/PCI/SSE2/3DNOW! supported 0 NVIDIA GeForce 6200
+NVIDIA GeForce 6500 supported 0 NVIDIA GeForce 6500
+NVIDIA GeForce 6500/PCI/SSE2 supported 0 NVIDIA GeForce 6500
+NVIDIA GeForce 6600 supported 1 NVIDIA GeForce 6600
+NVIDIA GeForce 6600 GT/AGP/SSE/3DNOW! supported 1 NVIDIA GeForce 6600
+NVIDIA GeForce 6600 GT/AGP/SSE2 supported 1 NVIDIA GeForce 6600
+NVIDIA GeForce 6600 GT/PCI/SSE/3DNOW! supported 1 NVIDIA GeForce 6600
+NVIDIA GeForce 6600 GT/PCI/SSE2 supported 1 NVIDIA GeForce 6600
+NVIDIA GeForce 6600 GT/PCI/SSE2/3DNOW! supported 1 NVIDIA GeForce 6600
+NVIDIA GeForce 6600 LE/PCI/SSE2 supported 1 NVIDIA GeForce 6600
+NVIDIA GeForce 6600/AGP/SSE/3DNOW! supported 1 NVIDIA GeForce 6600
+NVIDIA GeForce 6600/AGP/SSE2 supported 1 NVIDIA GeForce 6600
+NVIDIA GeForce 6600/AGP/SSE2/3DNOW! supported 1 NVIDIA GeForce 6600
+NVIDIA GeForce 6600/PCI/SSE2 supported 1 NVIDIA GeForce 6600
+NVIDIA GeForce 6600/PCI/SSE2/3DNOW! supported 1 NVIDIA GeForce 6600
+NVIDIA GeForce 6700 supported 2 NVIDIA GeForce 6700
+NVIDIA GeForce 6800 supported 2 NVIDIA GeForce 6800
+NVIDIA GeForce 6800 GS/PCI/SSE2/3DNOW! supported 2 NVIDIA GeForce 6800
+NVIDIA GeForce 6800 GT/AGP/SSE2 supported 2 NVIDIA GeForce 6800
+NVIDIA GeForce 6800 GT/PCI/SSE2 supported 2 NVIDIA GeForce 6800
+NVIDIA GeForce 6800 XT/AGP/SSE2 supported 2 NVIDIA GeForce 6800
+NVIDIA GeForce 6800 XT/PCI/SSE2 supported 2 NVIDIA GeForce 6800
+NVIDIA GeForce 6800/PCI/SSE2 supported 2 NVIDIA GeForce 6800
+NVIDIA GeForce 6800/PCI/SSE2/3DNOW! supported 2 NVIDIA GeForce 6800
+NVIDIA GeForce 7000 supported 0 NVIDIA GeForce 7000
+NVIDIA GeForce 7000M supported 0 NVIDIA GeForce 7000
+NVIDIA GeForce 7000M / nForce 610M/PCI/SSE2 supported 0 NVIDIA GeForce 7000
+NVIDIA GeForce 7000M / nForce 610M/PCI/SSE2/3DNOW! supported 0 NVIDIA GeForce 7000
+NVIDIA GeForce 7025 / NVIDIA nForce 630a/PCI/SSE2/3DNOW! supported 0 NVIDIA GeForce 7000
+NVIDIA GeForce 7025 / nForce 630a/PCI/SSE2 supported 0 NVIDIA GeForce 7000
+NVIDIA GeForce 7025 / nForce 630a/PCI/SSE2/3DNOW! supported 0 NVIDIA GeForce 7000
+NVIDIA GeForce 7050 / NVIDIA nForce 610i/PCI/SSE2 supported 0 NVIDIA GeForce 7000
+NVIDIA GeForce 7050 / NVIDIA nForce 620i/PCI/SSE2 supported 0 NVIDIA GeForce 7000
+NVIDIA GeForce 7050 / nForce 610i/PCI/SSE2 supported 0 NVIDIA GeForce 7000
+NVIDIA GeForce 7050 / nForce 620i/PCI/SSE2 supported 0 NVIDIA GeForce 7000
+NVIDIA GeForce 7050 PV / NVIDIA nForce 630a/PCI/SSE2/3DNOW! supported 0 NVIDIA GeForce 7000
+NVIDIA GeForce 7050 PV / nForce 630a/PCI/SSE2 supported 0 NVIDIA GeForce 7000
+NVIDIA GeForce 7050 PV / nForce 630a/PCI/SSE2/3DNOW! supported 0 NVIDIA GeForce 7000
+NVIDIA GeForce 7050 SE / NVIDIA nForce 630a/PCI/SSE2/3DNOW! supported 0 NVIDIA GeForce 7000
+NVIDIA GeForce 7100 supported 0 NVIDIA GeForce 7100
+NVIDIA GeForce 7100 / NVIDIA nForce 620i/PCI/SSE2 supported 0 NVIDIA GeForce 7100
+NVIDIA GeForce 7100 / NVIDIA nForce 630i/PCI/SSE2 supported 0 NVIDIA GeForce 7100
+NVIDIA GeForce 7100 / nForce 630i/PCI/SSE2 supported 0 NVIDIA GeForce 7100
+NVIDIA GeForce 7100 GS/PCI/SSE2 supported 0 NVIDIA GeForce 7100
+NVIDIA GeForce 7100 GS/PCI/SSE2/3DNOW! supported 0 NVIDIA GeForce 7100
+NVIDIA GeForce 7150M / nForce 630M/PCI/SSE2 supported 0 NVIDIA GeForce 7100
+NVIDIA GeForce 7150M / nForce 630M/PCI/SSE2/3DNOW! supported 0 NVIDIA GeForce 7100
+NVIDIA GeForce 7300 supported 1 NVIDIA GeForce 7300
+NVIDIA GeForce 7300 GS/PCI/SSE2 supported 1 NVIDIA GeForce 7300
+NVIDIA GeForce 7300 GS/PCI/SSE2/3DNOW! supported 1 NVIDIA GeForce 7300
+NVIDIA GeForce 7300 GT/AGP/SSE2 supported 1 NVIDIA GeForce 7300
+NVIDIA GeForce 7300 GT/AGP/SSE2/3DNOW! supported 1 NVIDIA GeForce 7300
+NVIDIA GeForce 7300 GT/PCI/SSE2 supported 1 NVIDIA GeForce 7300
+NVIDIA GeForce 7300 GT/PCI/SSE2/3DNOW! supported 1 NVIDIA GeForce 7300
+NVIDIA GeForce 7300 LE/PCI/SSE2 supported 1 NVIDIA GeForce 7300
+NVIDIA GeForce 7300 LE/PCI/SSE2/3DNOW! supported 1 NVIDIA GeForce 7300
+NVIDIA GeForce 7300 SE/7200 GS/PCI/SSE2 supported 1 NVIDIA GeForce 7300
+NVIDIA GeForce 7300 SE/7200 GS/PCI/SSE2/3DNOW! supported 1 NVIDIA GeForce 7300
+NVIDIA GeForce 7300 SE/PCI/SSE2 supported 1 NVIDIA GeForce 7300
+NVIDIA GeForce 7300 SE/PCI/SSE2/3DNOW! supported 1 NVIDIA GeForce 7300
+NVIDIA GeForce 7350 LE/PCI/SSE2 supported 1 NVIDIA GeForce 7300
+NVIDIA GeForce 7500 supported 1 NVIDIA GeForce 7500
+NVIDIA GeForce 7500 LE/PCI/SSE2 supported 1 NVIDIA GeForce 7500
+NVIDIA GeForce 7500 LE/PCI/SSE2/3DNOW! supported 1 NVIDIA GeForce 7500
+NVIDIA GeForce 7600 supported 2 NVIDIA GeForce 7600
+NVIDIA GeForce 7600 GS/AGP/SSE2 supported 2 NVIDIA GeForce 7600
+NVIDIA GeForce 7600 GS/AGP/SSE2/3DNOW! supported 2 NVIDIA GeForce 7600
+NVIDIA GeForce 7600 GS/PCI/SSE2 supported 2 NVIDIA GeForce 7600
+NVIDIA GeForce 7600 GS/PCI/SSE2/3DNOW! supported 2 NVIDIA GeForce 7600
+NVIDIA GeForce 7600 GT/AGP/SSE/3DNOW! supported 2 NVIDIA GeForce 7600
+NVIDIA GeForce 7600 GT/AGP/SSE2 supported 2 NVIDIA GeForce 7600
+NVIDIA GeForce 7600 GT/PCI/SSE2 supported 2 NVIDIA GeForce 7600
+NVIDIA GeForce 7600 GT/PCI/SSE2/3DNOW! supported 2 NVIDIA GeForce 7600
+NVIDIA GeForce 7650 GS/PCI/SSE2 supported 2 NVIDIA GeForce 7600
+NVIDIA GeForce 7800 supported 2 NVIDIA GeForce 7800
+NVIDIA GeForce 7800 GS/AGP/SSE2 supported 2 NVIDIA GeForce 7800
+NVIDIA GeForce 7800 GS/AGP/SSE2/3DNOW! supported 2 NVIDIA GeForce 7800
+NVIDIA GeForce 7800 GT/PCI/SSE2 supported 2 NVIDIA GeForce 7800
+NVIDIA GeForce 7800 GTX/PCI/SSE2 supported 2 NVIDIA GeForce 7800
+NVIDIA GeForce 7800 GTX/PCI/SSE2/3DNOW! supported 2 NVIDIA GeForce 7800
+NVIDIA GeForce 7900 supported 2 NVIDIA GeForce 7900
+NVIDIA GeForce 7900 GS/PCI/SSE2 supported 2 NVIDIA GeForce 7900
+NVIDIA GeForce 7900 GS/PCI/SSE2/3DNOW! supported 2 NVIDIA GeForce 7900
+NVIDIA GeForce 7900 GT/GTO/PCI/SSE2 supported 2 NVIDIA GeForce 7900
+NVIDIA GeForce 7900 GT/PCI/SSE2/3DNOW! supported 2 NVIDIA GeForce 7900
+NVIDIA GeForce 7900 GTX/PCI/SSE2 supported 2 NVIDIA GeForce 7900
+NVIDIA GeForce 7950 GT/PCI/SSE2 supported 2 NVIDIA GeForce 7900
+NVIDIA GeForce 7950 GT/PCI/SSE2/3DNOW! supported 2 NVIDIA GeForce 7900
+NVIDIA GeForce 8100 supported 1 NVIDIA GeForce 8100
+NVIDIA GeForce 8100 / nForce 720a/PCI/SSE2/3DNOW! supported 1 NVIDIA GeForce 8100
+NVIDIA GeForce 8200 supported 1 NVIDIA GeForce 8200
+NVIDIA GeForce 8200/PCI/SSE2 supported 1 NVIDIA GeForce 8200
+NVIDIA GeForce 8200/PCI/SSE2/3DNOW! supported 1 NVIDIA GeForce 8200
+NVIDIA GeForce 8200M supported 1 NVIDIA GeForce 8200M
+NVIDIA GeForce 8200M G/PCI/SSE2 supported 1 NVIDIA GeForce 8200M
+NVIDIA GeForce 8200M G/PCI/SSE2/3DNOW! supported 1 NVIDIA GeForce 8200M
+NVIDIA GeForce 8300 supported 1 NVIDIA GeForce 8300
+NVIDIA GeForce 8300 GS/PCI/SSE2 supported 1 NVIDIA GeForce 8300
+NVIDIA GeForce 8400 supported 1 NVIDIA GeForce 8400
+NVIDIA GeForce 8400 GS/PCI/SSE/3DNOW! supported 1 NVIDIA GeForce 8400
+NVIDIA GeForce 8400 GS/PCI/SSE2 supported 1 NVIDIA GeForce 8400
+NVIDIA GeForce 8400 GS/PCI/SSE2/3DNOW! supported 1 NVIDIA GeForce 8400
+NVIDIA GeForce 8400/PCI/SSE2/3DNOW! supported 1 NVIDIA GeForce 8400
+NVIDIA GeForce 8400GS/PCI/SSE2 supported 1 NVIDIA GeForce 8400
+NVIDIA GeForce 8400GS/PCI/SSE2/3DNOW! supported 1 NVIDIA GeForce 8400
+NVIDIA GeForce 8400M supported 1 NVIDIA GeForce 8400M
+NVIDIA GeForce 8400M G/PCI/SSE2 supported 1 NVIDIA GeForce 8400M
+NVIDIA GeForce 8400M G/PCI/SSE2/3DNOW! supported 1 NVIDIA GeForce 8400M
+NVIDIA GeForce 8400M GS/PCI/SSE2 supported 1 NVIDIA GeForce 8400M
+NVIDIA GeForce 8400M GS/PCI/SSE2/3DNOW! supported 1 NVIDIA GeForce 8400M
+NVIDIA GeForce 8400M GT/PCI/SSE2 supported 1 NVIDIA GeForce 8400M
+NVIDIA GeForce 8500 supported 3 NVIDIA GeForce 8500
+NVIDIA GeForce 8500 GT/PCI/SSE2 supported 3 NVIDIA GeForce 8500
+NVIDIA GeForce 8500 GT/PCI/SSE2/3DNOW! supported 3 NVIDIA GeForce 8500
+NVIDIA GeForce 8600 supported 3 NVIDIA GeForce 8600
+NVIDIA GeForce 8600 GS/PCI/SSE2 supported 3 NVIDIA GeForce 8600
+NVIDIA GeForce 8600 GS/PCI/SSE2/3DNOW! supported 3 NVIDIA GeForce 8600
+NVIDIA GeForce 8600 GT/PCI/SSE2 supported 3 NVIDIA GeForce 8600
+NVIDIA GeForce 8600 GT/PCI/SSE2/3DNOW! supported 3 NVIDIA GeForce 8600
+NVIDIA GeForce 8600 GTS/PCI/SSE2 supported 3 NVIDIA GeForce 8600
+NVIDIA GeForce 8600 GTS/PCI/SSE2/3DNOW! supported 3 NVIDIA GeForce 8600
+NVIDIA GeForce 8600GS/PCI/SSE2 supported 3 NVIDIA GeForce 8600
+NVIDIA GeForce 8600M supported 1 NVIDIA GeForce 8600M
+NVIDIA GeForce 8600M GS/PCI/SSE2 supported 1 NVIDIA GeForce 8600M
+NVIDIA GeForce 8600M GS/PCI/SSE2/3DNOW! supported 1 NVIDIA GeForce 8600M
+NVIDIA GeForce 8600M GT/PCI/SSE2 supported 1 NVIDIA GeForce 8600M
+NVIDIA GeForce 8700 supported 3 NVIDIA GeForce 8700
+NVIDIA GeForce 8700M supported 3 NVIDIA GeForce 8700M
+NVIDIA GeForce 8700M GT/PCI/SSE2 supported 3 NVIDIA GeForce 8700M
+NVIDIA GeForce 8800 supported 3 NVIDIA GeForce 8800
+NVIDIA GeForce 8800 GS/PCI/SSE2 supported 3 NVIDIA GeForce 8800
+NVIDIA GeForce 8800 GT/PCI/SSE2 supported 3 NVIDIA GeForce 8800
+NVIDIA GeForce 8800 GT/PCI/SSE2/3DNOW! supported 3 NVIDIA GeForce 8800
+NVIDIA GeForce 8800 GTS 512/PCI/SSE2 supported 3 NVIDIA GeForce 8800
+NVIDIA GeForce 8800 GTS 512/PCI/SSE2/3DNOW! supported 3 NVIDIA GeForce 8800
+NVIDIA GeForce 8800 GTS/PCI/SSE2 supported 3 NVIDIA GeForce 8800
+NVIDIA GeForce 8800 GTS/PCI/SSE2/3DNOW! supported 3 NVIDIA GeForce 8800
+NVIDIA GeForce 8800 GTX/PCI/SSE2 supported 3 NVIDIA GeForce 8800
+NVIDIA GeForce 8800 Ultra/PCI/SSE2 supported 3 NVIDIA GeForce 8800
+NVIDIA GeForce 8800M GTS/PCI/SSE2 supported 3 NVIDIA GeForce 8800M
+NVIDIA GeForce 8800M GTX/PCI/SSE2 supported 3 NVIDIA GeForce 8800M
+NVIDIA GeForce 9100 supported 0 NVIDIA GeForce 9100
+NVIDIA GeForce 9100/PCI/SSE2 supported 0 NVIDIA GeForce 9100
+NVIDIA GeForce 9100/PCI/SSE2/3DNOW! supported 0 NVIDIA GeForce 9100
+NVIDIA GeForce 9100M supported 0 NVIDIA GeForce 9100M
+NVIDIA GeForce 9100M G/PCI/SSE2 supported 0 NVIDIA GeForce 9100M
+NVIDIA GeForce 9100M G/PCI/SSE2/3DNOW! supported 0 NVIDIA GeForce 9100M
+NVIDIA GeForce 9200 supported 1 NVIDIA GeForce 9200
+NVIDIA GeForce 9200/PCI/SSE2 supported 1 NVIDIA GeForce 9200
+NVIDIA GeForce 9200/PCI/SSE2/3DNOW! supported 1 NVIDIA GeForce 9200
+NVIDIA GeForce 9200M GE/PCI/SSE2 supported 1 NVIDIA GeForce 9200M
+NVIDIA GeForce 9200M GS/PCI/SSE2 supported 1 NVIDIA GeForce 9200M
+NVIDIA GeForce 9300 supported 1 NVIDIA GeForce 9300
+NVIDIA GeForce 9300 / nForce 730i/PCI/SSE2 supported 1 NVIDIA GeForce 9300
+NVIDIA GeForce 9300 GE/PCI/SSE2 supported 1 NVIDIA GeForce 9300
+NVIDIA GeForce 9300 GE/PCI/SSE2/3DNOW! supported 1 NVIDIA GeForce 9300
+NVIDIA GeForce 9300 GS/PCI/SSE2 supported 1 NVIDIA GeForce 9300
+NVIDIA GeForce 9300 GS/PCI/SSE2/3DNOW! supported 1 NVIDIA GeForce 9300
+NVIDIA GeForce 9300 SE/PCI/SSE2 supported 1 NVIDIA GeForce 9300
+NVIDIA GeForce 9300M supported 1 NVIDIA GeForce 9300M
+NVIDIA GeForce 9300M G/PCI/SSE2 supported 1 NVIDIA GeForce 9300M
+NVIDIA GeForce 9300M G/PCI/SSE2/3DNOW! supported 1 NVIDIA GeForce 9300M
+NVIDIA GeForce 9300M GS/PCI/SSE2 supported 1 NVIDIA GeForce 9300M
+NVIDIA GeForce 9300M GS/PCI/SSE2/3DNOW! supported 1 NVIDIA GeForce 9300M
+NVIDIA GeForce 9400 supported 1 NVIDIA GeForce 9400
+NVIDIA GeForce 9400 GT/PCI/SSE2 supported 1 NVIDIA GeForce 9400
+NVIDIA GeForce 9400 GT/PCI/SSE2/3DNOW! supported 1 NVIDIA GeForce 9400
+NVIDIA GeForce 9400/PCI/SSE2 supported 1 NVIDIA GeForce 9400
+NVIDIA GeForce 9400M supported 1 NVIDIA GeForce 9400M
+NVIDIA GeForce 9400M G/PCI/SSE2 supported 1 NVIDIA GeForce 9400M
+NVIDIA GeForce 9400M/PCI/SSE2 supported 1 NVIDIA GeForce 9400M
+NVIDIA GeForce 9500 supported 2 NVIDIA GeForce 9500
+NVIDIA GeForce 9500 GS/PCI/SSE2 supported 2 NVIDIA GeForce 9500
+NVIDIA GeForce 9500 GS/PCI/SSE2/3DNOW! supported 2 NVIDIA GeForce 9500
+NVIDIA GeForce 9500 GT/PCI/SSE2 supported 2 NVIDIA GeForce 9500
+NVIDIA GeForce 9500 GT/PCI/SSE2/3DNOW! supported 2 NVIDIA GeForce 9500
+NVIDIA GeForce 9500M supported 2 NVIDIA GeForce 9500M
+NVIDIA GeForce 9500M GS/PCI/SSE2 supported 2 NVIDIA GeForce 9500M
+NVIDIA GeForce 9600 supported 2 NVIDIA GeForce 9600
+NVIDIA GeForce 9600 GS/PCI/SSE2 supported 2 NVIDIA GeForce 9600
+NVIDIA GeForce 9600 GSO 512/PCI/SSE2 supported 2 NVIDIA GeForce 9600
+NVIDIA GeForce 9600 GSO/PCI/SSE2 supported 2 NVIDIA GeForce 9600
+NVIDIA GeForce 9600 GSO/PCI/SSE2/3DNOW! supported 2 NVIDIA GeForce 9600
+NVIDIA GeForce 9600 GT/PCI/SSE2 supported 2 NVIDIA GeForce 9600
+NVIDIA GeForce 9600 GT/PCI/SSE2/3DNOW! supported 2 NVIDIA GeForce 9600
+NVIDIA GeForce 9600M supported 3 NVIDIA GeForce 9600M
+NVIDIA GeForce 9600M GS/PCI/SSE2 supported 3 NVIDIA GeForce 9600M
+NVIDIA GeForce 9600M GT/PCI/SSE2 supported 3 NVIDIA GeForce 9600M
+NVIDIA GeForce 9650M GT/PCI/SSE2 supported 2 NVIDIA GeForce 9600
+NVIDIA GeForce 9700M supported 2 NVIDIA GeForce 9700M
+NVIDIA GeForce 9700M GT/PCI/SSE2 supported 2 NVIDIA GeForce 9700M
+NVIDIA GeForce 9700M GTS/PCI/SSE2 supported 2 NVIDIA GeForce 9700M
+NVIDIA GeForce 9800 supported 3 NVIDIA GeForce 9800
+NVIDIA GeForce 9800 GT/PCI/SSE2 supported 3 NVIDIA GeForce 9800
+NVIDIA GeForce 9800 GT/PCI/SSE2/3DNOW! supported 3 NVIDIA GeForce 9800
+NVIDIA GeForce 9800 GTX+/PCI/SSE2 supported 3 NVIDIA GeForce 9800
+NVIDIA GeForce 9800 GTX+/PCI/SSE2/3DNOW! supported 3 NVIDIA GeForce 9800
+NVIDIA GeForce 9800 GTX/9800 GTX+/PCI/SSE2 supported 3 NVIDIA GeForce 9800
+NVIDIA GeForce 9800 GTX/PCI/SSE2 supported 3 NVIDIA GeForce 9800
+NVIDIA GeForce 9800 GX2/PCI/SSE2 supported 3 NVIDIA GeForce 9800
+NVIDIA GeForce 9800M supported 3 NVIDIA GeForce 9800M
+NVIDIA GeForce 9800M GS/PCI/SSE2 supported 3 NVIDIA GeForce 9800M
+NVIDIA GeForce 9800M GT/PCI/SSE2 supported 3 NVIDIA GeForce 9800M
+NVIDIA GeForce 9800M GTS/PCI/SSE2 supported 3 NVIDIA GeForce 9800M
+NVIDIA GeForce FX 5100 supported 0 NVIDIA GeForce FX 5100
+NVIDIA GeForce FX 5100/AGP/SSE/3DNOW! supported 0 NVIDIA GeForce FX 5100
+NVIDIA GeForce FX 5200 supported 0 NVIDIA GeForce FX 5200
+NVIDIA GeForce FX 5200/AGP/SSE supported 0 NVIDIA GeForce FX 5200
+NVIDIA GeForce FX 5200/AGP/SSE/3DNOW! supported 0 NVIDIA GeForce FX 5200
+NVIDIA GeForce FX 5200/AGP/SSE2 supported 0 NVIDIA GeForce FX 5200
+NVIDIA GeForce FX 5200/AGP/SSE2/3DNOW! supported 0 NVIDIA GeForce FX 5200
+NVIDIA GeForce FX 5200/PCI/SSE2 supported 0 NVIDIA GeForce FX 5200
+NVIDIA GeForce FX 5200/PCI/SSE2/3DNOW! supported 0 NVIDIA GeForce FX 5200
+NVIDIA GeForce FX 5200LE/AGP/SSE2 supported 0 NVIDIA GeForce FX 5200
+NVIDIA GeForce FX 5500 supported 0 NVIDIA GeForce FX 5500
+NVIDIA GeForce FX 5500/AGP/SSE/3DNOW! supported 0 NVIDIA GeForce FX 5500
+NVIDIA GeForce FX 5500/AGP/SSE2 supported 0 NVIDIA GeForce FX 5500
+NVIDIA GeForce FX 5500/AGP/SSE2/3DNOW! supported 0 NVIDIA GeForce FX 5500
+NVIDIA GeForce FX 5500/PCI/SSE2 supported 0 NVIDIA GeForce FX 5500
+NVIDIA GeForce FX 5500/PCI/SSE2/3DNOW! supported 0 NVIDIA GeForce FX 5500
+NVIDIA GeForce FX 5600 supported 0 NVIDIA GeForce FX 5600
+NVIDIA GeForce FX 5600/AGP/SSE2 supported 0 NVIDIA GeForce FX 5600
+NVIDIA GeForce FX 5600/AGP/SSE2/3DNOW! supported 0 NVIDIA GeForce FX 5600
+NVIDIA GeForce FX 5600XT/AGP/SSE2/3DNOW! supported 0 NVIDIA GeForce FX 5600
+NVIDIA GeForce FX 5700 supported 1 NVIDIA GeForce FX 5700
+NVIDIA GeForce FX 5700/AGP/SSE/3DNOW! supported 1 NVIDIA GeForce FX 5700
+NVIDIA GeForce FX 5700LE/AGP/SSE supported 1 NVIDIA GeForce FX 5700
+NVIDIA GeForce FX 5700LE/AGP/SSE/3DNOW! supported 1 NVIDIA GeForce FX 5700
+NVIDIA GeForce FX 5800 supported 1 NVIDIA GeForce FX 5800
+NVIDIA GeForce FX 5900 supported 1 NVIDIA GeForce FX 5900
+NVIDIA GeForce FX 5900/AGP/SSE2 supported 1 NVIDIA GeForce FX 5900
+NVIDIA GeForce FX 5900XT/AGP/SSE2 supported 1 NVIDIA GeForce FX 5900
+NVIDIA GeForce FX Go5100 supported 0 NVIDIA GeForce FX Go5100
+NVIDIA GeForce FX Go5100/AGP/SSE2 supported 0 NVIDIA GeForce FX Go5100
+NVIDIA GeForce FX Go5200 supported 0 NVIDIA GeForce FX Go5200
+NVIDIA GeForce FX Go5200/AGP/SSE2 supported 0 NVIDIA GeForce FX Go5200
+NVIDIA GeForce FX Go5300 supported 0 NVIDIA GeForce FX Go5300
+NVIDIA GeForce FX Go5600 supported 0 NVIDIA GeForce FX Go5600
+NVIDIA GeForce FX Go5600/AGP/SSE2 supported 0 NVIDIA GeForce FX Go5600
+NVIDIA GeForce FX Go5650/AGP/SSE2 supported 0 NVIDIA GeForce FX Go5600
+NVIDIA GeForce FX Go5700 supported 1 NVIDIA GeForce FX Go5700
+NVIDIA GeForce FX Go5xxx/AGP/SSE2 supported 0 NVIDIA GeForce FX Go5xxx
+NVIDIA GeForce G 103M/PCI/SSE2 supported 0 NVIDIA G103M
+NVIDIA GeForce G 105M/PCI/SSE2 supported 0 NVIDIA G105M
+NVIDIA GeForce G 110M/PCI/SSE2 supported 0 NVIDIA G 110M
+NVIDIA GeForce G100/PCI/SSE2 supported 0 NVIDIA G100
+NVIDIA GeForce G100/PCI/SSE2/3DNOW! supported 0 NVIDIA G100
+NVIDIA GeForce G102M/PCI/SSE2 supported 0 NVIDIA G102M
+NVIDIA GeForce G105M/PCI/SSE2 supported 0 NVIDIA G105M
+NVIDIA GeForce G200/PCI/SSE2 supported 0 NVIDIA G 200
+NVIDIA GeForce G205M/PCI/SSE2 supported 0 NVIDIA G 205M
+NVIDIA GeForce G210/PCI/SSE2 supported 1 NVIDIA G 210
+NVIDIA GeForce G210/PCI/SSE2/3DNOW! supported 1 NVIDIA G 210
+NVIDIA GeForce G210M/PCI/SSE2 supported 1 NVIDIA G 210
+NVIDIA GeForce G310M/PCI/SSE2 supported 2 NVIDIA G 310M
+NVIDIA GeForce GT 120/PCI/SSE2 supported 2 NVIDIA GT 120M
+NVIDIA GeForce GT 120/PCI/SSE2/3DNOW! supported 2 NVIDIA GT 120M
+NVIDIA GeForce GT 120M/PCI/SSE2 supported 2 NVIDIA GT 120M
+NVIDIA GeForce GT 130M/PCI/SSE2 supported 2 NVIDIA GT 130M
+NVIDIA GeForce GT 140/PCI/SSE2 supported 2 NVIDIA GT 140M
+NVIDIA GeForce GT 220/PCI/SSE2 supported 2 NVIDIA GT 220M
+NVIDIA GeForce GT 220/PCI/SSE2/3DNOW! supported 2 NVIDIA GT 220M
+NVIDIA GeForce GT 220M/PCI/SSE2 supported 2 NVIDIA GT 220M
+NVIDIA GeForce GT 230/PCI/SSE2 supported 2 NVIDIA GT 230M
+NVIDIA GeForce GT 230M/PCI/SSE2 supported 2 NVIDIA GT 230M
+NVIDIA GeForce GT 240 supported 2 NVIDIA GT 240M
+NVIDIA GeForce GT 240/PCI/SSE2 supported 2 NVIDIA GT 240M
+NVIDIA GeForce GT 240/PCI/SSE2/3DNOW! supported 2 NVIDIA GT 240M
+NVIDIA GeForce GT 240M/PCI/SSE2 supported 2 NVIDIA GT 240M
+NVIDIA GeForce GT 320/PCI/SSE2 supported 2 NVIDIA GT 320M
+NVIDIA GeForce GT 320M/PCI/SSE2 supported 2 NVIDIA GT 320M
+NVIDIA GeForce GT 325M/PCI/SSE2 supported 0 NVIDIA GT 325M
+NVIDIA GeForce GT 330/PCI/SSE2 supported 3 NVIDIA GT 330M
+NVIDIA GeForce GT 330/PCI/SSE2/3DNOW! supported 3 NVIDIA GT 330M
+NVIDIA GeForce GT 330M/PCI/SSE2 supported 3 NVIDIA GT 330M
+NVIDIA GeForce GT 335M/PCI/SSE2 supported 1 NVIDIA GT 335M
+NVIDIA GeForce GT 340/PCI/SSE2 supported 2 NVIDIA GT 340M
+NVIDIA GeForce GT 340/PCI/SSE2/3DNOW! supported 2 NVIDIA GT 340M
+NVIDIA GeForce GT 415M/PCI/SSE2 supported 2 NVIDIA GT 415M
+NVIDIA GeForce GT 420/PCI/SSE2 supported 2 NVIDIA GT 420M
+NVIDIA GeForce GT 420M/PCI/SSE2 supported 2 NVIDIA GT 420M
+NVIDIA GeForce GT 425M/PCI/SSE2 supported 3 NVIDIA GT 425M
+NVIDIA GeForce GT 430/PCI/SSE2 supported 3 NVIDIA GT 430M
+NVIDIA GeForce GT 430/PCI/SSE2/3DNOW! supported 3 NVIDIA GT 430M
+NVIDIA GeForce GT 435M/PCI/SSE2 supported 3 NVIDIA GT 435M
+NVIDIA GeForce GT 440/PCI/SSE2 supported 3 NVIDIA GT 440M
+NVIDIA GeForce GT 440/PCI/SSE2/3DNOW! supported 3 NVIDIA GT 440M
+NVIDIA GeForce GT 445M/PCI/SSE2 supported 3 NVIDIA GT 445M
+NVIDIA GeForce GT 520M/PCI/SSE2 supported 3 NVIDIA GT 520M
+NVIDIA GeForce GT 525M/PCI/SSE2 supported 3 NVIDIA GT 525M
+NVIDIA GeForce GT 540M/PCI/SSE2 supported 3 NVIDIA GT 540M
+NVIDIA GeForce GT 550M/PCI/SSE2 supported 3 NVIDIA GT 550M
+NVIDIA GeForce GT 555M/PCI/SSE2 supported 3 NVIDIA GT 555M
+NVIDIA GeForce GTS 150/PCI/SSE2 supported 2 NVIDIA GT 150M
+NVIDIA GeForce GTS 160M/PCI/SSE2 supported 2 NVIDIA GTS 160M
+NVIDIA GeForce GTS 240/PCI/SSE2 supported 3 NVIDIA GTS 240
+NVIDIA GeForce GTS 250/PCI/SSE2 supported 3 NVIDIA GTS 250
+NVIDIA GeForce GTS 250/PCI/SSE2/3DNOW! supported 3 NVIDIA GTS 250
+NVIDIA GeForce GTS 250M/PCI/SSE2 supported 3 NVIDIA GTS 250
+NVIDIA GeForce GTS 350M/PCI/SSE2 supported 3 NVIDIA GTS 350M
+NVIDIA GeForce GTS 360M/PCI/SSE2 supported 3 NVIDIA GTS 360M
+NVIDIA GeForce GTS 450/PCI/SSE2 supported 3 NVIDIA GTS 450
+NVIDIA GeForce GTS 450/PCI/SSE2/3DNOW! supported 3 NVIDIA GTS 450
+NVIDIA GeForce GTS 455/PCI/SSE2 supported 3 NVIDIA GTS 450
+NVIDIA GeForce GTX 260/PCI/SSE2 supported 3 NVIDIA GTX 260
+NVIDIA GeForce GTX 260/PCI/SSE2/3DNOW! supported 3 NVIDIA GTX 260
+NVIDIA GeForce GTX 260M/PCI/SSE2 supported 3 NVIDIA GTX 260
+NVIDIA GeForce GTX 275/PCI/SSE2 supported 3 NVIDIA GTX 275
+NVIDIA GeForce GTX 280 supported 3 NVIDIA GTX 280
+NVIDIA GeForce GTX 280/PCI/SSE2 supported 3 NVIDIA GTX 280
+NVIDIA GeForce GTX 280M/PCI/SSE2 supported 3 NVIDIA GTX 280
+NVIDIA GeForce GTX 285/PCI/SSE2 supported 3 NVIDIA GTX 285
+NVIDIA GeForce GTX 295/PCI/SSE2 supported 3 NVIDIA GTX 295
+NVIDIA GeForce GTX 460 SE/PCI/SSE2 supported 3 NVIDIA GTX 460
+NVIDIA GeForce GTX 460 SE/PCI/SSE2/3DNOW! supported 3 NVIDIA GTX 460
+NVIDIA GeForce GTX 460/PCI/SSE2 supported 3 NVIDIA GTX 460
+NVIDIA GeForce GTX 460/PCI/SSE2/3DNOW! supported 3 NVIDIA GTX 460
+NVIDIA GeForce GTX 460M/PCI/SSE2 supported 3 NVIDIA GTX 460M
+NVIDIA GeForce GTX 465/PCI/SSE2 supported 3 NVIDIA GTX 465
+NVIDIA GeForce GTX 465/PCI/SSE2/3DNOW! supported 3 NVIDIA GTX 465
+NVIDIA GeForce GTX 470/PCI/SSE2 supported 3 NVIDIA GTX 470
+NVIDIA GeForce GTX 470/PCI/SSE2/3DNOW! supported 3 NVIDIA GTX 470
+NVIDIA GeForce GTX 480/PCI/SSE2 supported 3 NVIDIA GTX 480
+NVIDIA GeForce GTX 550 Ti/PCI/SSE2 supported 3 NVIDIA GTX 550
+NVIDIA GeForce GTX 550 Ti/PCI/SSE2/3DNOW! supported 3 NVIDIA GTX 550
+NVIDIA GeForce GTX 560 Ti/PCI/SSE2 supported 3 NVIDIA GTX 560
+NVIDIA GeForce GTX 560 Ti/PCI/SSE2/3DNOW! supported 3 NVIDIA GTX 560
+NVIDIA GeForce GTX 560/PCI/SSE2 supported 3 NVIDIA GTX 560
+NVIDIA GeForce GTX 570/PCI/SSE2 supported 3 NVIDIA GTX 570
+NVIDIA GeForce GTX 570/PCI/SSE2/3DNOW! supported 3 NVIDIA GTX 570
+NVIDIA GeForce GTX 580/PCI/SSE2 supported 3 NVIDIA GTX 580
+NVIDIA GeForce GTX 580/PCI/SSE2/3DNOW! supported 3 NVIDIA GTX 580
+NVIDIA GeForce GTX 580M/PCI/SSE2 supported 3 NVIDIA GTX 580M
+NVIDIA GeForce GTX 590/PCI/SSE2 supported 3 NVIDIA GTX 590
+NVIDIA GeForce Go 6 supported 1 NVIDIA GeForce Go 6
+NVIDIA GeForce Go 6100 supported 0 NVIDIA GeForce Go 6100
+NVIDIA GeForce Go 6100/PCI/SSE2 supported 0 NVIDIA GeForce Go 6100
+NVIDIA GeForce Go 6100/PCI/SSE2/3DNOW! supported 0 NVIDIA GeForce Go 6100
+NVIDIA GeForce Go 6150/PCI/SSE2 supported 0 NVIDIA GeForce Go 6100
+NVIDIA GeForce Go 6150/PCI/SSE2/3DNOW! supported 0 NVIDIA GeForce Go 6100
+NVIDIA GeForce Go 6200 supported 0 NVIDIA GeForce Go 6200
+NVIDIA GeForce Go 6200/PCI/SSE2 supported 0 NVIDIA GeForce Go 6200
+NVIDIA GeForce Go 6400 supported 1 NVIDIA GeForce Go 6400
+NVIDIA GeForce Go 6400/PCI/SSE2 supported 1 NVIDIA GeForce Go 6400
+NVIDIA GeForce Go 6600 supported 1 NVIDIA GeForce Go 6600
+NVIDIA GeForce Go 6600/PCI/SSE2 supported 1 NVIDIA GeForce Go 6600
+NVIDIA GeForce Go 6800 supported 1 NVIDIA GeForce Go 6800
+NVIDIA GeForce Go 6800 Ultra/PCI/SSE2 supported 1 NVIDIA GeForce Go 6800
+NVIDIA GeForce Go 6800/PCI/SSE2 supported 1 NVIDIA GeForce Go 6800
+NVIDIA GeForce Go 7200 supported 1 NVIDIA GeForce Go 7200
+NVIDIA GeForce Go 7200/PCI/SSE2 supported 1 NVIDIA GeForce Go 7200
+NVIDIA GeForce Go 7200/PCI/SSE2/3DNOW! supported 1 NVIDIA GeForce Go 7200
+NVIDIA GeForce Go 7300 supported 1 NVIDIA GeForce Go 7300
+NVIDIA GeForce Go 7300/PCI/SSE2 supported 1 NVIDIA GeForce Go 7300
+NVIDIA GeForce Go 7300/PCI/SSE2/3DNOW! supported 1 NVIDIA GeForce Go 7300
+NVIDIA GeForce Go 7400 supported 1 NVIDIA GeForce Go 7400
+NVIDIA GeForce Go 7400/PCI/SSE2 supported 1 NVIDIA GeForce Go 7400
+NVIDIA GeForce Go 7400/PCI/SSE2/3DNOW! supported 1 NVIDIA GeForce Go 7400
+NVIDIA GeForce Go 7600 supported 2 NVIDIA GeForce Go 7600
+NVIDIA GeForce Go 7600/PCI/SSE2 supported 2 NVIDIA GeForce Go 7600
+NVIDIA GeForce Go 7600/PCI/SSE2/3DNOW! supported 2 NVIDIA GeForce Go 7600
+NVIDIA GeForce Go 7700 supported 2 NVIDIA GeForce Go 7700
+NVIDIA GeForce Go 7800 supported 2 NVIDIA GeForce Go 7800
+NVIDIA GeForce Go 7800 GTX/PCI/SSE2 supported 2 NVIDIA GeForce Go 7800
+NVIDIA GeForce Go 7900 supported 2 NVIDIA GeForce Go 7900
+NVIDIA GeForce Go 7900 GS/PCI/SSE2 supported 2 NVIDIA GeForce Go 7900
+NVIDIA GeForce Go 7900 GTX/PCI/SSE2 supported 2 NVIDIA GeForce Go 7900
+NVIDIA GeForce Go 7950 GTX/PCI/SSE2 supported 2 NVIDIA GeForce Go 7900
+NVIDIA GeForce PCX supported 0 NVIDIA GeForce PCX
+NVIDIA GeForce2 GTS/AGP/SSE supported 0 NVIDIA GeForce 2
+NVIDIA GeForce2 MX/AGP/3DNOW! supported 0 NVIDIA GeForce 2
+NVIDIA GeForce2 MX/AGP/SSE/3DNOW! supported 0 NVIDIA GeForce 2
+NVIDIA GeForce2 MX/AGP/SSE2 supported 0 NVIDIA GeForce 2
+NVIDIA GeForce2 MX/PCI/SSE2 supported 0 NVIDIA GeForce 2
+NVIDIA GeForce3/AGP/SSE/3DNOW! supported 0 NVIDIA GeForce 3
+NVIDIA GeForce3/AGP/SSE2 supported 0 NVIDIA GeForce 3
+NVIDIA GeForce4 420 Go 32M/AGP/SSE2 supported 0 NVIDIA GeForce 4
+NVIDIA GeForce4 420 Go 32M/AGP/SSE2/3DNOW! supported 0 NVIDIA GeForce 4
+NVIDIA GeForce4 420 Go 32M/PCI/SSE2/3DNOW! supported 0 NVIDIA GeForce 4
+NVIDIA GeForce4 440 Go 64M/AGP/SSE2/3DNOW! supported 0 NVIDIA GeForce 4
+NVIDIA GeForce4 460 Go/AGP/SSE2 supported 0 NVIDIA GeForce 4
+NVIDIA GeForce4 MX 4000/AGP/SSE/3DNOW! supported 0 NVIDIA GeForce 4
+NVIDIA GeForce4 MX 4000/AGP/SSE2 supported 0 NVIDIA GeForce 4
+NVIDIA GeForce4 MX 4000/PCI/3DNOW! supported 0 NVIDIA GeForce 4
+NVIDIA GeForce4 MX 4000/PCI/SSE/3DNOW! supported 0 NVIDIA GeForce 4
+NVIDIA GeForce4 MX 4000/PCI/SSE2 supported 0 NVIDIA GeForce 4
+NVIDIA GeForce4 MX 420/AGP/SSE/3DNOW! supported 0 NVIDIA GeForce 4
+NVIDIA GeForce4 MX 420/AGP/SSE2 supported 0 NVIDIA GeForce 4
+NVIDIA GeForce4 MX 440 with AGP8X/AGP/SSE2 supported 0 NVIDIA GeForce 4
+NVIDIA GeForce4 MX 440/AGP/SSE2 supported 0 NVIDIA GeForce 4
+NVIDIA GeForce4 MX 440/AGP/SSE2/3DNOW! supported 0 NVIDIA GeForce 4
+NVIDIA GeForce4 MX 440SE with AGP8X/AGP/SSE2 supported 0 NVIDIA GeForce 4
+NVIDIA GeForce4 MX Integrated GPU/AGP/SSE/3DNOW! supported 0 NVIDIA GeForce 4
+NVIDIA GeForce4 Ti 4200 with AGP8X/AGP/SSE supported 0 NVIDIA GeForce 4
+NVIDIA GeForce4 Ti 4200/AGP/SSE/3DNOW! supported 0 NVIDIA GeForce 4
+NVIDIA GeForce4 Ti 4400/AGP/SSE2 supported 0 NVIDIA GeForce 4
+NVIDIA Generic UNRECOGNIZED
+NVIDIA ION LE/PCI/SSE2 supported 2 NVIDIA ION
+NVIDIA ION/PCI/SSE2 supported 2 NVIDIA ION
+NVIDIA ION/PCI/SSE2/3DNOW! supported 2 NVIDIA ION
+NVIDIA MCP61/PCI/SSE2 UNRECOGNIZED
+NVIDIA MCP61/PCI/SSE2/3DNOW! UNRECOGNIZED
+NVIDIA MCP73/PCI/SSE2 UNRECOGNIZED
+NVIDIA MCP79MH/PCI/SSE2 UNRECOGNIZED
+NVIDIA MCP79MX/PCI/SSE2 UNRECOGNIZED
+NVIDIA MCP7A-O/PCI/SSE2 UNRECOGNIZED
+NVIDIA MCP7A-S/PCI/SSE2 UNRECOGNIZED
+NVIDIA MCP89-EPT/PCI/SSE2 UNRECOGNIZED
+NVIDIA N10M-GE1/PCI/SSE2 UNRECOGNIZED
+NVIDIA N10P-GE1/PCI/SSE2 UNRECOGNIZED
+NVIDIA N10P-GV2/PCI/SSE2 UNRECOGNIZED
+NVIDIA N11M-GE1/PCI/SSE2 UNRECOGNIZED
+NVIDIA N11M-GE2/PCI/SSE2 UNRECOGNIZED
+NVIDIA N12E-GS-A1/PCI/SSE2 UNRECOGNIZED
+NVIDIA NB9M-GE/PCI/SSE2 UNRECOGNIZED
+NVIDIA NB9M-GE1/PCI/SSE2 UNRECOGNIZED
+NVIDIA NB9M-GS/PCI/SSE2 UNRECOGNIZED
+NVIDIA NB9M-NS/PCI/SSE2 UNRECOGNIZED
+NVIDIA NB9P-GE1/PCI/SSE2 UNRECOGNIZED
+NVIDIA NB9P-GS/PCI/SSE2 UNRECOGNIZED
+NVIDIA NV17/AGP/3DNOW! UNRECOGNIZED
+NVIDIA NV17/AGP/SSE2 UNRECOGNIZED
+NVIDIA NV34 supported 0 NVIDIA NV34
+NVIDIA NV35 supported 0 NVIDIA NV35
+NVIDIA NV36/AGP/SSE/3DNOW! UNRECOGNIZED
+NVIDIA NV36/AGP/SSE2 UNRECOGNIZED
+NVIDIA NV41/PCI/SSE2 UNRECOGNIZED
+NVIDIA NV43 supported 1 NVIDIA NV43
+NVIDIA NV44 supported 1 NVIDIA NV44
+NVIDIA NVIDIA GeForce 210 OpenGL Engine supported 2 NVIDIA 210
+NVIDIA NVIDIA GeForce 320M OpenGL Engine supported 2 NVIDIA 320M
+NVIDIA NVIDIA GeForce 7300 GT OpenGL Engine supported 1 NVIDIA GeForce 7300
+NVIDIA NVIDIA GeForce 7600 GT OpenGL Engine supported 2 NVIDIA GeForce 7600
+NVIDIA NVIDIA GeForce 8600M GT OpenGL Engine supported 1 NVIDIA GeForce 8600M
+NVIDIA NVIDIA GeForce 8800 GS OpenGL Engine supported 3 NVIDIA GeForce 8800
+NVIDIA NVIDIA GeForce 8800 GT OpenGL Engine supported 3 NVIDIA GeForce 8800
+NVIDIA NVIDIA GeForce 9400 OpenGL Engine supported 1 NVIDIA GeForce 9400
+NVIDIA NVIDIA GeForce 9400M OpenGL Engine supported 1 NVIDIA GeForce 9400M
+NVIDIA NVIDIA GeForce 9500 GT OpenGL Engine supported 2 NVIDIA GeForce 9500
+NVIDIA NVIDIA GeForce 9600M GT OpenGL Engine supported 3 NVIDIA GeForce 9600M
+NVIDIA NVIDIA GeForce GT 120 OpenGL Engine supported 2 NVIDIA GT 120M
+NVIDIA NVIDIA GeForce GT 130 OpenGL Engine supported 2 NVIDIA GT 130M
+NVIDIA NVIDIA GeForce GT 220 OpenGL Engine supported 2 NVIDIA GT 220M
+NVIDIA NVIDIA GeForce GT 230M OpenGL Engine supported 2 NVIDIA GT 230M
+NVIDIA NVIDIA GeForce GT 240M OpenGL Engine supported 2 NVIDIA GT 240M
+NVIDIA NVIDIA GeForce GT 330M OpenGL Engine supported 3 NVIDIA GT 330M
+NVIDIA NVIDIA GeForce GT 420M OpenGL Engine supported 2 NVIDIA GT 420M
+NVIDIA NVIDIA GeForce GT 425M OpenGL Engine supported 3 NVIDIA GT 425M
+NVIDIA NVIDIA GeForce GT 430 OpenGL Engine supported 3 NVIDIA GT 430M
+NVIDIA NVIDIA GeForce GT 440 OpenGL Engine supported 3 NVIDIA GT 440M
+NVIDIA NVIDIA GeForce GT 540M OpenGL Engine supported 3 NVIDIA GT 540M
+NVIDIA NVIDIA GeForce GTS 240 OpenGL Engine supported 3 NVIDIA GTS 240
+NVIDIA NVIDIA GeForce GTS 250 OpenGL Engine supported 3 NVIDIA GTS 250
+NVIDIA NVIDIA GeForce GTS 450 OpenGL Engine supported 3 NVIDIA GTS 450
+NVIDIA NVIDIA GeForce GTX 285 OpenGL Engine supported 3 NVIDIA GTX 285
+NVIDIA NVIDIA GeForce GTX 460 OpenGL Engine supported 3 NVIDIA GTX 460
+NVIDIA NVIDIA GeForce GTX 460M OpenGL Engine supported 3 NVIDIA GTX 460M
+NVIDIA NVIDIA GeForce GTX 465 OpenGL Engine supported 3 NVIDIA GTX 465
+NVIDIA NVIDIA GeForce GTX 470 OpenGL Engine supported 3 NVIDIA GTX 470
+NVIDIA NVIDIA GeForce GTX 480 OpenGL Engine supported 3 NVIDIA GTX 480
+NVIDIA NVIDIA GeForce Pre-Release ION OpenGL Engine UNRECOGNIZED
+NVIDIA NVIDIA GeForce4 OpenGL Engine supported 0 NVIDIA GeForce 4
+NVIDIA NVIDIA NV34MAP OpenGL Engine supported 0 NVIDIA NV34
+NVIDIA NVIDIA Quadro 4000 OpenGL Engine supported 3 NVIDIA Quadro 4000
+NVIDIA NVIDIA Quadro FX 4800 OpenGL Engine supported 3 NVIDIA Quadro FX 4800
+NVIDIA NVS 2100M/PCI/SSE2 supported 2 NVIDIA Quadro NVS 2100M
+NVIDIA NVS 300/PCI/SSE2 supported 0 NVIDIA Quadro NVS
+NVIDIA NVS 3100M/PCI/SSE2 supported 2 NVIDIA Quadro NVS 3100M
+NVIDIA NVS 4100/PCI/SSE2/3DNOW! supported 0 NVIDIA Quadro NVS
+NVIDIA NVS 4200M/PCI/SSE2 supported 2 NVIDIA Quadro NVS 4200M
+NVIDIA NVS 5100M/PCI/SSE2 supported 2 NVIDIA Quadro NVS 5100M
+NVIDIA PCI UNRECOGNIZED
+NVIDIA Quadro 2000/PCI/SSE2 supported 3 NVIDIA Quadro 2000 M/D
+NVIDIA Quadro 4000 supported 3 NVIDIA Quadro 4000
+NVIDIA Quadro 4000 OpenGL Engine supported 3 NVIDIA Quadro 4000
+NVIDIA Quadro 4000/PCI/SSE2 supported 3 NVIDIA Quadro 4000
+NVIDIA Quadro 5000/PCI/SSE2 supported 3 NVIDIA Quadro 50x0 M
+NVIDIA Quadro 5000M/PCI/SSE2 supported 3 NVIDIA Quadro 50x0 M
+NVIDIA Quadro 600 supported 2 NVIDIA Quadro 600
+NVIDIA Quadro 600/PCI/SSE2 supported 2 NVIDIA Quadro 600
+NVIDIA Quadro 600/PCI/SSE2/3DNOW! supported 2 NVIDIA Quadro 600
+NVIDIA Quadro 6000 supported 3 NVIDIA Quadro 6000
+NVIDIA Quadro 6000/PCI/SSE2 supported 3 NVIDIA Quadro 6000
+NVIDIA Quadro CX/PCI/SSE2 UNRECOGNIZED
+NVIDIA Quadro DCC supported 0 NVIDIA Quadro DCC
+NVIDIA Quadro FX supported 1 NVIDIA Quadro FX
+NVIDIA Quadro FX 1100/AGP/SSE2 supported 1 NVIDIA Quadro FX
+NVIDIA Quadro FX 1400/PCI/SSE2 supported 2 NVIDIA Quadro 400
+NVIDIA Quadro FX 1500 supported 1 NVIDIA Quadro FX
+NVIDIA Quadro FX 1500M/PCI/SSE2 supported 1 NVIDIA Quadro FX 1500M
+NVIDIA Quadro FX 1600M/PCI/SSE2 supported 2 NVIDIA Quadro 600
+NVIDIA Quadro FX 1700 supported 1 NVIDIA Quadro FX
+NVIDIA Quadro FX 1700M/PCI/SSE2 supported 1 NVIDIA Quadro FX
+NVIDIA Quadro FX 1800 supported 1 NVIDIA Quadro FX
+NVIDIA Quadro FX 1800/PCI/SSE2 supported 1 NVIDIA Quadro FX
+NVIDIA Quadro FX 1800M/PCI/SSE2 supported 1 NVIDIA Quadro FX
+NVIDIA Quadro FX 2500M/PCI/SSE2 supported 2 NVIDIA Quadro FX 2500M
+NVIDIA Quadro FX 2700M/PCI/SSE2 supported 3 NVIDIA Quadro FX 2700M
+NVIDIA Quadro FX 2800M/PCI/SSE2 supported 3 NVIDIA Quadro FX 2800M
+NVIDIA Quadro FX 3400 supported 2 NVIDIA Quadro 400
+NVIDIA Quadro FX 3450 supported 1 NVIDIA Quadro FX
+NVIDIA Quadro FX 3450/4000 SDI/PCI/SSE2 supported 2 NVIDIA Quadro 400
+NVIDIA Quadro FX 3500 supported 2 NVIDIA Quadro FX 3500
+NVIDIA Quadro FX 3500M/PCI/SSE2 supported 2 NVIDIA Quadro FX 3500
+NVIDIA Quadro FX 360M/PCI/SSE2 supported 1 NVIDIA Quadro FX
+NVIDIA Quadro FX 370 supported 1 NVIDIA Quadro FX
+NVIDIA Quadro FX 370/PCI/SSE2 supported 1 NVIDIA Quadro FX
+NVIDIA Quadro FX 3700 supported 3 NVIDIA Quadro FX 3700
+NVIDIA Quadro FX 3700M/PCI/SSE2 supported 3 NVIDIA Quadro FX 3700
+NVIDIA Quadro FX 370M/PCI/SSE2 supported 1 NVIDIA Quadro FX
+NVIDIA Quadro FX 3800 supported 3 NVIDIA Quadro FX 3800
+NVIDIA Quadro FX 3800M/PCI/SSE2 supported 3 NVIDIA Quadro FX 3800
+NVIDIA Quadro FX 4500 supported 3 NVIDIA Quadro FX 4500
+NVIDIA Quadro FX 4600 supported 2 NVIDIA Quadro 600
+NVIDIA Quadro FX 4800 supported 3 NVIDIA Quadro FX 4800
+NVIDIA Quadro FX 4800/PCI/SSE2 supported 3 NVIDIA Quadro FX 4800
+NVIDIA Quadro FX 560 supported 1 NVIDIA Quadro FX
+NVIDIA Quadro FX 5600 supported 2 NVIDIA Quadro 600
+NVIDIA Quadro FX 570 supported 1 NVIDIA Quadro FX
+NVIDIA Quadro FX 570/PCI/SSE2 supported 1 NVIDIA Quadro FX
+NVIDIA Quadro FX 570M/PCI/SSE2 supported 1 NVIDIA Quadro FX
+NVIDIA Quadro FX 580/PCI/SSE2 supported 1 NVIDIA Quadro FX
+NVIDIA Quadro FX 770M/PCI/SSE2 supported 2 NVIDIA Quadro FX 770M
+NVIDIA Quadro FX 880M supported 3 NVIDIA Quadro FX 880M
+NVIDIA Quadro FX 880M/PCI/SSE2 supported 3 NVIDIA Quadro FX 880M
+NVIDIA Quadro FX Go700/AGP/SSE2 supported 1 NVIDIA Quadro FX
+NVIDIA Quadro NVS supported 0 NVIDIA Quadro NVS
+NVIDIA Quadro NVS 110M/PCI/SSE2 supported 0 NVIDIA Quadro NVS 1xxM
+NVIDIA Quadro NVS 130M/PCI/SSE2 supported 0 NVIDIA Quadro NVS 1xxM
+NVIDIA Quadro NVS 135M/PCI/SSE2 supported 0 NVIDIA Quadro NVS 1xxM
+NVIDIA Quadro NVS 140M/PCI/SSE2 supported 0 NVIDIA Quadro NVS 1xxM
+NVIDIA Quadro NVS 150M/PCI/SSE2 supported 0 NVIDIA Quadro NVS 1xxM
+NVIDIA Quadro NVS 160M/PCI/SSE2 supported 0 NVIDIA Quadro NVS 1xxM
+NVIDIA Quadro NVS 210S/PCI/SSE2/3DNOW! supported 0 NVIDIA Quadro NVS
+NVIDIA Quadro NVS 285/PCI/SSE2 supported 0 NVIDIA Quadro NVS
+NVIDIA Quadro NVS 290/PCI/SSE2 supported 0 NVIDIA Quadro NVS
+NVIDIA Quadro NVS 295/PCI/SSE2 supported 0 NVIDIA Quadro NVS
+NVIDIA Quadro NVS 320M/PCI/SSE2 supported 2 NVIDIA Quadro NVS 320M
+NVIDIA Quadro NVS 55/280 PCI/PCI/SSE2 supported 0 NVIDIA Quadro NVS
+NVIDIA Quadro NVS/PCI/SSE2 supported 0 NVIDIA Quadro NVS
+NVIDIA Quadro PCI-E Series/PCI/SSE2/3DNOW! UNRECOGNIZED
+NVIDIA Quadro VX 200/PCI/SSE2 UNRECOGNIZED
+NVIDIA Quadro/AGP/SSE2 UNRECOGNIZED
+NVIDIA Quadro2 supported 0 NVIDIA Quadro2
+NVIDIA Quadro4 supported 0 NVIDIA Quadro4
+NVIDIA RIVA TNT unsupported 0 NVIDIA RIVA TNT
+NVIDIA RIVA TNT2/AGP/SSE2 unsupported 0 NVIDIA RIVA TNT
+NVIDIA RIVA TNT2/PCI/3DNOW! unsupported 0 NVIDIA RIVA TNT
+NVIDIA nForce unsupported 0 NVIDIA nForce
+NVIDIA unknown board/AGP/SSE2 UNRECOGNIZED
+NVIDIA unknown board/PCI/SSE2 UNRECOGNIZED
+NVIDIA unknown board/PCI/SSE2/3DNOW! UNRECOGNIZED
+Parallels and ATI Technologies Inc. Parallels using ATI Radeon HD 5670 OpenGL Engine supported 3 ATI Radeon HD 5600
+Parallels and ATI Technologies Inc. Parallels using ATI Radeon HD 5750 OpenGL Engine supported 3 ATI Radeon HD 5700
+Parallels and ATI Technologies Inc. Parallels using ATI Radeon HD 5770 OpenGL Engine supported 3 ATI Radeon HD 5700
+Parallels and ATI Technologies Inc. Parallels using ATI Radeon HD 6490M OpenGL Engine supported 3 ATI Radeon HD 6400
+Parallels and ATI Technologies Inc. Parallels using ATI Radeon HD 6750M OpenGL Engine supported 3 ATI Radeon HD 6700
+Parallels and Intel Inc. 3D-Analyze v2.3 - http://www.tommti-systems.com UNRECOGNIZED
+Parallels and Intel Inc. Parallels using Intel HD Graphics 3000 OpenGL Engine supported 2 Intel HD Graphics
+Parallels and NVIDIA Parallels using NVIDIA GeForce 320M OpenGL Engine supported 2 NVIDIA 320M
+Parallels and NVIDIA Parallels using NVIDIA GeForce 9400 OpenGL Engine supported 1 NVIDIA GeForce 9400
+Parallels and NVIDIA Parallels using NVIDIA GeForce GT 120 OpenGL Engine supported 2 NVIDIA GT 120M
+Parallels and NVIDIA Parallels using NVIDIA GeForce GT 330M OpenGL Engine supported 3 NVIDIA GT 330M
+Radeon RV350 on Gallium supported 0 ATI RV350 (9600)
+S3 UNRECOGNIZED
+S3 Graphics VIA/S3G UniChrome IGP/MMX/K3D unsupported 0 S3
+S3 Graphics VIA/S3G UniChrome Pro IGP/MMX/SSE unsupported 0 S3
+S3 Graphics, Incorporated ProSavage/Twister unsupported 0 S3
+S3 Graphics, Incorporated S3 Graphics Chrome9 HC unsupported 0 S3
+S3 Graphics, Incorporated S3 Graphics DeltaChrome unsupported 0 S3
+S3 Graphics, Incorporated VIA Chrome9 HC IGP unsupported 0 S3
+SiS unsupported 0 SiS
+SiS 661 VGA unsupported 0 SiS
+SiS 662 VGA unsupported 0 SiS
+SiS 741 VGA unsupported 0 SiS
+SiS 760 VGA unsupported 0 SiS
+SiS 761GX VGA unsupported 0 SiS
+SiS Mirage Graphics3 unsupported 0 SiS
+Trident unsupported 0 Trident
+Tungsten Graphics unsupported 0 Tungsten Graphics
+Tungsten Graphics, Inc Mesa DRI 865G GEM 20091221 2009Q4 x86/MMX/SSE2 unsupported 0 Mesa
+Tungsten Graphics, Inc Mesa DRI 865G GEM 20100330 DEVELOPMENT x86/MMX/SSE2 unsupported 0 Mesa
+Tungsten Graphics, Inc Mesa DRI 915G GEM 20091221 2009Q4 x86/MMX/SSE2 unsupported 0 Mesa
+Tungsten Graphics, Inc Mesa DRI 915G GEM 20100330 DEVELOPMENT x86/MMX/SSE2 unsupported 0 Mesa
+Tungsten Graphics, Inc Mesa DRI 915GM GEM 20090712 2009Q2 RC3 x86/MMX/SSE2 unsupported 0 Mesa
+Tungsten Graphics, Inc Mesa DRI 915GM GEM 20091221 2009Q4 x86/MMX/SSE2 unsupported 0 Mesa
+Tungsten Graphics, Inc Mesa DRI 915GM GEM 20100330 DEVELOPMENT x86/MMX/SSE2 unsupported 0 Mesa
+Tungsten Graphics, Inc Mesa DRI 945G unsupported 0 Mesa
+Tungsten Graphics, Inc Mesa DRI 945G GEM 20091221 2009Q4 x86/MMX/SSE2 unsupported 0 Mesa
+Tungsten Graphics, Inc Mesa DRI 945G GEM 20100330 DEVELOPMENT unsupported 0 Mesa
+Tungsten Graphics, Inc Mesa DRI 945G GEM 20100330 DEVELOPMENT x86/MMX/SSE2 unsupported 0 Mesa
+Tungsten Graphics, Inc Mesa DRI 945GM GEM 20090712 2009Q2 RC3 x86/MMX/SSE2 unsupported 0 Mesa
+Tungsten Graphics, Inc Mesa DRI 945GM GEM 20091221 2009Q4 x86/MMX/SSE2 unsupported 0 Mesa
+Tungsten Graphics, Inc Mesa DRI 945GM GEM 20100328 2010Q1 x86/MMX/SSE2 unsupported 0 Mesa
+Tungsten Graphics, Inc Mesa DRI 945GM GEM 20100330 DEVELOPMENT x86/MMX/SSE2 unsupported 0 Mesa
+Tungsten Graphics, Inc Mesa DRI 945GME x86/MMX/SSE2 unsupported 0 Mesa
+Tungsten Graphics, Inc Mesa DRI 945GME 20061017 unsupported 0 Mesa
+Tungsten Graphics, Inc Mesa DRI 945GME GEM 20090712 2009Q2 RC3 x86/MMX/SSE2 unsupported 0 Mesa
+Tungsten Graphics, Inc Mesa DRI 945GME GEM 20091221 2009Q4 x86/MMX/SSE2 unsupported 0 Mesa
+Tungsten Graphics, Inc Mesa DRI 945GME GEM 20100330 DEVELOPMENT x86/MMX/SSE2 unsupported 0 Mesa
+Tungsten Graphics, Inc Mesa DRI 965GM GEM 20090326 2009Q1 RC2 x86/MMX/SSE2 unsupported 0 Mesa
+Tungsten Graphics, Inc Mesa DRI 965GM GEM 20090712 2009Q2 RC3 x86/MMX/SSE2 unsupported 0 Mesa
+Tungsten Graphics, Inc Mesa DRI 965GM GEM 20091221 2009Q4 x86/MMX/SSE2 unsupported 0 Mesa
+Tungsten Graphics, Inc Mesa DRI 965GM GEM 20100330 DEVELOPMENT x86/MMX/SSE2 unsupported 0 Mesa
+Tungsten Graphics, Inc Mesa DRI G33 20061017 x86/MMX/SSE2 unsupported 0 Mesa
+Tungsten Graphics, Inc Mesa DRI G33 GEM 20090712 2009Q2 RC3 x86/MMX/SSE2 unsupported 0 Mesa
+Tungsten Graphics, Inc Mesa DRI G33 GEM 20091221 2009Q4 x86/MMX/SSE2 unsupported 0 Mesa
+Tungsten Graphics, Inc Mesa DRI G41 GEM 20091221 2009Q4 x86/MMX/SSE2 unsupported 0 Mesa
+Tungsten Graphics, Inc Mesa DRI G41 GEM 20100330 DEVELOPMENT x86/MMX/SSE2 unsupported 0 Mesa
+Tungsten Graphics, Inc Mesa DRI GMA500 20081116 - 5.0.1.0046 x86/MMX/SSE2 unsupported 0 Mesa
+Tungsten Graphics, Inc Mesa DRI IGD GEM 20091221 2009Q4 x86/MMX/SSE2 unsupported 0 Mesa
+Tungsten Graphics, Inc Mesa DRI IGD GEM 20100330 DEVELOPMENT unsupported 0 Mesa
+Tungsten Graphics, Inc Mesa DRI IGD GEM 20100330 DEVELOPMENT x86/MMX/SSE2 unsupported 0 Mesa
+Tungsten Graphics, Inc Mesa DRI IGDNG_D GEM 20091221 2009Q4 x86/MMX/SSE2 unsupported 0 Mesa
+Tungsten Graphics, Inc Mesa DRI Ironlake Desktop GEM 20100330 DEVELOPMENT x86/MMX/SSE2 unsupported 0 Mesa
+Tungsten Graphics, Inc Mesa DRI Ironlake Mobile GEM 20100330 DEVELOPMENT x86/MMX/SSE2 unsupported 0 Mesa
+Tungsten Graphics, Inc Mesa DRI Mobile Intelå¨ GM45 Express Chipset 20080716 x86/MMX/SSE2 unsupported 0 Mesa
+Tungsten Graphics, Inc Mesa DRI Mobile Intelå¨ GM45 Express Chipset GEM 20090712 2009Q2 RC3 x86/MMX... unsupported 0 Mesa
+Tungsten Graphics, Inc Mesa DRI Mobile Intelå¨ GM45 Express Chipset GEM 20091221 2009Q4 x86/MMX/SSE2 unsupported 0 Mesa
+Tungsten Graphics, Inc Mesa DRI Mobile Intelå¨ GM45 Express Chipset GEM 20100328 2010Q1 unsupported 0 Mesa
+Tungsten Graphics, Inc Mesa DRI Mobile Intelå¨ GM45 Express Chipset GEM 20100330 DEVELOPMENT unsupported 0 Mesa
+Tungsten Graphics, Inc Mesa DRI Mobile Intelå¨ GM45 Express Chipset GEM 20100330 DEVELOPMENT x86/MM... unsupported 0 Mesa
+Tungsten Graphics, Inc. Mesa DRI R200 (RV280 5964) 20090101 x86/MMX+/3DNow!+/SSE2 TCL DRI2 unsupported 0 Mesa
+VIA unsupported 0 VIA
+VMware, Inc. Gallium 0.3 on SVGA3D; build: RELEASE; UNRECOGNIZED
+VMware, Inc. Gallium 0.4 on i915 (chipset: 945GM) UNRECOGNIZED
+VMware, Inc. Gallium 0.4 on llvmpipe UNRECOGNIZED
+VMware, Inc. Gallium 0.4 on softpipe UNRECOGNIZED
+X.Org Gallium 0.4 on AMD BARTS supported 3 AMD BARTS (HD 6800)
+X.Org Gallium 0.4 on AMD CEDAR supported 2 AMD CEDAR (HD 5450)
+X.Org Gallium 0.4 on AMD HEMLOCK supported 3 AMD HEMLOCK (HD 5970)
+X.Org Gallium 0.4 on AMD JUNIPER supported 3 AMD JUNIPER (HD 5700)
+X.Org Gallium 0.4 on AMD REDWOOD supported 3 AMD REDWOOD (HD 5500/5600)
+X.Org Gallium 0.4 on AMD RS780 supported 0 AMD RS780 (HD 3200)
+X.Org Gallium 0.4 on AMD RS880 supported 1 AMD RS880 (HD 4200)
+X.Org Gallium 0.4 on AMD RV610 supported 1 AMD RV610 (HD 2400)
+X.Org Gallium 0.4 on AMD RV620 supported 1 AMD RV620 (HD 3400)
+X.Org Gallium 0.4 on AMD RV630 supported 2 AMD RV630 (HD 2600)
+X.Org Gallium 0.4 on AMD RV635 supported 3 AMD RV635 (HD 3600)
+X.Org Gallium 0.4 on AMD RV710 supported 1 AMD RV710 (HD 4300)
+X.Org Gallium 0.4 on AMD RV730 supported 3 AMD RV730 (HD 4600)
+X.Org Gallium 0.4 on AMD RV740 supported 3 AMD RV740 (HD 4700)
+X.Org Gallium 0.4 on AMD RV770 supported 3 AMD RV770 (HD 4800)
+X.Org R300 Project Gallium 0.4 on ATI R300 supported 1 ATI R300 (9700)
+X.Org R300 Project Gallium 0.4 on ATI R580 supported 3 ATI R580 (X1900)
+X.Org R300 Project Gallium 0.4 on ATI RC410 unsupported 0 ATI RC410 (Xpress 200)
+X.Org R300 Project Gallium 0.4 on ATI RS482 unsupported 0 ATI RS48x (Xpress 200x)
+X.Org R300 Project Gallium 0.4 on ATI RS600 unsupported 0 ATI RS600 (Xpress 3200)
+X.Org R300 Project Gallium 0.4 on ATI RS690 supported 1 ATI R300 (9700)
+X.Org R300 Project Gallium 0.4 on ATI RV350 supported 0 ATI RV350 (9600)
+X.Org R300 Project Gallium 0.4 on ATI RV370 supported 0 ATI RV370 (X300)
+X.Org R300 Project Gallium 0.4 on ATI RV410 supported 1 ATI RV410 (X700)
+X.Org R300 Project Gallium 0.4 on ATI RV515 supported 1 ATI RV515
+X.Org R300 Project Gallium 0.4 on ATI RV530 supported 1 ATI RV530
+X.Org R300 Project Gallium 0.4 on ATI RV570 supported 3 ATI RV570 (X1900 GT/PRO)
+X.Org R300 Project Gallium 0.4 on R420 supported 1 ATI R300 (9700)
+X.Org R300 Project Gallium 0.4 on R580 supported 3 ATI R580 (X1900)
+X.Org R300 Project Gallium 0.4 on RC410 unsupported 0 ATI RC410 (Xpress 200)
+X.Org R300 Project Gallium 0.4 on RS480 unsupported 0 ATI RS48x (Xpress 200x)
+X.Org R300 Project Gallium 0.4 on RS482 unsupported 0 ATI RS48x (Xpress 200x)
+X.Org R300 Project Gallium 0.4 on RS600 unsupported 0 ATI RS600 (Xpress 3200)
+X.Org R300 Project Gallium 0.4 on RS690 supported 1 ATI R300 (9700)
+X.Org R300 Project Gallium 0.4 on RS740 supported 1 ATI R300 (9700)
+X.Org R300 Project Gallium 0.4 on RV350 supported 0 ATI RV350 (9600)
+X.Org R300 Project Gallium 0.4 on RV370 supported 0 ATI RV370 (X300)
+X.Org R300 Project Gallium 0.4 on RV410 supported 1 ATI RV410 (X700)
+X.Org R300 Project Gallium 0.4 on RV515 supported 1 ATI RV515
+X.Org R300 Project Gallium 0.4 on RV530 supported 1 ATI RV530
+XGI unsupported 0 XGI
+nouveau Gallium 0.4 on NV34 UNRECOGNIZED
+nouveau Gallium 0.4 on NV36 UNRECOGNIZED
+nouveau Gallium 0.4 on NV46 UNRECOGNIZED
+nouveau Gallium 0.4 on NV49 UNRECOGNIZED
+nouveau Gallium 0.4 on NV4A UNRECOGNIZED
+nouveau Gallium 0.4 on NV4B UNRECOGNIZED
+nouveau Gallium 0.4 on NV4E UNRECOGNIZED
+nouveau Gallium 0.4 on NV50 UNRECOGNIZED
+nouveau Gallium 0.4 on NV84 UNRECOGNIZED
+nouveau Gallium 0.4 on NV86 UNRECOGNIZED
+nouveau Gallium 0.4 on NV92 UNRECOGNIZED
+nouveau Gallium 0.4 on NV94 UNRECOGNIZED
+nouveau Gallium 0.4 on NV96 UNRECOGNIZED
+nouveau Gallium 0.4 on NV98 UNRECOGNIZED
+nouveau Gallium 0.4 on NVA0 UNRECOGNIZED
+nouveau Gallium 0.4 on NVA3 UNRECOGNIZED
+nouveau Gallium 0.4 on NVA5 UNRECOGNIZED
+nouveau Gallium 0.4 on NVA8 UNRECOGNIZED
+nouveau Gallium 0.4 on NVAA UNRECOGNIZED
+nouveau Gallium 0.4 on NVAC UNRECOGNIZED
diff --git a/indra/newview/tests/gpus_seen.txt b/indra/newview/tests/gpus_seen.txt
new file mode 100644
index 0000000000..c807f22b58
--- /dev/null
+++ b/indra/newview/tests/gpus_seen.txt
@@ -0,0 +1,1593 @@
+ATI
+ATI 3D-Analyze
+ATI ASUS A9xxx
+ATI ASUS AH24xx
+ATI ASUS AH26xx
+ATI ASUS AH34xx
+ATI ASUS AH36xx
+ATI ASUS AH46xx
+ATI ASUS AX3xx
+ATI ASUS AX5xx
+ATI ASUS AX8xx
+ATI ASUS EAH38xx
+ATI ASUS EAH43xx
+ATI ASUS EAH45xx
+ATI ASUS EAH48xx
+ATI ASUS EAH57xx
+ATI ASUS EAH58xx
+ATI ASUS X1xxx
+ATI All-in-Wonder 9xxx
+ATI All-in-Wonder HD
+ATI All-in-Wonder PCI-E
+ATI All-in-Wonder X1800
+ATI All-in-Wonder X1900
+ATI All-in-Wonder X600
+ATI All-in-Wonder X800
+ATI Diamond X1xxx
+ATI Display Adapter
+ATI FireGL
+ATI FireGL 5200
+ATI FireGL 5xxx
+ATI FireMV
+ATI Generic
+ATI Hercules 9800
+ATI IGP 340M
+ATI M52
+ATI M54
+ATI M56
+ATI M71
+ATI M72
+ATI M76
+ATI Mobility Radeon
+ATI Mobility Radeon 7xxx
+ATI Mobility Radeon 9600
+ATI Mobility Radeon 9700
+ATI Mobility Radeon 9800
+ATI Mobility Radeon HD 2300
+ATI Mobility Radeon HD 2400
+ATI Mobility Radeon HD 2600
+ATI Mobility Radeon HD 2700
+ATI Mobility Radeon HD 3400
+ATI Mobility Radeon HD 3600
+ATI Mobility Radeon HD 3800
+ATI Mobility Radeon HD 4200
+ATI Mobility Radeon HD 4300
+ATI Mobility Radeon HD 4500
+ATI Mobility Radeon HD 4600
+ATI Mobility Radeon HD 4800
+ATI Mobility Radeon HD 5400
+ATI Mobility Radeon HD 5600
+ATI Mobility Radeon X1xxx
+ATI Mobility Radeon X2xxx
+ATI Mobility Radeon X3xx
+ATI Mobility Radeon X6xx
+ATI Mobility Radeon X7xx
+ATI Mobility Radeon Xxxx
+ATI RV380
+ATI RV530
+ATI Radeon 2100
+ATI Radeon 3000
+ATI Radeon 3100
+ATI Radeon 7000
+ATI Radeon 7xxx
+ATI Radeon 8xxx
+ATI Radeon 9000
+ATI Radeon 9100
+ATI Radeon 9200
+ATI Radeon 9500
+ATI Radeon 9600
+ATI Radeon 9700
+ATI Radeon 9800
+ATI Radeon HD 2300
+ATI Radeon HD 2400
+ATI Radeon HD 2600
+ATI Radeon HD 2900
+ATI Radeon HD 3000
+ATI Radeon HD 3100
+ATI Radeon HD 3200
+ATI Radeon HD 3300
+ATI Radeon HD 3400
+ATI Radeon HD 3600
+ATI Radeon HD 3800
+ATI Radeon HD 4200
+ATI Radeon HD 4300
+ATI Radeon HD 4500
+ATI Radeon HD 4600
+ATI Radeon HD 4700
+ATI Radeon HD 4800
+ATI Radeon HD 5400
+ATI Radeon HD 5500
+ATI Radeon HD 5600
+ATI Radeon HD 5700
+ATI Radeon HD 5800
+ATI Radeon HD 5900
+ATI Radeon HD 6200
+ATI Radeon HD 6300
+ATI Radeon HD 6500
+ATI Radeon HD 6800
+ATI Radeon HD 6900
+ATI Radeon OpenGL
+ATI Radeon RV250
+ATI Radeon RV600
+ATI Radeon RX9550
+ATI Radeon VE
+ATI Radeon X1000
+ATI Radeon X1200
+ATI Radeon X1300
+ATI Radeon X13xx
+ATI Radeon X1400
+ATI Radeon X1500
+ATI Radeon X1600
+ATI Radeon X16xx
+ATI Radeon X1700
+ATI Radeon X1800
+ATI Radeon X1900
+ATI Radeon X19xx
+ATI Radeon X1xxx
+ATI Radeon X300
+ATI Radeon X500
+ATI Radeon X600
+ATI Radeon X700
+ATI Radeon X7xx
+ATI Radeon X800
+ATI Radeon Xpress
+ATI Rage 128
+ATI Technologies Inc.
+ATI Technologies Inc. x86
+ATI Technologies Inc. x86/SSE2
+ATI Technologies Inc. (Vista) ATI Mobility Radeon HD 5730
+ATI Technologies Inc. 256MB ATI Radeon X1300PRO x86/SSE2
+ATI Technologies Inc. AMD 760G
+ATI Technologies Inc. AMD 760G (Microsoft WDDM 1.1)
+ATI Technologies Inc. AMD 780L
+ATI Technologies Inc. AMD FirePro 2270
+ATI Technologies Inc. AMD M860G with ATI Mobility Radeon 4100
+ATI Technologies Inc. AMD M880G with ATI Mobility Radeon HD 4200
+ATI Technologies Inc. AMD M880G with ATI Mobility Radeon HD 4250
+ATI Technologies Inc. AMD RADEON HD 6450
+ATI Technologies Inc. AMD Radeon HD 6200 series Graphics
+ATI Technologies Inc. AMD Radeon HD 6250 Graphics
+ATI Technologies Inc. AMD Radeon HD 6300 series Graphics
+ATI Technologies Inc. AMD Radeon HD 6300M Series
+ATI Technologies Inc. AMD Radeon HD 6310 Graphics
+ATI Technologies Inc. AMD Radeon HD 6310M
+ATI Technologies Inc. AMD Radeon HD 6330M
+ATI Technologies Inc. AMD Radeon HD 6350
+ATI Technologies Inc. AMD Radeon HD 6370M
+ATI Technologies Inc. AMD Radeon HD 6400M Series
+ATI Technologies Inc. AMD Radeon HD 6450
+ATI Technologies Inc. AMD Radeon HD 6470M
+ATI Technologies Inc. AMD Radeon HD 6490M
+ATI Technologies Inc. AMD Radeon HD 6500M/5600/5700 Series
+ATI Technologies Inc. AMD Radeon HD 6530M
+ATI Technologies Inc. AMD Radeon HD 6550M
+ATI Technologies Inc. AMD Radeon HD 6570
+ATI Technologies Inc. AMD Radeon HD 6570M
+ATI Technologies Inc. AMD Radeon HD 6570M/5700 Series
+ATI Technologies Inc. AMD Radeon HD 6600M Series
+ATI Technologies Inc. AMD Radeon HD 6650M
+ATI Technologies Inc. AMD Radeon HD 6670
+ATI Technologies Inc. AMD Radeon HD 6700 Series
+ATI Technologies Inc. AMD Radeon HD 6750
+ATI Technologies Inc. AMD Radeon HD 6750M
+ATI Technologies Inc. AMD Radeon HD 6770
+ATI Technologies Inc. AMD Radeon HD 6800 Series
+ATI Technologies Inc. AMD Radeon HD 6850M
+ATI Technologies Inc. AMD Radeon HD 6870
+ATI Technologies Inc. AMD Radeon HD 6870M
+ATI Technologies Inc. AMD Radeon HD 6900 Series
+ATI Technologies Inc. AMD Radeon HD 6970M
+ATI Technologies Inc. AMD Radeon HD 6990
+ATI Technologies Inc. AMD Radeon(TM) HD 6470M
+ATI Technologies Inc. ASUS 5870 Eyefinity 6
+ATI Technologies Inc. ASUS AH2600 Series
+ATI Technologies Inc. ASUS AH3450 Series
+ATI Technologies Inc. ASUS AH3650 Series
+ATI Technologies Inc. ASUS AH4650 Series
+ATI Technologies Inc. ASUS ARES
+ATI Technologies Inc. ASUS EAH2900 Series
+ATI Technologies Inc. ASUS EAH3450 Series
+ATI Technologies Inc. ASUS EAH3650 Series
+ATI Technologies Inc. ASUS EAH4350 series
+ATI Technologies Inc. ASUS EAH4550 series
+ATI Technologies Inc. ASUS EAH4650 series
+ATI Technologies Inc. ASUS EAH4670 series
+ATI Technologies Inc. ASUS EAH4750 Series
+ATI Technologies Inc. ASUS EAH4770 Series
+ATI Technologies Inc. ASUS EAH4770 series
+ATI Technologies Inc. ASUS EAH4850 series
+ATI Technologies Inc. ASUS EAH5450 Series
+ATI Technologies Inc. ASUS EAH5550 Series
+ATI Technologies Inc. ASUS EAH5570 series
+ATI Technologies Inc. ASUS EAH5670 Series
+ATI Technologies Inc. ASUS EAH5750 Series
+ATI Technologies Inc. ASUS EAH5770 Series
+ATI Technologies Inc. ASUS EAH5830 Series
+ATI Technologies Inc. ASUS EAH5850 Series
+ATI Technologies Inc. ASUS EAH5870 Series
+ATI Technologies Inc. ASUS EAH5970 Series
+ATI Technologies Inc. ASUS EAH6850 Series
+ATI Technologies Inc. ASUS EAH6870 Series
+ATI Technologies Inc. ASUS EAH6950 Series
+ATI Technologies Inc. ASUS EAH6970 Series
+ATI Technologies Inc. ASUS EAHG4670 series
+ATI Technologies Inc. ASUS Extreme AX600 Series
+ATI Technologies Inc. ASUS Extreme AX600XT-TD
+ATI Technologies Inc. ASUS X1300 Series x86/SSE2
+ATI Technologies Inc. ASUS X1550 Series
+ATI Technologies Inc. ASUS X1950 Series x86/SSE2
+ATI Technologies Inc. ASUS X800 Series
+ATI Technologies Inc. ASUS X850 Series
+ATI Technologies Inc. ATI All-in-Wonder HD
+ATI Technologies Inc. ATI FirePro 2260
+ATI Technologies Inc. ATI FirePro 2450
+ATI Technologies Inc. ATI FirePro M5800
+ATI Technologies Inc. ATI FirePro M7740
+ATI Technologies Inc. ATI FirePro M7820
+ATI Technologies Inc. ATI FirePro V3700 (FireGL)
+ATI Technologies Inc. ATI FirePro V3800
+ATI Technologies Inc. ATI FirePro V4800
+ATI Technologies Inc. ATI FirePro V4800 (FireGL)
+ATI Technologies Inc. ATI FirePro V5800
+ATI Technologies Inc. ATI FirePro V7800
+ATI Technologies Inc. ATI MOBILITY RADEON 9XXX x86/SSE2
+ATI Technologies Inc. ATI MOBILITY RADEON HD 3450
+ATI Technologies Inc. ATI MOBILITY RADEON X1600
+ATI Technologies Inc. ATI MOBILITY RADEON X2300
+ATI Technologies Inc. ATI MOBILITY RADEON X2300 HD x86/SSE2
+ATI Technologies Inc. ATI MOBILITY RADEON X2300 x86/MMX/3DNow!/SSE2
+ATI Technologies Inc. ATI MOBILITY RADEON X2300 x86/SSE2
+ATI Technologies Inc. ATI MOBILITY RADEON X300
+ATI Technologies Inc. ATI MOBILITY RADEON X600
+ATI Technologies Inc. ATI MOBILITY RADEON XPRESS 200
+ATI Technologies Inc. ATI Mobility FireGL V5700
+ATI Technologies Inc. ATI Mobility Radeon 4100
+ATI Technologies Inc. ATI Mobility Radeon Graphics
+ATI Technologies Inc. ATI Mobility Radeon HD 2300
+ATI Technologies Inc. ATI Mobility Radeon HD 2400
+ATI Technologies Inc. ATI Mobility Radeon HD 2400 XT
+ATI Technologies Inc. ATI Mobility Radeon HD 2600
+ATI Technologies Inc. ATI Mobility Radeon HD 2600 XT
+ATI Technologies Inc. ATI Mobility Radeon HD 2700
+ATI Technologies Inc. ATI Mobility Radeon HD 3400 Series
+ATI Technologies Inc. ATI Mobility Radeon HD 3430
+ATI Technologies Inc. ATI Mobility Radeon HD 3450
+ATI Technologies Inc. ATI Mobility Radeon HD 3470
+ATI Technologies Inc. ATI Mobility Radeon HD 3470 Hybrid X2
+ATI Technologies Inc. ATI Mobility Radeon HD 3650
+ATI Technologies Inc. ATI Mobility Radeon HD 4200
+ATI Technologies Inc. ATI Mobility Radeon HD 4200 Series
+ATI Technologies Inc. ATI Mobility Radeon HD 4225
+ATI Technologies Inc. ATI Mobility Radeon HD 4225 Series
+ATI Technologies Inc. ATI Mobility Radeon HD 4250
+ATI Technologies Inc. ATI Mobility Radeon HD 4250 Graphics
+ATI Technologies Inc. ATI Mobility Radeon HD 4270
+ATI Technologies Inc. ATI Mobility Radeon HD 4300 Series
+ATI Technologies Inc. ATI Mobility Radeon HD 4300/4500 Series
+ATI Technologies Inc. ATI Mobility Radeon HD 4330
+ATI Technologies Inc. ATI Mobility Radeon HD 4330 Series
+ATI Technologies Inc. ATI Mobility Radeon HD 4350
+ATI Technologies Inc. ATI Mobility Radeon HD 4350 Series
+ATI Technologies Inc. ATI Mobility Radeon HD 4500 Series
+ATI Technologies Inc. ATI Mobility Radeon HD 4500/5100 Series
+ATI Technologies Inc. ATI Mobility Radeon HD 4530
+ATI Technologies Inc. ATI Mobility Radeon HD 4530 Series
+ATI Technologies Inc. ATI Mobility Radeon HD 4550
+ATI Technologies Inc. ATI Mobility Radeon HD 4570
+ATI Technologies Inc. ATI Mobility Radeon HD 4600 Series
+ATI Technologies Inc. ATI Mobility Radeon HD 4650
+ATI Technologies Inc. ATI Mobility Radeon HD 4650 Series
+ATI Technologies Inc. ATI Mobility Radeon HD 4670
+ATI Technologies Inc. ATI Mobility Radeon HD 4830 Series
+ATI Technologies Inc. ATI Mobility Radeon HD 4850
+ATI Technologies Inc. ATI Mobility Radeon HD 4870
+ATI Technologies Inc. ATI Mobility Radeon HD 5000
+ATI Technologies Inc. ATI Mobility Radeon HD 5000 Series
+ATI Technologies Inc. ATI Mobility Radeon HD 5145
+ATI Technologies Inc. ATI Mobility Radeon HD 5165
+ATI Technologies Inc. ATI Mobility Radeon HD 530v
+ATI Technologies Inc. ATI Mobility Radeon HD 5400 Series
+ATI Technologies Inc. ATI Mobility Radeon HD 540v
+ATI Technologies Inc. ATI Mobility Radeon HD 5430
+ATI Technologies Inc. ATI Mobility Radeon HD 5450
+ATI Technologies Inc. ATI Mobility Radeon HD 5450 Series
+ATI Technologies Inc. ATI Mobility Radeon HD 545v
+ATI Technologies Inc. ATI Mobility Radeon HD 5470
+ATI Technologies Inc. ATI Mobility Radeon HD 550v
+ATI Technologies Inc. ATI Mobility Radeon HD 5600/5700 Series
+ATI Technologies Inc. ATI Mobility Radeon HD 560v
+ATI Technologies Inc. ATI Mobility Radeon HD 5650
+ATI Technologies Inc. ATI Mobility Radeon HD 5700 Series
+ATI Technologies Inc. ATI Mobility Radeon HD 5730
+ATI Technologies Inc. ATI Mobility Radeon HD 5800 Series
+ATI Technologies Inc. ATI Mobility Radeon HD 5850
+ATI Technologies Inc. ATI Mobility Radeon HD 5870
+ATI Technologies Inc. ATI Mobility Radeon HD 6300 series
+ATI Technologies Inc. ATI Mobility Radeon HD 6370
+ATI Technologies Inc. ATI Mobility Radeon HD 6470M
+ATI Technologies Inc. ATI Mobility Radeon HD 6550
+ATI Technologies Inc. ATI Mobility Radeon HD 6570
+ATI Technologies Inc. ATI Mobility Radeon X1300
+ATI Technologies Inc. ATI Mobility Radeon X1300 x86/MMX/3DNow!/SSE2
+ATI Technologies Inc. ATI Mobility Radeon X1300 x86/SSE2
+ATI Technologies Inc. ATI Mobility Radeon X1350
+ATI Technologies Inc. ATI Mobility Radeon X1350 x86/SSE2
+ATI Technologies Inc. ATI Mobility Radeon X1400
+ATI Technologies Inc. ATI Mobility Radeon X1400 x86/SSE2
+ATI Technologies Inc. ATI Mobility Radeon X1600
+ATI Technologies Inc. ATI Mobility Radeon X1600 x86/SSE2
+ATI Technologies Inc. ATI Mobility Radeon X1700 x86/SSE2
+ATI Technologies Inc. ATI Mobility Radeon X2300
+ATI Technologies Inc. ATI Mobility Radeon X2300 (Omega 3.8.442)
+ATI Technologies Inc. ATI Mobility Radeon X2300 x86
+ATI Technologies Inc. ATI Mobility Radeon X2300 x86/MMX/3DNow!/SSE2
+ATI Technologies Inc. ATI Mobility Radeon X2300 x86/SSE2
+ATI Technologies Inc. ATI Mobility Radeon X2500
+ATI Technologies Inc. ATI Mobility Radeon X2500 x86/SSE2
+ATI Technologies Inc. ATI Mobility Radeon. HD 530v
+ATI Technologies Inc. ATI Mobility Radeon. HD 5470
+ATI Technologies Inc. ATI RADEON HD 3200 T25XX by CAMILO
+ATI Technologies Inc. ATI RADEON XPRESS 1100
+ATI Technologies Inc. ATI RADEON XPRESS 200 Series
+ATI Technologies Inc. ATI RADEON XPRESS 200 Series x86/SSE2
+ATI Technologies Inc. ATI RADEON XPRESS 200M SERIES
+ATI Technologies Inc. ATI Radeon
+ATI Technologies Inc. ATI Radeon 2100
+ATI Technologies Inc. ATI Radeon 2100 (Microsoft - WDDM)
+ATI Technologies Inc. ATI Radeon 2100 Graphics
+ATI Technologies Inc. ATI Radeon 3000
+ATI Technologies Inc. ATI Radeon 3000 Graphics
+ATI Technologies Inc. ATI Radeon 3100 Graphics
+ATI Technologies Inc. ATI Radeon 5xxx series
+ATI Technologies Inc. ATI Radeon 9550 / X1050 Series
+ATI Technologies Inc. ATI Radeon 9550 / X1050 Series x86/MMX/3DNow!/SSE
+ATI Technologies Inc. ATI Radeon 9550 / X1050 Series x86/SSE2
+ATI Technologies Inc. ATI Radeon 9550 / X1050 Series(Microsoft - WDDM)
+ATI Technologies Inc. ATI Radeon 9600 / X1050 Series
+ATI Technologies Inc. ATI Radeon 9600/9550/X1050 Series
+ATI Technologies Inc. ATI Radeon BA Prototype OpenGL Engine
+ATI Technologies Inc. ATI Radeon BB Prototype OpenGL Engine
+ATI Technologies Inc. ATI Radeon Cedar PRO Prototype OpenGL Engine
+ATI Technologies Inc. ATI Radeon Cypress PRO Prototype OpenGL Engine
+ATI Technologies Inc. ATI Radeon Graphics Processor
+ATI Technologies Inc. ATI Radeon HD 2200 Graphics
+ATI Technologies Inc. ATI Radeon HD 2350
+ATI Technologies Inc. ATI Radeon HD 2400
+ATI Technologies Inc. ATI Radeon HD 2400 OpenGL Engine
+ATI Technologies Inc. ATI Radeon HD 2400 PRO
+ATI Technologies Inc. ATI Radeon HD 2400 PRO AGP
+ATI Technologies Inc. ATI Radeon HD 2400 Pro
+ATI Technologies Inc. ATI Radeon HD 2400 Series
+ATI Technologies Inc. ATI Radeon HD 2400 XT
+ATI Technologies Inc. ATI Radeon HD 2400 XT OpenGL Engine
+ATI Technologies Inc. ATI Radeon HD 2600 OpenGL Engine
+ATI Technologies Inc. ATI Radeon HD 2600 PRO
+ATI Technologies Inc. ATI Radeon HD 2600 PRO OpenGL Engine
+ATI Technologies Inc. ATI Radeon HD 2600 Pro
+ATI Technologies Inc. ATI Radeon HD 2600 Series
+ATI Technologies Inc. ATI Radeon HD 2600 XT
+ATI Technologies Inc. ATI Radeon HD 2900 GT
+ATI Technologies Inc. ATI Radeon HD 2900 XT
+ATI Technologies Inc. ATI Radeon HD 3200 Graphics
+ATI Technologies Inc. ATI Radeon HD 3300 Graphics
+ATI Technologies Inc. ATI Radeon HD 3400 Series
+ATI Technologies Inc. ATI Radeon HD 3450
+ATI Technologies Inc. ATI Radeon HD 3450 - Dell Optiplex
+ATI Technologies Inc. ATI Radeon HD 3470
+ATI Technologies Inc. ATI Radeon HD 3470 - Dell Optiplex
+ATI Technologies Inc. ATI Radeon HD 3550
+ATI Technologies Inc. ATI Radeon HD 3600 Series
+ATI Technologies Inc. ATI Radeon HD 3650
+ATI Technologies Inc. ATI Radeon HD 3650 AGP
+ATI Technologies Inc. ATI Radeon HD 3730
+ATI Technologies Inc. ATI Radeon HD 3800 Series
+ATI Technologies Inc. ATI Radeon HD 3850
+ATI Technologies Inc. ATI Radeon HD 3850 AGP
+ATI Technologies Inc. ATI Radeon HD 3870
+ATI Technologies Inc. ATI Radeon HD 3870 X2
+ATI Technologies Inc. ATI Radeon HD 4200
+ATI Technologies Inc. ATI Radeon HD 4250
+ATI Technologies Inc. ATI Radeon HD 4250 Graphics
+ATI Technologies Inc. ATI Radeon HD 4270
+ATI Technologies Inc. ATI Radeon HD 4290
+ATI Technologies Inc. ATI Radeon HD 4300 Series
+ATI Technologies Inc. ATI Radeon HD 4300/4500 Series
+ATI Technologies Inc. ATI Radeon HD 4350
+ATI Technologies Inc. ATI Radeon HD 4350 (Microsoft WDDM 1.1)
+ATI Technologies Inc. ATI Radeon HD 4450
+ATI Technologies Inc. ATI Radeon HD 4500 Series
+ATI Technologies Inc. ATI Radeon HD 4550
+ATI Technologies Inc. ATI Radeon HD 4600 Series
+ATI Technologies Inc. ATI Radeon HD 4650
+ATI Technologies Inc. ATI Radeon HD 4670
+ATI Technologies Inc. ATI Radeon HD 4670 OpenGL Engine
+ATI Technologies Inc. ATI Radeon HD 4700 Series
+ATI Technologies Inc. ATI Radeon HD 4720
+ATI Technologies Inc. ATI Radeon HD 4730
+ATI Technologies Inc. ATI Radeon HD 4730 Series
+ATI Technologies Inc. ATI Radeon HD 4750
+ATI Technologies Inc. ATI Radeon HD 4770
+ATI Technologies Inc. ATI Radeon HD 4800 Series
+ATI Technologies Inc. ATI Radeon HD 4850
+ATI Technologies Inc. ATI Radeon HD 4850 OpenGL Engine
+ATI Technologies Inc. ATI Radeon HD 4850 Series
+ATI Technologies Inc. ATI Radeon HD 4870
+ATI Technologies Inc. ATI Radeon HD 4870 OpenGL Engine
+ATI Technologies Inc. ATI Radeon HD 4870 X2
+ATI Technologies Inc. ATI Radeon HD 5400 Series
+ATI Technologies Inc. ATI Radeon HD 5450
+ATI Technologies Inc. ATI Radeon HD 5500 Series
+ATI Technologies Inc. ATI Radeon HD 5570
+ATI Technologies Inc. ATI Radeon HD 5600 Series
+ATI Technologies Inc. ATI Radeon HD 5630
+ATI Technologies Inc. ATI Radeon HD 5670
+ATI Technologies Inc. ATI Radeon HD 5670 OpenGL Engine
+ATI Technologies Inc. ATI Radeon HD 5700 Series
+ATI Technologies Inc. ATI Radeon HD 5750
+ATI Technologies Inc. ATI Radeon HD 5750 OpenGL Engine
+ATI Technologies Inc. ATI Radeon HD 5770
+ATI Technologies Inc. ATI Radeon HD 5770 OpenGL Engine
+ATI Technologies Inc. ATI Radeon HD 5800 Series
+ATI Technologies Inc. ATI Radeon HD 5850
+ATI Technologies Inc. ATI Radeon HD 5870
+ATI Technologies Inc. ATI Radeon HD 5870 OpenGL Engine
+ATI Technologies Inc. ATI Radeon HD 5900 Series
+ATI Technologies Inc. ATI Radeon HD 5970
+ATI Technologies Inc. ATI Radeon HD 6230
+ATI Technologies Inc. ATI Radeon HD 6250
+ATI Technologies Inc. ATI Radeon HD 6350
+ATI Technologies Inc. ATI Radeon HD 6390
+ATI Technologies Inc. ATI Radeon HD 6490M OpenGL Engine
+ATI Technologies Inc. ATI Radeon HD 6510
+ATI Technologies Inc. ATI Radeon HD 6570M
+ATI Technologies Inc. ATI Radeon HD 6750
+ATI Technologies Inc. ATI Radeon HD 6750M OpenGL Engine
+ATI Technologies Inc. ATI Radeon HD 6770
+ATI Technologies Inc. ATI Radeon HD 6770M OpenGL Engine
+ATI Technologies Inc. ATI Radeon HD 6800 Series
+ATI Technologies Inc. ATI Radeon HD 6970M OpenGL Engine
+ATI Technologies Inc. ATI Radeon HD3750
+ATI Technologies Inc. ATI Radeon HD4300/HD4500 series
+ATI Technologies Inc. ATI Radeon HD4670
+ATI Technologies Inc. ATI Radeon Juniper LE Prototype OpenGL Engine
+ATI Technologies Inc. ATI Radeon RV710 Prototype OpenGL Engine
+ATI Technologies Inc. ATI Radeon RV730 Prototype OpenGL Engine
+ATI Technologies Inc. ATI Radeon RV770 Prototype OpenGL Engine
+ATI Technologies Inc. ATI Radeon RV790 Prototype OpenGL Engine
+ATI Technologies Inc. ATI Radeon Redwood PRO Prototype OpenGL Engine
+ATI Technologies Inc. ATI Radeon Redwood XT Prototype OpenGL Engine
+ATI Technologies Inc. ATI Radeon Whistler PRO/LP Prototype OpenGL Engine
+ATI Technologies Inc. ATI Radeon X1050
+ATI Technologies Inc. ATI Radeon X1050 Series
+ATI Technologies Inc. ATI Radeon X1200
+ATI Technologies Inc. ATI Radeon X1200 Series
+ATI Technologies Inc. ATI Radeon X1200 Series x86/MMX/3DNow!/SSE2
+ATI Technologies Inc. ATI Radeon X1250
+ATI Technologies Inc. ATI Radeon X1250 x86/MMX/3DNow!/SSE2
+ATI Technologies Inc. ATI Radeon X1270
+ATI Technologies Inc. ATI Radeon X1270 x86/MMX/3DNow!/SSE2
+ATI Technologies Inc. ATI Radeon X1300/X1550 Series
+ATI Technologies Inc. ATI Radeon X1550 Series
+ATI Technologies Inc. ATI Radeon X1600 OpenGL Engine
+ATI Technologies Inc. ATI Radeon X1900 OpenGL Engine
+ATI Technologies Inc. ATI Radeon X1950 GT
+ATI Technologies Inc. ATI Radeon X300/X550/X1050 Series
+ATI Technologies Inc. ATI Radeon Xpress 1100
+ATI Technologies Inc. ATI Radeon Xpress 1150
+ATI Technologies Inc. ATI Radeon Xpress 1150 x86/MMX/3DNow!/SSE2
+ATI Technologies Inc. ATI Radeon Xpress 1200
+ATI Technologies Inc. ATI Radeon Xpress 1200 Series
+ATI Technologies Inc. ATI Radeon Xpress 1200 Series x86/MMX/3DNow!/SSE2
+ATI Technologies Inc. ATI Radeon Xpress 1200 x86/MMX/3DNow!/SSE2
+ATI Technologies Inc. ATI Radeon Xpress 1250
+ATI Technologies Inc. ATI Radeon Xpress 1250 x86/SSE2
+ATI Technologies Inc. ATI Radeon Xpress Series
+ATI Technologies Inc. ATI Yamaha HD 9000
+ATI Technologies Inc. ATi RS880M
+ATI Technologies Inc. Carte graphique VGA standard
+ATI Technologies Inc. Diamond Radeon X1550 Series
+ATI Technologies Inc. EG JUNIPER
+ATI Technologies Inc. EG PARK
+ATI Technologies Inc. FireGL V3100 Pentium 4 (SSE2)
+ATI Technologies Inc. FireMV 2400 PCI DDR x86
+ATI Technologies Inc. FireMV 2400 PCI DDR x86/SSE2
+ATI Technologies Inc. GeCube Radeon X1550
+ATI Technologies Inc. Geforce 9500 GT
+ATI Technologies Inc. Geforce 9500GT
+ATI Technologies Inc. Geforce 9800 GT
+ATI Technologies Inc. HD3730
+ATI Technologies Inc. HIGHTECH EXCALIBUR RADEON 9550SE Series
+ATI Technologies Inc. HIGHTECH EXCALIBUR X700 PRO
+ATI Technologies Inc. M21 x86/MMX/3DNow!/SSE2
+ATI Technologies Inc. M76M
+ATI Technologies Inc. MOBILITY RADEON 7500 DDR x86/SSE2
+ATI Technologies Inc. MOBILITY RADEON 9000 DDR x86/SSE2
+ATI Technologies Inc. MOBILITY RADEON 9000 IGPRADEON 9100 IGP DDR x86/SSE2
+ATI Technologies Inc. MOBILITY RADEON 9600 x86/SSE2
+ATI Technologies Inc. MOBILITY RADEON 9700 x86/SSE2
+ATI Technologies Inc. MOBILITY RADEON X300 x86/SSE2
+ATI Technologies Inc. MOBILITY RADEON X600 x86/SSE2
+ATI Technologies Inc. MOBILITY RADEON X700 SE x86
+ATI Technologies Inc. MOBILITY RADEON X700 x86/SSE2
+ATI Technologies Inc. MSI RX9550SE
+ATI Technologies Inc. Mobility Radeon X2300 HD
+ATI Technologies Inc. Mobility Radeon X2300 HD x86/SSE2
+ATI Technologies Inc. RADEON 7000 DDR x86/MMX/3DNow!/SSE
+ATI Technologies Inc. RADEON 7000 DDR x86/SSE2
+ATI Technologies Inc. RADEON 7500 DDR x86/MMX/3DNow!/SSE2
+ATI Technologies Inc. RADEON 7500 DDR x86/SSE2
+ATI Technologies Inc. RADEON 9100 IGP DDR x86/SSE2
+ATI Technologies Inc. RADEON 9200 DDR x86/MMX/3DNow!/SSE
+ATI Technologies Inc. RADEON 9200 DDR x86/SSE2
+ATI Technologies Inc. RADEON 9200 PRO DDR x86/MMX/3DNow!/SSE
+ATI Technologies Inc. RADEON 9200 Series DDR x86/MMX/3DNow!/SSE
+ATI Technologies Inc. RADEON 9200 Series DDR x86/MMX/3DNow!/SSE2
+ATI Technologies Inc. RADEON 9200 Series DDR x86/SSE
+ATI Technologies Inc. RADEON 9200 Series DDR x86/SSE2
+ATI Technologies Inc. RADEON 9200SE DDR x86/MMX/3DNow!/SSE2
+ATI Technologies Inc. RADEON 9200SE DDR x86/SSE2
+ATI Technologies Inc. RADEON 9250/9200 Series DDR x86/MMX/3DNow!/SSE
+ATI Technologies Inc. RADEON 9250/9200 Series DDR x86/MMX/3DNow!/SSE2
+ATI Technologies Inc. RADEON 9250/9200 Series DDR x86/SSE2
+ATI Technologies Inc. RADEON 9500
+ATI Technologies Inc. RADEON 9550 x86/SSE2
+ATI Technologies Inc. RADEON 9600 SERIES
+ATI Technologies Inc. RADEON 9600 SERIES x86/MMX/3DNow!/SSE2
+ATI Technologies Inc. RADEON 9600 TX x86/SSE2
+ATI Technologies Inc. RADEON 9600 x86/MMX/3DNow!/SSE2
+ATI Technologies Inc. RADEON 9600 x86/SSE2
+ATI Technologies Inc. RADEON 9700 PRO x86/MMX/3DNow!/SSE
+ATI Technologies Inc. RADEON 9800 PRO
+ATI Technologies Inc. RADEON 9800 x86/SSE2
+ATI Technologies Inc. RADEON IGP 340M DDR x86/SSE2
+ATI Technologies Inc. RADEON X300 Series x86/SSE2
+ATI Technologies Inc. RADEON X300 x86/SSE2
+ATI Technologies Inc. RADEON X300/X550 Series x86/SSE2
+ATI Technologies Inc. RADEON X550 x86/MMX/3DNow!/SSE2
+ATI Technologies Inc. RADEON X550 x86/SSE2
+ATI Technologies Inc. RADEON X600 Series
+ATI Technologies Inc. RADEON X600 x86/SSE2
+ATI Technologies Inc. RADEON X700 PRO x86/SSE2
+ATI Technologies Inc. RADEON X800 SE x86/MMX/3DNow!/SSE2
+ATI Technologies Inc. RADEON X800GT
+ATI Technologies Inc. RADEON XPRESS 200 Series SW TCL x86/MMX/3DNow!/SSE2
+ATI Technologies Inc. RADEON XPRESS 200 Series SW TCL x86/SSE2
+ATI Technologies Inc. RADEON XPRESS 200 Series x86/SSE2
+ATI Technologies Inc. RADEON XPRESS 200M Series SW TCL x86/MMX/3DNow!/SSE2
+ATI Technologies Inc. RADEON XPRESS 200M Series SW TCL x86/SSE2
+ATI Technologies Inc. RADEON XPRESS 200M Series x86/MMX/3DNow!/SSE2
+ATI Technologies Inc. RADEON XPRESS 200M Series x86/SSE2
+ATI Technologies Inc. RADEON XPRESS Series x86/MMX/3DNow!/SSE2
+ATI Technologies Inc. RADEON XPRESS Series x86/SSE2
+ATI Technologies Inc. RS740
+ATI Technologies Inc. RS780C
+ATI Technologies Inc. RS780M
+ATI Technologies Inc. RS880
+ATI Technologies Inc. RV410 Pro x86/SSE2
+ATI Technologies Inc. RV790
+ATI Technologies Inc. Radeon (TM) HD 6470M
+ATI Technologies Inc. Radeon (TM) HD 6490M
+ATI Technologies Inc. Radeon (TM) HD 6770M
+ATI Technologies Inc. Radeon 7000 DDR x86/SSE2
+ATI Technologies Inc. Radeon 7000 SDR x86/SSE2
+ATI Technologies Inc. Radeon 7500 DDR x86/SSE2
+ATI Technologies Inc. Radeon 9000 DDR x86/SSE2
+ATI Technologies Inc. Radeon DDR x86/MMX/3DNow!/SSE2
+ATI Technologies Inc. Radeon DDR x86/SSE
+ATI Technologies Inc. Radeon DDR x86/SSE2
+ATI Technologies Inc. Radeon HD 6310
+ATI Technologies Inc. Radeon HD 6800 Series
+ATI Technologies Inc. Radeon SDR x86/SSE2
+ATI Technologies Inc. Radeon X1300 Series
+ATI Technologies Inc. Radeon X1300 Series x86/MMX/3DNow!/SSE2
+ATI Technologies Inc. Radeon X1300 Series x86/SSE2
+ATI Technologies Inc. Radeon X1300/X1550 Series
+ATI Technologies Inc. Radeon X1300/X1550 Series x86/SSE2
+ATI Technologies Inc. Radeon X1550 64-bit (Microsoft - WDDM)
+ATI Technologies Inc. Radeon X1550 Series
+ATI Technologies Inc. Radeon X1550 Series x86/SSE2
+ATI Technologies Inc. Radeon X1600
+ATI Technologies Inc. Radeon X1600 Pro / X1300XT x86/MMX/3DNow!/SSE2
+ATI Technologies Inc. Radeon X1600 Series x86/SSE2
+ATI Technologies Inc. Radeon X1600/X1650 Series
+ATI Technologies Inc. Radeon X1650 Series
+ATI Technologies Inc. Radeon X1650 Series x86/MMX/3DNow!/SSE2
+ATI Technologies Inc. Radeon X1650 Series x86/SSE2
+ATI Technologies Inc. Radeon X1900 Series x86/MMX/3DNow!/SSE2
+ATI Technologies Inc. Radeon X1950 Pro
+ATI Technologies Inc. Radeon X1950 Pro x86/MMX/3DNow!/SSE2
+ATI Technologies Inc. Radeon X1950 Series
+ATI Technologies Inc. Radeon X1950 Series (Microsoft - WDDM)
+ATI Technologies Inc. Radeon X300/X550/X1050 Series
+ATI Technologies Inc. Radeon X550/X700 Series
+ATI Technologies Inc. Radeon X550XTX x86/MMX/3DNow!/SSE2
+ATI Technologies Inc. SAPPHIRE RADEON X300SE
+ATI Technologies Inc. SAPPHIRE RADEON X300SE x86/MMX/3DNow!/SSE2
+ATI Technologies Inc. SAPPHIRE RADEON X300SE x86/SSE2
+ATI Technologies Inc. SAPPHIRE Radeon X1550 Series
+ATI Technologies Inc. SAPPHIRE Radeon X1550 Series x86/MMX/3DNow!/SSE2
+ATI Technologies Inc. Sapphire Radeon HD 3730
+ATI Technologies Inc. Sapphire Radeon HD 3750
+ATI Technologies Inc. Standard VGA Graphics Adapter
+ATI Technologies Inc. Tul, RADEON X600 PRO
+ATI Technologies Inc. Tul, RADEON X600 PRO x86/SSE2
+ATI Technologies Inc. Tul, RADEON X700 PRO
+ATI Technologies Inc. Tul, RADEON X700 PRO x86/MMX/3DNow!/SSE2
+ATI Technologies Inc. VisionTek Radeon 4350
+ATI Technologies Inc. VisionTek Radeon X1550 Series
+ATI Technologies Inc. WRESTLER 9802
+ATI Technologies Inc. WRESTLER 9803
+ATI Technologies Inc. XFX Radeon HD 4570
+ATI Technologies Inc. Yamaha ATI HD 9000da/s
+ATI Technologies Inc. Yamaha ATI HD 9000da/s 2048
+Advanced Micro Devices, Inc. Mesa DRI R600 (RS780 9612) 20090101 x86/MMX+/3DNow!+/SSE2 TCL DRI2
+Advanced Micro Devices, Inc. Mesa DRI R600 (RS880 9710) 20090101 x86/MMX+/3DNow!+/SSE2 TCL DRI2
+Advanced Micro Devices, Inc. Mesa DRI R600 (RS880 9712) 20090101 TCL
+Advanced Micro Devices, Inc. Mesa DRI R600 (RV610 94C1) 20090101 x86/MMX+/3DNow!+/SSE2 TCL DRI2
+Advanced Micro Devices, Inc. Mesa DRI R600 (RV610 94C9) 20090101 x86/MMX/SSE2 TCL DRI2
+Advanced Micro Devices, Inc. Mesa DRI R600 (RV620 95C4) 20090101 x86/MMX/SSE2 TCL DRI2
+Advanced Micro Devices, Inc. Mesa DRI R600 (RV620 95C5) 20090101 x86/MMX+/3DNow!+/SSE2 TCL DRI2
+Advanced Micro Devices, Inc. Mesa DRI R600 (RV620 95C5) 20090101 x86/MMX/SSE2 TCL DRI2
+Advanced Micro Devices, Inc. Mesa DRI R600 (RV635 9596) 20090101 x86/MMX+/3DNow!+/SSE TCL DRI2
+Advanced Micro Devices, Inc. Mesa DRI R600 (RV670 9505) 20090101 x86/MMX+/3DNow!+/SSE2 TCL DRI2
+Advanced Micro Devices, Inc. Mesa DRI R600 (RV710 9552) 20090101 x86/MMX/SSE2 TCL DRI2
+Advanced Micro Devices, Inc. Mesa DRI R600 (RV730 9490) 20090101 x86/MMX+/3DNow!+/SSE2 TCL DRI2
+Advanced Micro Devices, Inc. Mesa DRI R600 (RV730 9490) 20090101 x86/MMX/SSE2 TCL DRI2
+Advanced Micro Devices, Inc. Mesa DRI R600 (RV730 9498) 20090101 TCL DRI2
+Advanced Micro Devices, Inc. Mesa DRI R600 (RV770 9440) 20090101 x86/MMX+/3DNow!+/SSE2 TCL DRI2
+Advanced Micro Devices, Inc. Mesa DRI R600 (RV770 9442) 20090101 x86/MMX/SSE2 TCL DRI2
+Alex Mohr GL Hijacker!
+Apple Software Renderer
+DRI R300 Project Mesa DRI R300 (RS400 5954) 20090101 x86/MMX+/3DNow!+/SSE2 NO-TCL DRI2
+DRI R300 Project Mesa DRI R300 (RS400 5975) 20090101 x86/MMX+/3DNow!+/SSE2 NO-TCL DRI2
+DRI R300 Project Mesa DRI R300 (RS400 5A62) 20090101 x86/MMX/SSE2 NO-TCL DRI2
+DRI R300 Project Mesa DRI R300 (RS600 7941) 20090101 x86/MMX/SSE2 NO-TCL
+DRI R300 Project Mesa DRI R300 (RS690 791F) 20090101 x86/MMX+/3DNow!+/SSE2 NO-TCL DRI2
+DRI R300 Project Mesa DRI R300 (RV350 4151) 20090101 AGP 4x x86/MMX+/3DNow!+/SSE TCL
+DRI R300 Project Mesa DRI R300 (RV350 4153) 20090101 AGP 8x x86/MMX+/3DNow!+/SSE TCL
+DRI R300 Project Mesa DRI R300 (RV380 3150) 20090101 x86/MMX+/3DNow!+/SSE2 TCL DRI2
+DRI R300 Project Mesa DRI R300 (RV380 3150) 20090101 x86/MMX/SSE2 TCL DRI2
+DRI R300 Project Mesa DRI R300 (RV380 5B60) 20090101 x86/MMX/SSE2 TCL DRI2
+DRI R300 Project Mesa DRI R300 (RV380 5B62) 20090101 x86/MMX+/3DNow!+/SSE2 TCL DRI2
+DRI R300 Project Mesa DRI R300 (RV515 7145) 20090101 x86/MMX/SSE2 TCL DRI2
+DRI R300 Project Mesa DRI R300 (RV515 7146) 20090101 x86/MMX+/3DNow!+/SSE2 TCL DRI2
+DRI R300 Project Mesa DRI R300 (RV515 7146) 20090101 x86/MMX/SSE2 TCL DRI2
+DRI R300 Project Mesa DRI R300 (RV515 7149) 20090101 x86/MMX/SSE2 TCL DRI2
+DRI R300 Project Mesa DRI R300 (RV515 714A) 20090101 x86/MMX/SSE2 TCL
+DRI R300 Project Mesa DRI R300 (RV515 714A) 20090101 x86/MMX/SSE2 TCL DRI2
+DRI R300 Project Mesa DRI R300 (RV530 71C4) 20090101 x86/MMX/SSE2 TCL DRI2
+GPU_CLASS_UNKNOWN
+Humper Chromium
+Intel
+Intel HD Graphics Family
+Intel 3D-Analyze v2.2 - http://www.tommti-systems.com
+Intel 3D-Analyze v2.3 - http://www.tommti-systems.com
+Intel 4 Series Internal Chipset
+Intel 830M
+Intel 845G
+Intel 855GM
+Intel 865G
+Intel 915G
+Intel 915GM
+Intel 945G
+Intel 945GM
+Intel 950
+Intel 965
+Intel B43 Express Chipset
+Intel Bear Lake
+Intel Broadwater
+Intel Brookdale
+Intel Cantiga
+Intel Eaglelake
+Intel Familia Mobile 45 Express Chipset (Microsoft Corporation - WDDM 1.1)
+Intel G33
+Intel G41
+Intel G41 Express Chipset
+Intel G45
+Intel G45/G43 Express Chipset
+Intel Graphics Media Accelerator HD
+Intel HD Graphics
+Intel HD Graphics 100
+Intel HD Graphics 200
+Intel HD Graphics 200 BR-1101-00SH
+Intel HD Graphics 200 BR-1101-00SJ
+Intel HD Graphics 200 BR-1101-00SK
+Intel HD Graphics 200 BR-1101-01M5
+Intel HD Graphics 200 BR-1101-01M6
+Intel HD Graphics BR-1004-01Y1
+Intel HD Graphics BR-1006-0364
+Intel HD Graphics BR-1006-0365
+Intel HD Graphics BR-1006-0366
+Intel HD Graphics BR-1007-02G4
+Intel HD Graphics BR-1101-04SY
+Intel HD Graphics BR-1101-04SZ
+Intel HD Graphics BR-1101-04T0
+Intel HD Graphics BR-1101-04T9
+Intel HD Graphics Family
+Intel HD Graphics Family BR-1012-00Y8
+Intel HD Graphics Family BR-1012-00YF
+Intel HD Graphics Family BR-1012-00ZD
+Intel HD Graphics Family BR-1102-00ML
+Intel Inc. Intel GMA 900 OpenGL Engine
+Intel Inc. Intel GMA 950 OpenGL Engine
+Intel Inc. Intel GMA X3100 OpenGL Engine
+Intel Inc. Intel HD Graphics 3000 OpenGL Engine
+Intel Inc. Intel HD Graphics OpenGL Engine
+Intel Inc. Intel HD xxxx OpenGL Engine
+Intel Intel 845G
+Intel Intel 855GM
+Intel Intel 865G
+Intel Intel 915G
+Intel Intel 915GM
+Intel Intel 945G
+Intel Intel 945GM
+Intel Intel 965/963 Graphics Media Accelerator
+Intel Intel Bear Lake B
+Intel Intel Broadwater G
+Intel Intel Brookdale-G
+Intel Intel Calistoga
+Intel Intel Cantiga
+Intel Intel Eaglelake
+Intel Intel Grantsdale-G
+Intel Intel HD Graphics 3000
+Intel Intel Lakeport
+Intel Intel Montara-GM
+Intel Intel Pineview Platform
+Intel Intel Springdale-G
+Intel Mobile - famiglia Express Chipset 45 (Microsoft Corporation - WDDM 1.1)
+Intel Mobile 4 Series
+Intel Mobile 4 Series Express Chipset Family
+Intel Mobile 45 Express Chipset Family (Microsoft Corporation - WDDM 1.1)
+Intel Mobile HD Graphics
+Intel Mobile SandyBridge HD Graphics
+Intel Montara
+Intel Pineview
+Intel Q45/Q43 Express Chipset
+Intel Royal BNA Driver
+Intel SandyBridge HD Graphics
+Intel SandyBridge HD Graphics BR-1006-00V8
+Intel Springdale
+Intel X3100
+Intergraph wcgdrv 06.05.06.18
+Intergraph wcgdrv 06.06.00.35
+LegendgrafiX Mobile 945 Express C/TitaniumGL/GAC/D3D ACCELERATION/6x86/1 THREADs | http://LegendgrafiX.tk
+LegendgrafiX NVIDIA GeForce GT 430/TitaniumGL/GAC/D3D ACCELERATION/6x86/1 THREADs | http://LegendgrafiX.tk
+Linden Lab Headless
+Matrox
+Mesa
+Mesa Project Software Rasterizer
+NVIDIA /PCI/SSE2
+NVIDIA /PCI/SSE2/3DNOW!
+NVIDIA 205
+NVIDIA 210
+NVIDIA 310
+NVIDIA 310M
+NVIDIA 315
+NVIDIA 315M
+NVIDIA 320M
+NVIDIA C51
+NVIDIA D10M2-20/PCI/SSE2
+NVIDIA D10P1-25/PCI/SSE2
+NVIDIA D10P1-30/PCI/SSE2
+NVIDIA D10P2-50/PCI/SSE2
+NVIDIA D11M2-30/PCI/SSE2
+NVIDIA D12-P1-35/PCI/SSE2
+NVIDIA D12U-15/PCI/SSE2
+NVIDIA D13M1-40/PCI/SSE2
+NVIDIA D13P1-40/PCI/SSE2
+NVIDIA D13U-10/PCI/SSE2
+NVIDIA D13U/PCI/SSE2
+NVIDIA D9M
+NVIDIA D9M-20/PCI/SSE2
+NVIDIA Entry Graphics/PCI/SSE2
+NVIDIA Entry Graphics/PCI/SSE2/3DNOW!
+NVIDIA G 102M
+NVIDIA G 103M
+NVIDIA G 105M
+NVIDIA G 110M
+NVIDIA G100
+NVIDIA G102M
+NVIDIA G103M
+NVIDIA G105M
+NVIDIA G210
+NVIDIA G210M
+NVIDIA G70/PCI/SSE2
+NVIDIA G72
+NVIDIA G73
+NVIDIA G84
+NVIDIA G86
+NVIDIA G92
+NVIDIA G92-200/PCI/SSE2
+NVIDIA G94
+NVIDIA G96/PCI/SSE2
+NVIDIA G98/PCI/SSE2
+NVIDIA GT 120
+NVIDIA GT 130
+NVIDIA GT 130M
+NVIDIA GT 140
+NVIDIA GT 150
+NVIDIA GT 160M
+NVIDIA GT 220
+NVIDIA GT 220/PCI/SSE2
+NVIDIA GT 220/PCI/SSE2/3DNOW!
+NVIDIA GT 230
+NVIDIA GT 230M
+NVIDIA GT 240
+NVIDIA GT 240M
+NVIDIA GT 250M
+NVIDIA GT 260M
+NVIDIA GT 320
+NVIDIA GT 320M
+NVIDIA GT 330
+NVIDIA GT 330M
+NVIDIA GT 340
+NVIDIA GT 420
+NVIDIA GT 430
+NVIDIA GT 440
+NVIDIA GT 450
+NVIDIA GT 520
+NVIDIA GT 540
+NVIDIA GT 540M
+NVIDIA GT-120
+NVIDIA GT200/PCI/SSE2
+NVIDIA GTS 150
+NVIDIA GTS 240
+NVIDIA GTS 250
+NVIDIA GTS 350M
+NVIDIA GTS 360
+NVIDIA GTS 360M
+NVIDIA GTS 450
+NVIDIA GTX 260
+NVIDIA GTX 260M
+NVIDIA GTX 270
+NVIDIA GTX 280
+NVIDIA GTX 285
+NVIDIA GTX 290
+NVIDIA GTX 460
+NVIDIA GTX 460M
+NVIDIA GTX 465
+NVIDIA GTX 470
+NVIDIA GTX 470M
+NVIDIA GTX 480
+NVIDIA GTX 480M
+NVIDIA GTX 550 Ti
+NVIDIA GTX 560
+NVIDIA GTX 560 Ti
+NVIDIA GTX 570
+NVIDIA GTX 580
+NVIDIA GTX 590
+NVIDIA GeForce
+NVIDIA GeForce 2
+NVIDIA GeForce 205/PCI/SSE2
+NVIDIA GeForce 210
+NVIDIA GeForce 210/PCI/SSE2
+NVIDIA GeForce 210/PCI/SSE2/3DNOW!
+NVIDIA GeForce 3
+NVIDIA GeForce 305M/PCI/SSE2
+NVIDIA GeForce 310/PCI/SSE2
+NVIDIA GeForce 310/PCI/SSE2/3DNOW!
+NVIDIA GeForce 310M/PCI/SSE2
+NVIDIA GeForce 315/PCI/SSE2
+NVIDIA GeForce 315/PCI/SSE2/3DNOW!
+NVIDIA GeForce 315M/PCI/SSE2
+NVIDIA GeForce 320M/PCI/SSE2
+NVIDIA GeForce 4 Go
+NVIDIA GeForce 4 MX
+NVIDIA GeForce 4 Ti
+NVIDIA GeForce 405/PCI/SSE2
+NVIDIA GeForce 6100
+NVIDIA GeForce 6100 nForce 400/PCI/SSE2/3DNOW!
+NVIDIA GeForce 6100 nForce 405/PCI/SSE2
+NVIDIA GeForce 6100 nForce 405/PCI/SSE2/3DNOW!
+NVIDIA GeForce 6100 nForce 420/PCI/SSE2/3DNOW!
+NVIDIA GeForce 6100 nForce 430/PCI/SSE2/3DNOW!
+NVIDIA GeForce 6100/PCI/SSE2/3DNOW!
+NVIDIA GeForce 6150 LE/PCI/SSE2/3DNOW!
+NVIDIA GeForce 6150/PCI/SSE2
+NVIDIA GeForce 6150/PCI/SSE2/3DNOW!
+NVIDIA GeForce 6150SE nForce 430/PCI/SSE2
+NVIDIA GeForce 6150SE nForce 430/PCI/SSE2/3DNOW!
+NVIDIA GeForce 6150SE/PCI/SSE2/3DNOW!
+NVIDIA GeForce 6200
+NVIDIA GeForce 6200 A-LE/AGP/SSE/3DNOW!
+NVIDIA GeForce 6200 A-LE/AGP/SSE2
+NVIDIA GeForce 6200 A-LE/AGP/SSE2/3DNOW!
+NVIDIA GeForce 6200 LE/PCI/SSE2
+NVIDIA GeForce 6200 LE/PCI/SSE2/3DNOW!
+NVIDIA GeForce 6200 TurboCache(TM)/PCI/SSE2
+NVIDIA GeForce 6200 TurboCache(TM)/PCI/SSE2/3DNOW!
+NVIDIA GeForce 6200/AGP/SSE/3DNOW!
+NVIDIA GeForce 6200/AGP/SSE2
+NVIDIA GeForce 6200/AGP/SSE2/3DNOW!
+NVIDIA GeForce 6200/PCI/SSE/3DNOW!
+NVIDIA GeForce 6200/PCI/SSE2
+NVIDIA GeForce 6200/PCI/SSE2/3DNOW!
+NVIDIA GeForce 6200SE TurboCache(TM)/PCI/SSE2/3DNOW!
+NVIDIA GeForce 6500
+NVIDIA GeForce 6500/PCI/SSE2
+NVIDIA GeForce 6600
+NVIDIA GeForce 6600 GT/AGP/SSE/3DNOW!
+NVIDIA GeForce 6600 GT/AGP/SSE2
+NVIDIA GeForce 6600 GT/PCI/SSE/3DNOW!
+NVIDIA GeForce 6600 GT/PCI/SSE2
+NVIDIA GeForce 6600 GT/PCI/SSE2/3DNOW!
+NVIDIA GeForce 6600 LE/PCI/SSE2
+NVIDIA GeForce 6600/AGP/SSE/3DNOW!
+NVIDIA GeForce 6600/AGP/SSE2
+NVIDIA GeForce 6600/AGP/SSE2/3DNOW!
+NVIDIA GeForce 6600/PCI/SSE2
+NVIDIA GeForce 6600/PCI/SSE2/3DNOW!
+NVIDIA GeForce 6700
+NVIDIA GeForce 6800
+NVIDIA GeForce 6800 GS/PCI/SSE2/3DNOW!
+NVIDIA GeForce 6800 GT/AGP/SSE2
+NVIDIA GeForce 6800 GT/PCI/SSE2
+NVIDIA GeForce 6800 XT/AGP/SSE2
+NVIDIA GeForce 6800 XT/PCI/SSE2
+NVIDIA GeForce 6800/PCI/SSE2
+NVIDIA GeForce 6800/PCI/SSE2/3DNOW!
+NVIDIA GeForce 7000
+NVIDIA GeForce 7000M
+NVIDIA GeForce 7000M / nForce 610M/PCI/SSE2
+NVIDIA GeForce 7000M / nForce 610M/PCI/SSE2/3DNOW!
+NVIDIA GeForce 7025 / NVIDIA nForce 630a/PCI/SSE2/3DNOW!
+NVIDIA GeForce 7025 / nForce 630a/PCI/SSE2
+NVIDIA GeForce 7025 / nForce 630a/PCI/SSE2/3DNOW!
+NVIDIA GeForce 7050 / NVIDIA nForce 610i/PCI/SSE2
+NVIDIA GeForce 7050 / NVIDIA nForce 620i/PCI/SSE2
+NVIDIA GeForce 7050 / nForce 610i/PCI/SSE2
+NVIDIA GeForce 7050 / nForce 620i/PCI/SSE2
+NVIDIA GeForce 7050 PV / NVIDIA nForce 630a/PCI/SSE2/3DNOW!
+NVIDIA GeForce 7050 PV / nForce 630a/PCI/SSE2
+NVIDIA GeForce 7050 PV / nForce 630a/PCI/SSE2/3DNOW!
+NVIDIA GeForce 7050 SE / NVIDIA nForce 630a/PCI/SSE2/3DNOW!
+NVIDIA GeForce 7100
+NVIDIA GeForce 7100 / NVIDIA nForce 620i/PCI/SSE2
+NVIDIA GeForce 7100 / NVIDIA nForce 630i/PCI/SSE2
+NVIDIA GeForce 7100 / nForce 630i/PCI/SSE2
+NVIDIA GeForce 7100 GS/PCI/SSE2
+NVIDIA GeForce 7100 GS/PCI/SSE2/3DNOW!
+NVIDIA GeForce 7150M / nForce 630M/PCI/SSE2
+NVIDIA GeForce 7150M / nForce 630M/PCI/SSE2/3DNOW!
+NVIDIA GeForce 7300
+NVIDIA GeForce 7300 GS/PCI/SSE2
+NVIDIA GeForce 7300 GS/PCI/SSE2/3DNOW!
+NVIDIA GeForce 7300 GT/AGP/SSE2
+NVIDIA GeForce 7300 GT/AGP/SSE2/3DNOW!
+NVIDIA GeForce 7300 GT/PCI/SSE2
+NVIDIA GeForce 7300 GT/PCI/SSE2/3DNOW!
+NVIDIA GeForce 7300 LE/PCI/SSE2
+NVIDIA GeForce 7300 LE/PCI/SSE2/3DNOW!
+NVIDIA GeForce 7300 SE/7200 GS/PCI/SSE2
+NVIDIA GeForce 7300 SE/7200 GS/PCI/SSE2/3DNOW!
+NVIDIA GeForce 7300 SE/PCI/SSE2
+NVIDIA GeForce 7300 SE/PCI/SSE2/3DNOW!
+NVIDIA GeForce 7350 LE/PCI/SSE2
+NVIDIA GeForce 7500
+NVIDIA GeForce 7500 LE/PCI/SSE2
+NVIDIA GeForce 7500 LE/PCI/SSE2/3DNOW!
+NVIDIA GeForce 7600
+NVIDIA GeForce 7600 GS/AGP/SSE2
+NVIDIA GeForce 7600 GS/AGP/SSE2/3DNOW!
+NVIDIA GeForce 7600 GS/PCI/SSE2
+NVIDIA GeForce 7600 GS/PCI/SSE2/3DNOW!
+NVIDIA GeForce 7600 GT/AGP/SSE/3DNOW!
+NVIDIA GeForce 7600 GT/AGP/SSE2
+NVIDIA GeForce 7600 GT/PCI/SSE2
+NVIDIA GeForce 7600 GT/PCI/SSE2/3DNOW!
+NVIDIA GeForce 7650 GS/PCI/SSE2
+NVIDIA GeForce 7800
+NVIDIA GeForce 7800 GS/AGP/SSE2
+NVIDIA GeForce 7800 GS/AGP/SSE2/3DNOW!
+NVIDIA GeForce 7800 GT/PCI/SSE2
+NVIDIA GeForce 7800 GTX/PCI/SSE2
+NVIDIA GeForce 7800 GTX/PCI/SSE2/3DNOW!
+NVIDIA GeForce 7900
+NVIDIA GeForce 7900 GS/PCI/SSE2
+NVIDIA GeForce 7900 GS/PCI/SSE2/3DNOW!
+NVIDIA GeForce 7900 GT/GTO/PCI/SSE2
+NVIDIA GeForce 7900 GT/PCI/SSE2/3DNOW!
+NVIDIA GeForce 7900 GTX/PCI/SSE2
+NVIDIA GeForce 7950 GT/PCI/SSE2
+NVIDIA GeForce 7950 GT/PCI/SSE2/3DNOW!
+NVIDIA GeForce 8100
+NVIDIA GeForce 8100 / nForce 720a/PCI/SSE2/3DNOW!
+NVIDIA GeForce 8200
+NVIDIA GeForce 8200/PCI/SSE2
+NVIDIA GeForce 8200/PCI/SSE2/3DNOW!
+NVIDIA GeForce 8200M
+NVIDIA GeForce 8200M G/PCI/SSE2
+NVIDIA GeForce 8200M G/PCI/SSE2/3DNOW!
+NVIDIA GeForce 8300
+NVIDIA GeForce 8300 GS/PCI/SSE2
+NVIDIA GeForce 8400
+NVIDIA GeForce 8400 GS/PCI/SSE/3DNOW!
+NVIDIA GeForce 8400 GS/PCI/SSE2
+NVIDIA GeForce 8400 GS/PCI/SSE2/3DNOW!
+NVIDIA GeForce 8400/PCI/SSE2/3DNOW!
+NVIDIA GeForce 8400GS/PCI/SSE2
+NVIDIA GeForce 8400GS/PCI/SSE2/3DNOW!
+NVIDIA GeForce 8400M
+NVIDIA GeForce 8400M G/PCI/SSE2
+NVIDIA GeForce 8400M G/PCI/SSE2/3DNOW!
+NVIDIA GeForce 8400M GS/PCI/SSE2
+NVIDIA GeForce 8400M GS/PCI/SSE2/3DNOW!
+NVIDIA GeForce 8400M GT/PCI/SSE2
+NVIDIA GeForce 8500
+NVIDIA GeForce 8500 GT/PCI/SSE2
+NVIDIA GeForce 8500 GT/PCI/SSE2/3DNOW!
+NVIDIA GeForce 8600
+NVIDIA GeForce 8600 GS/PCI/SSE2
+NVIDIA GeForce 8600 GS/PCI/SSE2/3DNOW!
+NVIDIA GeForce 8600 GT/PCI/SSE2
+NVIDIA GeForce 8600 GT/PCI/SSE2/3DNOW!
+NVIDIA GeForce 8600 GTS/PCI/SSE2
+NVIDIA GeForce 8600 GTS/PCI/SSE2/3DNOW!
+NVIDIA GeForce 8600GS/PCI/SSE2
+NVIDIA GeForce 8600M
+NVIDIA GeForce 8600M GS/PCI/SSE2
+NVIDIA GeForce 8600M GS/PCI/SSE2/3DNOW!
+NVIDIA GeForce 8600M GT/PCI/SSE2
+NVIDIA GeForce 8700
+NVIDIA GeForce 8700M
+NVIDIA GeForce 8700M GT/PCI/SSE2
+NVIDIA GeForce 8800
+NVIDIA GeForce 8800 GS/PCI/SSE2
+NVIDIA GeForce 8800 GT/PCI/SSE2
+NVIDIA GeForce 8800 GT/PCI/SSE2/3DNOW!
+NVIDIA GeForce 8800 GTS 512/PCI/SSE2
+NVIDIA GeForce 8800 GTS 512/PCI/SSE2/3DNOW!
+NVIDIA GeForce 8800 GTS/PCI/SSE2
+NVIDIA GeForce 8800 GTS/PCI/SSE2/3DNOW!
+NVIDIA GeForce 8800 GTX/PCI/SSE2
+NVIDIA GeForce 8800 Ultra/PCI/SSE2
+NVIDIA GeForce 8800M GTS/PCI/SSE2
+NVIDIA GeForce 8800M GTX/PCI/SSE2
+NVIDIA GeForce 9100
+NVIDIA GeForce 9100/PCI/SSE2
+NVIDIA GeForce 9100/PCI/SSE2/3DNOW!
+NVIDIA GeForce 9100M
+NVIDIA GeForce 9100M G/PCI/SSE2
+NVIDIA GeForce 9100M G/PCI/SSE2/3DNOW!
+NVIDIA GeForce 9200
+NVIDIA GeForce 9200/PCI/SSE2
+NVIDIA GeForce 9200/PCI/SSE2/3DNOW!
+NVIDIA GeForce 9200M GE/PCI/SSE2
+NVIDIA GeForce 9200M GS/PCI/SSE2
+NVIDIA GeForce 9300
+NVIDIA GeForce 9300 / nForce 730i/PCI/SSE2
+NVIDIA GeForce 9300 GE/PCI/SSE2
+NVIDIA GeForce 9300 GE/PCI/SSE2/3DNOW!
+NVIDIA GeForce 9300 GS/PCI/SSE2
+NVIDIA GeForce 9300 GS/PCI/SSE2/3DNOW!
+NVIDIA GeForce 9300 SE/PCI/SSE2
+NVIDIA GeForce 9300M
+NVIDIA GeForce 9300M G/PCI/SSE2
+NVIDIA GeForce 9300M G/PCI/SSE2/3DNOW!
+NVIDIA GeForce 9300M GS/PCI/SSE2
+NVIDIA GeForce 9300M GS/PCI/SSE2/3DNOW!
+NVIDIA GeForce 9400
+NVIDIA GeForce 9400 GT/PCI/SSE2
+NVIDIA GeForce 9400 GT/PCI/SSE2/3DNOW!
+NVIDIA GeForce 9400/PCI/SSE2
+NVIDIA GeForce 9400M
+NVIDIA GeForce 9400M G/PCI/SSE2
+NVIDIA GeForce 9400M/PCI/SSE2
+NVIDIA GeForce 9500
+NVIDIA GeForce 9500 GS/PCI/SSE2
+NVIDIA GeForce 9500 GS/PCI/SSE2/3DNOW!
+NVIDIA GeForce 9500 GT/PCI/SSE2
+NVIDIA GeForce 9500 GT/PCI/SSE2/3DNOW!
+NVIDIA GeForce 9500M
+NVIDIA GeForce 9500M GS/PCI/SSE2
+NVIDIA GeForce 9600
+NVIDIA GeForce 9600 GS/PCI/SSE2
+NVIDIA GeForce 9600 GSO 512/PCI/SSE2
+NVIDIA GeForce 9600 GSO/PCI/SSE2
+NVIDIA GeForce 9600 GSO/PCI/SSE2/3DNOW!
+NVIDIA GeForce 9600 GT/PCI/SSE2
+NVIDIA GeForce 9600 GT/PCI/SSE2/3DNOW!
+NVIDIA GeForce 9600M
+NVIDIA GeForce 9600M GS/PCI/SSE2
+NVIDIA GeForce 9600M GT/PCI/SSE2
+NVIDIA GeForce 9650M GT/PCI/SSE2
+NVIDIA GeForce 9700M
+NVIDIA GeForce 9700M GT/PCI/SSE2
+NVIDIA GeForce 9700M GTS/PCI/SSE2
+NVIDIA GeForce 9800
+NVIDIA GeForce 9800 GT/PCI/SSE2
+NVIDIA GeForce 9800 GT/PCI/SSE2/3DNOW!
+NVIDIA GeForce 9800 GTX+/PCI/SSE2
+NVIDIA GeForce 9800 GTX+/PCI/SSE2/3DNOW!
+NVIDIA GeForce 9800 GTX/9800 GTX+/PCI/SSE2
+NVIDIA GeForce 9800 GTX/PCI/SSE2
+NVIDIA GeForce 9800 GX2/PCI/SSE2
+NVIDIA GeForce 9800M
+NVIDIA GeForce 9800M GS/PCI/SSE2
+NVIDIA GeForce 9800M GT/PCI/SSE2
+NVIDIA GeForce 9800M GTS/PCI/SSE2
+NVIDIA GeForce FX 5100
+NVIDIA GeForce FX 5100/AGP/SSE/3DNOW!
+NVIDIA GeForce FX 5200
+NVIDIA GeForce FX 5200/AGP/SSE
+NVIDIA GeForce FX 5200/AGP/SSE/3DNOW!
+NVIDIA GeForce FX 5200/AGP/SSE2
+NVIDIA GeForce FX 5200/AGP/SSE2/3DNOW!
+NVIDIA GeForce FX 5200/PCI/SSE2
+NVIDIA GeForce FX 5200/PCI/SSE2/3DNOW!
+NVIDIA GeForce FX 5200LE/AGP/SSE2
+NVIDIA GeForce FX 5500
+NVIDIA GeForce FX 5500/AGP/SSE/3DNOW!
+NVIDIA GeForce FX 5500/AGP/SSE2
+NVIDIA GeForce FX 5500/AGP/SSE2/3DNOW!
+NVIDIA GeForce FX 5500/PCI/SSE2
+NVIDIA GeForce FX 5500/PCI/SSE2/3DNOW!
+NVIDIA GeForce FX 5600
+NVIDIA GeForce FX 5600/AGP/SSE2
+NVIDIA GeForce FX 5600/AGP/SSE2/3DNOW!
+NVIDIA GeForce FX 5600XT/AGP/SSE2/3DNOW!
+NVIDIA GeForce FX 5700
+NVIDIA GeForce FX 5700/AGP/SSE/3DNOW!
+NVIDIA GeForce FX 5700LE/AGP/SSE
+NVIDIA GeForce FX 5700LE/AGP/SSE/3DNOW!
+NVIDIA GeForce FX 5800
+NVIDIA GeForce FX 5900
+NVIDIA GeForce FX 5900/AGP/SSE2
+NVIDIA GeForce FX 5900XT/AGP/SSE2
+NVIDIA GeForce FX Go5100
+NVIDIA GeForce FX Go5100/AGP/SSE2
+NVIDIA GeForce FX Go5200
+NVIDIA GeForce FX Go5200/AGP/SSE2
+NVIDIA GeForce FX Go5300
+NVIDIA GeForce FX Go5600
+NVIDIA GeForce FX Go5600/AGP/SSE2
+NVIDIA GeForce FX Go5650/AGP/SSE2
+NVIDIA GeForce FX Go5700
+NVIDIA GeForce FX Go5xxx/AGP/SSE2
+NVIDIA GeForce G 103M/PCI/SSE2
+NVIDIA GeForce G 105M/PCI/SSE2
+NVIDIA GeForce G 110M/PCI/SSE2
+NVIDIA GeForce G100/PCI/SSE2
+NVIDIA GeForce G100/PCI/SSE2/3DNOW!
+NVIDIA GeForce G102M/PCI/SSE2
+NVIDIA GeForce G105M/PCI/SSE2
+NVIDIA GeForce G200/PCI/SSE2
+NVIDIA GeForce G205M/PCI/SSE2
+NVIDIA GeForce G210/PCI/SSE2
+NVIDIA GeForce G210/PCI/SSE2/3DNOW!
+NVIDIA GeForce G210M/PCI/SSE2
+NVIDIA GeForce G310M/PCI/SSE2
+NVIDIA GeForce GT 120/PCI/SSE2
+NVIDIA GeForce GT 120/PCI/SSE2/3DNOW!
+NVIDIA GeForce GT 120M/PCI/SSE2
+NVIDIA GeForce GT 130M/PCI/SSE2
+NVIDIA GeForce GT 140/PCI/SSE2
+NVIDIA GeForce GT 220/PCI/SSE2
+NVIDIA GeForce GT 220/PCI/SSE2/3DNOW!
+NVIDIA GeForce GT 220M/PCI/SSE2
+NVIDIA GeForce GT 230/PCI/SSE2
+NVIDIA GeForce GT 230M/PCI/SSE2
+NVIDIA GeForce GT 240
+NVIDIA GeForce GT 240/PCI/SSE2
+NVIDIA GeForce GT 240/PCI/SSE2/3DNOW!
+NVIDIA GeForce GT 240M/PCI/SSE2
+NVIDIA GeForce GT 320/PCI/SSE2
+NVIDIA GeForce GT 320M/PCI/SSE2
+NVIDIA GeForce GT 325M/PCI/SSE2
+NVIDIA GeForce GT 330/PCI/SSE2
+NVIDIA GeForce GT 330/PCI/SSE2/3DNOW!
+NVIDIA GeForce GT 330M/PCI/SSE2
+NVIDIA GeForce GT 335M/PCI/SSE2
+NVIDIA GeForce GT 340/PCI/SSE2
+NVIDIA GeForce GT 340/PCI/SSE2/3DNOW!
+NVIDIA GeForce GT 415M/PCI/SSE2
+NVIDIA GeForce GT 420/PCI/SSE2
+NVIDIA GeForce GT 420M/PCI/SSE2
+NVIDIA GeForce GT 425M/PCI/SSE2
+NVIDIA GeForce GT 430/PCI/SSE2
+NVIDIA GeForce GT 430/PCI/SSE2/3DNOW!
+NVIDIA GeForce GT 435M/PCI/SSE2
+NVIDIA GeForce GT 440/PCI/SSE2
+NVIDIA GeForce GT 440/PCI/SSE2/3DNOW!
+NVIDIA GeForce GT 445M/PCI/SSE2
+NVIDIA GeForce GT 520M/PCI/SSE2
+NVIDIA GeForce GT 525M/PCI/SSE2
+NVIDIA GeForce GT 540M/PCI/SSE2
+NVIDIA GeForce GT 550M/PCI/SSE2
+NVIDIA GeForce GT 555M/PCI/SSE2
+NVIDIA GeForce GTS 150/PCI/SSE2
+NVIDIA GeForce GTS 160M/PCI/SSE2
+NVIDIA GeForce GTS 240/PCI/SSE2
+NVIDIA GeForce GTS 250/PCI/SSE2
+NVIDIA GeForce GTS 250/PCI/SSE2/3DNOW!
+NVIDIA GeForce GTS 250M/PCI/SSE2
+NVIDIA GeForce GTS 350M/PCI/SSE2
+NVIDIA GeForce GTS 360M/PCI/SSE2
+NVIDIA GeForce GTS 450/PCI/SSE2
+NVIDIA GeForce GTS 450/PCI/SSE2/3DNOW!
+NVIDIA GeForce GTS 455/PCI/SSE2
+NVIDIA GeForce GTX 260/PCI/SSE2
+NVIDIA GeForce GTX 260/PCI/SSE2/3DNOW!
+NVIDIA GeForce GTX 260M/PCI/SSE2
+NVIDIA GeForce GTX 275/PCI/SSE2
+NVIDIA GeForce GTX 280
+NVIDIA GeForce GTX 280/PCI/SSE2
+NVIDIA GeForce GTX 280M/PCI/SSE2
+NVIDIA GeForce GTX 285/PCI/SSE2
+NVIDIA GeForce GTX 295/PCI/SSE2
+NVIDIA GeForce GTX 460 SE/PCI/SSE2
+NVIDIA GeForce GTX 460 SE/PCI/SSE2/3DNOW!
+NVIDIA GeForce GTX 460/PCI/SSE2
+NVIDIA GeForce GTX 460/PCI/SSE2/3DNOW!
+NVIDIA GeForce GTX 460M/PCI/SSE2
+NVIDIA GeForce GTX 465/PCI/SSE2
+NVIDIA GeForce GTX 465/PCI/SSE2/3DNOW!
+NVIDIA GeForce GTX 470/PCI/SSE2
+NVIDIA GeForce GTX 470/PCI/SSE2/3DNOW!
+NVIDIA GeForce GTX 480/PCI/SSE2
+NVIDIA GeForce GTX 550 Ti/PCI/SSE2
+NVIDIA GeForce GTX 550 Ti/PCI/SSE2/3DNOW!
+NVIDIA GeForce GTX 560 Ti/PCI/SSE2
+NVIDIA GeForce GTX 560 Ti/PCI/SSE2/3DNOW!
+NVIDIA GeForce GTX 560/PCI/SSE2
+NVIDIA GeForce GTX 570/PCI/SSE2
+NVIDIA GeForce GTX 570/PCI/SSE2/3DNOW!
+NVIDIA GeForce GTX 580/PCI/SSE2
+NVIDIA GeForce GTX 580/PCI/SSE2/3DNOW!
+NVIDIA GeForce GTX 580M/PCI/SSE2
+NVIDIA GeForce GTX 590/PCI/SSE2
+NVIDIA GeForce Go 6
+NVIDIA GeForce Go 6100
+NVIDIA GeForce Go 6100/PCI/SSE2
+NVIDIA GeForce Go 6100/PCI/SSE2/3DNOW!
+NVIDIA GeForce Go 6150/PCI/SSE2
+NVIDIA GeForce Go 6150/PCI/SSE2/3DNOW!
+NVIDIA GeForce Go 6200
+NVIDIA GeForce Go 6200/PCI/SSE2
+NVIDIA GeForce Go 6400
+NVIDIA GeForce Go 6400/PCI/SSE2
+NVIDIA GeForce Go 6600
+NVIDIA GeForce Go 6600/PCI/SSE2
+NVIDIA GeForce Go 6800
+NVIDIA GeForce Go 6800 Ultra/PCI/SSE2
+NVIDIA GeForce Go 6800/PCI/SSE2
+NVIDIA GeForce Go 7200
+NVIDIA GeForce Go 7200/PCI/SSE2
+NVIDIA GeForce Go 7200/PCI/SSE2/3DNOW!
+NVIDIA GeForce Go 7300
+NVIDIA GeForce Go 7300/PCI/SSE2
+NVIDIA GeForce Go 7300/PCI/SSE2/3DNOW!
+NVIDIA GeForce Go 7400
+NVIDIA GeForce Go 7400/PCI/SSE2
+NVIDIA GeForce Go 7400/PCI/SSE2/3DNOW!
+NVIDIA GeForce Go 7600
+NVIDIA GeForce Go 7600/PCI/SSE2
+NVIDIA GeForce Go 7600/PCI/SSE2/3DNOW!
+NVIDIA GeForce Go 7700
+NVIDIA GeForce Go 7800
+NVIDIA GeForce Go 7800 GTX/PCI/SSE2
+NVIDIA GeForce Go 7900
+NVIDIA GeForce Go 7900 GS/PCI/SSE2
+NVIDIA GeForce Go 7900 GTX/PCI/SSE2
+NVIDIA GeForce Go 7950 GTX/PCI/SSE2
+NVIDIA GeForce PCX
+NVIDIA GeForce2 GTS/AGP/SSE
+NVIDIA GeForce2 MX/AGP/3DNOW!
+NVIDIA GeForce2 MX/AGP/SSE/3DNOW!
+NVIDIA GeForce2 MX/AGP/SSE2
+NVIDIA GeForce2 MX/PCI/SSE2
+NVIDIA GeForce3/AGP/SSE/3DNOW!
+NVIDIA GeForce3/AGP/SSE2
+NVIDIA GeForce4 420 Go 32M/AGP/SSE2
+NVIDIA GeForce4 420 Go 32M/AGP/SSE2/3DNOW!
+NVIDIA GeForce4 420 Go 32M/PCI/SSE2/3DNOW!
+NVIDIA GeForce4 440 Go 64M/AGP/SSE2/3DNOW!
+NVIDIA GeForce4 460 Go/AGP/SSE2
+NVIDIA GeForce4 MX 4000/AGP/SSE/3DNOW!
+NVIDIA GeForce4 MX 4000/AGP/SSE2
+NVIDIA GeForce4 MX 4000/PCI/3DNOW!
+NVIDIA GeForce4 MX 4000/PCI/SSE/3DNOW!
+NVIDIA GeForce4 MX 4000/PCI/SSE2
+NVIDIA GeForce4 MX 420/AGP/SSE/3DNOW!
+NVIDIA GeForce4 MX 420/AGP/SSE2
+NVIDIA GeForce4 MX 440 with AGP8X/AGP/SSE2
+NVIDIA GeForce4 MX 440/AGP/SSE2
+NVIDIA GeForce4 MX 440/AGP/SSE2/3DNOW!
+NVIDIA GeForce4 MX 440SE with AGP8X/AGP/SSE2
+NVIDIA GeForce4 MX Integrated GPU/AGP/SSE/3DNOW!
+NVIDIA GeForce4 Ti 4200 with AGP8X/AGP/SSE
+NVIDIA GeForce4 Ti 4200/AGP/SSE/3DNOW!
+NVIDIA GeForce4 Ti 4400/AGP/SSE2
+NVIDIA Generic
+NVIDIA ION LE/PCI/SSE2
+NVIDIA ION/PCI/SSE2
+NVIDIA ION/PCI/SSE2/3DNOW!
+NVIDIA MCP61/PCI/SSE2
+NVIDIA MCP61/PCI/SSE2/3DNOW!
+NVIDIA MCP73/PCI/SSE2
+NVIDIA MCP79MH/PCI/SSE2
+NVIDIA MCP79MX/PCI/SSE2
+NVIDIA MCP7A-O/PCI/SSE2
+NVIDIA MCP7A-S/PCI/SSE2
+NVIDIA MCP89-EPT/PCI/SSE2
+NVIDIA N10M-GE1/PCI/SSE2
+NVIDIA N10P-GE1/PCI/SSE2
+NVIDIA N10P-GV2/PCI/SSE2
+NVIDIA N11M-GE1/PCI/SSE2
+NVIDIA N11M-GE2/PCI/SSE2
+NVIDIA N12E-GS-A1/PCI/SSE2
+NVIDIA NB9M-GE/PCI/SSE2
+NVIDIA NB9M-GE1/PCI/SSE2
+NVIDIA NB9M-GS/PCI/SSE2
+NVIDIA NB9M-NS/PCI/SSE2
+NVIDIA NB9P-GE1/PCI/SSE2
+NVIDIA NB9P-GS/PCI/SSE2
+NVIDIA NV17/AGP/3DNOW!
+NVIDIA NV17/AGP/SSE2
+NVIDIA NV34
+NVIDIA NV35
+NVIDIA NV36/AGP/SSE/3DNOW!
+NVIDIA NV36/AGP/SSE2
+NVIDIA NV41/PCI/SSE2
+NVIDIA NV43
+NVIDIA NV44
+NVIDIA NVIDIA GeForce 210 OpenGL Engine
+NVIDIA NVIDIA GeForce 320M OpenGL Engine
+NVIDIA NVIDIA GeForce 7300 GT OpenGL Engine
+NVIDIA NVIDIA GeForce 7600 GT OpenGL Engine
+NVIDIA NVIDIA GeForce 8600M GT OpenGL Engine
+NVIDIA NVIDIA GeForce 8800 GS OpenGL Engine
+NVIDIA NVIDIA GeForce 8800 GT OpenGL Engine
+NVIDIA NVIDIA GeForce 9400 OpenGL Engine
+NVIDIA NVIDIA GeForce 9400M OpenGL Engine
+NVIDIA NVIDIA GeForce 9500 GT OpenGL Engine
+NVIDIA NVIDIA GeForce 9600M GT OpenGL Engine
+NVIDIA NVIDIA GeForce GT 120 OpenGL Engine
+NVIDIA NVIDIA GeForce GT 130 OpenGL Engine
+NVIDIA NVIDIA GeForce GT 220 OpenGL Engine
+NVIDIA NVIDIA GeForce GT 230M OpenGL Engine
+NVIDIA NVIDIA GeForce GT 240M OpenGL Engine
+NVIDIA NVIDIA GeForce GT 330M OpenGL Engine
+NVIDIA NVIDIA GeForce GT 420M OpenGL Engine
+NVIDIA NVIDIA GeForce GT 425M OpenGL Engine
+NVIDIA NVIDIA GeForce GT 430 OpenGL Engine
+NVIDIA NVIDIA GeForce GT 440 OpenGL Engine
+NVIDIA NVIDIA GeForce GT 540M OpenGL Engine
+NVIDIA NVIDIA GeForce GTS 240 OpenGL Engine
+NVIDIA NVIDIA GeForce GTS 250 OpenGL Engine
+NVIDIA NVIDIA GeForce GTS 450 OpenGL Engine
+NVIDIA NVIDIA GeForce GTX 285 OpenGL Engine
+NVIDIA NVIDIA GeForce GTX 460 OpenGL Engine
+NVIDIA NVIDIA GeForce GTX 460M OpenGL Engine
+NVIDIA NVIDIA GeForce GTX 465 OpenGL Engine
+NVIDIA NVIDIA GeForce GTX 470 OpenGL Engine
+NVIDIA NVIDIA GeForce GTX 480 OpenGL Engine
+NVIDIA NVIDIA GeForce Pre-Release ION OpenGL Engine
+NVIDIA NVIDIA GeForce4 OpenGL Engine
+NVIDIA NVIDIA NV34MAP OpenGL Engine
+NVIDIA NVIDIA Quadro 4000 OpenGL Engine
+NVIDIA NVIDIA Quadro FX 4800 OpenGL Engine
+NVIDIA NVS 2100M/PCI/SSE2
+NVIDIA NVS 300/PCI/SSE2
+NVIDIA NVS 3100M/PCI/SSE2
+NVIDIA NVS 4100/PCI/SSE2/3DNOW!
+NVIDIA NVS 4200M/PCI/SSE2
+NVIDIA NVS 5100M/PCI/SSE2
+NVIDIA PCI
+NVIDIA Quadro 2000/PCI/SSE2
+NVIDIA Quadro 4000
+NVIDIA Quadro 4000 OpenGL Engine
+NVIDIA Quadro 4000/PCI/SSE2
+NVIDIA Quadro 5000/PCI/SSE2
+NVIDIA Quadro 5000M/PCI/SSE2
+NVIDIA Quadro 600
+NVIDIA Quadro 600/PCI/SSE2
+NVIDIA Quadro 600/PCI/SSE2/3DNOW!
+NVIDIA Quadro 6000
+NVIDIA Quadro 6000/PCI/SSE2
+NVIDIA Quadro CX/PCI/SSE2
+NVIDIA Quadro DCC
+NVIDIA Quadro FX
+NVIDIA Quadro FX 1100/AGP/SSE2
+NVIDIA Quadro FX 1400/PCI/SSE2
+NVIDIA Quadro FX 1500
+NVIDIA Quadro FX 1500M/PCI/SSE2
+NVIDIA Quadro FX 1600M/PCI/SSE2
+NVIDIA Quadro FX 1700
+NVIDIA Quadro FX 1700M/PCI/SSE2
+NVIDIA Quadro FX 1800
+NVIDIA Quadro FX 1800/PCI/SSE2
+NVIDIA Quadro FX 1800M/PCI/SSE2
+NVIDIA Quadro FX 2500M/PCI/SSE2
+NVIDIA Quadro FX 2700M/PCI/SSE2
+NVIDIA Quadro FX 2800M/PCI/SSE2
+NVIDIA Quadro FX 3400
+NVIDIA Quadro FX 3450
+NVIDIA Quadro FX 3450/4000 SDI/PCI/SSE2
+NVIDIA Quadro FX 3500
+NVIDIA Quadro FX 3500M/PCI/SSE2
+NVIDIA Quadro FX 360M/PCI/SSE2
+NVIDIA Quadro FX 370
+NVIDIA Quadro FX 370/PCI/SSE2
+NVIDIA Quadro FX 3700
+NVIDIA Quadro FX 3700M/PCI/SSE2
+NVIDIA Quadro FX 370M/PCI/SSE2
+NVIDIA Quadro FX 3800
+NVIDIA Quadro FX 3800M/PCI/SSE2
+NVIDIA Quadro FX 4500
+NVIDIA Quadro FX 4600
+NVIDIA Quadro FX 4800
+NVIDIA Quadro FX 4800/PCI/SSE2
+NVIDIA Quadro FX 560
+NVIDIA Quadro FX 5600
+NVIDIA Quadro FX 570
+NVIDIA Quadro FX 570/PCI/SSE2
+NVIDIA Quadro FX 570M/PCI/SSE2
+NVIDIA Quadro FX 580/PCI/SSE2
+NVIDIA Quadro FX 770M/PCI/SSE2
+NVIDIA Quadro FX 880M
+NVIDIA Quadro FX 880M/PCI/SSE2
+NVIDIA Quadro FX Go700/AGP/SSE2
+NVIDIA Quadro NVS
+NVIDIA Quadro NVS 110M/PCI/SSE2
+NVIDIA Quadro NVS 130M/PCI/SSE2
+NVIDIA Quadro NVS 135M/PCI/SSE2
+NVIDIA Quadro NVS 140M/PCI/SSE2
+NVIDIA Quadro NVS 150M/PCI/SSE2
+NVIDIA Quadro NVS 160M/PCI/SSE2
+NVIDIA Quadro NVS 210S/PCI/SSE2/3DNOW!
+NVIDIA Quadro NVS 285/PCI/SSE2
+NVIDIA Quadro NVS 290/PCI/SSE2
+NVIDIA Quadro NVS 295/PCI/SSE2
+NVIDIA Quadro NVS 320M/PCI/SSE2
+NVIDIA Quadro NVS 55/280 PCI/PCI/SSE2
+NVIDIA Quadro NVS/PCI/SSE2
+NVIDIA Quadro PCI-E Series/PCI/SSE2/3DNOW!
+NVIDIA Quadro VX 200/PCI/SSE2
+NVIDIA Quadro/AGP/SSE2
+NVIDIA Quadro2
+NVIDIA Quadro4
+NVIDIA RIVA TNT
+NVIDIA RIVA TNT2/AGP/SSE2
+NVIDIA RIVA TNT2/PCI/3DNOW!
+NVIDIA nForce
+NVIDIA unknown board/AGP/SSE2
+NVIDIA unknown board/PCI/SSE2
+NVIDIA unknown board/PCI/SSE2/3DNOW!
+Parallels and ATI Technologies Inc. Parallels using ATI Radeon HD 5670 OpenGL Engine
+Parallels and ATI Technologies Inc. Parallels using ATI Radeon HD 5750 OpenGL Engine
+Parallels and ATI Technologies Inc. Parallels using ATI Radeon HD 5770 OpenGL Engine
+Parallels and ATI Technologies Inc. Parallels using ATI Radeon HD 6490M OpenGL Engine
+Parallels and ATI Technologies Inc. Parallels using ATI Radeon HD 6750M OpenGL Engine
+Parallels and Intel Inc. 3D-Analyze v2.3 - http://www.tommti-systems.com
+Parallels and Intel Inc. Parallels using Intel HD Graphics 3000 OpenGL Engine
+Parallels and NVIDIA Parallels using NVIDIA GeForce 320M OpenGL Engine
+Parallels and NVIDIA Parallels using NVIDIA GeForce 9400 OpenGL Engine
+Parallels and NVIDIA Parallels using NVIDIA GeForce GT 120 OpenGL Engine
+Parallels and NVIDIA Parallels using NVIDIA GeForce GT 330M OpenGL Engine
+Radeon RV350 on Gallium
+S3
+S3 Graphics VIA/S3G UniChrome IGP/MMX/K3D
+S3 Graphics VIA/S3G UniChrome Pro IGP/MMX/SSE
+S3 Graphics, Incorporated ProSavage/Twister
+S3 Graphics, Incorporated S3 Graphics Chrome9 HC
+S3 Graphics, Incorporated S3 Graphics DeltaChrome
+S3 Graphics, Incorporated VIA Chrome9 HC IGP
+SiS
+SiS 661 VGA
+SiS 662 VGA
+SiS 741 VGA
+SiS 760 VGA
+SiS 761GX VGA
+SiS Mirage Graphics3
+Trident
+Tungsten Graphics
+Tungsten Graphics, Inc Mesa DRI 865G GEM 20091221 2009Q4 x86/MMX/SSE2
+Tungsten Graphics, Inc Mesa DRI 865G GEM 20100330 DEVELOPMENT x86/MMX/SSE2
+Tungsten Graphics, Inc Mesa DRI 915G GEM 20091221 2009Q4 x86/MMX/SSE2
+Tungsten Graphics, Inc Mesa DRI 915G GEM 20100330 DEVELOPMENT x86/MMX/SSE2
+Tungsten Graphics, Inc Mesa DRI 915GM GEM 20090712 2009Q2 RC3 x86/MMX/SSE2
+Tungsten Graphics, Inc Mesa DRI 915GM GEM 20091221 2009Q4 x86/MMX/SSE2
+Tungsten Graphics, Inc Mesa DRI 915GM GEM 20100330 DEVELOPMENT x86/MMX/SSE2
+Tungsten Graphics, Inc Mesa DRI 945G
+Tungsten Graphics, Inc Mesa DRI 945G GEM 20091221 2009Q4 x86/MMX/SSE2
+Tungsten Graphics, Inc Mesa DRI 945G GEM 20100330 DEVELOPMENT
+Tungsten Graphics, Inc Mesa DRI 945G GEM 20100330 DEVELOPMENT x86/MMX/SSE2
+Tungsten Graphics, Inc Mesa DRI 945GM GEM 20090712 2009Q2 RC3 x86/MMX/SSE2
+Tungsten Graphics, Inc Mesa DRI 945GM GEM 20091221 2009Q4 x86/MMX/SSE2
+Tungsten Graphics, Inc Mesa DRI 945GM GEM 20100328 2010Q1 x86/MMX/SSE2
+Tungsten Graphics, Inc Mesa DRI 945GM GEM 20100330 DEVELOPMENT x86/MMX/SSE2
+Tungsten Graphics, Inc Mesa DRI 945GME x86/MMX/SSE2
+Tungsten Graphics, Inc Mesa DRI 945GME 20061017
+Tungsten Graphics, Inc Mesa DRI 945GME GEM 20090712 2009Q2 RC3 x86/MMX/SSE2
+Tungsten Graphics, Inc Mesa DRI 945GME GEM 20091221 2009Q4 x86/MMX/SSE2
+Tungsten Graphics, Inc Mesa DRI 945GME GEM 20100330 DEVELOPMENT x86/MMX/SSE2
+Tungsten Graphics, Inc Mesa DRI 965GM GEM 20090326 2009Q1 RC2 x86/MMX/SSE2
+Tungsten Graphics, Inc Mesa DRI 965GM GEM 20090712 2009Q2 RC3 x86/MMX/SSE2
+Tungsten Graphics, Inc Mesa DRI 965GM GEM 20091221 2009Q4 x86/MMX/SSE2
+Tungsten Graphics, Inc Mesa DRI 965GM GEM 20100330 DEVELOPMENT x86/MMX/SSE2
+Tungsten Graphics, Inc Mesa DRI G33 20061017 x86/MMX/SSE2
+Tungsten Graphics, Inc Mesa DRI G33 GEM 20090712 2009Q2 RC3 x86/MMX/SSE2
+Tungsten Graphics, Inc Mesa DRI G33 GEM 20091221 2009Q4 x86/MMX/SSE2
+Tungsten Graphics, Inc Mesa DRI G41 GEM 20091221 2009Q4 x86/MMX/SSE2
+Tungsten Graphics, Inc Mesa DRI G41 GEM 20100330 DEVELOPMENT x86/MMX/SSE2
+Tungsten Graphics, Inc Mesa DRI GMA500 20081116 - 5.0.1.0046 x86/MMX/SSE2
+Tungsten Graphics, Inc Mesa DRI IGD GEM 20091221 2009Q4 x86/MMX/SSE2
+Tungsten Graphics, Inc Mesa DRI IGD GEM 20100330 DEVELOPMENT
+Tungsten Graphics, Inc Mesa DRI IGD GEM 20100330 DEVELOPMENT x86/MMX/SSE2
+Tungsten Graphics, Inc Mesa DRI IGDNG_D GEM 20091221 2009Q4 x86/MMX/SSE2
+Tungsten Graphics, Inc Mesa DRI Ironlake Desktop GEM 20100330 DEVELOPMENT x86/MMX/SSE2
+Tungsten Graphics, Inc Mesa DRI Ironlake Mobile GEM 20100330 DEVELOPMENT x86/MMX/SSE2
+Tungsten Graphics, Inc Mesa DRI Mobile Intelå¨ GM45 Express Chipset 20080716 x86/MMX/SSE2
+Tungsten Graphics, Inc Mesa DRI Mobile Intelå¨ GM45 Express Chipset GEM 20090712 2009Q2 RC3 x86/MMX/SSE2
+Tungsten Graphics, Inc Mesa DRI Mobile Intelå¨ GM45 Express Chipset GEM 20091221 2009Q4 x86/MMX/SSE2
+Tungsten Graphics, Inc Mesa DRI Mobile Intelå¨ GM45 Express Chipset GEM 20100328 2010Q1
+Tungsten Graphics, Inc Mesa DRI Mobile Intelå¨ GM45 Express Chipset GEM 20100330 DEVELOPMENT
+Tungsten Graphics, Inc Mesa DRI Mobile Intelå¨ GM45 Express Chipset GEM 20100330 DEVELOPMENT x86/MMX/SSE2
+Tungsten Graphics, Inc. Mesa DRI R200 (RV280 5964) 20090101 x86/MMX+/3DNow!+/SSE2 TCL DRI2
+VIA
+VMware, Inc. Gallium 0.3 on SVGA3D; build: RELEASE;
+VMware, Inc. Gallium 0.4 on i915 (chipset: 945GM)
+VMware, Inc. Gallium 0.4 on llvmpipe
+VMware, Inc. Gallium 0.4 on softpipe
+X.Org Gallium 0.4 on AMD BARTS
+X.Org Gallium 0.4 on AMD CEDAR
+X.Org Gallium 0.4 on AMD HEMLOCK
+X.Org Gallium 0.4 on AMD JUNIPER
+X.Org Gallium 0.4 on AMD REDWOOD
+X.Org Gallium 0.4 on AMD RS780
+X.Org Gallium 0.4 on AMD RS880
+X.Org Gallium 0.4 on AMD RV610
+X.Org Gallium 0.4 on AMD RV620
+X.Org Gallium 0.4 on AMD RV630
+X.Org Gallium 0.4 on AMD RV635
+X.Org Gallium 0.4 on AMD RV710
+X.Org Gallium 0.4 on AMD RV730
+X.Org Gallium 0.4 on AMD RV740
+X.Org Gallium 0.4 on AMD RV770
+X.Org R300 Project Gallium 0.4 on ATI R300
+X.Org R300 Project Gallium 0.4 on ATI R580
+X.Org R300 Project Gallium 0.4 on ATI RC410
+X.Org R300 Project Gallium 0.4 on ATI RS482
+X.Org R300 Project Gallium 0.4 on ATI RS600
+X.Org R300 Project Gallium 0.4 on ATI RS690
+X.Org R300 Project Gallium 0.4 on ATI RV350
+X.Org R300 Project Gallium 0.4 on ATI RV370
+X.Org R300 Project Gallium 0.4 on ATI RV410
+X.Org R300 Project Gallium 0.4 on ATI RV515
+X.Org R300 Project Gallium 0.4 on ATI RV530
+X.Org R300 Project Gallium 0.4 on ATI RV570
+X.Org R300 Project Gallium 0.4 on R420
+X.Org R300 Project Gallium 0.4 on R580
+X.Org R300 Project Gallium 0.4 on RC410
+X.Org R300 Project Gallium 0.4 on RS480
+X.Org R300 Project Gallium 0.4 on RS482
+X.Org R300 Project Gallium 0.4 on RS600
+X.Org R300 Project Gallium 0.4 on RS690
+X.Org R300 Project Gallium 0.4 on RS740
+X.Org R300 Project Gallium 0.4 on RV350
+X.Org R300 Project Gallium 0.4 on RV370
+X.Org R300 Project Gallium 0.4 on RV410
+X.Org R300 Project Gallium 0.4 on RV515
+X.Org R300 Project Gallium 0.4 on RV530
+XGI
+nouveau Gallium 0.4 on NV34
+nouveau Gallium 0.4 on NV36
+nouveau Gallium 0.4 on NV46
+nouveau Gallium 0.4 on NV49
+nouveau Gallium 0.4 on NV4A
+nouveau Gallium 0.4 on NV4B
+nouveau Gallium 0.4 on NV4E
+nouveau Gallium 0.4 on NV50
+nouveau Gallium 0.4 on NV84
+nouveau Gallium 0.4 on NV86
+nouveau Gallium 0.4 on NV92
+nouveau Gallium 0.4 on NV94
+nouveau Gallium 0.4 on NV96
+nouveau Gallium 0.4 on NV98
+nouveau Gallium 0.4 on NVA0
+nouveau Gallium 0.4 on NVA3
+nouveau Gallium 0.4 on NVA5
+nouveau Gallium 0.4 on NVA8
+nouveau Gallium 0.4 on NVAA
+nouveau Gallium 0.4 on NVAC
diff --git a/indra/newview/tests/llcapabilitylistener_test.cpp b/indra/newview/tests/llcapabilitylistener_test.cpp
index 9da851ffc4..2ad08dc1f3 100644
--- a/indra/newview/tests/llcapabilitylistener_test.cpp
+++ b/indra/newview/tests/llcapabilitylistener_test.cpp
@@ -72,7 +72,7 @@ struct TestCapabilityProvider: public LLCapabilityProvider
{
mCaps[cap] = url;
}
- LLHost getHost() const { return mHost; }
+ const LLHost& getHost() const { return mHost; }
std::string getDescription() const { return "TestCapabilityProvider"; }
LLHost mHost;
@@ -114,6 +114,7 @@ namespace tut
regionListener("testCapabilityListener", NULL, provider, LLUUID(), LLUUID()),
regionPump(regionListener.getCapAPI())
{
+ LLCurl::initClass();
provider.setCapability("good", server + "capability-test");
provider.setCapability("fail", server + "fail");
}
diff --git a/indra/newview/tests/lllogininstance_test.cpp b/indra/newview/tests/lllogininstance_test.cpp
index db50b89620..9e321db889 100644
--- a/indra/newview/tests/lllogininstance_test.cpp
+++ b/indra/newview/tests/lllogininstance_test.cpp
@@ -40,6 +40,7 @@
#if defined(LL_WINDOWS)
#pragma warning(disable: 4355) // using 'this' in base-class ctor initializer expr
+#pragma warning(disable: 4702) // disable 'unreachable code' so we can safely use skip().
#endif
// Constants
@@ -48,6 +49,9 @@ const std::string VIEWERLOGIN_GRIDLABEL("viewerlogin_grid");
const std::string APPVIEWER_SERIALNUMBER("appviewer_serialno");
+const std::string VIEWERLOGIN_CHANNEL("invalid_channel");
+const std::string VIEWERLOGIN_VERSION_CHANNEL("invalid_version");
+
// Link seams.
//-----------------------------------------------------------------------------
@@ -65,6 +69,7 @@ static bool gDisconnectCalled = false;
#include "../llviewerwindow.h"
void LLViewerWindow::setShowProgress(BOOL show) {}
+LLProgressView * LLViewerWindow::getProgressView(void) const { return 0; }
LLViewerWindow* gViewerWindow;
@@ -160,7 +165,6 @@ std::string LLGridManager::getAppSLURLBase(const std::string& grid_name)
//-----------------------------------------------------------------------------
#include "../llviewercontrol.h"
LLControlGroup gSavedSettings("Global");
-std::string gCurrentVersion = "invalid_version";
LLControlGroup::LLControlGroup(const std::string& name) :
LLInstanceTracker<LLControlGroup, std::string>(name){}
@@ -177,6 +181,45 @@ BOOL LLControlGroup::declareString(const std::string& name, const std::string &i
#include "lluicolortable.h"
void LLUIColorTable::saveUserSettings(void)const {}
+//-----------------------------------------------------------------------------
+#include "../llversioninfo.h"
+const std::string &LLVersionInfo::getChannelAndVersion() { return VIEWERLOGIN_VERSION_CHANNEL; }
+const std::string &LLVersionInfo::getChannel() { return VIEWERLOGIN_CHANNEL; }
+
+//-----------------------------------------------------------------------------
+#include "../llappviewer.h"
+void LLAppViewer::forceQuit(void) {}
+LLAppViewer * LLAppViewer::sInstance = 0;
+
+//-----------------------------------------------------------------------------
+#include "llnotificationsutil.h"
+LLNotificationPtr LLNotificationsUtil::add(const std::string& name,
+ const LLSD& substitutions,
+ const LLSD& payload,
+ boost::function<void (const LLSD&, const LLSD&)> functor) { return LLNotificationPtr((LLNotification*)0); }
+
+
+//-----------------------------------------------------------------------------
+#include "llupdaterservice.h"
+
+std::string const & LLUpdaterService::pumpName(void)
+{
+ static std::string wakka = "wakka wakka wakka";
+ return wakka;
+}
+bool LLUpdaterService::updateReadyToInstall(void) { return false; }
+void LLUpdaterService::initialize(const std::string& protocol_version,
+ const std::string& url,
+ const std::string& path,
+ const std::string& channel,
+ const std::string& version) {}
+
+void LLUpdaterService::setCheckPeriod(unsigned int seconds) {}
+void LLUpdaterService::startChecking(bool install_if_ready) {}
+void LLUpdaterService::stopChecking() {}
+bool LLUpdaterService::isChecking() { return false; }
+LLUpdaterService::eUpdaterState LLUpdaterService::getState() { return INITIAL; }
+std::string LLUpdaterService::updatedVersion() { return ""; }
//-----------------------------------------------------------------------------
#include "llnotifications.h"
@@ -192,6 +235,12 @@ LLFloater* LLFloaterReg::showInstance(const std::string& name, const LLSD& key,
return NULL;
}
+//----------------------------------------------------------------------------
+#include "../llprogressview.h"
+void LLProgressView::setText(std::string const &){}
+void LLProgressView::setPercent(float){}
+void LLProgressView::setMessage(std::string const &){}
+
//-----------------------------------------------------------------------------
// LLNotifications
class MockNotifications : public LLNotificationsInterface
@@ -290,7 +339,6 @@ namespace tut
gSavedSettings.declareBOOL("UseDebugMenus", FALSE, "", FALSE);
gSavedSettings.declareBOOL("ForceMandatoryUpdate", FALSE, "", FALSE);
gSavedSettings.declareString("ClientSettingsFile", "test_settings.xml", "", FALSE);
- gSavedSettings.declareString("VersionChannelName", "test_version_string", "", FALSE);
gSavedSettings.declareString("NextLoginLocation", "", "", FALSE);
gSavedSettings.declareBOOL("LoginLastLocation", FALSE, "", FALSE);
@@ -430,6 +478,8 @@ namespace tut
template<> template<>
void lllogininstance_object::test<3>()
{
+ skip();
+
set_test_name("Test Mandatory Update User Accepts");
// Part 1 - Mandatory Update, with User accepts response.
@@ -457,6 +507,8 @@ namespace tut
template<> template<>
void lllogininstance_object::test<4>()
{
+ skip();
+
set_test_name("Test Mandatory Update User Decline");
// Test connect with update needed.
diff --git a/indra/newview/tests/llremoteparcelrequest_test.cpp b/indra/newview/tests/llremoteparcelrequest_test.cpp
new file mode 100644
index 0000000000..ed66066b0a
--- /dev/null
+++ b/indra/newview/tests/llremoteparcelrequest_test.cpp
@@ -0,0 +1,134 @@
+/**
+ * @file llremoteparcelrequest_test.cpp
+ * @author Brad Kittenbrink <brad@lindenlab.com>
+ *
+ * $LicenseInfo:firstyear=2010&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 "../test/lltut.h"
+
+#include "../llremoteparcelrequest.h"
+
+#include "../llagent.h"
+#include "message.h"
+#include "llurlentry.h"
+
+namespace {
+ const LLUUID TEST_PARCEL_ID("11111111-1111-1111-1111-111111111111");
+}
+
+LLCurl::Responder::Responder() { }
+LLCurl::Responder::~Responder() { }
+void LLCurl::Responder::error(U32,std::string const &) { }
+void LLCurl::Responder::result(LLSD const &) { }
+void LLCurl::Responder::errorWithContent(U32 status,std::string const &,LLSD const &) { }
+void LLCurl::Responder::completedRaw(U32 status, std::string const &, LLChannelDescriptors const &,boost::shared_ptr<LLBufferArray> const &) { }
+void LLCurl::Responder::completed(U32 status, std::string const &, LLSD const &) { }
+void LLCurl::Responder::completedHeader(U32 status, std::string const &, LLSD const &) { }
+void LLMessageSystem::getF32(char const *,char const *,F32 &,S32) { }
+void LLMessageSystem::getU8(char const *,char const *,U8 &,S32) { }
+void LLMessageSystem::getS32(char const *,char const *,S32 &,S32) { }
+void LLMessageSystem::getString(char const *,char const *, std::string &,S32) { }
+void LLMessageSystem::getUUID(char const *,char const *, LLUUID & out_id,S32)
+{
+ out_id = TEST_PARCEL_ID;
+}
+void LLMessageSystem::nextBlock(char const *) { }
+void LLMessageSystem::addUUID(char const *,LLUUID const &) { }
+void LLMessageSystem::addUUIDFast(char const *,LLUUID const &) { }
+void LLMessageSystem::nextBlockFast(char const *) { }
+void LLMessageSystem::newMessage(char const *) { }
+LLMessageSystem * gMessageSystem;
+char const* const _PREHASH_AgentID = 0; // never dereferenced during this test
+char const* const _PREHASH_AgentData = 0; // never dereferenced during this test
+LLAgent gAgent;
+LLAgent::LLAgent() : mAgentAccess(NULL) { }
+LLAgent::~LLAgent() { }
+void LLAgent::sendReliableMessage(void) { }
+LLUUID gAgentSessionID;
+LLUUID gAgentID;
+LLUIColor::LLUIColor(void) { }
+LLControlGroup::LLControlGroup(std::string const & name) : LLInstanceTracker<LLControlGroup, std::string>(name) { }
+LLControlGroup::~LLControlGroup(void) { }
+void LLUrlEntryParcel::processParcelInfo(const LLUrlEntryParcel::LLParcelData& parcel_data) { }
+
+namespace tut
+{
+ struct TestObserver : public LLRemoteParcelInfoObserver {
+ TestObserver() : mProcessed(false) { }
+
+ virtual void processParcelInfo(const LLParcelData& parcel_data)
+ {
+ mProcessed = true;
+ }
+
+ virtual void setParcelID(const LLUUID& parcel_id) { }
+
+ virtual void setErrorStatus(U32 status, const std::string& reason) { }
+
+ bool mProcessed;
+ };
+
+ struct RemoteParcelRequestData
+ {
+ RemoteParcelRequestData()
+ {
+ }
+ };
+
+ typedef test_group<RemoteParcelRequestData> remoteparcelrequest_t;
+ typedef remoteparcelrequest_t::object remoteparcelrequest_object_t;
+ tut::remoteparcelrequest_t tut_remoteparcelrequest("LLRemoteParcelRequest");
+
+ template<> template<>
+ void remoteparcelrequest_object_t::test<1>()
+ {
+ set_test_name("observer pointer");
+
+ boost::scoped_ptr<TestObserver> observer(new TestObserver());
+
+ LLRemoteParcelInfoProcessor & processor = LLRemoteParcelInfoProcessor::instance();
+ processor.addObserver(LLUUID(TEST_PARCEL_ID), observer.get());
+
+ processor.processParcelInfoReply(gMessageSystem, NULL);
+
+ ensure(observer->mProcessed);
+ }
+
+ template<> template<>
+ void remoteparcelrequest_object_t::test<2>()
+ {
+ set_test_name("CHOP-220: dangling observer pointer");
+
+ LLRemoteParcelInfoObserver * observer = new TestObserver();
+
+ LLRemoteParcelInfoProcessor & processor = LLRemoteParcelInfoProcessor::instance();
+ processor.addObserver(LLUUID(TEST_PARCEL_ID), observer);
+
+ delete observer;
+ observer = NULL;
+
+ processor.processParcelInfoReply(gMessageSystem, NULL);
+ }
+}
diff --git a/indra/newview/tests/llsimplestat_test.cpp b/indra/newview/tests/llsimplestat_test.cpp
new file mode 100644
index 0000000000..b556941f4a
--- /dev/null
+++ b/indra/newview/tests/llsimplestat_test.cpp
@@ -0,0 +1,580 @@
+/**
+ * @file llsimplestats_test.cpp
+ * @date 2010-10-22
+ * @brief Test cases for some of llsimplestat.h
+ *
+ * $LicenseInfo:firstyear=2010&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 <tut/tut.hpp>
+
+#include "lltut.h"
+#include "../llsimplestat.h"
+#include "llsd.h"
+#include "llmath.h"
+
+// @brief Used as a pointer cast type to get access to LLSimpleStatCounter
+class TutStatCounter: public LLSimpleStatCounter
+{
+public:
+ TutStatCounter(); // Not defined
+ ~TutStatCounter(); // Not defined
+ void operator=(const TutStatCounter &); // Not defined
+
+ void setRawCount(U32 c) { mCount = c; }
+ U32 getRawCount() const { return mCount; }
+};
+
+
+namespace tut
+{
+ struct stat_counter_index
+ {};
+ typedef test_group<stat_counter_index> stat_counter_index_t;
+ typedef stat_counter_index_t::object stat_counter_index_object_t;
+ tut::stat_counter_index_t tut_stat_counter_index("stat_counter_test");
+
+ // Testing LLSimpleStatCounter's external interface
+ template<> template<>
+ void stat_counter_index_object_t::test<1>()
+ {
+ LLSimpleStatCounter c1;
+ ensure("Initialized counter is zero", (0 == c1.getCount()));
+
+ ensure("Counter increment return is 1", (1 == ++c1));
+ ensure("Counter increment return is 2", (2 == ++c1));
+
+ ensure("Current counter is 2", (2 == c1.getCount()));
+
+ c1.reset();
+ ensure("Counter is 0 after reset", (0 == c1.getCount()));
+
+ ensure("Counter increment return is 1", (1 == ++c1));
+ }
+
+ // Testing LLSimpleStatCounter's internal state
+ template<> template<>
+ void stat_counter_index_object_t::test<2>()
+ {
+ LLSimpleStatCounter c1;
+ TutStatCounter * tc1 = (TutStatCounter *) &c1;
+
+ ensure("Initialized private counter is zero", (0 == tc1->getRawCount()));
+
+ ++c1;
+ ++c1;
+
+ ensure("Current private counter is 2", (2 == tc1->getRawCount()));
+
+ c1.reset();
+ ensure("Raw counter is 0 after reset", (0 == tc1->getRawCount()));
+ }
+
+ // Testing LLSimpleStatCounter's wrapping behavior
+ template<> template<>
+ void stat_counter_index_object_t::test<3>()
+ {
+ LLSimpleStatCounter c1;
+ TutStatCounter * tc1 = (TutStatCounter *) &c1;
+
+ tc1->setRawCount(U32_MAX);
+ ensure("Initialized private counter is zero", (U32_MAX == c1.getCount()));
+
+ ensure("Increment of max value wraps to 0", (0 == ++c1));
+ }
+
+ // Testing LLSimpleStatMMM's external behavior
+ template<> template<>
+ void stat_counter_index_object_t::test<4>()
+ {
+ LLSimpleStatMMM<> m1;
+ typedef LLSimpleStatMMM<>::Value lcl_float;
+ lcl_float zero(0);
+
+ // Freshly-constructed
+ ensure("Constructed MMM<> has 0 count", (0 == m1.getCount()));
+ ensure("Constructed MMM<> has 0 min", (zero == m1.getMin()));
+ ensure("Constructed MMM<> has 0 max", (zero == m1.getMax()));
+ ensure("Constructed MMM<> has 0 mean no div-by-zero", (zero == m1.getMean()));
+
+ // Single insert
+ m1.record(1.0);
+ ensure("Single insert MMM<> has 1 count", (1 == m1.getCount()));
+ ensure("Single insert MMM<> has 1.0 min", (1.0 == m1.getMin()));
+ ensure("Single insert MMM<> has 1.0 max", (1.0 == m1.getMax()));
+ ensure("Single insert MMM<> has 1.0 mean", (1.0 == m1.getMean()));
+
+ // Second insert
+ m1.record(3.0);
+ ensure("2nd insert MMM<> has 2 count", (2 == m1.getCount()));
+ ensure("2nd insert MMM<> has 1.0 min", (1.0 == m1.getMin()));
+ ensure("2nd insert MMM<> has 3.0 max", (3.0 == m1.getMax()));
+ ensure_approximately_equals("2nd insert MMM<> has 2.0 mean", m1.getMean(), lcl_float(2.0), 1);
+
+ // Third insert
+ m1.record(5.0);
+ ensure("3rd insert MMM<> has 3 count", (3 == m1.getCount()));
+ ensure("3rd insert MMM<> has 1.0 min", (1.0 == m1.getMin()));
+ ensure("3rd insert MMM<> has 5.0 max", (5.0 == m1.getMax()));
+ ensure_approximately_equals("3rd insert MMM<> has 3.0 mean", m1.getMean(), lcl_float(3.0), 1);
+
+ // Fourth insert
+ m1.record(1000000.0);
+ ensure("4th insert MMM<> has 4 count", (4 == m1.getCount()));
+ ensure("4th insert MMM<> has 1.0 min", (1.0 == m1.getMin()));
+ ensure("4th insert MMM<> has 100000.0 max", (1000000.0 == m1.getMax()));
+ ensure_approximately_equals("4th insert MMM<> has 250002.0 mean", m1.getMean(), lcl_float(250002.0), 1);
+
+ // Reset
+ m1.reset();
+ ensure("Reset MMM<> has 0 count", (0 == m1.getCount()));
+ ensure("Reset MMM<> has 0 min", (zero == m1.getMin()));
+ ensure("Reset MMM<> has 0 max", (zero == m1.getMax()));
+ ensure("Reset MMM<> has 0 mean no div-by-zero", (zero == m1.getMean()));
+ }
+
+ // Testing LLSimpleStatMMM's response to large values
+ template<> template<>
+ void stat_counter_index_object_t::test<5>()
+ {
+ LLSimpleStatMMM<> m1;
+ typedef LLSimpleStatMMM<>::Value lcl_float;
+ lcl_float zero(0);
+
+ // Insert overflowing values
+ const lcl_float bignum(F32_MAX / 2);
+
+ m1.record(bignum);
+ m1.record(bignum);
+ m1.record(bignum);
+ m1.record(bignum);
+ m1.record(bignum);
+ m1.record(bignum);
+ m1.record(bignum);
+ m1.record(zero);
+
+ ensure("Overflowed MMM<> has 8 count", (8 == m1.getCount()));
+ ensure("Overflowed MMM<> has 0 min", (zero == m1.getMin()));
+ ensure("Overflowed MMM<> has huge max", (bignum == m1.getMax()));
+ ensure("Overflowed MMM<> has fetchable mean", (1.0 == m1.getMean() || true));
+ // We should be infinte but not interested in proving the IEEE standard here.
+ LLSD sd1(m1.getMean());
+ // std::cout << "Thingy: " << m1.getMean() << " and as LLSD: " << sd1 << std::endl;
+ ensure("Overflowed MMM<> produces LLSDable Real", (sd1.isReal()));
+ }
+
+ // Testing LLSimpleStatMMM<F32>'s external behavior
+ template<> template<>
+ void stat_counter_index_object_t::test<6>()
+ {
+ LLSimpleStatMMM<F32> m1;
+ typedef LLSimpleStatMMM<F32>::Value lcl_float;
+ lcl_float zero(0);
+
+ // Freshly-constructed
+ ensure("Constructed MMM<F32> has 0 count", (0 == m1.getCount()));
+ ensure("Constructed MMM<F32> has 0 min", (zero == m1.getMin()));
+ ensure("Constructed MMM<F32> has 0 max", (zero == m1.getMax()));
+ ensure("Constructed MMM<F32> has 0 mean no div-by-zero", (zero == m1.getMean()));
+
+ // Single insert
+ m1.record(1.0);
+ ensure("Single insert MMM<F32> has 1 count", (1 == m1.getCount()));
+ ensure("Single insert MMM<F32> has 1.0 min", (1.0 == m1.getMin()));
+ ensure("Single insert MMM<F32> has 1.0 max", (1.0 == m1.getMax()));
+ ensure("Single insert MMM<F32> has 1.0 mean", (1.0 == m1.getMean()));
+
+ // Second insert
+ m1.record(3.0);
+ ensure("2nd insert MMM<F32> has 2 count", (2 == m1.getCount()));
+ ensure("2nd insert MMM<F32> has 1.0 min", (1.0 == m1.getMin()));
+ ensure("2nd insert MMM<F32> has 3.0 max", (3.0 == m1.getMax()));
+ ensure_approximately_equals("2nd insert MMM<F32> has 2.0 mean", m1.getMean(), lcl_float(2.0), 1);
+
+ // Third insert
+ m1.record(5.0);
+ ensure("3rd insert MMM<F32> has 3 count", (3 == m1.getCount()));
+ ensure("3rd insert MMM<F32> has 1.0 min", (1.0 == m1.getMin()));
+ ensure("3rd insert MMM<F32> has 5.0 max", (5.0 == m1.getMax()));
+ ensure_approximately_equals("3rd insert MMM<F32> has 3.0 mean", m1.getMean(), lcl_float(3.0), 1);
+
+ // Fourth insert
+ m1.record(1000000.0);
+ ensure("4th insert MMM<F32> has 4 count", (4 == m1.getCount()));
+ ensure("4th insert MMM<F32> has 1.0 min", (1.0 == m1.getMin()));
+ ensure("4th insert MMM<F32> has 1000000.0 max", (1000000.0 == m1.getMax()));
+ ensure_approximately_equals("4th insert MMM<F32> has 250002.0 mean", m1.getMean(), lcl_float(250002.0), 1);
+
+ // Reset
+ m1.reset();
+ ensure("Reset MMM<F32> has 0 count", (0 == m1.getCount()));
+ ensure("Reset MMM<F32> has 0 min", (zero == m1.getMin()));
+ ensure("Reset MMM<F32> has 0 max", (zero == m1.getMax()));
+ ensure("Reset MMM<F32> has 0 mean no div-by-zero", (zero == m1.getMean()));
+ }
+
+ // Testing LLSimpleStatMMM's response to large values
+ template<> template<>
+ void stat_counter_index_object_t::test<7>()
+ {
+ LLSimpleStatMMM<F32> m1;
+ typedef LLSimpleStatMMM<F32>::Value lcl_float;
+ lcl_float zero(0);
+
+ // Insert overflowing values
+ const lcl_float bignum(F32_MAX / 2);
+
+ m1.record(bignum);
+ m1.record(bignum);
+ m1.record(bignum);
+ m1.record(bignum);
+ m1.record(bignum);
+ m1.record(bignum);
+ m1.record(bignum);
+ m1.record(zero);
+
+ ensure("Overflowed MMM<F32> has 8 count", (8 == m1.getCount()));
+ ensure("Overflowed MMM<F32> has 0 min", (zero == m1.getMin()));
+ ensure("Overflowed MMM<F32> has huge max", (bignum == m1.getMax()));
+ ensure("Overflowed MMM<F32> has fetchable mean", (1.0 == m1.getMean() || true));
+ // We should be infinte but not interested in proving the IEEE standard here.
+ LLSD sd1(m1.getMean());
+ // std::cout << "Thingy: " << m1.getMean() << " and as LLSD: " << sd1 << std::endl;
+ ensure("Overflowed MMM<F32> produces LLSDable Real", (sd1.isReal()));
+ }
+
+ // Testing LLSimpleStatMMM<F64>'s external behavior
+ template<> template<>
+ void stat_counter_index_object_t::test<8>()
+ {
+ LLSimpleStatMMM<F64> m1;
+ typedef LLSimpleStatMMM<F64>::Value lcl_float;
+ lcl_float zero(0);
+
+ // Freshly-constructed
+ ensure("Constructed MMM<F64> has 0 count", (0 == m1.getCount()));
+ ensure("Constructed MMM<F64> has 0 min", (zero == m1.getMin()));
+ ensure("Constructed MMM<F64> has 0 max", (zero == m1.getMax()));
+ ensure("Constructed MMM<F64> has 0 mean no div-by-zero", (zero == m1.getMean()));
+
+ // Single insert
+ m1.record(1.0);
+ ensure("Single insert MMM<F64> has 1 count", (1 == m1.getCount()));
+ ensure("Single insert MMM<F64> has 1.0 min", (1.0 == m1.getMin()));
+ ensure("Single insert MMM<F64> has 1.0 max", (1.0 == m1.getMax()));
+ ensure("Single insert MMM<F64> has 1.0 mean", (1.0 == m1.getMean()));
+
+ // Second insert
+ m1.record(3.0);
+ ensure("2nd insert MMM<F64> has 2 count", (2 == m1.getCount()));
+ ensure("2nd insert MMM<F64> has 1.0 min", (1.0 == m1.getMin()));
+ ensure("2nd insert MMM<F64> has 3.0 max", (3.0 == m1.getMax()));
+ ensure_approximately_equals("2nd insert MMM<F64> has 2.0 mean", m1.getMean(), lcl_float(2.0), 1);
+
+ // Third insert
+ m1.record(5.0);
+ ensure("3rd insert MMM<F64> has 3 count", (3 == m1.getCount()));
+ ensure("3rd insert MMM<F64> has 1.0 min", (1.0 == m1.getMin()));
+ ensure("3rd insert MMM<F64> has 5.0 max", (5.0 == m1.getMax()));
+ ensure_approximately_equals("3rd insert MMM<F64> has 3.0 mean", m1.getMean(), lcl_float(3.0), 1);
+
+ // Fourth insert
+ m1.record(1000000.0);
+ ensure("4th insert MMM<F64> has 4 count", (4 == m1.getCount()));
+ ensure("4th insert MMM<F64> has 1.0 min", (1.0 == m1.getMin()));
+ ensure("4th insert MMM<F64> has 1000000.0 max", (1000000.0 == m1.getMax()));
+ ensure_approximately_equals("4th insert MMM<F64> has 250002.0 mean", m1.getMean(), lcl_float(250002.0), 1);
+
+ // Reset
+ m1.reset();
+ ensure("Reset MMM<F64> has 0 count", (0 == m1.getCount()));
+ ensure("Reset MMM<F64> has 0 min", (zero == m1.getMin()));
+ ensure("Reset MMM<F64> has 0 max", (zero == m1.getMax()));
+ ensure("Reset MMM<F64> has 0 mean no div-by-zero", (zero == m1.getMean()));
+ }
+
+ // Testing LLSimpleStatMMM's response to large values
+ template<> template<>
+ void stat_counter_index_object_t::test<9>()
+ {
+ LLSimpleStatMMM<F64> m1;
+ typedef LLSimpleStatMMM<F64>::Value lcl_float;
+ lcl_float zero(0);
+
+ // Insert overflowing values
+ const lcl_float bignum(F64_MAX / 2);
+
+ m1.record(bignum);
+ m1.record(bignum);
+ m1.record(bignum);
+ m1.record(bignum);
+ m1.record(bignum);
+ m1.record(bignum);
+ m1.record(bignum);
+ m1.record(zero);
+
+ ensure("Overflowed MMM<F64> has 8 count", (8 == m1.getCount()));
+ ensure("Overflowed MMM<F64> has 0 min", (zero == m1.getMin()));
+ ensure("Overflowed MMM<F64> has huge max", (bignum == m1.getMax()));
+ ensure("Overflowed MMM<F64> has fetchable mean", (1.0 == m1.getMean() || true));
+ // We should be infinte but not interested in proving the IEEE standard here.
+ LLSD sd1(m1.getMean());
+ // std::cout << "Thingy: " << m1.getMean() << " and as LLSD: " << sd1 << std::endl;
+ ensure("Overflowed MMM<F64> produces LLSDable Real", (sd1.isReal()));
+ }
+
+ // Testing LLSimpleStatMMM<U64>'s external behavior
+ template<> template<>
+ void stat_counter_index_object_t::test<10>()
+ {
+ LLSimpleStatMMM<U64> m1;
+ typedef LLSimpleStatMMM<U64>::Value lcl_int;
+ lcl_int zero(0);
+
+ // Freshly-constructed
+ ensure("Constructed MMM<U64> has 0 count", (0 == m1.getCount()));
+ ensure("Constructed MMM<U64> has 0 min", (zero == m1.getMin()));
+ ensure("Constructed MMM<U64> has 0 max", (zero == m1.getMax()));
+ ensure("Constructed MMM<U64> has 0 mean no div-by-zero", (zero == m1.getMean()));
+
+ // Single insert
+ m1.record(1);
+ ensure("Single insert MMM<U64> has 1 count", (1 == m1.getCount()));
+ ensure("Single insert MMM<U64> has 1 min", (1 == m1.getMin()));
+ ensure("Single insert MMM<U64> has 1 max", (1 == m1.getMax()));
+ ensure("Single insert MMM<U64> has 1 mean", (1 == m1.getMean()));
+
+ // Second insert
+ m1.record(3);
+ ensure("2nd insert MMM<U64> has 2 count", (2 == m1.getCount()));
+ ensure("2nd insert MMM<U64> has 1 min", (1 == m1.getMin()));
+ ensure("2nd insert MMM<U64> has 3 max", (3 == m1.getMax()));
+ ensure("2nd insert MMM<U64> has 2 mean", (2 == m1.getMean()));
+
+ // Third insert
+ m1.record(5);
+ ensure("3rd insert MMM<U64> has 3 count", (3 == m1.getCount()));
+ ensure("3rd insert MMM<U64> has 1 min", (1 == m1.getMin()));
+ ensure("3rd insert MMM<U64> has 5 max", (5 == m1.getMax()));
+ ensure("3rd insert MMM<U64> has 3 mean", (3 == m1.getMean()));
+
+ // Fourth insert
+ m1.record(U64L(1000000000000));
+ ensure("4th insert MMM<U64> has 4 count", (4 == m1.getCount()));
+ ensure("4th insert MMM<U64> has 1 min", (1 == m1.getMin()));
+ ensure("4th insert MMM<U64> has 1000000000000ULL max", (U64L(1000000000000) == m1.getMax()));
+ ensure("4th insert MMM<U64> has 250000000002ULL mean", (U64L( 250000000002) == m1.getMean()));
+
+ // Reset
+ m1.reset();
+ ensure("Reset MMM<U64> has 0 count", (0 == m1.getCount()));
+ ensure("Reset MMM<U64> has 0 min", (zero == m1.getMin()));
+ ensure("Reset MMM<U64> has 0 max", (zero == m1.getMax()));
+ ensure("Reset MMM<U64> has 0 mean no div-by-zero", (zero == m1.getMean()));
+ }
+
+ // Testing LLSimpleStatMMM's response to large values
+ template<> template<>
+ void stat_counter_index_object_t::test<11>()
+ {
+ LLSimpleStatMMM<U64> m1;
+ typedef LLSimpleStatMMM<U64>::Value lcl_int;
+ lcl_int zero(0);
+
+ // Insert overflowing values
+ const lcl_int bignum(U64L(0xffffffffffffffff) / 2);
+
+ m1.record(bignum);
+ m1.record(bignum);
+ m1.record(bignum);
+ m1.record(bignum);
+ m1.record(bignum);
+ m1.record(bignum);
+ m1.record(bignum);
+ m1.record(zero);
+
+ ensure("Overflowed MMM<U64> has 8 count", (8 == m1.getCount()));
+ ensure("Overflowed MMM<U64> has 0 min", (zero == m1.getMin()));
+ ensure("Overflowed MMM<U64> has huge max", (bignum == m1.getMax()));
+ ensure("Overflowed MMM<U64> has fetchable mean", (zero == m1.getMean() || true));
+ }
+
+ // Testing LLSimpleStatCounter's merge() method
+ template<> template<>
+ void stat_counter_index_object_t::test<12>()
+ {
+ LLSimpleStatCounter c1;
+ LLSimpleStatCounter c2;
+
+ ++c1;
+ ++c1;
+ ++c1;
+ ++c1;
+
+ ++c2;
+ ++c2;
+ c2.merge(c1);
+
+ ensure_equals("4 merged into 2 results in 6", 6, c2.getCount());
+
+ ensure_equals("Source of merge is undamaged", 4, c1.getCount());
+ }
+
+ // Testing LLSimpleStatMMM's merge() method
+ template<> template<>
+ void stat_counter_index_object_t::test<13>()
+ {
+ LLSimpleStatMMM<> m1;
+ LLSimpleStatMMM<> m2;
+
+ m1.record(3.5);
+ m1.record(4.5);
+ m1.record(5.5);
+ m1.record(6.5);
+
+ m2.record(5.0);
+ m2.record(7.0);
+ m2.record(9.0);
+
+ m2.merge(m1);
+
+ ensure_equals("Count after merge (p1)", 7, m2.getCount());
+ ensure_approximately_equals("Min after merge (p1)", F32(3.5), m2.getMin(), 22);
+ ensure_approximately_equals("Max after merge (p1)", F32(9.0), m2.getMax(), 22);
+ ensure_approximately_equals("Mean after merge (p1)", F32(41.000/7.000), m2.getMean(), 22);
+
+
+ ensure_equals("Source count of merge is undamaged (p1)", 4, m1.getCount());
+ ensure_approximately_equals("Source min of merge is undamaged (p1)", F32(3.5), m1.getMin(), 22);
+ ensure_approximately_equals("Source max of merge is undamaged (p1)", F32(6.5), m1.getMax(), 22);
+ ensure_approximately_equals("Source mean of merge is undamaged (p1)", F32(5.0), m1.getMean(), 22);
+
+ m2.reset();
+
+ m2.record(-22.0);
+ m2.record(-1.0);
+ m2.record(30.0);
+
+ m2.merge(m1);
+
+ ensure_equals("Count after merge (p2)", 7, m2.getCount());
+ ensure_approximately_equals("Min after merge (p2)", F32(-22.0), m2.getMin(), 22);
+ ensure_approximately_equals("Max after merge (p2)", F32(30.0), m2.getMax(), 22);
+ ensure_approximately_equals("Mean after merge (p2)", F32(27.000/7.000), m2.getMean(), 22);
+
+ }
+
+ // Testing LLSimpleStatMMM's merge() method when src contributes nothing
+ template<> template<>
+ void stat_counter_index_object_t::test<14>()
+ {
+ LLSimpleStatMMM<> m1;
+ LLSimpleStatMMM<> m2;
+
+ m2.record(5.0);
+ m2.record(7.0);
+ m2.record(9.0);
+
+ m2.merge(m1);
+
+ ensure_equals("Count after merge (p1)", 3, m2.getCount());
+ ensure_approximately_equals("Min after merge (p1)", F32(5.0), m2.getMin(), 22);
+ ensure_approximately_equals("Max after merge (p1)", F32(9.0), m2.getMax(), 22);
+ ensure_approximately_equals("Mean after merge (p1)", F32(7.000), m2.getMean(), 22);
+
+ ensure_equals("Source count of merge is undamaged (p1)", 0, m1.getCount());
+ ensure_approximately_equals("Source min of merge is undamaged (p1)", F32(0), m1.getMin(), 22);
+ ensure_approximately_equals("Source max of merge is undamaged (p1)", F32(0), m1.getMax(), 22);
+ ensure_approximately_equals("Source mean of merge is undamaged (p1)", F32(0), m1.getMean(), 22);
+
+ m2.reset();
+
+ m2.record(-22.0);
+ m2.record(-1.0);
+
+ m2.merge(m1);
+
+ ensure_equals("Count after merge (p2)", 2, m2.getCount());
+ ensure_approximately_equals("Min after merge (p2)", F32(-22.0), m2.getMin(), 22);
+ ensure_approximately_equals("Max after merge (p2)", F32(-1.0), m2.getMax(), 22);
+ ensure_approximately_equals("Mean after merge (p2)", F32(-11.5), m2.getMean(), 22);
+ }
+
+ // Testing LLSimpleStatMMM's merge() method when dst contributes nothing
+ template<> template<>
+ void stat_counter_index_object_t::test<15>()
+ {
+ LLSimpleStatMMM<> m1;
+ LLSimpleStatMMM<> m2;
+
+ m1.record(5.0);
+ m1.record(7.0);
+ m1.record(9.0);
+
+ m2.merge(m1);
+
+ ensure_equals("Count after merge (p1)", 3, m2.getCount());
+ ensure_approximately_equals("Min after merge (p1)", F32(5.0), m2.getMin(), 22);
+ ensure_approximately_equals("Max after merge (p1)", F32(9.0), m2.getMax(), 22);
+ ensure_approximately_equals("Mean after merge (p1)", F32(7.000), m2.getMean(), 22);
+
+ ensure_equals("Source count of merge is undamaged (p1)", 3, m1.getCount());
+ ensure_approximately_equals("Source min of merge is undamaged (p1)", F32(5.0), m1.getMin(), 22);
+ ensure_approximately_equals("Source max of merge is undamaged (p1)", F32(9.0), m1.getMax(), 22);
+ ensure_approximately_equals("Source mean of merge is undamaged (p1)", F32(7.0), m1.getMean(), 22);
+
+ m1.reset();
+ m2.reset();
+
+ m1.record(-22.0);
+ m1.record(-1.0);
+
+ m2.merge(m1);
+
+ ensure_equals("Count after merge (p2)", 2, m2.getCount());
+ ensure_approximately_equals("Min after merge (p2)", F32(-22.0), m2.getMin(), 22);
+ ensure_approximately_equals("Max after merge (p2)", F32(-1.0), m2.getMax(), 22);
+ ensure_approximately_equals("Mean after merge (p2)", F32(-11.5), m2.getMean(), 22);
+ }
+
+ // Testing LLSimpleStatMMM's merge() method when neither dst nor src contributes
+ template<> template<>
+ void stat_counter_index_object_t::test<16>()
+ {
+ LLSimpleStatMMM<> m1;
+ LLSimpleStatMMM<> m2;
+
+ m2.merge(m1);
+
+ ensure_equals("Count after merge (p1)", 0, m2.getCount());
+ ensure_approximately_equals("Min after merge (p1)", F32(0), m2.getMin(), 22);
+ ensure_approximately_equals("Max after merge (p1)", F32(0), m2.getMax(), 22);
+ ensure_approximately_equals("Mean after merge (p1)", F32(0), m2.getMean(), 22);
+
+ ensure_equals("Source count of merge is undamaged (p1)", 0, m1.getCount());
+ ensure_approximately_equals("Source min of merge is undamaged (p1)", F32(0), m1.getMin(), 22);
+ ensure_approximately_equals("Source max of merge is undamaged (p1)", F32(0), m1.getMax(), 22);
+ ensure_approximately_equals("Source mean of merge is undamaged (p1)", F32(0), m1.getMean(), 22);
+ }
+}
diff --git a/indra/newview/tests/llversioninfo_test.cpp b/indra/newview/tests/llversioninfo_test.cpp
new file mode 100644
index 0000000000..398d8f16ed
--- /dev/null
+++ b/indra/newview/tests/llversioninfo_test.cpp
@@ -0,0 +1,114 @@
+/**
+ * @file llversioninfo_test.cpp
+ *
+ * $LicenseInfo:firstyear=2010&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 "../test/lltut.h"
+
+#include "../llversioninfo.h"
+#include "llversionviewer.h"
+
+namespace tut
+{
+ struct versioninfo
+ {
+ versioninfo()
+ : mResetChannel("Reset Channel")
+ {
+ std::ostringstream stream;
+ stream << LL_VERSION_MAJOR << "."
+ << LL_VERSION_MINOR << "."
+ << LL_VERSION_PATCH << "."
+ << LL_VERSION_BUILD;
+ mVersion = stream.str();
+ stream.str("");
+
+ stream << LL_VERSION_MAJOR << "."
+ << LL_VERSION_MINOR << "."
+ << LL_VERSION_PATCH;
+ mShortVersion = stream.str();
+ stream.str("");
+
+ stream << LL_CHANNEL
+ << " "
+ << mVersion;
+ mVersionAndChannel = stream.str();
+ stream.str("");
+
+ stream << mResetChannel
+ << " "
+ << mVersion;
+ mResetVersionAndChannel = stream.str();
+ }
+ std::string mResetChannel;
+ std::string mVersion;
+ std::string mShortVersion;
+ std::string mVersionAndChannel;
+ std::string mResetVersionAndChannel;
+ };
+
+ typedef test_group<versioninfo> versioninfo_t;
+ typedef versioninfo_t::object versioninfo_object_t;
+ tut::versioninfo_t tut_versioninfo("LLVersionInfo");
+
+ template<> template<>
+ void versioninfo_object_t::test<1>()
+ {
+ ensure_equals("Major version",
+ LLVersionInfo::getMajor(),
+ LL_VERSION_MAJOR);
+ ensure_equals("Minor version",
+ LLVersionInfo::getMinor(),
+ LL_VERSION_MINOR);
+ ensure_equals("Patch version",
+ LLVersionInfo::getPatch(),
+ LL_VERSION_PATCH);
+ ensure_equals("Build version",
+ LLVersionInfo::getBuild(),
+ LL_VERSION_BUILD);
+ ensure_equals("Channel version",
+ LLVersionInfo::getChannel(),
+ LL_CHANNEL);
+
+ ensure_equals("Version String",
+ LLVersionInfo::getVersion(),
+ mVersion);
+ ensure_equals("Short Version String",
+ LLVersionInfo::getShortVersion(),
+ mShortVersion);
+ ensure_equals("Version and channel String",
+ LLVersionInfo::getChannelAndVersion(),
+ mVersionAndChannel);
+
+ LLVersionInfo::resetChannel(mResetChannel);
+ ensure_equals("Reset channel version",
+ LLVersionInfo::getChannel(),
+ mResetChannel);
+
+ ensure_equals("Reset Version and channel String",
+ LLVersionInfo::getChannelAndVersion(),
+ mResetVersionAndChannel);
+ }
+}
diff --git a/indra/newview/tests/llviewerassetstats_test.cpp b/indra/newview/tests/llviewerassetstats_test.cpp
new file mode 100644
index 0000000000..3faddc13c1
--- /dev/null
+++ b/indra/newview/tests/llviewerassetstats_test.cpp
@@ -0,0 +1,984 @@
+/**
+ * @file llviewerassetstats_tut.cpp
+ * @date 2010-10-28
+ * @brief Test cases for some of newview/llviewerassetstats.cpp
+ *
+ * $LicenseInfo:firstyear=2010&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 <tut/tut.hpp>
+#include <iostream>
+
+#include "lltut.h"
+#include "../llviewerassetstats.h"
+#include "lluuid.h"
+#include "llsdutil.h"
+#include "llregionhandle.h"
+
+static const char * all_keys[] =
+{
+ "duration",
+ "fps",
+ "get_other",
+ "get_texture_temp_http",
+ "get_texture_temp_udp",
+ "get_texture_non_temp_http",
+ "get_texture_non_temp_udp",
+ "get_wearable_udp",
+ "get_sound_udp",
+ "get_gesture_udp"
+};
+
+static const char * resp_keys[] =
+{
+ "get_other",
+ "get_texture_temp_http",
+ "get_texture_temp_udp",
+ "get_texture_non_temp_http",
+ "get_texture_non_temp_udp",
+ "get_wearable_udp",
+ "get_sound_udp",
+ "get_gesture_udp"
+};
+
+static const char * sub_keys[] =
+{
+ "dequeued",
+ "enqueued",
+ "resp_count",
+ "resp_max",
+ "resp_min",
+ "resp_mean"
+};
+
+static const char * mmm_resp_keys[] =
+{
+ "fps"
+};
+
+static const char * mmm_sub_keys[] =
+{
+ "count",
+ "max",
+ "min",
+ "mean"
+};
+
+static const LLUUID region1("4e2d81a3-6263-6ffe-ad5c-8ce04bee07e8");
+static const LLUUID region2("68762cc8-b68b-4e45-854b-e830734f2d4a");
+static const U64 region1_handle(0x0000040000003f00ULL);
+static const U64 region2_handle(0x0000030000004200ULL);
+static const std::string region1_handle_str("0000040000003f00");
+static const std::string region2_handle_str("0000030000004200");
+
+#if 0
+static bool
+is_empty_map(const LLSD & sd)
+{
+ return sd.isMap() && 0 == sd.size();
+}
+
+static bool
+is_single_key_map(const LLSD & sd, const std::string & key)
+{
+ return sd.isMap() && 1 == sd.size() && sd.has(key);
+}
+#endif
+
+static bool
+is_double_key_map(const LLSD & sd, const std::string & key1, const std::string & key2)
+{
+ return sd.isMap() && 2 == sd.size() && sd.has(key1) && sd.has(key2);
+}
+
+static bool
+is_no_stats_map(const LLSD & sd)
+{
+ return is_double_key_map(sd, "duration", "regions");
+}
+
+static bool
+is_single_slot_array(const LLSD & sd, U64 region_handle)
+{
+ U32 grid_x(0), grid_y(0);
+ grid_from_region_handle(region_handle, &grid_x, &grid_y);
+
+ return (sd.isArray() &&
+ 1 == sd.size() &&
+ sd[0].has("grid_x") &&
+ sd[0].has("grid_y") &&
+ sd[0]["grid_x"].isInteger() &&
+ sd[0]["grid_y"].isInteger() &&
+ grid_x == sd[0]["grid_x"].asInteger() &&
+ grid_y == sd[0]["grid_y"].asInteger());
+}
+
+static bool
+is_double_slot_array(const LLSD & sd, U64 region_handle1, U64 region_handle2)
+{
+ U32 grid_x1(0), grid_y1(0);
+ U32 grid_x2(0), grid_y2(0);
+ grid_from_region_handle(region_handle1, &grid_x1, &grid_y1);
+ grid_from_region_handle(region_handle2, &grid_x2, &grid_y2);
+
+ return (sd.isArray() &&
+ 2 == sd.size() &&
+ sd[0].has("grid_x") &&
+ sd[0].has("grid_y") &&
+ sd[0]["grid_x"].isInteger() &&
+ sd[0]["grid_y"].isInteger() &&
+ sd[1].has("grid_x") &&
+ sd[1].has("grid_y") &&
+ sd[1]["grid_x"].isInteger() &&
+ sd[1]["grid_y"].isInteger() &&
+ ((grid_x1 == sd[0]["grid_x"].asInteger() &&
+ grid_y1 == sd[0]["grid_y"].asInteger() &&
+ grid_x2 == sd[1]["grid_x"].asInteger() &&
+ grid_y2 == sd[1]["grid_y"].asInteger()) ||
+ (grid_x1 == sd[1]["grid_x"].asInteger() &&
+ grid_y1 == sd[1]["grid_y"].asInteger() &&
+ grid_x2 == sd[0]["grid_x"].asInteger() &&
+ grid_y2 == sd[0]["grid_y"].asInteger())));
+}
+
+static LLSD
+get_region(const LLSD & sd, U64 region_handle1)
+{
+ U32 grid_x(0), grid_y(0);
+ grid_from_region_handle(region_handle1, &grid_x, &grid_y);
+
+ for (LLSD::array_const_iterator it(sd["regions"].beginArray());
+ sd["regions"].endArray() != it;
+ ++it)
+ {
+ if ((*it).has("grid_x") &&
+ (*it).has("grid_y") &&
+ (*it)["grid_x"].isInteger() &&
+ (*it)["grid_y"].isInteger() &&
+ (*it)["grid_x"].asInteger() == grid_x &&
+ (*it)["grid_y"].asInteger() == grid_y)
+ {
+ return *it;
+ }
+ }
+ return LLSD();
+}
+
+namespace tut
+{
+ struct tst_viewerassetstats_index
+ {};
+ typedef test_group<tst_viewerassetstats_index> tst_viewerassetstats_index_t;
+ typedef tst_viewerassetstats_index_t::object tst_viewerassetstats_index_object_t;
+ tut::tst_viewerassetstats_index_t tut_tst_viewerassetstats_index("tst_viewerassetstats_test");
+
+ // Testing free functions without global stats allocated
+ template<> template<>
+ void tst_viewerassetstats_index_object_t::test<1>()
+ {
+ // Check that helpers aren't bothered by missing global stats
+ ensure("Global gViewerAssetStatsMain should be NULL", (NULL == gViewerAssetStatsMain));
+
+ LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false);
+
+ LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_TEXTURE, false, false);
+
+ LLViewerAssetStatsFF::record_response_main(LLViewerAssetType::AT_GESTURE, false, false, 12300000ULL);
+ }
+
+ // Create a non-global instance and check the structure
+ template<> template<>
+ void tst_viewerassetstats_index_object_t::test<2>()
+ {
+ ensure("Global gViewerAssetStatsMain should be NULL", (NULL == gViewerAssetStatsMain));
+
+ LLViewerAssetStats * it = new LLViewerAssetStats();
+
+ ensure("Global gViewerAssetStatsMain should still be NULL", (NULL == gViewerAssetStatsMain));
+
+ LLSD sd_full = it->asLLSD(false);
+
+ // Default (NULL) region ID doesn't produce LLSD results so should
+ // get an empty map back from output
+ ensure("Stat-less LLSD initially", is_no_stats_map(sd_full));
+
+ // Once the region is set, we will get a response even with no data collection
+ it->setRegion(region1_handle);
+ sd_full = it->asLLSD(false);
+ ensure("Correct single-key LLSD map root", is_double_key_map(sd_full, "duration", "regions"));
+ ensure("Correct single-slot LLSD array regions", is_single_slot_array(sd_full["regions"], region1_handle));
+
+ LLSD sd = sd_full["regions"][0];
+
+ delete it;
+
+ // Check the structure of the LLSD
+ for (int i = 0; i < LL_ARRAY_SIZE(all_keys); ++i)
+ {
+ std::string line = llformat("Has '%s' key", all_keys[i]);
+ ensure(line, sd.has(all_keys[i]));
+ }
+
+ for (int i = 0; i < LL_ARRAY_SIZE(resp_keys); ++i)
+ {
+ for (int j = 0; j < LL_ARRAY_SIZE(sub_keys); ++j)
+ {
+ std::string line = llformat("Key '%s' has '%s' key", resp_keys[i], sub_keys[j]);
+ ensure(line, sd[resp_keys[i]].has(sub_keys[j]));
+ }
+ }
+
+ for (int i = 0; i < LL_ARRAY_SIZE(mmm_resp_keys); ++i)
+ {
+ for (int j = 0; j < LL_ARRAY_SIZE(mmm_sub_keys); ++j)
+ {
+ std::string line = llformat("Key '%s' has '%s' key", mmm_resp_keys[i], mmm_sub_keys[j]);
+ ensure(line, sd[mmm_resp_keys[i]].has(mmm_sub_keys[j]));
+ }
+ }
+ }
+
+ // Create a non-global instance and check some content
+ template<> template<>
+ void tst_viewerassetstats_index_object_t::test<3>()
+ {
+ LLViewerAssetStats * it = new LLViewerAssetStats();
+ it->setRegion(region1_handle);
+
+ LLSD sd = it->asLLSD(false);
+ ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration"));
+ ensure("Correct single-slot LLSD array regions", is_single_slot_array(sd["regions"], region1_handle));
+ sd = sd[0];
+
+ delete it;
+
+ // Check a few points on the tree for content
+ ensure("sd[get_texture_temp_http][dequeued] is 0", (0 == sd["get_texture_temp_http"]["dequeued"].asInteger()));
+ ensure("sd[get_sound_udp][resp_min] is 0", (0.0 == sd["get_sound_udp"]["resp_min"].asReal()));
+ }
+
+ // Create a global instance and verify free functions do something useful
+ template<> template<>
+ void tst_viewerassetstats_index_object_t::test<4>()
+ {
+ gViewerAssetStatsMain = new LLViewerAssetStats();
+ LLViewerAssetStatsFF::set_region_main(region1_handle);
+
+ LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false);
+ LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_TEXTURE, false, false);
+
+ LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, false, false);
+ LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, false, false);
+
+ LLSD sd = gViewerAssetStatsMain->asLLSD(false);
+ ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration"));
+ ensure("Correct single-slot LLSD array regions", is_single_slot_array(sd["regions"], region1_handle));
+ sd = sd["regions"][0];
+
+ // Check a few points on the tree for content
+ ensure("sd[get_texture_non_temp_udp][enqueued] is 1", (1 == sd["get_texture_non_temp_udp"]["enqueued"].asInteger()));
+ ensure("sd[get_texture_temp_udp][enqueued] is 0", (0 == sd["get_texture_temp_udp"]["enqueued"].asInteger()));
+ ensure("sd[get_texture_non_temp_http][enqueued] is 0", (0 == sd["get_texture_non_temp_http"]["enqueued"].asInteger()));
+ ensure("sd[get_texture_temp_http][enqueued] is 0", (0 == sd["get_texture_temp_http"]["enqueued"].asInteger()));
+ ensure("sd[get_gesture_udp][dequeued] is 0", (0 == sd["get_gesture_udp"]["dequeued"].asInteger()));
+
+ // Reset and check zeros...
+ // Reset leaves current region in place
+ gViewerAssetStatsMain->reset();
+ sd = gViewerAssetStatsMain->asLLSD(false)["regions"][region1_handle_str];
+
+ delete gViewerAssetStatsMain;
+ gViewerAssetStatsMain = NULL;
+
+ ensure("sd[get_texture_non_temp_udp][enqueued] is reset", (0 == sd["get_texture_non_temp_udp"]["enqueued"].asInteger()));
+ ensure("sd[get_gesture_udp][dequeued] is reset", (0 == sd["get_gesture_udp"]["dequeued"].asInteger()));
+ }
+
+ // Create two global instances and verify no interactions
+ template<> template<>
+ void tst_viewerassetstats_index_object_t::test<5>()
+ {
+ gViewerAssetStatsThread1 = new LLViewerAssetStats();
+ gViewerAssetStatsMain = new LLViewerAssetStats();
+ LLViewerAssetStatsFF::set_region_main(region1_handle);
+
+ LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false);
+ LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_TEXTURE, false, false);
+
+ LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, false, false);
+ LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, false, false);
+
+ LLSD sd = gViewerAssetStatsThread1->asLLSD(false);
+ ensure("Other collector is empty", is_no_stats_map(sd));
+ sd = gViewerAssetStatsMain->asLLSD(false);
+ ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration"));
+ ensure("Correct single-slot LLSD array regions", is_single_slot_array(sd["regions"], region1_handle));
+ sd = sd["regions"][0];
+
+ // Check a few points on the tree for content
+ ensure("sd[get_texture_non_temp_udp][enqueued] is 1", (1 == sd["get_texture_non_temp_udp"]["enqueued"].asInteger()));
+ ensure("sd[get_texture_temp_udp][enqueued] is 0", (0 == sd["get_texture_temp_udp"]["enqueued"].asInteger()));
+ ensure("sd[get_texture_non_temp_http][enqueued] is 0", (0 == sd["get_texture_non_temp_http"]["enqueued"].asInteger()));
+ ensure("sd[get_texture_temp_http][enqueued] is 0", (0 == sd["get_texture_temp_http"]["enqueued"].asInteger()));
+ ensure("sd[get_gesture_udp][dequeued] is 0", (0 == sd["get_gesture_udp"]["dequeued"].asInteger()));
+
+ // Reset and check zeros...
+ // Reset leaves current region in place
+ gViewerAssetStatsMain->reset();
+ sd = gViewerAssetStatsMain->asLLSD(false)["regions"][0];
+
+ delete gViewerAssetStatsMain;
+ gViewerAssetStatsMain = NULL;
+ delete gViewerAssetStatsThread1;
+ gViewerAssetStatsThread1 = NULL;
+
+ ensure("sd[get_texture_non_temp_udp][enqueued] is reset", (0 == sd["get_texture_non_temp_udp"]["enqueued"].asInteger()));
+ ensure("sd[get_gesture_udp][dequeued] is reset", (0 == sd["get_gesture_udp"]["dequeued"].asInteger()));
+ }
+
+ // Check multiple region collection
+ template<> template<>
+ void tst_viewerassetstats_index_object_t::test<6>()
+ {
+ gViewerAssetStatsMain = new LLViewerAssetStats();
+
+ LLViewerAssetStatsFF::set_region_main(region1_handle);
+
+ LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false);
+ LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_TEXTURE, false, false);
+
+ LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, false, false);
+ LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, false, false);
+
+ LLViewerAssetStatsFF::set_region_main(region2_handle);
+
+ LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false);
+ LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false);
+ LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false);
+ LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false);
+
+ LLSD sd = gViewerAssetStatsMain->asLLSD(false);
+
+ // std::cout << sd << std::endl;
+
+ ensure("Correct double-key LLSD map root", is_double_key_map(sd, "duration", "regions"));
+ ensure("Correct double-slot LLSD array regions", is_double_slot_array(sd["regions"], region1_handle, region2_handle));
+ LLSD sd1 = get_region(sd, region1_handle);
+ LLSD sd2 = get_region(sd, region2_handle);
+ ensure("Region1 is present in results", sd1.isMap());
+ ensure("Region2 is present in results", sd2.isMap());
+
+ // Check a few points on the tree for content
+ ensure_equals("sd1[get_texture_non_temp_udp][enqueued] is 1", sd1["get_texture_non_temp_udp"]["enqueued"].asInteger(), 1);
+ ensure_equals("sd1[get_texture_temp_udp][enqueued] is 0", sd1["get_texture_temp_udp"]["enqueued"].asInteger(), 0);
+ ensure_equals("sd1[get_texture_non_temp_http][enqueued] is 0", sd1["get_texture_non_temp_http"]["enqueued"].asInteger(), 0);
+ ensure_equals("sd1[get_texture_temp_http][enqueued] is 0", sd1["get_texture_temp_http"]["enqueued"].asInteger(), 0);
+ ensure_equals("sd1[get_gesture_udp][dequeued] is 0", sd1["get_gesture_udp"]["dequeued"].asInteger(), 0);
+
+ // Check a few points on the tree for content
+ ensure("sd2[get_gesture_udp][enqueued] is 4", (4 == sd2["get_gesture_udp"]["enqueued"].asInteger()));
+ ensure("sd2[get_gesture_udp][dequeued] is 0", (0 == sd2["get_gesture_udp"]["dequeued"].asInteger()));
+ ensure("sd2[get_texture_non_temp_udp][enqueued] is 0", (0 == sd2["get_texture_non_temp_udp"]["enqueued"].asInteger()));
+
+ // Reset and check zeros...
+ // Reset leaves current region in place
+ gViewerAssetStatsMain->reset();
+ sd = gViewerAssetStatsMain->asLLSD(false);
+ ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration"));
+ ensure("Correct single-slot LLSD array regions (p2)", is_single_slot_array(sd["regions"], region2_handle));
+ sd2 = sd["regions"][0];
+
+ delete gViewerAssetStatsMain;
+ gViewerAssetStatsMain = NULL;
+
+ ensure("sd2[get_texture_non_temp_udp][enqueued] is reset", (0 == sd2["get_texture_non_temp_udp"]["enqueued"].asInteger()));
+ ensure("sd2[get_gesture_udp][enqueued] is reset", (0 == sd2["get_gesture_udp"]["enqueued"].asInteger()));
+ }
+
+ // Check multiple region collection jumping back-and-forth between regions
+ template<> template<>
+ void tst_viewerassetstats_index_object_t::test<7>()
+ {
+ gViewerAssetStatsMain = new LLViewerAssetStats();
+
+ LLViewerAssetStatsFF::set_region_main(region1_handle);
+
+ LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false);
+ LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_TEXTURE, false, false);
+
+ LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, false, false);
+ LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, false, false);
+
+ LLViewerAssetStatsFF::set_region_main(region2_handle);
+
+ LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false);
+ LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false);
+ LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false);
+ LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false);
+
+ LLViewerAssetStatsFF::set_region_main(region1_handle);
+
+ LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, true, true);
+ LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_TEXTURE, true, true);
+
+ LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, false, false);
+ LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, false, false);
+
+ LLViewerAssetStatsFF::set_region_main(region2_handle);
+
+ LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false);
+ LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false);
+ LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false);
+ LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false);
+
+ LLSD sd = gViewerAssetStatsMain->asLLSD(false);
+
+ ensure("Correct double-key LLSD map root", is_double_key_map(sd, "duration", "regions"));
+ ensure("Correct double-slot LLSD array regions", is_double_slot_array(sd["regions"], region1_handle, region2_handle));
+ LLSD sd1 = get_region(sd, region1_handle);
+ LLSD sd2 = get_region(sd, region2_handle);
+ ensure("Region1 is present in results", sd1.isMap());
+ ensure("Region2 is present in results", sd2.isMap());
+
+ // Check a few points on the tree for content
+ ensure("sd1[get_texture_non_temp_udp][enqueued] is 1", (1 == sd1["get_texture_non_temp_udp"]["enqueued"].asInteger()));
+ ensure("sd1[get_texture_temp_udp][enqueued] is 0", (0 == sd1["get_texture_temp_udp"]["enqueued"].asInteger()));
+ ensure("sd1[get_texture_non_temp_http][enqueued] is 0", (0 == sd1["get_texture_non_temp_http"]["enqueued"].asInteger()));
+ ensure("sd1[get_texture_temp_http][enqueued] is 1", (1 == sd1["get_texture_temp_http"]["enqueued"].asInteger()));
+ ensure("sd1[get_gesture_udp][dequeued] is 0", (0 == sd1["get_gesture_udp"]["dequeued"].asInteger()));
+
+ // Check a few points on the tree for content
+ ensure("sd2[get_gesture_udp][enqueued] is 8", (8 == sd2["get_gesture_udp"]["enqueued"].asInteger()));
+ ensure("sd2[get_gesture_udp][dequeued] is 0", (0 == sd2["get_gesture_udp"]["dequeued"].asInteger()));
+ ensure("sd2[get_texture_non_temp_udp][enqueued] is 0", (0 == sd2["get_texture_non_temp_udp"]["enqueued"].asInteger()));
+
+ // Reset and check zeros...
+ // Reset leaves current region in place
+ gViewerAssetStatsMain->reset();
+ sd = gViewerAssetStatsMain->asLLSD(false);
+ ensure("Correct single-key LLSD map root", is_double_key_map(sd, "duration", "regions"));
+ ensure("Correct single-slot LLSD array regions (p2)", is_single_slot_array(sd["regions"], region2_handle));
+ sd2 = get_region(sd, region2_handle);
+ ensure("Region2 is present in results", sd2.isMap());
+
+ delete gViewerAssetStatsMain;
+ gViewerAssetStatsMain = NULL;
+
+ ensure_equals("sd2[get_texture_non_temp_udp][enqueued] is reset", sd2["get_texture_non_temp_udp"]["enqueued"].asInteger(), 0);
+ ensure_equals("sd2[get_gesture_udp][enqueued] is reset", sd2["get_gesture_udp"]["enqueued"].asInteger(), 0);
+ }
+
+ // Non-texture assets ignore transport and persistence flags
+ template<> template<>
+ void tst_viewerassetstats_index_object_t::test<8>()
+ {
+ gViewerAssetStatsThread1 = new LLViewerAssetStats();
+ gViewerAssetStatsMain = new LLViewerAssetStats();
+ LLViewerAssetStatsFF::set_region_main(region1_handle);
+
+ LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false);
+ LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_TEXTURE, false, false);
+
+ LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, false, false);
+ LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, false, false);
+
+ LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, false, true);
+ LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, false, true);
+
+ LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, true, false);
+ LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, true, false);
+
+ LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, true, true);
+ LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, true, true);
+
+ LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_LSL_BYTECODE, false, false);
+
+ LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_LSL_BYTECODE, false, true);
+
+ LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_LSL_BYTECODE, true, false);
+
+ LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+
+ LLSD sd = gViewerAssetStatsThread1->asLLSD(false);
+ ensure("Other collector is empty", is_no_stats_map(sd));
+ sd = gViewerAssetStatsMain->asLLSD(false);
+ ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration"));
+ ensure("Correct single-slot LLSD array regions", is_single_slot_array(sd["regions"], region1_handle));
+ sd = get_region(sd, region1_handle);
+ ensure("Region1 is present in results", sd.isMap());
+
+ // Check a few points on the tree for content
+ ensure("sd[get_gesture_udp][enqueued] is 0", (0 == sd["get_gesture_udp"]["enqueued"].asInteger()));
+ ensure("sd[get_gesture_udp][dequeued] is 0", (0 == sd["get_gesture_udp"]["dequeued"].asInteger()));
+
+ ensure("sd[get_wearable_udp][enqueued] is 4", (4 == sd["get_wearable_udp"]["enqueued"].asInteger()));
+ ensure("sd[get_wearable_udp][dequeued] is 4", (4 == sd["get_wearable_udp"]["dequeued"].asInteger()));
+
+ ensure("sd[get_other][enqueued] is 4", (4 == sd["get_other"]["enqueued"].asInteger()));
+ ensure("sd[get_other][dequeued] is 0", (0 == sd["get_other"]["dequeued"].asInteger()));
+
+ // Reset and check zeros...
+ // Reset leaves current region in place
+ gViewerAssetStatsMain->reset();
+ sd = get_region(gViewerAssetStatsMain->asLLSD(false), region1_handle);
+ ensure("Region1 is present in results", sd.isMap());
+
+ delete gViewerAssetStatsMain;
+ gViewerAssetStatsMain = NULL;
+ delete gViewerAssetStatsThread1;
+ gViewerAssetStatsThread1 = NULL;
+
+ ensure_equals("sd[get_texture_non_temp_udp][enqueued] is reset", sd["get_texture_non_temp_udp"]["enqueued"].asInteger(), 0);
+ ensure_equals("sd[get_gesture_udp][dequeued] is reset", sd["get_gesture_udp"]["dequeued"].asInteger(), 0);
+ }
+
+
+ // LLViewerAssetStats::merge() basic functions work
+ template<> template<>
+ void tst_viewerassetstats_index_object_t::test<9>()
+ {
+ LLViewerAssetStats s1;
+ LLViewerAssetStats s2;
+
+ s1.setRegion(region1_handle);
+ s2.setRegion(region1_handle);
+
+ s1.recordGetServiced(LLViewerAssetType::AT_TEXTURE, true, true, 5000000);
+ s1.recordGetServiced(LLViewerAssetType::AT_TEXTURE, true, true, 6000000);
+ s1.recordGetServiced(LLViewerAssetType::AT_TEXTURE, true, true, 8000000);
+ s1.recordGetServiced(LLViewerAssetType::AT_TEXTURE, true, true, 7000000);
+ s1.recordGetServiced(LLViewerAssetType::AT_TEXTURE, true, true, 9000000);
+
+ s2.recordGetServiced(LLViewerAssetType::AT_TEXTURE, true, true, 2000000);
+ s2.recordGetServiced(LLViewerAssetType::AT_TEXTURE, true, true, 3000000);
+ s2.recordGetServiced(LLViewerAssetType::AT_TEXTURE, true, true, 4000000);
+
+ s2.merge(s1);
+
+ LLSD s2_llsd = get_region(s2.asLLSD(false), region1_handle);
+ ensure("Region1 is present in results", s2_llsd.isMap());
+
+ ensure_equals("count after merge", s2_llsd["get_texture_temp_http"]["resp_count"].asInteger(), 8);
+ ensure_approximately_equals("min after merge", s2_llsd["get_texture_temp_http"]["resp_min"].asReal(), 2.0, 22);
+ ensure_approximately_equals("max after merge", s2_llsd["get_texture_temp_http"]["resp_max"].asReal(), 9.0, 22);
+ ensure_approximately_equals("max after merge", s2_llsd["get_texture_temp_http"]["resp_mean"].asReal(), 5.5, 22);
+ }
+
+ // LLViewerAssetStats::merge() basic functions work without corrupting source data
+ template<> template<>
+ void tst_viewerassetstats_index_object_t::test<10>()
+ {
+ LLViewerAssetStats s1;
+ LLViewerAssetStats s2;
+
+ s1.setRegion(region1_handle);
+ s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+
+ s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+
+ s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 23289200);
+ s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 282900);
+
+
+ s2.setRegion(region2_handle);
+ s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+
+ s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+
+ s2.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 6500000);
+ s2.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 10000);
+
+ {
+ s2.merge(s1);
+
+ LLSD src = s1.asLLSD(false);
+ LLSD dst = s2.asLLSD(false);
+
+ ensure_equals("merge src has single region", src["regions"].size(), 1);
+ ensure_equals("merge dst has dual regions", dst["regions"].size(), 2);
+
+ // Remove time stamps, they're a problem
+ src.erase("duration");
+ src["regions"][0].erase("duration");
+ dst.erase("duration");
+ dst["regions"][0].erase("duration");
+ dst["regions"][1].erase("duration");
+
+ LLSD s1_llsd = get_region(src, region1_handle);
+ ensure("Region1 is present in src", s1_llsd.isMap());
+ LLSD s2_llsd = get_region(dst, region1_handle);
+ ensure("Region1 is present in dst", s2_llsd.isMap());
+
+ ensure("result from src is in dst", llsd_equals(s1_llsd, s2_llsd));
+ }
+
+ s1.setRegion(region1_handle);
+ s2.setRegion(region1_handle);
+ s1.reset();
+ s2.reset();
+
+ s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+
+ s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+
+ s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 23289200);
+ s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 282900);
+
+
+ s2.setRegion(region1_handle);
+ s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+
+ s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+
+ s2.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 6500000);
+ s2.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 10000);
+
+ {
+ s2.merge(s1);
+
+ LLSD src = s1.asLLSD(false);
+ LLSD dst = s2.asLLSD(false);
+
+ ensure_equals("merge src has single region (p2)", src["regions"].size(), 1);
+ ensure_equals("merge dst has single region (p2)", dst["regions"].size(), 1);
+
+ // Remove time stamps, they're a problem
+ src.erase("duration");
+ src["regions"][0].erase("duration");
+ dst.erase("duration");
+ dst["regions"][0].erase("duration");
+
+ LLSD s1_llsd = get_region(src, region1_handle);
+ ensure("Region1 is present in src", s1_llsd.isMap());
+ LLSD s2_llsd = get_region(dst, region1_handle);
+ ensure("Region1 is present in dst", s2_llsd.isMap());
+
+ ensure_equals("src counts okay (enq)", s1_llsd["get_other"]["enqueued"].asInteger(), 4);
+ ensure_equals("src counts okay (deq)", s1_llsd["get_other"]["dequeued"].asInteger(), 4);
+ ensure_equals("src resp counts okay", s1_llsd["get_other"]["resp_count"].asInteger(), 2);
+ ensure_approximately_equals("src respmin okay", s1_llsd["get_other"]["resp_min"].asReal(), 0.2829, 20);
+ ensure_approximately_equals("src respmax okay", s1_llsd["get_other"]["resp_max"].asReal(), 23.2892, 20);
+
+ ensure_equals("dst counts okay (enq)", s2_llsd["get_other"]["enqueued"].asInteger(), 12);
+ ensure_equals("src counts okay (deq)", s2_llsd["get_other"]["dequeued"].asInteger(), 11);
+ ensure_equals("dst resp counts okay", s2_llsd["get_other"]["resp_count"].asInteger(), 4);
+ ensure_approximately_equals("dst respmin okay", s2_llsd["get_other"]["resp_min"].asReal(), 0.010, 20);
+ ensure_approximately_equals("dst respmax okay", s2_llsd["get_other"]["resp_max"].asReal(), 23.2892, 20);
+ }
+ }
+
+
+ // Maximum merges are interesting when one side contributes nothing
+ template<> template<>
+ void tst_viewerassetstats_index_object_t::test<11>()
+ {
+ LLViewerAssetStats s1;
+ LLViewerAssetStats s2;
+
+ s1.setRegion(region1_handle);
+ s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+
+ s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+
+ // Want to test negative numbers here but have to work in U64
+ s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 0);
+ s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 0);
+ s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 0);
+
+ s2.setRegion(region1_handle);
+ s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+
+ s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+
+ {
+ s2.merge(s1);
+
+ LLSD src = s1.asLLSD(false);
+ LLSD dst = s2.asLLSD(false);
+
+ ensure_equals("merge src has single region", src["regions"].size(), 1);
+ ensure_equals("merge dst has single region", dst["regions"].size(), 1);
+
+ // Remove time stamps, they're a problem
+ src.erase("duration");
+ src["regions"][0].erase("duration");
+ dst.erase("duration");
+ dst["regions"][0].erase("duration");
+
+ LLSD s2_llsd = get_region(dst, region1_handle);
+ ensure("Region1 is present in dst", s2_llsd.isMap());
+
+ ensure_equals("dst counts come from src only", s2_llsd["get_other"]["resp_count"].asInteger(), 3);
+
+ ensure_approximately_equals("dst maximum with count 0 does not contribute to merged maximum",
+ s2_llsd["get_other"]["resp_max"].asReal(), F64(0.0), 20);
+ }
+
+ // Other way around
+ s1.setRegion(region1_handle);
+ s2.setRegion(region1_handle);
+ s1.reset();
+ s2.reset();
+
+ s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+
+ s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+
+ // Want to test negative numbers here but have to work in U64
+ s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 0);
+ s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 0);
+ s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 0);
+
+ s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+
+ s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+
+ {
+ s1.merge(s2);
+
+ LLSD src = s2.asLLSD(false);
+ LLSD dst = s1.asLLSD(false);
+
+ ensure_equals("merge src has single region", src["regions"].size(), 1);
+ ensure_equals("merge dst has single region", dst["regions"].size(), 1);
+
+ // Remove time stamps, they're a problem
+ src.erase("duration");
+ src["regions"][0].erase("duration");
+ dst.erase("duration");
+ dst["regions"][0].erase("duration");
+
+ LLSD s2_llsd = get_region(dst, region1_handle);
+ ensure("Region1 is present in dst", s2_llsd.isMap());
+
+ ensure_equals("dst counts come from src only (flipped)", s2_llsd["get_other"]["resp_count"].asInteger(), 3);
+
+ ensure_approximately_equals("dst maximum with count 0 does not contribute to merged maximum (flipped)",
+ s2_llsd["get_other"]["resp_max"].asReal(), F64(0.0), 20);
+ }
+ }
+
+ // Minimum merges are interesting when one side contributes nothing
+ template<> template<>
+ void tst_viewerassetstats_index_object_t::test<12>()
+ {
+ LLViewerAssetStats s1;
+ LLViewerAssetStats s2;
+
+ s1.setRegion(region1_handle);
+ s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+
+ s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+
+ s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 3800000);
+ s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 2700000);
+ s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 2900000);
+
+ s2.setRegion(region1_handle);
+ s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+
+ s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+
+ {
+ s2.merge(s1);
+
+ LLSD src = s1.asLLSD(false);
+ LLSD dst = s2.asLLSD(false);
+
+ ensure_equals("merge src has single region", src["regions"].size(), 1);
+ ensure_equals("merge dst has single region", dst["regions"].size(), 1);
+
+ // Remove time stamps, they're a problem
+ src.erase("duration");
+ src["regions"][0].erase("duration");
+ dst.erase("duration");
+ dst["regions"][0].erase("duration");
+
+ LLSD s2_llsd = get_region(dst, region1_handle);
+ ensure("Region1 is present in dst", s2_llsd.isMap());
+
+ ensure_equals("dst counts come from src only", s2_llsd["get_other"]["resp_count"].asInteger(), 3);
+
+ ensure_approximately_equals("dst minimum with count 0 does not contribute to merged minimum",
+ s2_llsd["get_other"]["resp_min"].asReal(), F64(2.7), 20);
+ }
+
+ // Other way around
+ s1.setRegion(region1_handle);
+ s2.setRegion(region1_handle);
+ s1.reset();
+ s2.reset();
+
+ s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+
+ s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+
+ s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 3800000);
+ s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 2700000);
+ s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 2900000);
+
+ s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+
+ s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+ s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+
+ {
+ s1.merge(s2);
+
+ LLSD src = s2.asLLSD(false);
+ LLSD dst = s1.asLLSD(false);
+
+ ensure_equals("merge src has single region", src["regions"].size(), 1);
+ ensure_equals("merge dst has single region", dst["regions"].size(), 1);
+
+ // Remove time stamps, they're a problem
+ src.erase("duration");
+ src["regions"][0].erase("duration");
+ dst.erase("duration");
+ dst["regions"][0].erase("duration");
+
+ LLSD s2_llsd = get_region(dst, region1_handle);
+ ensure("Region1 is present in dst", s2_llsd.isMap());
+
+ ensure_equals("dst counts come from src only (flipped)", s2_llsd["get_other"]["resp_count"].asInteger(), 3);
+
+ ensure_approximately_equals("dst minimum with count 0 does not contribute to merged minimum (flipped)",
+ s2_llsd["get_other"]["resp_min"].asReal(), F64(2.7), 20);
+ }
+ }
+
+}
diff --git a/indra/newview/tests/llviewerhelputil_test.cpp b/indra/newview/tests/llviewerhelputil_test.cpp
index a0f1d1c3c3..710881d811 100644
--- a/indra/newview/tests/llviewerhelputil_test.cpp
+++ b/indra/newview/tests/llviewerhelputil_test.cpp
@@ -72,16 +72,11 @@ static void substitute_string(std::string &input, const std::string &search, con
}
}
-class LLAgent
-{
-public:
- LLAgent() {}
- ~LLAgent() {}
-#ifdef __GNUC__
- __attribute__ ((noinline))
-#endif
- bool isGodlike() const { return FALSE; }
-};
+#include "../llagent.h"
+LLAgent::LLAgent() : mAgentAccess(NULL) { }
+LLAgent::~LLAgent() { }
+bool LLAgent::isGodlike() const { return FALSE; }
+
LLAgent gAgent;
std::string LLWeb::expandURLSubstitutions(const std::string &url,
diff --git a/indra/newview/tests/llworldmap_test.cpp b/indra/newview/tests/llworldmap_test.cpp
index b976ac5ea9..acc6e814bc 100644
--- a/indra/newview/tests/llworldmap_test.cpp
+++ b/indra/newview/tests/llworldmap_test.cpp
@@ -25,13 +25,16 @@
* $/LicenseInfo$
*/
-// Precompiled header: almost always required for newview cpp files
-#include "../llviewerprecompiledheaders.h"
-// Class to test
-#include "../llworldmap.h"
// Dependencies
-#include "../llviewerimagelist.h"
+#include "linden_common.h"
+#include "llapr.h"
+#include "llsingleton.h"
+#include "lltrans.h"
+#include "lluistring.h"
+#include "../llviewertexture.h"
#include "../llworldmapmessage.h"
+// Class to test
+#include "../llworldmap.h"
// Tut header
#include "../test/lltut.h"
@@ -44,34 +47,29 @@
// * A simulator for a class can be implemented here. Please comment and document thoroughly.
// Stub image calls
-LLViewerImageList::LLViewerImageList() { }
-LLViewerImageList::~LLViewerImageList() { }
-LLViewerImageList gImageList;
-LLViewerImage* LLViewerImageList::getImage(const LLUUID &image_id,
- BOOL usemipmaps,
- BOOL level_immediate,
- LLGLint internal_format,
- LLGLenum primary_format,
- LLHost request_from_host)
-{ return NULL; }
-void LLViewerImage::setBoostLevel(S32 level) { }
-void LLImageGL::setAddressMode(LLTexUnit::eTextureAddressMode mode) { }
+void LLViewerTexture::setBoostLevel(S32 ) { }
+void LLViewerTexture::setAddressMode(LLTexUnit::eTextureAddressMode ) { }
+LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTexture(const LLUUID&, BOOL, LLViewerTexture::EBoostLevel, S8,
+ LLGLint, LLGLenum, LLHost ) { return NULL; }
// Stub related map calls
LLWorldMapMessage::LLWorldMapMessage() { }
LLWorldMapMessage::~LLWorldMapMessage() { }
void LLWorldMapMessage::sendItemRequest(U32 type, U64 handle) { }
void LLWorldMapMessage::sendMapBlockRequest(U16 min_x, U16 min_y, U16 max_x, U16 max_y, bool return_nonexistent) { }
+
LLWorldMipmap::LLWorldMipmap() { }
LLWorldMipmap::~LLWorldMipmap() { }
void LLWorldMipmap::reset() { }
void LLWorldMipmap::dropBoostLevels() { }
void LLWorldMipmap::equalizeBoostLevels() { }
-LLPointer<LLViewerImage> LLWorldMipmap::getObjectsTile(U32 grid_x, U32 grid_y, S32 level, bool load)
-{ return NULL; }
+LLPointer<LLViewerFetchedTexture> LLWorldMipmap::getObjectsTile(U32 grid_x, U32 grid_y, S32 level, bool load) { return NULL; }
// Stub other stuff
-BOOL gPacificDaylightTime;
+std::string LLTrans::getString(const std::string &, const LLStringUtil::format_map_t& ) { return std::string("test_trans"); }
+void LLUIString::updateResult() const { }
+void LLUIString::setArg(const std::string& , const std::string& ) { }
+void LLUIString::assign(const std::string& ) { }
// End Stubbing
// -------------------------------------------------------------------------------------------
@@ -237,7 +235,7 @@ namespace tut
// Test 9 : setLandForSaleImage() / getLandForSaleImage()
LLUUID id;
mSim->setLandForSaleImage(id);
- LLPointer<LLViewerImage> image = mSim->getLandForSaleImage();
+ LLPointer<LLViewerFetchedTexture> image = mSim->getLandForSaleImage();
ensure("LLSimInfo::getLandForSaleImage() test failed", image.isNull());
// Test 10 : isPG()
mSim->setAccess(SIM_ACCESS_PG);
@@ -370,7 +368,7 @@ namespace tut
}
// Test 7 : getObjectsTile()
try {
- LLPointer<LLViewerImage> image = mWorld->getObjectsTile((U32)(X_WORLD_TEST/REGION_WIDTH_METERS), (U32)(Y_WORLD_TEST/REGION_WIDTH_METERS), 1);
+ LLPointer<LLViewerFetchedTexture> image = mWorld->getObjectsTile((U32)(X_WORLD_TEST/REGION_WIDTH_METERS), (U32)(Y_WORLD_TEST/REGION_WIDTH_METERS), 1);
ensure("LLWorldMap::getObjectsTile() failed", image.isNull());
} catch (...) {
fail("LLWorldMap::getObjectsTile() test failed with exception");
diff --git a/indra/newview/tests/llworldmipmap_test.cpp b/indra/newview/tests/llworldmipmap_test.cpp
index 54887ae219..4c0959d1a9 100644
--- a/indra/newview/tests/llworldmipmap_test.cpp
+++ b/indra/newview/tests/llworldmipmap_test.cpp
@@ -25,12 +25,12 @@
* $/LicenseInfo$
*/
-// Precompiled header: almost always required for newview cpp files
-#include "../llviewerprecompiledheaders.h"
+// Dependencies
+#include "linden_common.h"
+#include "../llviewertexture.h"
+#include "../llviewercontrol.h"
// Class to test
#include "../llworldmipmap.h"
-// Dependencies
-#include "../llviewerimagelist.h"
// Tut header
#include "../test/lltut.h"
@@ -42,19 +42,14 @@
// * Do not make any assumption as to how those classes or methods work (i.e. don't copy/paste code)
// * A simulator for a class can be implemented here. Please comment and document thoroughly.
-LLViewerImageList::LLViewerImageList() { }
-LLViewerImageList::~LLViewerImageList() { }
-
-LLViewerImageList gImageList;
+void LLViewerTexture::setBoostLevel(S32 ) { }
+LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromUrl(const std::string&, BOOL, LLViewerTexture::EBoostLevel, S8,
+ LLGLint, LLGLenum, const LLUUID& ) { return NULL; }
-LLViewerImage* LLViewerImageList::getImageFromUrl(const std::string& url,
- BOOL usemipmaps,
- BOOL level_immediate,
- LLGLint internal_format,
- LLGLenum primary_format,
- const LLUUID& force_id)
-{ return NULL; }
-void LLViewerImage::setBoostLevel(S32 level) { }
+LLControlGroup::LLControlGroup(const std::string& name) : LLInstanceTracker<LLControlGroup, std::string>(name) { }
+LLControlGroup::~LLControlGroup() { }
+std::string LLControlGroup::getString(const std::string& ) { return std::string("test_url"); }
+LLControlGroup gSavedSettings("test_settings");
// End Stubbing
// -------------------------------------------------------------------------------------------
diff --git a/indra/newview/tests/llxmlrpclistener_test.cpp b/indra/newview/tests/llxmlrpclistener_test.cpp
index 4d5df1043e..711c2a3d51 100644
--- a/indra/newview/tests/llxmlrpclistener_test.cpp
+++ b/indra/newview/tests/llxmlrpclistener_test.cpp
@@ -40,8 +40,10 @@
#include "llevents.h"
#include "lleventfilter.h"
#include "llsd.h"
+#include "llhost.h"
#include "llcontrol.h"
#include "tests/wrapllerrs.h"
+#include "tests/commtest.h"
LLControlGroup gSavedSettings("Global");
@@ -54,7 +56,8 @@ namespace tut
{
data():
pumps(LLEventPumps::instance()),
- uri("http://127.0.0.1:8000")
+ uri(std::string("http://") +
+ LLHost("127.0.0.1", commtest_data::getport("PORT")).getString())
{
// These variables are required by machinery used by
// LLXMLRPCTransaction. The values reflect reality for this test
@@ -145,7 +148,7 @@ namespace tut
pumps.obtain("LLXMLRPCTransaction").post(request);
// Set the timer
F32 timeout(10);
- watchdog.eventAfter(timeout, LLSD().insert("timeout", 0));
+ watchdog.eventAfter(timeout, LLSD().with("timeout", 0));
// and pump "mainloop" until we get something, whether from
// LLXMLRPCListener or from the watchdog filter.
LLTimer timer;
@@ -182,7 +185,7 @@ namespace tut
pumps.obtain("LLXMLRPCTransaction").post(request);
// Set the timer
F32 timeout(10);
- watchdog.eventAfter(timeout, LLSD().insert("timeout", 0));
+ watchdog.eventAfter(timeout, LLSD().with("timeout", 0));
// and pump "mainloop" until we get something, whether from
// LLXMLRPCListener or from the watchdog filter.
LLTimer timer;
@@ -218,7 +221,7 @@ namespace tut
pumps.obtain("LLXMLRPCTransaction").post(request);
// Set the timer
F32 timeout(10);
- watchdog.eventAfter(timeout, LLSD().insert("timeout", 0));
+ watchdog.eventAfter(timeout, LLSD().with("timeout", 0));
// and pump "mainloop" until we get something, whether from
// LLXMLRPCListener or from the watchdog filter.
LLTimer timer;
diff --git a/indra/newview/tests/test_llxmlrpc_peer.py b/indra/newview/tests/test_llxmlrpc_peer.py
index aeebb0cfd1..281b72a058 100644
--- a/indra/newview/tests/test_llxmlrpc_peer.py
+++ b/indra/newview/tests/test_llxmlrpc_peer.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
"""\
@file test_llxmlrpc_peer.py
@author Nat Goodspeed
@@ -37,7 +37,7 @@ from SimpleXMLRPCServer import SimpleXMLRPCServer
mydir = os.path.dirname(__file__) # expected to be .../indra/newview/tests/
sys.path.insert(0, os.path.join(mydir, os.pardir, os.pardir, "lib", "python"))
sys.path.insert(1, os.path.join(mydir, os.pardir, os.pardir, "llmessage", "tests"))
-from testrunner import run, debug
+from testrunner import freeport, run, debug
class TestServer(SimpleXMLRPCServer):
def _dispatch(self, method, params):
@@ -66,11 +66,16 @@ class TestServer(SimpleXMLRPCServer):
# Suppress error output as well
pass
-class ServerRunner(Thread):
- def run(self):
- server = TestServer(('127.0.0.1', 8000))
- debug("Starting XMLRPC server...\n")
- server.serve_forever()
-
if __name__ == "__main__":
- sys.exit(run(server=ServerRunner(name="xmlrpc"), *sys.argv[1:]))
+ # Instantiate a TestServer on the first free port in the specified port
+ # range. Doing this inline is better than in a daemon thread: if it blows
+ # up here, we'll get a traceback. If it blew up in some other thread, the
+ # traceback would get eaten and we'd run the subject test program anyway.
+ xmlrpcd, port = freeport(xrange(8000, 8020),
+ lambda port: TestServer(('127.0.0.1', port)))
+ # Pass the selected port number to the subject test program via the
+ # environment. We don't want to impose requirements on the test program's
+ # command-line parsing -- and anyway, for C++ integration tests, that's
+ # performed in TUT code rather than our own.
+ os.environ["PORT"] = str(port)
+ sys.exit(run(server=Thread(name="xmlrpc", target=xmlrpcd.serve_forever), *sys.argv[1:]))
diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py
index 6861f02bfb..8aa94616d6 100644
--- a/indra/newview/viewer_manifest.py
+++ b/indra/newview/viewer_manifest.py
@@ -1,29 +1,31 @@
-#!/usr/bin/python
-# @file viewer_manifest.py
-# @author Ryan Williams
-# @brief Description of all installer viewer files, and methods for packaging
-# them into installers for all supported platforms.
-#
-# $LicenseInfo:firstyear=2006&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$
+#!/usr/bin/env python
+"""\
+@file viewer_manifest.py
+@author Ryan Williams
+@brief Description of all installer viewer files, and methods for packaging
+ them into installers for all supported platforms.
+
+$LicenseInfo:firstyear=2006&license=viewerlgpl$
+Second Life Viewer Source Code
+Copyright (C) 2006-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$
+"""
import sys
import os.path
import re
@@ -112,6 +114,16 @@ class ViewerManifest(LLManifest):
# Files in the newview/ directory
self.path("gpu_table.txt")
+ # The summary.json file gets left in the base checkout dir by
+ # build.sh. It's only created for a build.sh build, therefore we
+ # have to check whether it exists. :-P
+ summary_json = "summary.json"
+ summary_json_path = os.path.join(os.pardir, os.pardir, summary_json)
+ if os.path.exists(os.path.join(self.get_src_prefix(), summary_json_path)):
+ self.path(summary_json_path, summary_json)
+ else:
+ print "No %s" % os.path.join(self.get_src_prefix(), summary_json_path)
+
def login_channel(self):
"""Channel reported for login and upgrade purposes ONLY;
used for A/B testing"""
@@ -219,22 +231,25 @@ class WindowsManifest(ViewerManifest):
else:
print "Doesn't exist:", src
- def enable_crt_manifest_check(self):
- if self.is_packaging_viewer():
- WindowsManifest.copy_action = WindowsManifest.test_msvcrt_and_copy_action
+ ### DISABLED MANIFEST CHECKING for vs2010. we may need to reenable this
+ # shortly. If this hasn't been reenabled by the 2.9 viewer release then it
+ # should be deleted -brad
+ #def enable_crt_manifest_check(self):
+ # if self.is_packaging_viewer():
+ # WindowsManifest.copy_action = WindowsManifest.test_msvcrt_and_copy_action
- def enable_no_crt_manifest_check(self):
- if self.is_packaging_viewer():
- WindowsManifest.copy_action = WindowsManifest.test_for_no_msvcrt_manifest_and_copy_action
+ #def enable_no_crt_manifest_check(self):
+ # if self.is_packaging_viewer():
+ # WindowsManifest.copy_action = WindowsManifest.test_for_no_msvcrt_manifest_and_copy_action
- def disable_manifest_check(self):
- if self.is_packaging_viewer():
- del WindowsManifest.copy_action
+ #def disable_manifest_check(self):
+ # if self.is_packaging_viewer():
+ # del WindowsManifest.copy_action
def construct(self):
super(WindowsManifest, self).construct()
- self.enable_crt_manifest_check()
+ #self.enable_crt_manifest_check()
if self.is_packaging_viewer():
# Find secondlife-bin.exe in the 'configuration' dir, then rename it to the result of final_exe.
@@ -245,31 +260,40 @@ class WindowsManifest(ViewerManifest):
'llplugin', 'slplugin', self.args['configuration'], "slplugin.exe"),
"slplugin.exe")
- self.disable_manifest_check()
+ #self.disable_manifest_check()
+ self.path(src="../viewer_components/updater/scripts/windows/update_install.bat", dst="update_install.bat")
# Get shared libs from the shared libs staging directory
if self.prefix(src=os.path.join(os.pardir, 'sharedlibs', self.args['configuration']),
dst=""):
- self.enable_crt_manifest_check()
-
- # Get kdu dll, continue if missing.
- try:
- self.path('llkdu.dll', dst='llkdu.dll')
- except RuntimeError:
- print "Skipping llkdu.dll"
-
+ #self.enable_crt_manifest_check()
+
# Get llcommon and deps. If missing assume static linkage and continue.
try:
self.path('llcommon.dll')
self.path('libapr-1.dll')
self.path('libaprutil-1.dll')
self.path('libapriconv-1.dll')
+
except RuntimeError, err:
print err.message
print "Skipping llcommon.dll (assuming llcommon was linked statically)"
- self.disable_manifest_check()
+ #self.disable_manifest_check()
+
+ # Mesh 3rd party libs needed for auto LOD and collada reading
+ try:
+ if self.args['configuration'].lower() == 'debug':
+ self.path("libcollada14dom22-d.dll")
+ else:
+ self.path("libcollada14dom22.dll")
+
+ self.path("glod.dll")
+ except RuntimeError, err:
+ print err.message
+ print "Skipping COLLADA and GLOD libraries (assumming linked statically)"
+
# Get fmod dll, continue if missing
try:
@@ -286,13 +310,11 @@ class WindowsManifest(ViewerManifest):
# These need to be installed as a SxS assembly, currently a 'private' assembly.
# See http://msdn.microsoft.com/en-us/library/ms235291(VS.80).aspx
if self.args['configuration'].lower() == 'debug':
- self.path("msvcr80d.dll")
- self.path("msvcp80d.dll")
- self.path("Microsoft.VC80.DebugCRT.manifest")
+ self.path("msvcr100d.dll")
+ self.path("msvcp100d.dll")
else:
- self.path("msvcr80.dll")
- self.path("msvcp80.dll")
- self.path("Microsoft.VC80.CRT.manifest")
+ self.path("msvcr100.dll")
+ self.path("msvcp100.dll")
# Vivox runtimes
self.path("SLVoice.exe")
@@ -302,6 +324,10 @@ class WindowsManifest(ViewerManifest):
self.path("zlib1.dll")
self.path("vivoxplatform.dll")
self.path("vivoxoal.dll")
+
+ # Security
+ self.path("ssleay32.dll")
+ self.path("libeay32.dll")
# For google-perftools tcmalloc allocator.
try:
@@ -318,11 +344,8 @@ class WindowsManifest(ViewerManifest):
self.path("featuretable.txt")
self.path("featuretable_xp.txt")
- # For use in crash reporting (generates minidumps)
- self.path("dbghelp.dll")
+ #self.enable_no_crt_manifest_check()
- self.enable_no_crt_manifest_check()
-
# Media plugins - QuickTime
if self.prefix(src='../media_plugins/quicktime/%s' % self.args['configuration'], dst="llplugin"):
self.path("media_plugin_quicktime.dll")
@@ -334,13 +357,13 @@ class WindowsManifest(ViewerManifest):
self.end_prefix()
# winmm.dll shim
- if self.prefix(src='../media_plugins/winmmshim/%s' % self.args['configuration'], dst="llplugin"):
+ if self.prefix(src='../media_plugins/winmmshim/%s' % self.args['configuration'], dst=""):
self.path("winmm.dll")
self.end_prefix()
if self.args['configuration'].lower() == 'debug':
- if self.prefix(src=os.path.join(os.pardir, os.pardir, 'libraries', 'i686-win32', 'lib', 'debug'),
+ if self.prefix(src=os.path.join(os.pardir, 'packages', 'lib', 'debug'),
dst="llplugin"):
self.path("libeay32.dll")
self.path("qtcored4.dll")
@@ -371,7 +394,7 @@ class WindowsManifest(ViewerManifest):
self.end_prefix()
else:
- if self.prefix(src=os.path.join(os.pardir, os.pardir, 'libraries', 'i686-win32', 'lib', 'release'),
+ if self.prefix(src=os.path.join(os.pardir, 'packages', 'lib', 'release'),
dst="llplugin"):
self.path("libeay32.dll")
self.path("qtcore4.dll")
@@ -402,7 +425,7 @@ class WindowsManifest(ViewerManifest):
self.end_prefix()
- self.disable_manifest_check()
+ #self.disable_manifest_check()
# pull in the crash logger and updater from other projects
# tag:"crash-logger" here as a cue to the exporter
@@ -570,7 +593,9 @@ class DarwinManifest(ViewerManifest):
self.path("Info-SecondLife.plist", dst="Info.plist")
# copy additional libs in <bundle>/Contents/MacOS/
- self.path("../../libraries/universal-darwin/lib_release/libndofdev.dylib", dst="MacOS/libndofdev.dylib")
+ self.path("../packages/lib/release/libndofdev.dylib", dst="Resources/libndofdev.dylib")
+
+ self.path("../viewer_components/updater/scripts/darwin/update_install", "MacOS/update_install")
# most everything goes in the Resources directory
if self.prefix(src="", dst="Resources"):
@@ -610,41 +635,40 @@ class DarwinManifest(ViewerManifest):
self.path("uk.lproj")
self.path("zh-Hans.lproj")
- # SLVoice and vivox lols
- self.path("vivox-runtime/universal-darwin/libsndfile.dylib", "libsndfile.dylib")
- self.path("vivox-runtime/universal-darwin/libvivoxoal.dylib", "libvivoxoal.dylib")
- self.path("vivox-runtime/universal-darwin/libortp.dylib", "libortp.dylib")
- self.path("vivox-runtime/universal-darwin/libvivoxsdk.dylib", "libvivoxsdk.dylib")
- self.path("vivox-runtime/universal-darwin/libvivoxplatform.dylib", "libvivoxplatform.dylib")
- self.path("vivox-runtime/universal-darwin/SLVoice", "SLVoice")
-
- libdir = "../../libraries/universal-darwin/lib_release"
+ libdir = "../packages/lib/release"
dylibs = {}
- # need to get the kdu dll from any of the build directories as well
- for lib in "llkdu", "llcommon":
- libfile = "lib%s.dylib" % lib
- try:
- self.path(self.find_existing_file(os.path.join(os.pardir,
- lib,
- self.args['configuration'],
- libfile),
- os.path.join(libdir, libfile)),
- dst=libfile)
- except RuntimeError:
- print "Skipping %s" % libfile
- dylibs[lib] = False
- else:
- dylibs[lib] = True
+ # Need to get the llcommon dll from any of the build directories as well
+ lib = "llcommon"
+ libfile = "lib%s.dylib" % lib
+ try:
+ self.path(self.find_existing_file(os.path.join(os.pardir,
+ lib,
+ self.args['configuration'],
+ libfile),
+ os.path.join(libdir, libfile)),
+ dst=libfile)
+ except RuntimeError:
+ print "Skipping %s" % libfile
+ dylibs[lib] = False
+ else:
+ dylibs[lib] = True
if dylibs["llcommon"]:
- for libfile in ("libapr-1.0.3.7.dylib",
- "libaprutil-1.0.3.8.dylib",
- "libexpat.0.5.0.dylib",
+ for libfile in ("libapr-1.0.dylib",
+ "libaprutil-1.0.dylib",
+ "libexpat.1.5.2.dylib",
"libexception_handler.dylib",
+ "libGLOD.dylib",
+ "libcollada14dom.dylib"
):
self.path(os.path.join(libdir, libfile), libfile)
+ # SLVoice and vivox lols
+ for libfile in ('libsndfile.dylib', 'libvivoxoal.dylib', 'libortp.dylib', \
+ 'libvivoxsdk.dylib', 'libvivoxplatform.dylib', 'SLVoice') :
+ self.path(os.path.join(libdir, libfile), libfile)
+
try:
# FMOD for sound
self.path(self.args['configuration'] + "/libfmodwrapper.dylib", "libfmodwrapper.dylib")
@@ -664,10 +688,12 @@ class DarwinManifest(ViewerManifest):
mac_updater_res_path = self.dst_path_of("mac-updater.app/Contents/Resources")
slplugin_res_path = self.dst_path_of("SLPlugin.app/Contents/Resources")
for libfile in ("libllcommon.dylib",
- "libapr-1.0.3.7.dylib",
- "libaprutil-1.0.3.8.dylib",
- "libexpat.0.5.0.dylib",
+ "libapr-1.0.dylib",
+ "libaprutil-1.0.dylib",
+ "libexpat.1.5.2.dylib",
"libexception_handler.dylib",
+ "libGLOD.dylib",
+ "libcollada14dom.dylib"
):
target_lib = os.path.join('../../..', libfile)
self.run_command("ln -sf %(target)r %(link)r" %
@@ -687,7 +713,7 @@ class DarwinManifest(ViewerManifest):
if self.prefix(src="", dst="llplugin"):
self.path("../media_plugins/quicktime/" + self.args['configuration'] + "/media_plugin_quicktime.dylib", "media_plugin_quicktime.dylib")
self.path("../media_plugins/webkit/" + self.args['configuration'] + "/media_plugin_webkit.dylib", "media_plugin_webkit.dylib")
- self.path("../../libraries/universal-darwin/lib_release/libllqtwebkit.dylib", "libllqtwebkit.dylib")
+ self.path("../packages/lib/release/libllqtwebkit.dylib", "libllqtwebkit.dylib")
self.end_prefix("llplugin")
@@ -708,6 +734,12 @@ class DarwinManifest(ViewerManifest):
{ 'viewer_binary' : self.dst_path_of('Contents/MacOS/Second Life')})
+ def copy_finish(self):
+ # Force executable permissions to be set for scripts
+ # see CHOP-223 and http://mercurial.selenic.com/bts/issue1802
+ for script in 'Contents/MacOS/update_install',:
+ self.run_command("chmod +x %r" % os.path.join(self.get_dst_prefix(), script))
+
def package_finish(self):
channel_standin = 'Second Life Viewer 2' # hah, our default channel is not usable on its own
if not self.default_channel():
@@ -743,6 +775,11 @@ class DarwinManifest(ViewerManifest):
devfile = re.search("/dev/disk([0-9]+)[^s]", hdi_output).group(0).strip()
volpath = re.search('HFS\s+(.+)', hdi_output).group(1).strip()
+ if devfile != '/dev/disk1':
+ # adding more debugging info based upon nat's hunches to the
+ # logs to help track down 'SetFile -a V' failures -brad
+ print "WARNING: 'SetFile -a V' command below is probably gonna fail"
+
# Copy everything in to the mounted .dmg
if self.default_channel() and not self.default_grid():
@@ -793,7 +830,7 @@ class DarwinManifest(ViewerManifest):
self.run_command('SetFile -a V %r' % pathname)
# Create the alias file (which is a resource file) from the .r
- self.run_command('rez %r -o %r' %
+ self.run_command('Rez %r -o %r' %
(self.src_path_of("installers/darwin/release-dmg/Applications-alias.r"),
os.path.join(volpath, "Applications")))
@@ -842,6 +879,8 @@ class LinuxManifest(ViewerManifest):
# recurse
self.end_prefix("res-sdl")
+ self.path("../viewer_components/updater/scripts/linux/update_install", "bin/update_install")
+
# plugins
if self.prefix(src="", dst="bin/llplugin"):
self.path("../media_plugins/webkit/libmedia_plugin_webkit.so", "libmedia_plugin_webkit.so")
@@ -855,6 +894,12 @@ class LinuxManifest(ViewerManifest):
self.path("featuretable_linux.txt")
+ def copy_finish(self):
+ # Force executable permissions to be set for scripts
+ # see CHOP-223 and http://mercurial.selenic.com/bts/issue1802
+ for script in 'secondlife', 'bin/update_install':
+ self.run_command("chmod +x %r" % os.path.join(self.get_dst_prefix(), script))
+
def package_finish(self):
if 'installer_name' in self.args:
installer_name = self.args['installer_name']
@@ -870,7 +915,7 @@ class LinuxManifest(ViewerManifest):
if self.args['buildtype'].lower() == 'release' and self.is_packaging_viewer():
print "* Going strip-crazy on the packaged binaries, since this is a RELEASE build"
- self.run_command("find %(d)r/bin %(d)r/lib -type f | xargs --no-run-if-empty strip -S" % {'d': self.get_dst_prefix()} ) # makes some small assumptions about our packaged dir structure
+ self.run_command("find %(d)r/bin %(d)r/lib -type f \\! -name update_install | xargs --no-run-if-empty strip -S" % {'d': self.get_dst_prefix()} ) # makes some small assumptions about our packaged dir structure
# Fix access permissions
self.run_command("""
@@ -897,6 +942,9 @@ class LinuxManifest(ViewerManifest):
'dir': self.get_build_prefix(),
'inst_name': installer_name,
'inst_path':self.build_path_of(installer_name)})
+ else:
+ print "Skipping %s.tar.bz2 for non-Release build (%s)" % \
+ (installer_name, self.args['buildtype'])
finally:
self.run_command("mv %(inst)s %(dst)s" % {
'dst': self.get_dst_prefix(),
@@ -906,36 +954,42 @@ class Linux_i686Manifest(LinuxManifest):
def construct(self):
super(Linux_i686Manifest, self).construct()
- # install either the libllkdu we just built, or a prebuilt one, in
- # decreasing order of preference. for linux package, this goes to bin/
- try:
- self.path(self.find_existing_file('../llkdu/libllkdu.so',
- '../../libraries/i686-linux/lib_release_client/libllkdu.so'),
- dst='bin/libllkdu.so')
- except:
- print "Skipping libllkdu.so - not found"
-
- if self.prefix("../../libraries/i686-linux/lib_release_client", dst="lib"):
+ if self.prefix("../packages/lib/release", dst="lib"):
+ self.path("libapr-1.so")
self.path("libapr-1.so.0")
+ self.path("libapr-1.so.0.4.2")
+ self.path("libaprutil-1.so")
self.path("libaprutil-1.so.0")
- self.path("libbreakpad_client.so.0.0.0", "libbreakpad_client.so.0")
- self.path("libdb-4.2.so")
- self.path("libcrypto.so.0.9.7")
- self.path("libexpat.so.1")
- self.path("libssl.so.0.9.7")
- self.path("libuuid.so.1")
- self.path("libSDL-1.2.so.0")
- self.path("libELFIO.so")
- self.path("libopenjpeg.so.1.3.0", "libopenjpeg.so.1.3")
+ self.path("libaprutil-1.so.0.3.10")
+ self.path("libbreakpad_client.so.0.0.0")
+ self.path("libbreakpad_client.so.0")
+ self.path("libbreakpad_client.so")
+ self.path("libcollada14dom.so")
+ self.path("libdb-5.1.so")
+ self.path("libdb-5.so")
+ self.path("libdb.so")
+ self.path("libcrypto.so.1.0.0")
+ self.path("libexpat.so.1.5.2")
+ self.path("libssl.so.1.0.0")
+ self.path("libglod.so")
+ self.path("libminizip.so")
+ self.path("libuuid.so")
+ self.path("libuuid.so.16")
+ self.path("libuuid.so.16.0.22")
+ self.path("libSDL-1.2.so.0.11.3")
+ self.path("libdirectfb-1.4.so.5.0.4")
+ self.path("libfusion-1.4.so.5.0.4")
+ self.path("libdirect-1.4.so.5.0.4")
+ self.path("libopenjpeg.so.1.4.0")
+ self.path("libopenjpeg.so.1")
+ self.path("libopenjpeg.so")
self.path("libalut.so")
self.path("libopenal.so", "libopenal.so.1")
self.path("libopenal.so", "libvivoxoal.so.1") # vivox's sdk expects this soname
- try:
- self.path("libkdu.so")
- pass
- except:
- print "Skipping libkdu.so - not found"
- pass
+ self.path("libfontconfig.so.1.4.4")
+ self.path("libtcmalloc.so", "libtcmalloc.so") #formerly called google perf tools
+ self.path("libtcmalloc.so.0", "libtcmalloc.so.0") #formerly called google perf tools
+ self.path("libtcmalloc.so.0.1.0", "libtcmalloc.so.0.1.0") #formerly called google perf tools
try:
self.path("libfmod-3.75.so")
pass
@@ -945,10 +999,10 @@ class Linux_i686Manifest(LinuxManifest):
self.end_prefix("lib")
# Vivox runtimes
- if self.prefix(src="vivox-runtime/i686-linux", dst="bin"):
+ if self.prefix(src="../packages/lib/release", dst="bin"):
self.path("SLVoice")
self.end_prefix()
- if self.prefix(src="vivox-runtime/i686-linux", dst="lib"):
+ if self.prefix(src="../packages/lib/release", dst="lib"):
self.path("libortp.so")
self.path("libsndfile.so.1")
#self.path("libvivoxoal.so.1") # no - we'll re-use the viewer's own OpenAL lib
@@ -956,6 +1010,11 @@ class Linux_i686Manifest(LinuxManifest):
self.path("libvivoxplatform.so")
self.end_prefix("lib")
+ if self.args['buildtype'].lower() == 'release' and self.is_packaging_viewer():
+ print "* Going strip-crazy on the packaged binaries, since this is a RELEASE build"
+ self.run_command("find %(d)r/bin %(d)r/lib -type f \\! -name update_install | xargs --no-run-if-empty strip -S" % {'d': self.get_dst_prefix()} ) # makes some small assumptions about our packaged dir structure
+
+
class Linux_x86_64Manifest(LinuxManifest):
def construct(self):
super(Linux_x86_64Manifest, self).construct()
diff --git a/indra/test/CMakeLists.txt b/indra/test/CMakeLists.txt
index 66c78a86c4..e9eb3c1884 100644
--- a/indra/test/CMakeLists.txt
+++ b/indra/test/CMakeLists.txt
@@ -27,6 +27,7 @@ include_directories(
${LLXML_INCLUDE_DIRS}
${LSCRIPT_INCLUDE_DIRS}
${GOOGLEMOCK_INCLUDE_DIRS}
+ ${TUT_INCLUDE_DIR}
)
set(test_SOURCE_FILES
diff --git a/indra/test/test_llmanifest.py b/indra/test/test_llmanifest.py
index 89c36f95dd..a97abbc6ee 100644
--- a/indra/test/test_llmanifest.py
+++ b/indra/test/test_llmanifest.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
"""
@file test_llmanifest.py
@author Ryan Williams
diff --git a/indra/test_apps/llplugintest/CMakeLists.txt b/indra/test_apps/llplugintest/CMakeLists.txt
index b4043b0fd9..1211bb7e5a 100644
--- a/indra/test_apps/llplugintest/CMakeLists.txt
+++ b/indra/test_apps/llplugintest/CMakeLists.txt
@@ -1,5 +1,4 @@
# -*- cmake -*-
-
project(llplugintest)
include(00-Common)
@@ -379,8 +378,8 @@ endif (DARWIN OR WINDOWS)
if (DARWIN)
add_custom_command(TARGET llmediaplugintest POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/../libraries/universal-darwin/lib_release/libllqtwebkit.dylib ${PLUGINS_DESTINATION_DIR}
- DEPENDS ${CMAKE_SOURCE_DIR}/../libraries/universal-darwin/lib_release/libllqtwebkit.dylib
+ COMMAND ${CMAKE_COMMAND} -E copy ${ARCH_PREBUILT_DIRS_RELEASE}/libllqtwebkit.dylib ${PLUGINS_DESTINATION_DIR}
+ DEPENDS ${ARCH_PREBUILT_DIRS_RELEASE}/libllqtwebkit.dylib
)
endif (DARWIN)
@@ -389,7 +388,7 @@ if(WINDOWS)
# Plugin test library deploy
#
# Debug config runtime files required for the plugin test mule
- set(plugintest_debug_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/debug")
+ set(plugintest_debug_src_dir "${ARCH_PREBUILT_DIRS_DEBUG}")
set(plugintest_debug_files
libeay32.dll
libglib-2.0-0.dll
@@ -412,7 +411,7 @@ if(WINDOWS)
set(plugin_test_targets ${plugin_test_targets} ${out_targets})
# Debug config runtime files required for the plugin test mule (Qt image format plugins)
- set(plugintest_debug_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/debug/imageformats")
+ set(plugintest_debug_src_dir "${ARCH_PREBUILT_DIRS_DEBUG}/imageformats")
set(plugintest_debug_files
qgifd4.dll
qicod4.dll
@@ -430,7 +429,7 @@ if(WINDOWS)
set(plugin_test_targets ${plugin_test_targets} ${out_targets})
# Debug config runtime files required for the plugin test mule (Qt codec plugins)
- set(plugintest_debug_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/debug/codecs")
+ set(plugintest_debug_src_dir "${ARCH_PREBUILT_DIRS_DEBUG}/codecs")
set(plugintest_debug_files
qcncodecsd4.dll
qjpcodecsd4.dll
@@ -446,7 +445,7 @@ if(WINDOWS)
set(plugin_test_targets ${plugin_test_targets} ${out_targets})
# Release & ReleaseDebInfo config runtime files required for the plugin test mule
- set(plugintest_release_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/release")
+ set(plugintest_release_src_dir "${ARCH_PREBUILT_DIRS_RELEASE}")
set(plugintest_release_files
libeay32.dll
libglib-2.0-0.dll
@@ -478,7 +477,7 @@ if(WINDOWS)
set(plugin_test_targets ${plugin_test_targets} ${out_targets})
# Release & ReleaseDebInfo config runtime files required for the plugin test mule (Qt image format plugins)
- set(plugintest_release_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/release/imageformats")
+ set(plugintest_release_src_dir "${ARCH_PREBUILT_DIRS_RELEASE}/imageformats")
set(plugintest_release_files
qgif4.dll
qico4.dll
@@ -504,7 +503,7 @@ if(WINDOWS)
set(plugin_test_targets ${plugin_test_targets} ${out_targets})
# Release & ReleaseDebInfo config runtime files required for the plugin test mule (Qt codec plugins)
- set(plugintest_release_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/release/codecs")
+ set(plugintest_release_src_dir "${ARCH_PREBUILT_DIRS_RELEASE}/codecs")
set(plugintest_release_files
qcncodecs4.dll
qjpcodecs4.dll
diff --git a/indra/test_apps/llplugintest/llmediaplugintest.cpp b/indra/test_apps/llplugintest/llmediaplugintest.cpp
index 873fa23db8..884b00f0cc 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
@@ -1620,7 +1620,7 @@ mediaPanel* LLMediaPluginTest::addMediaPanel( std::string url )
std::string user_data_path = std::string( cwd ) + "/";
#endif
media_source->setUserDataPath(user_data_path);
- media_source->init( launcher_name, plugin_name, false );
+ media_source->init( launcher_name, user_data_path, plugin_name, false );
media_source->setDisableTimeout(mDisableTimeout);
// make a new panel and save parameters
@@ -1860,7 +1860,7 @@ mediaPanel* LLMediaPluginTest::replaceMediaPanel( mediaPanel* panel, std::string
#endif
media_source->setUserDataPath(user_data_path);
- media_source->init( launcher_name, plugin_name, false );
+ media_source->init( launcher_name, user_data_path, plugin_name, false );
media_source->setDisableTimeout(mDisableTimeout);
// make a new panel and save parameters
@@ -2154,6 +2154,10 @@ void LLMediaPluginTest::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent e
}
break;
+ case MEDIA_EVENT_NAVIGATE_ERROR_PAGE:
+ std::cerr << "Media event: MEDIA_EVENT_NAVIGATE_ERROR_PAGE, uri is: " << self->getClickURL() << std::endl;
+ break;
+
case MEDIA_EVENT_CLICK_LINK_HREF:
{
std::cerr << "Media event: MEDIA_EVENT_CLICK_LINK_HREF, uri is " << self->getClickURL() << ", target is " << self->getClickTarget() << std::endl;
@@ -2220,6 +2224,27 @@ void LLMediaPluginTest::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent e
<< ", height = " << self->getGeometryHeight()
<< std::endl;
break;
+
+ case MEDIA_EVENT_AUTH_REQUEST:
+ {
+ //std::cerr << "Media event: MEDIA_EVENT_AUTH_REQUEST, url " << self->getAuthURL() ", realm " << self->getAuthRealm() << std::endl;
+
+ // TODO: display an auth dialog
+ self->sendAuthResponse(false, "", "");
+ }
+ break;
+
+ 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/indra/tools/vstool/VSTool.csproj b/indra/tools/vstool/VSTool.csproj
index 24f1031f81..7f431e85c7 100644
--- a/indra/tools/vstool/VSTool.csproj
+++ b/indra/tools/vstool/VSTool.csproj
@@ -1,4 +1,5 @@
-<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<PropertyGroup>
<ProjectType>Local</ProjectType>
<ProductVersion>8.0.50727</ProductVersion>
@@ -25,6 +26,8 @@
</FileUpgradeFlags>
<UpgradeBackupLocation>
</UpgradeBackupLocation>
+ <TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
+ <OldToolsVersion>2.0</OldToolsVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<OutputPath>.\</OutputPath>
diff --git a/indra/tools/vstool/VSTool.exe b/indra/tools/vstool/VSTool.exe
index 6d1497d5e5..8be428614e 100755
--- a/indra/tools/vstool/VSTool.exe
+++ b/indra/tools/vstool/VSTool.exe
Binary files differ
diff --git a/indra/tools/vstool/VSTool.sln b/indra/tools/vstool/VSTool.sln
index 8859671802..21e3d75971 100644
--- a/indra/tools/vstool/VSTool.sln
+++ b/indra/tools/vstool/VSTool.sln
@@ -1,5 +1,5 @@
-Microsoft Visual Studio Solution File, Format Version 9.00
-# Visual Studio 2005
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VSTool", "VSTool.csproj", "{96943E2D-1373-4617-A117-D0F997A94919}"
EndProject
Global
diff --git a/indra/tools/vstool/main.cs b/indra/tools/vstool/main.cs
index cc268d59d9..cc73261e30 100644
--- a/indra/tools/vstool/main.cs
+++ b/indra/tools/vstool/main.cs
@@ -550,6 +550,11 @@ namespace VSTool
case "10.00":
version = "VC90";
break;
+
+ case "11.00":
+ version = "VC100";
+ break;
+
default:
throw new ApplicationException("Unknown .sln version: " + format);
}
@@ -585,6 +590,11 @@ namespace VSTool
case "VC90":
progid = "VisualStudio.DTE.9.0";
break;
+
+ case "VC100":
+ progid = "VisualStudio.DTE.10.0";
+ break;
+
default:
throw new ApplicationException("Can't handle VS version: " + version);
}
diff --git a/indra/viewer_components/CMakeLists.txt b/indra/viewer_components/CMakeLists.txt
index 0993b64b14..74c9b4568d 100644
--- a/indra/viewer_components/CMakeLists.txt
+++ b/indra/viewer_components/CMakeLists.txt
@@ -1,4 +1,4 @@
# -*- cmake -*-
add_subdirectory(login)
-
+add_subdirectory(updater)
diff --git a/indra/viewer_components/login/CMakeLists.txt b/indra/viewer_components/login/CMakeLists.txt
index fe64926da6..7720619df3 100644
--- a/indra/viewer_components/login/CMakeLists.txt
+++ b/indra/viewer_components/login/CMakeLists.txt
@@ -9,13 +9,11 @@ endif(LL_TESTS)
include(LLCommon)
include(LLMath)
include(LLXML)
-include(Pth)
include_directories(
${LLCOMMON_INCLUDE_DIRS}
${LLMATH_INCLUDE_DIRS}
${LLXML_INCLUDE_DIRS}
- ${PTH_INCLUDE_DIRS}
)
set(login_SOURCE_FILES
@@ -42,7 +40,6 @@ target_link_libraries(lllogin
${LLCOMMON_LIBRARIES}
${LLMATH_LIBRARIES}
${LLXML_LIBRARIES}
- ${PTH_LIBRARIES}
)
if(LL_TESTS)
@@ -50,11 +47,5 @@ if(LL_TESTS)
lllogin.cpp
)
- set_source_files_properties(
- lllogin.cpp
- PROPERTIES
- LL_TEST_ADDITIONAL_LIBRARIES "${PTH_LIBRARIES}"
- )
-
LL_ADD_PROJECT_UNIT_TESTS(lllogin "${lllogin_TEST_SOURCE_FILES}")
endif(LL_TESTS)
diff --git a/indra/viewer_components/updater/CMakeLists.txt b/indra/viewer_components/updater/CMakeLists.txt
new file mode 100644
index 0000000000..0e288bb496
--- /dev/null
+++ b/indra/viewer_components/updater/CMakeLists.txt
@@ -0,0 +1,82 @@
+# -*- cmake -*-
+
+project(updater_service)
+
+include(00-Common)
+if(LL_TESTS)
+ include(LLAddBuildTest)
+endif(LL_TESTS)
+include(CMakeCopyIfDifferent)
+include(CURL)
+include(LLCommon)
+include(LLMessage)
+include(LLPlugin)
+include(LLVFS)
+
+include_directories(
+ ${LLCOMMON_INCLUDE_DIRS}
+ ${LLMESSAGE_INCLUDE_DIRS}
+ ${LLPLUGIN_INCLUDE_DIRS}
+ ${LLVFS_INCLUDE_DIRS}
+ ${CURL_INCLUDE_DIRS}
+ )
+
+set(updater_service_SOURCE_FILES
+ llupdaterservice.cpp
+ llupdatechecker.cpp
+ llupdatedownloader.cpp
+ llupdateinstaller.cpp
+ )
+
+set(updater_service_HEADER_FILES
+ llupdaterservice.h
+ llupdatechecker.h
+ llupdatedownloader.h
+ llupdateinstaller.h
+ )
+
+set_source_files_properties(${updater_service_HEADER_FILES}
+ PROPERTIES HEADER_FILE_ONLY TRUE)
+
+list(APPEND
+ updater_service_SOURCE_FILES
+ ${updater_service_HEADER_FILES}
+ )
+
+add_library(llupdaterservice
+ ${updater_service_SOURCE_FILES}
+ )
+
+target_link_libraries(llupdaterservice
+ ${LLCOMMON_LIBRARIES}
+ ${LLMESSAGE_LIBRARIES}
+ ${LLPLUGIN_LIBRARIES}
+ ${LLVFS_LIBRARIES}
+ )
+
+if(LL_TESTS)
+ SET(llupdater_service_TEST_SOURCE_FILES
+ llupdaterservice.cpp
+ )
+
+# *NOTE:Mani - I was trying to use the preprocessor seam to mock out
+# llifstream (and other) llcommon classes. I didn't work
+# because of the windows declspec(dllimport)attribute.
+#set_source_files_properties(
+# llupdaterservice.cpp
+# PROPERTIES
+# LL_TEST_ADDITIONAL_CFLAGS "-Dllifstream=llus_mock_llifstream"
+# )
+
+ LL_ADD_PROJECT_UNIT_TESTS(llupdaterservice "${llupdater_service_TEST_SOURCE_FILES}")
+endif(LL_TESTS)
+
+set(UPDATER_INCLUDE_DIRS
+ ${LIBS_OPEN_DIR}/viewer_components/updater
+ CACHE INTERNAL ""
+)
+
+set(UPDATER_LIBRARIES
+ llupdaterservice
+ CACHE INTERNAL ""
+)
diff --git a/indra/viewer_components/updater/llupdatechecker.cpp b/indra/viewer_components/updater/llupdatechecker.cpp
new file mode 100644
index 0000000000..c6aa9b0f11
--- /dev/null
+++ b/indra/viewer_components/updater/llupdatechecker.cpp
@@ -0,0 +1,194 @@
+/**
+ * @file llupdaterservice.cpp
+ *
+ * $LicenseInfo:firstyear=2010&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 <stdexcept>
+#include <boost/format.hpp>
+#include "llhttpclient.h"
+#include "llsd.h"
+#include "llupdatechecker.h"
+#include "lluri.h"
+
+
+#if LL_WINDOWS
+#pragma warning (disable : 4355) // 'this' used in initializer list: yes, intentionally
+#endif
+
+
+class LLUpdateChecker::CheckError:
+ public std::runtime_error
+{
+public:
+ CheckError(const char * message):
+ std::runtime_error(message)
+ {
+ ; // No op.
+ }
+};
+
+
+class LLUpdateChecker::Implementation:
+ public LLHTTPClient::Responder
+{
+public:
+ Implementation(Client & client);
+ ~Implementation();
+ void check(std::string const & protocolVersion, std::string const & hostUrl,
+ std::string const & servicePath, std::string channel, std::string version);
+
+ // Responder:
+ virtual void completed(U32 status,
+ const std::string & reason,
+ const LLSD& content);
+ virtual void error(U32 status, const std::string & reason);
+
+private:
+ static const char * sProtocolVersion;
+
+ Client & mClient;
+ LLHTTPClient mHttpClient;
+ bool mInProgress;
+ std::string mVersion;
+
+ std::string buildUrl(std::string const & protocolVersion, std::string const & hostUrl,
+ std::string const & servicePath, std::string channel, std::string version);
+
+ LOG_CLASS(LLUpdateChecker::Implementation);
+};
+
+
+
+// LLUpdateChecker
+//-----------------------------------------------------------------------------
+
+
+LLUpdateChecker::LLUpdateChecker(LLUpdateChecker::Client & client):
+ mImplementation(new LLUpdateChecker::Implementation(client))
+{
+ ; // No op.
+}
+
+
+void LLUpdateChecker::check(std::string const & protocolVersion, std::string const & hostUrl,
+ std::string const & servicePath, std::string channel, std::string version)
+{
+ mImplementation->check(protocolVersion, hostUrl, servicePath, channel, version);
+}
+
+
+
+// LLUpdateChecker::Implementation
+//-----------------------------------------------------------------------------
+
+
+const char * LLUpdateChecker::Implementation::sProtocolVersion = "v1.0";
+
+
+LLUpdateChecker::Implementation::Implementation(LLUpdateChecker::Client & client):
+ mClient(client),
+ mInProgress(false)
+{
+ ; // No op.
+}
+
+
+LLUpdateChecker::Implementation::~Implementation()
+{
+ ; // No op.
+}
+
+
+void LLUpdateChecker::Implementation::check(std::string const & protocolVersion, std::string const & hostUrl,
+ std::string const & servicePath, std::string channel, std::string version)
+{
+ llassert(!mInProgress);
+
+ if(protocolVersion != sProtocolVersion) throw CheckError("unsupported protocol");
+
+ mInProgress = true;
+ mVersion = version;
+ std::string checkUrl = buildUrl(protocolVersion, hostUrl, servicePath, channel, version);
+ LL_INFOS("UpdateCheck") << "checking for updates at " << checkUrl << llendl;
+
+ // The HTTP client will wrap a raw pointer in a boost::intrusive_ptr causing the
+ // passed object to be silently and automatically deleted. We pass a self-
+ // referential intrusive pointer to which we add a reference to keep the
+ // client from deleting the update checker implementation instance.
+ LLHTTPClient::ResponderPtr temporaryPtr(this);
+ boost::intrusive_ptr_add_ref(temporaryPtr.get());
+ mHttpClient.get(checkUrl, temporaryPtr);
+}
+
+void LLUpdateChecker::Implementation::completed(U32 status,
+ const std::string & reason,
+ const LLSD & content)
+{
+ mInProgress = false;
+
+ if(status != 200) {
+ LL_WARNS("UpdateCheck") << "html error " << status << " (" << reason << ")" << llendl;
+ mClient.error(reason);
+ } else if(!content.asBoolean()) {
+ LL_INFOS("UpdateCheck") << "up to date" << llendl;
+ mClient.upToDate();
+ } else if(content["required"].asBoolean()) {
+ LL_INFOS("UpdateCheck") << "version invalid" << llendl;
+ LLURI uri(content["url"].asString());
+ mClient.requiredUpdate(content["version"].asString(), uri, content["hash"].asString());
+ } else {
+ LL_INFOS("UpdateCheck") << "newer version " << content["version"].asString() << " available" << llendl;
+ LLURI uri(content["url"].asString());
+ mClient.optionalUpdate(content["version"].asString(), uri, content["hash"].asString());
+ }
+}
+
+
+void LLUpdateChecker::Implementation::error(U32 status, const std::string & reason)
+{
+ mInProgress = false;
+ LL_WARNS("UpdateCheck") << "update check failed; " << reason << llendl;
+ mClient.error(reason);
+}
+
+
+std::string LLUpdateChecker::Implementation::buildUrl(std::string const & protocolVersion, std::string const & hostUrl,
+ std::string const & servicePath, std::string channel, std::string version)
+{
+#ifdef LL_WINDOWS
+ static const char * platform = "win";
+#elif LL_DARWIN
+ static const char * platform = "mac";
+#else
+ static const char * platform = "lnx";
+#endif
+
+ LLSD path;
+ path.append(servicePath);
+ path.append(protocolVersion);
+ path.append(channel);
+ path.append(version);
+ path.append(platform);
+ return LLURI::buildHTTP(hostUrl, path).asString();
+}
diff --git a/indra/viewer_components/updater/llupdatechecker.h b/indra/viewer_components/updater/llupdatechecker.h
new file mode 100644
index 0000000000..cea1f13647
--- /dev/null
+++ b/indra/viewer_components/updater/llupdatechecker.h
@@ -0,0 +1,82 @@
+/**
+ * @file llupdatechecker.h
+ *
+ * $LicenseInfo:firstyear=2010&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_UPDATERCHECKER_H
+#define LL_UPDATERCHECKER_H
+
+
+#include <boost/shared_ptr.hpp>
+
+
+//
+// Implements asynchronous checking for updates.
+//
+class LLUpdateChecker {
+public:
+ class Client;
+ class Implementation;
+
+ // An exception that may be raised on check errors.
+ class CheckError;
+
+ LLUpdateChecker(Client & client);
+
+ // Check status of current app on the given host for the channel and version provided.
+ void check(std::string const & protocolVersion, std::string const & hostUrl,
+ std::string const & servicePath, std::string channel, std::string version);
+
+private:
+ boost::shared_ptr<Implementation> mImplementation;
+};
+
+
+class LLURI; // From lluri.h
+
+
+//
+// The client interface implemented by a requestor checking for an update.
+//
+class LLUpdateChecker::Client
+{
+public:
+ // An error occurred while checking for an update.
+ virtual void error(std::string const & message) = 0;
+
+ // A newer version is available, but the current version may still be used.
+ virtual void optionalUpdate(std::string const & newVersion,
+ LLURI const & uri,
+ std::string const & hash) = 0;
+
+ // A newer version is available, and the current version is no longer valid.
+ virtual void requiredUpdate(std::string const & newVersion,
+ LLURI const & uri,
+ std::string const & hash) = 0;
+
+ // The checked version is up to date; no newer version exists.
+ virtual void upToDate(void) = 0;
+};
+
+
+#endif
diff --git a/indra/viewer_components/updater/llupdatedownloader.cpp b/indra/viewer_components/updater/llupdatedownloader.cpp
new file mode 100644
index 0000000000..e88d1bf811
--- /dev/null
+++ b/indra/viewer_components/updater/llupdatedownloader.cpp
@@ -0,0 +1,517 @@
+/**
+ * @file llupdatedownloader.cpp
+ *
+ * $LicenseInfo:firstyear=2010&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 "llupdatedownloader.h"
+
+#include <stdexcept>
+#include <boost/format.hpp>
+#include <boost/lexical_cast.hpp>
+#include <curl/curl.h>
+#include "lldir.h"
+#include "llevents.h"
+#include "llfile.h"
+#include "llmd5.h"
+#include "llsd.h"
+#include "llsdserialize.h"
+#include "llthread.h"
+#include "llupdaterservice.h"
+
+
+class LLUpdateDownloader::Implementation:
+ public LLThread
+{
+public:
+ Implementation(LLUpdateDownloader::Client & client);
+ ~Implementation();
+ void cancel(void);
+ void download(LLURI const & uri,
+ std::string const & hash,
+ std::string const & updateVersion,
+ bool required);
+ bool isDownloading(void);
+ size_t onHeader(void * header, size_t size);
+ size_t onBody(void * header, size_t size);
+ int onProgress(double downloadSize, double bytesDownloaded);
+ void resume(void);
+ void setBandwidthLimit(U64 bytesPerSecond);
+
+private:
+ curl_off_t mBandwidthLimit;
+ bool mCancelled;
+ LLUpdateDownloader::Client & mClient;
+ CURL * mCurl;
+ LLSD mDownloadData;
+ llofstream mDownloadStream;
+ unsigned char mDownloadPercent;
+ std::string mDownloadRecordPath;
+ curl_slist * mHeaderList;
+
+ void initializeCurlGet(std::string const & url, bool processHeader);
+ void resumeDownloading(size_t startByte);
+ void run(void);
+ void startDownloading(LLURI const & uri, std::string const & hash);
+ void throwOnCurlError(CURLcode code);
+ bool validateDownload(void);
+
+ LOG_CLASS(LLUpdateDownloader::Implementation);
+};
+
+
+namespace {
+ class DownloadError:
+ public std::runtime_error
+ {
+ public:
+ DownloadError(const char * message):
+ std::runtime_error(message)
+ {
+ ; // No op.
+ }
+ };
+
+
+ const char * gSecondLifeUpdateRecord = "SecondLifeUpdateDownload.xml";
+};
+
+
+
+// LLUpdateDownloader
+//-----------------------------------------------------------------------------
+
+
+
+std::string LLUpdateDownloader::downloadMarkerPath(void)
+{
+ return gDirUtilp->getExpandedFilename(LL_PATH_LOGS, gSecondLifeUpdateRecord);
+}
+
+
+LLUpdateDownloader::LLUpdateDownloader(Client & client):
+ mImplementation(new LLUpdateDownloader::Implementation(client))
+{
+ ; // No op.
+}
+
+
+void LLUpdateDownloader::cancel(void)
+{
+ mImplementation->cancel();
+}
+
+
+void LLUpdateDownloader::download(LLURI const & uri,
+ std::string const & hash,
+ std::string const & updateVersion,
+ bool required)
+{
+ mImplementation->download(uri, hash, updateVersion, required);
+}
+
+
+bool LLUpdateDownloader::isDownloading(void)
+{
+ return mImplementation->isDownloading();
+}
+
+
+void LLUpdateDownloader::resume(void)
+{
+ mImplementation->resume();
+}
+
+
+void LLUpdateDownloader::setBandwidthLimit(U64 bytesPerSecond)
+{
+ mImplementation->setBandwidthLimit(bytesPerSecond);
+}
+
+
+
+// LLUpdateDownloader::Implementation
+//-----------------------------------------------------------------------------
+
+
+namespace {
+ size_t write_function(void * data, size_t blockSize, size_t blocks, void * downloader)
+ {
+ size_t bytes = blockSize * blocks;
+ return reinterpret_cast<LLUpdateDownloader::Implementation *>(downloader)->onBody(data, bytes);
+ }
+
+
+ size_t header_function(void * data, size_t blockSize, size_t blocks, void * downloader)
+ {
+ size_t bytes = blockSize * blocks;
+ return reinterpret_cast<LLUpdateDownloader::Implementation *>(downloader)->onHeader(data, bytes);
+ }
+
+
+ int progress_callback(void * downloader,
+ double dowloadTotal,
+ double downloadNow,
+ double uploadTotal,
+ double uploadNow)
+ {
+ return reinterpret_cast<LLUpdateDownloader::Implementation *>(downloader)->
+ onProgress(dowloadTotal, downloadNow);
+ }
+}
+
+
+LLUpdateDownloader::Implementation::Implementation(LLUpdateDownloader::Client & client):
+ LLThread("LLUpdateDownloader"),
+ mBandwidthLimit(0),
+ mCancelled(false),
+ mClient(client),
+ mCurl(0),
+ mDownloadPercent(0),
+ mHeaderList(0)
+{
+ CURLcode code = curl_global_init(CURL_GLOBAL_ALL); // Just in case.
+ llverify(code == CURLE_OK); // TODO: real error handling here.
+}
+
+
+LLUpdateDownloader::Implementation::~Implementation()
+{
+ if(isDownloading()) {
+ cancel();
+ shutdown();
+ } else {
+ ; // No op.
+ }
+ if(mCurl) curl_easy_cleanup(mCurl);
+}
+
+
+void LLUpdateDownloader::Implementation::cancel(void)
+{
+ mCancelled = true;
+}
+
+
+void LLUpdateDownloader::Implementation::download(LLURI const & uri,
+ std::string const & hash,
+ std::string const & updateVersion,
+ bool required)
+{
+ if(isDownloading()) mClient.downloadError("download in progress");
+
+ mDownloadRecordPath = downloadMarkerPath();
+ mDownloadData = LLSD();
+ mDownloadData["required"] = required;
+ mDownloadData["update_version"] = updateVersion;
+ try {
+ startDownloading(uri, hash);
+ } catch(DownloadError const & e) {
+ mClient.downloadError(e.what());
+ }
+}
+
+
+bool LLUpdateDownloader::Implementation::isDownloading(void)
+{
+ return !isStopped();
+}
+
+
+void LLUpdateDownloader::Implementation::resume(void)
+{
+ mCancelled = false;
+
+ if(isDownloading()) {
+ mClient.downloadError("download in progress");
+ }
+
+ mDownloadRecordPath = downloadMarkerPath();
+ llifstream dataStream(mDownloadRecordPath);
+ if(!dataStream) {
+ mClient.downloadError("no download marker");
+ return;
+ }
+
+ LLSDSerialize::fromXMLDocument(mDownloadData, dataStream);
+
+ if(!mDownloadData.asBoolean()) {
+ mClient.downloadError("no download information in marker");
+ return;
+ }
+
+ std::string filePath = mDownloadData["path"].asString();
+ try {
+ if(LLFile::isfile(filePath)) {
+ llstat fileStatus;
+ LLFile::stat(filePath, &fileStatus);
+ if(fileStatus.st_size != mDownloadData["size"].asInteger()) {
+ resumeDownloading(fileStatus.st_size);
+ } else if(!validateDownload()) {
+ LLFile::remove(filePath);
+ download(LLURI(mDownloadData["url"].asString()),
+ mDownloadData["hash"].asString(),
+ mDownloadData["update_version"].asString(),
+ mDownloadData["required"].asBoolean());
+ } else {
+ mClient.downloadComplete(mDownloadData);
+ }
+ } else {
+ download(LLURI(mDownloadData["url"].asString()),
+ mDownloadData["hash"].asString(),
+ mDownloadData["update_version"].asString(),
+ mDownloadData["required"].asBoolean());
+ }
+ } catch(DownloadError & e) {
+ mClient.downloadError(e.what());
+ }
+}
+
+
+void LLUpdateDownloader::Implementation::setBandwidthLimit(U64 bytesPerSecond)
+{
+ if((mBandwidthLimit != bytesPerSecond) && isDownloading() && !mDownloadData["required"].asBoolean()) {
+ llassert(mCurl != 0);
+ mBandwidthLimit = bytesPerSecond;
+ CURLcode code = curl_easy_setopt(mCurl, CURLOPT_MAX_RECV_SPEED_LARGE, &mBandwidthLimit);
+ if(code != CURLE_OK) LL_WARNS("UpdateDownload") <<
+ "unable to change dowload bandwidth" << LL_ENDL;
+ } else {
+ mBandwidthLimit = bytesPerSecond;
+ }
+}
+
+
+size_t LLUpdateDownloader::Implementation::onHeader(void * buffer, size_t size)
+{
+ char const * headerPtr = reinterpret_cast<const char *> (buffer);
+ std::string header(headerPtr, headerPtr + size);
+ size_t colonPosition = header.find(':');
+ if(colonPosition == std::string::npos) return size; // HTML response; ignore.
+
+ if(header.substr(0, colonPosition) == "Content-Length") {
+ try {
+ size_t firstDigitPos = header.find_first_of("0123456789", colonPosition);
+ size_t lastDigitPos = header.find_last_of("0123456789");
+ std::string contentLength = header.substr(firstDigitPos, lastDigitPos - firstDigitPos + 1);
+ size_t size = boost::lexical_cast<size_t>(contentLength);
+ LL_INFOS("UpdateDownload") << "download size is " << size << LL_ENDL;
+
+ mDownloadData["size"] = LLSD(LLSD::Integer(size));
+ llofstream odataStream(mDownloadRecordPath);
+ LLSDSerialize::toPrettyXML(mDownloadData, odataStream);
+ } catch (std::exception const & e) {
+ LL_WARNS("UpdateDownload") << "unable to read content length ("
+ << e.what() << ")" << LL_ENDL;
+ }
+ } else {
+ ; // No op.
+ }
+
+ return size;
+}
+
+
+size_t LLUpdateDownloader::Implementation::onBody(void * buffer, size_t size)
+{
+ if(mCancelled) return 0; // Forces a write error which will halt curl thread.
+ if((size == 0) || (buffer == 0)) return 0;
+
+ mDownloadStream.write(reinterpret_cast<const char *>(buffer), size);
+ if(mDownloadStream.bad()) {
+ return 0;
+ } else {
+ return size;
+ }
+}
+
+
+int LLUpdateDownloader::Implementation::onProgress(double downloadSize, double bytesDownloaded)
+{
+ int downloadPercent = static_cast<int>(100. * (bytesDownloaded / downloadSize));
+ if(downloadPercent > mDownloadPercent) {
+ mDownloadPercent = downloadPercent;
+
+ LLSD event;
+ event["pump"] = LLUpdaterService::pumpName();
+ LLSD payload;
+ payload["type"] = LLSD(LLUpdaterService::PROGRESS);
+ payload["download_size"] = downloadSize;
+ payload["bytes_downloaded"] = bytesDownloaded;
+ event["payload"] = payload;
+ LLEventPumps::instance().obtain("mainlooprepeater").post(event);
+
+ LL_INFOS("UpdateDownload") << "progress event " << payload << LL_ENDL;
+ } else {
+ ; // Keep events to a reasonalbe number.
+ }
+
+ return 0;
+}
+
+
+void LLUpdateDownloader::Implementation::run(void)
+{
+ CURLcode code = curl_easy_perform(mCurl);
+ mDownloadStream.close();
+ if(code == CURLE_OK) {
+ LLFile::remove(mDownloadRecordPath);
+ if(validateDownload()) {
+ LL_INFOS("UpdateDownload") << "download successful" << LL_ENDL;
+ mClient.downloadComplete(mDownloadData);
+ } else {
+ LL_INFOS("UpdateDownload") << "download failed hash check" << LL_ENDL;
+ std::string filePath = mDownloadData["path"].asString();
+ if(filePath.size() != 0) LLFile::remove(filePath);
+ mClient.downloadError("failed hash check");
+ }
+ } else if(mCancelled && (code == CURLE_WRITE_ERROR)) {
+ LL_INFOS("UpdateDownload") << "download canceled by user" << LL_ENDL;
+ // Do not call back client.
+ } else {
+ LL_WARNS("UpdateDownload") << "download failed with error '" <<
+ curl_easy_strerror(code) << "'" << LL_ENDL;
+ LLFile::remove(mDownloadRecordPath);
+ if(mDownloadData.has("path")) LLFile::remove(mDownloadData["path"].asString());
+ mClient.downloadError("curl error");
+ }
+
+ if(mHeaderList) {
+ curl_slist_free_all(mHeaderList);
+ mHeaderList = 0;
+ }
+}
+
+
+void LLUpdateDownloader::Implementation::initializeCurlGet(std::string const & url, bool processHeader)
+{
+ if(mCurl == 0) {
+ mCurl = curl_easy_init();
+ } else {
+ curl_easy_reset(mCurl);
+ }
+
+ if(mCurl == 0) throw DownloadError("failed to initialize curl");
+
+ throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_NOSIGNAL, true));
+ throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_FOLLOWLOCATION, true));
+ throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_WRITEFUNCTION, &write_function));
+ throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_WRITEDATA, this));
+ if(processHeader) {
+ throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_HEADERFUNCTION, &header_function));
+ throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_HEADERDATA, this));
+ }
+ throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_HTTPGET, true));
+ throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_URL, url.c_str()));
+ throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_PROGRESSFUNCTION, &progress_callback));
+ throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_PROGRESSDATA, this));
+ throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_NOPROGRESS, false));
+ // if it's a required update set the bandwidth limit to 0 (unlimited)
+ curl_off_t limit = mDownloadData["required"].asBoolean() ? 0 : mBandwidthLimit;
+ throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_MAX_RECV_SPEED_LARGE, limit));
+
+ mDownloadPercent = 0;
+}
+
+
+void LLUpdateDownloader::Implementation::resumeDownloading(size_t startByte)
+{
+ LL_INFOS("UpdateDownload") << "resuming download from " << mDownloadData["url"].asString()
+ << " at byte " << startByte << LL_ENDL;
+
+ initializeCurlGet(mDownloadData["url"].asString(), false);
+
+ // The header 'Range: bytes n-' will request the bytes remaining in the
+ // source begining with byte n and ending with the last byte.
+ boost::format rangeHeaderFormat("Range: bytes=%u-");
+ rangeHeaderFormat % startByte;
+ mHeaderList = curl_slist_append(mHeaderList, rangeHeaderFormat.str().c_str());
+ if(mHeaderList == 0) throw DownloadError("cannot add Range header");
+ throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_HTTPHEADER, mHeaderList));
+
+ mDownloadStream.open(mDownloadData["path"].asString(),
+ std::ios_base::out | std::ios_base::binary | std::ios_base::app);
+ start();
+}
+
+
+void LLUpdateDownloader::Implementation::startDownloading(LLURI const & uri, std::string const & hash)
+{
+ mDownloadData["url"] = uri.asString();
+ mDownloadData["hash"] = hash;
+ mDownloadData["current_version"] = ll_get_version();
+ LLSD path = uri.pathArray();
+ if(path.size() == 0) throw DownloadError("no file path");
+ std::string fileName = path[path.size() - 1].asString();
+ std::string filePath = gDirUtilp->getExpandedFilename(LL_PATH_TEMP, fileName);
+ mDownloadData["path"] = filePath;
+
+ LL_INFOS("UpdateDownload") << "downloading " << filePath
+ << " from " << uri.asString() << LL_ENDL;
+ LL_INFOS("UpdateDownload") << "hash of file is " << hash << LL_ENDL;
+
+ llofstream dataStream(mDownloadRecordPath);
+ LLSDSerialize::toPrettyXML(mDownloadData, dataStream);
+
+ mDownloadStream.open(filePath, std::ios_base::out | std::ios_base::binary);
+ initializeCurlGet(uri.asString(), true);
+ start();
+}
+
+
+void LLUpdateDownloader::Implementation::throwOnCurlError(CURLcode code)
+{
+ if(code != CURLE_OK) {
+ const char * errorString = curl_easy_strerror(code);
+ if(errorString != 0) {
+ throw DownloadError(curl_easy_strerror(code));
+ } else {
+ throw DownloadError("unknown curl error");
+ }
+ } else {
+ ; // No op.
+ }
+}
+
+
+bool LLUpdateDownloader::Implementation::validateDownload(void)
+{
+ std::string filePath = mDownloadData["path"].asString();
+ llifstream fileStream(filePath, std::ios_base::in | std::ios_base::binary);
+ if(!fileStream) return false;
+
+ std::string hash = mDownloadData["hash"].asString();
+ if(hash.size() != 0) {
+ LL_INFOS("UpdateDownload") << "checking hash..." << LL_ENDL;
+ char digest[33];
+ LLMD5(fileStream).hex_digest(digest);
+ if(hash != digest) {
+ LL_WARNS("UpdateDownload") << "download hash mismatch; expeted " << hash <<
+ " but download is " << digest << LL_ENDL;
+ }
+ return hash == digest;
+ } else {
+ return true; // No hash check provided.
+ }
+}
diff --git a/indra/viewer_components/updater/llupdatedownloader.h b/indra/viewer_components/updater/llupdatedownloader.h
new file mode 100644
index 0000000000..0d635640cf
--- /dev/null
+++ b/indra/viewer_components/updater/llupdatedownloader.h
@@ -0,0 +1,94 @@
+/**
+ * @file llupdatedownloader.h
+ *
+ * $LicenseInfo:firstyear=2010&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_UPDATE_DOWNLOADER_H
+#define LL_UPDATE_DOWNLOADER_H
+
+
+#include <string>
+#include <boost/shared_ptr.hpp>
+#include "lluri.h"
+
+
+//
+// An asynchronous download service for fetching updates.
+//
+class LLUpdateDownloader
+{
+public:
+ class Client;
+ class Implementation;
+
+ // Returns the path to the download marker file containing details of the
+ // latest download.
+ static std::string downloadMarkerPath(void);
+
+ LLUpdateDownloader(Client & client);
+
+ // Cancel any in progress download; a no op if none is in progress. The
+ // client will not receive a complete or error callback.
+ void cancel(void);
+
+ // Start a new download.
+ void download(LLURI const & uri,
+ std::string const & hash,
+ std::string const & updateVersion,
+ bool required=false);
+
+ // Returns true if a download is in progress.
+ bool isDownloading(void);
+
+ // Resume a partial download.
+ void resume(void);
+
+ // Set a limit on the dowload rate.
+ void setBandwidthLimit(U64 bytesPerSecond);
+
+private:
+ boost::shared_ptr<Implementation> mImplementation;
+};
+
+
+//
+// An interface to be implemented by clients initiating a update download.
+//
+class LLUpdateDownloader::Client {
+public:
+
+ // The download has completed successfully.
+ // data is a map containing the following items:
+ // url - source (remote) location
+ // hash - the md5 sum that should match the installer file.
+ // path - destination (local) location
+ // required - boolean indicating if this is a required update.
+ // size - the size of the installer in bytes
+ virtual void downloadComplete(LLSD const & data) = 0;
+
+ // The download failed.
+ virtual void downloadError(std::string const & message) = 0;
+};
+
+
+#endif
diff --git a/indra/viewer_components/updater/llupdateinstaller.cpp b/indra/viewer_components/updater/llupdateinstaller.cpp
new file mode 100644
index 0000000000..c7b70c2de8
--- /dev/null
+++ b/indra/viewer_components/updater/llupdateinstaller.cpp
@@ -0,0 +1,100 @@
+/**
+ * @file llupdateinstaller.cpp
+ *
+ * $LicenseInfo:firstyear=2010&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 <apr_file_io.h>
+#include "llapr.h"
+#include "llprocesslauncher.h"
+#include "llupdateinstaller.h"
+#include "lldir.h"
+
+
+#if defined(LL_WINDOWS)
+#pragma warning(disable: 4702) // disable 'unreachable code' so we can use lexical_cast (really!).
+#endif
+#include <boost/lexical_cast.hpp>
+
+
+namespace {
+ class RelocateError {};
+
+
+ std::string copy_to_temp(std::string const & path)
+ {
+ std::string scriptFile = gDirUtilp->getBaseFileName(path);
+ std::string newPath = gDirUtilp->getExpandedFilename(LL_PATH_TEMP, scriptFile);
+ apr_status_t status = apr_file_copy(path.c_str(), newPath.c_str(), APR_FILE_SOURCE_PERMS, gAPRPoolp);
+ if(status != APR_SUCCESS) throw RelocateError();
+
+ return newPath;
+ }
+}
+
+
+int ll_install_update(std::string const & script,
+ std::string const & updatePath,
+ bool required,
+ LLInstallScriptMode mode)
+{
+ std::string actualScriptPath;
+ switch(mode) {
+ case LL_COPY_INSTALL_SCRIPT_TO_TEMP:
+ try {
+ actualScriptPath = copy_to_temp(script);
+ }
+ catch (RelocateError &) {
+ return -1;
+ }
+ break;
+ case LL_RUN_INSTALL_SCRIPT_IN_PLACE:
+ actualScriptPath = script;
+ break;
+ default:
+ llassert(!"unpossible copy mode");
+ }
+
+ llinfos << "UpdateInstaller: installing " << updatePath << " using " <<
+ actualScriptPath << LL_ENDL;
+
+ LLProcessLauncher launcher;
+ launcher.setExecutable(actualScriptPath);
+ launcher.addArgument(updatePath);
+ launcher.addArgument(ll_install_failed_marker_path().c_str());
+ launcher.addArgument(boost::lexical_cast<std::string>(required));
+ int result = launcher.launch();
+ launcher.orphan();
+
+ return result;
+}
+
+
+std::string const & ll_install_failed_marker_path(void)
+{
+ static std::string path;
+ if(path.empty()) {
+ path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLifeInstallFailed.marker");
+ }
+ return path;
+}
diff --git a/indra/viewer_components/updater/llupdateinstaller.h b/indra/viewer_components/updater/llupdateinstaller.h
new file mode 100644
index 0000000000..fe5b1d19b5
--- /dev/null
+++ b/indra/viewer_components/updater/llupdateinstaller.h
@@ -0,0 +1,58 @@
+/**
+ * @file llupdateinstaller.h
+ *
+ * $LicenseInfo:firstyear=2010&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_UPDATE_INSTALLER_H
+#define LL_UPDATE_INSTALLER_H
+
+
+#include <string>
+
+
+enum LLInstallScriptMode {
+ LL_RUN_INSTALL_SCRIPT_IN_PLACE,
+ LL_COPY_INSTALL_SCRIPT_TO_TEMP
+};
+
+//
+// Launch the installation script.
+//
+// The updater will overwrite the current installation, so it is highly recommended
+// that the current application terminate once this function is called.
+//
+int ll_install_update(
+ std::string const & script, // Script to execute.
+ std::string const & updatePath, // Path to update file.
+ bool required, // Is the update required.
+ LLInstallScriptMode mode=LL_COPY_INSTALL_SCRIPT_TO_TEMP); // Run in place or copy to temp?
+
+
+//
+// Returns the path which points to the failed install marker file, should it
+// exist.
+//
+std::string const & ll_install_failed_marker_path(void);
+
+
+#endif
diff --git a/indra/viewer_components/updater/llupdaterservice.cpp b/indra/viewer_components/updater/llupdaterservice.cpp
new file mode 100644
index 0000000000..1888f191e2
--- /dev/null
+++ b/indra/viewer_components/updater/llupdaterservice.cpp
@@ -0,0 +1,621 @@
+/**
+ * @file llupdaterservice.cpp
+ *
+ * $LicenseInfo:firstyear=2010&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 "llupdaterservice.h"
+
+#include "llupdatedownloader.h"
+#include "llevents.h"
+#include "lltimer.h"
+#include "llupdatechecker.h"
+#include "llupdateinstaller.h"
+#include "llversionviewer.h"
+
+#include <boost/scoped_ptr.hpp>
+#include <boost/weak_ptr.hpp>
+#include "lldir.h"
+#include "llsdserialize.h"
+#include "llfile.h"
+
+#if LL_WINDOWS
+#pragma warning (disable : 4355) // 'this' used in initializer list: yes, intentionally
+#endif
+
+
+namespace
+{
+ boost::weak_ptr<LLUpdaterServiceImpl> gUpdater;
+
+ const std::string UPDATE_MARKER_FILENAME("SecondLifeUpdateReady.xml");
+ std::string update_marker_path()
+ {
+ return gDirUtilp->getExpandedFilename(LL_PATH_LOGS,
+ UPDATE_MARKER_FILENAME);
+ }
+
+ std::string install_script_path(void)
+ {
+#ifdef LL_WINDOWS
+ std::string scriptFile = "update_install.bat";
+#else
+ std::string scriptFile = "update_install";
+#endif
+ return gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, scriptFile);
+ }
+
+ LLInstallScriptMode install_script_mode(void)
+ {
+#ifdef LL_WINDOWS
+ return LL_COPY_INSTALL_SCRIPT_TO_TEMP;
+#else
+ return LL_RUN_INSTALL_SCRIPT_IN_PLACE;
+#endif
+ };
+
+}
+
+class LLUpdaterServiceImpl :
+ public LLUpdateChecker::Client,
+ public LLUpdateDownloader::Client
+{
+ static const std::string sListenerName;
+
+ std::string mProtocolVersion;
+ std::string mUrl;
+ std::string mPath;
+ std::string mChannel;
+ std::string mVersion;
+
+ unsigned int mCheckPeriod;
+ bool mIsChecking;
+ bool mIsDownloading;
+
+ LLUpdateChecker mUpdateChecker;
+ LLUpdateDownloader mUpdateDownloader;
+ LLTimer mTimer;
+
+ LLUpdaterService::app_exit_callback_t mAppExitCallback;
+
+ LLUpdaterService::eUpdaterState mState;
+
+ LOG_CLASS(LLUpdaterServiceImpl);
+
+public:
+ LLUpdaterServiceImpl();
+ virtual ~LLUpdaterServiceImpl();
+
+ void initialize(const std::string& protocol_version,
+ const std::string& url,
+ const std::string& path,
+ const std::string& channel,
+ const std::string& version);
+
+ void setCheckPeriod(unsigned int seconds);
+ void setBandwidthLimit(U64 bytesPerSecond);
+
+ void startChecking(bool install_if_ready);
+ void stopChecking();
+ bool isChecking();
+ LLUpdaterService::eUpdaterState getState();
+
+ void setAppExitCallback(LLUpdaterService::app_exit_callback_t aecb) { mAppExitCallback = aecb;}
+ std::string updatedVersion(void);
+
+ bool checkForInstall(bool launchInstaller); // Test if a local install is ready.
+ bool checkForResume(); // Test for resumeable d/l.
+
+ // LLUpdateChecker::Client:
+ virtual void error(std::string const & message);
+ virtual void optionalUpdate(std::string const & newVersion,
+ LLURI const & uri,
+ std::string const & hash);
+ virtual void requiredUpdate(std::string const & newVersion,
+ LLURI const & uri,
+ std::string const & hash);
+ virtual void upToDate(void);
+
+ // LLUpdateDownloader::Client
+ void downloadComplete(LLSD const & data);
+ void downloadError(std::string const & message);
+
+ bool onMainLoop(LLSD const & event);
+
+private:
+ std::string mNewVersion;
+
+ void restartTimer(unsigned int seconds);
+ void setState(LLUpdaterService::eUpdaterState state);
+ void stopTimer();
+};
+
+const std::string LLUpdaterServiceImpl::sListenerName = "LLUpdaterServiceImpl";
+
+LLUpdaterServiceImpl::LLUpdaterServiceImpl() :
+ mIsChecking(false),
+ mIsDownloading(false),
+ mCheckPeriod(0),
+ mUpdateChecker(*this),
+ mUpdateDownloader(*this),
+ mState(LLUpdaterService::INITIAL)
+{
+}
+
+LLUpdaterServiceImpl::~LLUpdaterServiceImpl()
+{
+ LL_INFOS("UpdaterService") << "shutting down updater service" << LL_ENDL;
+ LLEventPumps::instance().obtain("mainloop").stopListening(sListenerName);
+}
+
+void LLUpdaterServiceImpl::initialize(const std::string& protocol_version,
+ const std::string& url,
+ const std::string& path,
+ const std::string& channel,
+ const std::string& version)
+{
+ if(mIsChecking || mIsDownloading)
+ {
+ throw LLUpdaterService::UsageError("LLUpdaterService::initialize call "
+ "while updater is running.");
+ }
+
+ mProtocolVersion = protocol_version;
+ mUrl = url;
+ mPath = path;
+ mChannel = channel;
+ mVersion = version;
+}
+
+void LLUpdaterServiceImpl::setCheckPeriod(unsigned int seconds)
+{
+ mCheckPeriod = seconds;
+}
+
+void LLUpdaterServiceImpl::setBandwidthLimit(U64 bytesPerSecond)
+{
+ mUpdateDownloader.setBandwidthLimit(bytesPerSecond);
+}
+
+void LLUpdaterServiceImpl::startChecking(bool install_if_ready)
+{
+ if(mUrl.empty() || mChannel.empty() || mVersion.empty())
+ {
+ throw LLUpdaterService::UsageError("Set params before call to "
+ "LLUpdaterService::startCheck().");
+ }
+
+ mIsChecking = true;
+
+ // Check to see if an install is ready.
+ bool has_install = checkForInstall(install_if_ready);
+ if(!has_install)
+ {
+ checkForResume(); // will set mIsDownloading to true if resuming
+
+ if(!mIsDownloading)
+ {
+ setState(LLUpdaterService::CHECKING_FOR_UPDATE);
+
+ // Checking can only occur during the mainloop.
+ // reset the timer to 0 so that the next mainloop event
+ // triggers a check;
+ restartTimer(0);
+ }
+ else
+ {
+ setState(LLUpdaterService::DOWNLOADING);
+ }
+ }
+}
+
+void LLUpdaterServiceImpl::stopChecking()
+{
+ if(mIsChecking)
+ {
+ mIsChecking = false;
+ stopTimer();
+ }
+
+ if(mIsDownloading)
+ {
+ mUpdateDownloader.cancel();
+ mIsDownloading = false;
+ }
+
+ setState(LLUpdaterService::TERMINAL);
+}
+
+bool LLUpdaterServiceImpl::isChecking()
+{
+ return mIsChecking;
+}
+
+LLUpdaterService::eUpdaterState LLUpdaterServiceImpl::getState()
+{
+ return mState;
+}
+
+std::string LLUpdaterServiceImpl::updatedVersion(void)
+{
+ return mNewVersion;
+}
+
+bool LLUpdaterServiceImpl::checkForInstall(bool launchInstaller)
+{
+ bool foundInstall = false; // return true if install is found.
+
+ llifstream update_marker(update_marker_path(),
+ std::ios::in | std::ios::binary);
+
+ if(update_marker.is_open())
+ {
+ // Found an update info - now lets see if its valid.
+ LLSD update_info;
+ LLSDSerialize::fromXMLDocument(update_info, update_marker);
+ update_marker.close();
+
+ // Get the path to the installer file.
+ LLSD path = update_info.get("path");
+ if(update_info["current_version"].asString() != ll_get_version())
+ {
+ // This viewer is not the same version as the one that downloaded
+ // the update. Do not install this update.
+ if(!path.asString().empty())
+ {
+ llinfos << "ignoring update dowloaded by different client version" << llendl;
+ LLFile::remove(path.asString());
+ LLFile::remove(update_marker_path());
+ }
+ else
+ {
+ ; // Nothing to clean up.
+ }
+
+ foundInstall = false;
+ }
+ else if(path.isDefined() && !path.asString().empty())
+ {
+ if(launchInstaller)
+ {
+ setState(LLUpdaterService::INSTALLING);
+
+ LLFile::remove(update_marker_path());
+
+ int result = ll_install_update(install_script_path(),
+ update_info["path"].asString(),
+ update_info["required"].asBoolean(),
+ install_script_mode());
+
+ if((result == 0) && mAppExitCallback)
+ {
+ mAppExitCallback();
+ } else if(result != 0) {
+ llwarns << "failed to run update install script" << LL_ENDL;
+ } else {
+ ; // No op.
+ }
+ }
+
+ foundInstall = true;
+ }
+ }
+ return foundInstall;
+}
+
+bool LLUpdaterServiceImpl::checkForResume()
+{
+ bool result = false;
+ std::string download_marker_path = mUpdateDownloader.downloadMarkerPath();
+ if(LLFile::isfile(download_marker_path))
+ {
+ llifstream download_marker_stream(download_marker_path,
+ std::ios::in | std::ios::binary);
+ if(download_marker_stream.is_open())
+ {
+ LLSD download_info;
+ LLSDSerialize::fromXMLDocument(download_info, download_marker_stream);
+ download_marker_stream.close();
+ if(download_info["current_version"].asString() == ll_get_version())
+ {
+ mIsDownloading = true;
+ mNewVersion = download_info["update_version"].asString();
+ mUpdateDownloader.resume();
+ result = true;
+ }
+ else
+ {
+ // The viewer that started this download is not the same as this viewer; ignore.
+ llinfos << "ignoring partial download from different viewer version" << llendl;
+ std::string path = download_info["path"].asString();
+ if(!path.empty()) LLFile::remove(path);
+ LLFile::remove(download_marker_path);
+ }
+ }
+ }
+ return result;
+}
+
+void LLUpdaterServiceImpl::error(std::string const & message)
+{
+ if(mIsChecking)
+ {
+ setState(LLUpdaterService::TEMPORARY_ERROR);
+ restartTimer(mCheckPeriod);
+ }
+}
+
+void LLUpdaterServiceImpl::optionalUpdate(std::string const & newVersion,
+ LLURI const & uri,
+ std::string const & hash)
+{
+ stopTimer();
+ mNewVersion = newVersion;
+ mIsDownloading = true;
+ setState(LLUpdaterService::DOWNLOADING);
+ mUpdateDownloader.download(uri, hash, newVersion, false);
+}
+
+void LLUpdaterServiceImpl::requiredUpdate(std::string const & newVersion,
+ LLURI const & uri,
+ std::string const & hash)
+{
+ stopTimer();
+ mNewVersion = newVersion;
+ mIsDownloading = true;
+ setState(LLUpdaterService::DOWNLOADING);
+ mUpdateDownloader.download(uri, hash, newVersion, true);
+}
+
+void LLUpdaterServiceImpl::upToDate(void)
+{
+ if(mIsChecking)
+ {
+ restartTimer(mCheckPeriod);
+ }
+
+ setState(LLUpdaterService::UP_TO_DATE);
+}
+
+void LLUpdaterServiceImpl::downloadComplete(LLSD const & data)
+{
+ mIsDownloading = false;
+
+ // Save out the download data to the SecondLifeUpdateReady
+ // marker file.
+ llofstream update_marker(update_marker_path());
+ LLSDSerialize::toPrettyXML(data, update_marker);
+
+ LLSD event;
+ event["pump"] = LLUpdaterService::pumpName();
+ LLSD payload;
+ payload["type"] = LLSD(LLUpdaterService::DOWNLOAD_COMPLETE);
+ payload["required"] = data["required"];
+ payload["version"] = mNewVersion;
+ event["payload"] = payload;
+ LLEventPumps::instance().obtain("mainlooprepeater").post(event);
+
+ setState(LLUpdaterService::TERMINAL);
+}
+
+void LLUpdaterServiceImpl::downloadError(std::string const & message)
+{
+ LL_INFOS("UpdaterService") << "Error downloading: " << message << LL_ENDL;
+
+ mIsDownloading = false;
+
+ // Restart the timer on error
+ if(mIsChecking)
+ {
+ restartTimer(mCheckPeriod);
+ }
+
+ LLSD event;
+ event["pump"] = LLUpdaterService::pumpName();
+ LLSD payload;
+ payload["type"] = LLSD(LLUpdaterService::DOWNLOAD_ERROR);
+ payload["message"] = message;
+ event["payload"] = payload;
+ LLEventPumps::instance().obtain("mainlooprepeater").post(event);
+
+ setState(LLUpdaterService::FAILURE);
+}
+
+void LLUpdaterServiceImpl::restartTimer(unsigned int seconds)
+{
+ LL_INFOS("UpdaterService") << "will check for update again in " <<
+ seconds << " seconds" << LL_ENDL;
+ mTimer.start();
+ mTimer.setTimerExpirySec(seconds);
+ LLEventPumps::instance().obtain("mainloop").listen(
+ sListenerName, boost::bind(&LLUpdaterServiceImpl::onMainLoop, this, _1));
+}
+
+void LLUpdaterServiceImpl::setState(LLUpdaterService::eUpdaterState state)
+{
+ if(state != mState)
+ {
+ mState = state;
+
+ LLSD event;
+ event["pump"] = LLUpdaterService::pumpName();
+ LLSD payload;
+ payload["type"] = LLSD(LLUpdaterService::STATE_CHANGE);
+ payload["state"] = state;
+ event["payload"] = payload;
+ LLEventPumps::instance().obtain("mainlooprepeater").post(event);
+
+ LL_INFOS("UpdaterService") << "setting state to " << state << LL_ENDL;
+ }
+ else
+ {
+ ; // State unchanged; noop.
+ }
+}
+
+void LLUpdaterServiceImpl::stopTimer()
+{
+ mTimer.stop();
+ LLEventPumps::instance().obtain("mainloop").stopListening(sListenerName);
+}
+
+bool LLUpdaterServiceImpl::onMainLoop(LLSD const & event)
+{
+ if(mTimer.getStarted() && mTimer.hasExpired())
+ {
+ stopTimer();
+
+ // Check for failed install.
+ if(LLFile::isfile(ll_install_failed_marker_path()))
+ {
+ int requiredValue = 0;
+ {
+ llifstream stream(ll_install_failed_marker_path());
+ stream >> requiredValue;
+ if(stream.fail()) requiredValue = 0;
+ }
+ // TODO: notify the user.
+ llinfos << "found marker " << ll_install_failed_marker_path() << llendl;
+ llinfos << "last install attempt failed" << llendl;
+ LLFile::remove(ll_install_failed_marker_path());
+
+ LLSD event;
+ event["type"] = LLSD(LLUpdaterService::INSTALL_ERROR);
+ event["required"] = LLSD(requiredValue);
+ LLEventPumps::instance().obtain(LLUpdaterService::pumpName()).post(event);
+
+ setState(LLUpdaterService::TERMINAL);
+ }
+ else
+ {
+ mUpdateChecker.check(mProtocolVersion, mUrl, mPath, mChannel, mVersion);
+ setState(LLUpdaterService::CHECKING_FOR_UPDATE);
+ }
+ }
+ else
+ {
+ // Keep on waiting...
+ }
+
+ return false;
+}
+
+
+//-----------------------------------------------------------------------
+// Facade interface
+
+std::string const & LLUpdaterService::pumpName(void)
+{
+ static std::string name("updater_service");
+ return name;
+}
+
+bool LLUpdaterService::updateReadyToInstall(void)
+{
+ return LLFile::isfile(update_marker_path());
+}
+
+LLUpdaterService::LLUpdaterService()
+{
+ if(gUpdater.expired())
+ {
+ mImpl =
+ boost::shared_ptr<LLUpdaterServiceImpl>(new LLUpdaterServiceImpl());
+ gUpdater = mImpl;
+ }
+ else
+ {
+ mImpl = gUpdater.lock();
+ }
+}
+
+LLUpdaterService::~LLUpdaterService()
+{
+}
+
+void LLUpdaterService::initialize(const std::string& protocol_version,
+ const std::string& url,
+ const std::string& path,
+ const std::string& channel,
+ const std::string& version)
+{
+ mImpl->initialize(protocol_version, url, path, channel, version);
+}
+
+void LLUpdaterService::setCheckPeriod(unsigned int seconds)
+{
+ mImpl->setCheckPeriod(seconds);
+}
+
+void LLUpdaterService::setBandwidthLimit(U64 bytesPerSecond)
+{
+ mImpl->setBandwidthLimit(bytesPerSecond);
+}
+
+void LLUpdaterService::startChecking(bool install_if_ready)
+{
+ mImpl->startChecking(install_if_ready);
+}
+
+void LLUpdaterService::stopChecking()
+{
+ mImpl->stopChecking();
+}
+
+bool LLUpdaterService::isChecking()
+{
+ return mImpl->isChecking();
+}
+
+LLUpdaterService::eUpdaterState LLUpdaterService::getState()
+{
+ return mImpl->getState();
+}
+
+void LLUpdaterService::setImplAppExitCallback(LLUpdaterService::app_exit_callback_t aecb)
+{
+ return mImpl->setAppExitCallback(aecb);
+}
+
+std::string LLUpdaterService::updatedVersion(void)
+{
+ return mImpl->updatedVersion();
+}
+
+
+std::string const & ll_get_version(void) {
+ static std::string version("");
+
+ if (version.empty()) {
+ std::ostringstream stream;
+ stream << LL_VERSION_MAJOR << "."
+ << LL_VERSION_MINOR << "."
+ << LL_VERSION_PATCH << "."
+ << LL_VERSION_BUILD;
+ version = stream.str();
+ }
+
+ return version;
+}
+
diff --git a/indra/viewer_components/updater/llupdaterservice.h b/indra/viewer_components/updater/llupdaterservice.h
new file mode 100644
index 0000000000..450f19c1c6
--- /dev/null
+++ b/indra/viewer_components/updater/llupdaterservice.h
@@ -0,0 +1,108 @@
+/**
+ * @file llupdaterservice.h
+ *
+ * $LicenseInfo:firstyear=2010&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_UPDATERSERVICE_H
+#define LL_UPDATERSERVICE_H
+
+#include <boost/shared_ptr.hpp>
+#include <boost/function.hpp>
+
+class LLUpdaterServiceImpl;
+
+class LLUpdaterService
+{
+public:
+ class UsageError: public std::runtime_error
+ {
+ public:
+ UsageError(const std::string& msg) : std::runtime_error(msg) {}
+ };
+
+ // Name of the event pump through which update events will be delivered.
+ static std::string const & pumpName(void);
+
+ // Returns true if an update has been completely downloaded and is now ready to install.
+ static bool updateReadyToInstall(void);
+
+ // Type codes for events posted by this service. Stored the event's 'type' element.
+ enum eUpdaterEvent {
+ INVALID,
+ DOWNLOAD_COMPLETE,
+ DOWNLOAD_ERROR,
+ INSTALL_ERROR,
+ PROGRESS,
+ STATE_CHANGE
+ };
+
+ enum eUpdaterState {
+ INITIAL,
+ CHECKING_FOR_UPDATE,
+ TEMPORARY_ERROR,
+ DOWNLOADING,
+ INSTALLING,
+ UP_TO_DATE,
+ TERMINAL,
+ FAILURE
+ };
+
+ LLUpdaterService();
+ ~LLUpdaterService();
+
+ void initialize(const std::string& protocol_version,
+ const std::string& url,
+ const std::string& path,
+ const std::string& channel,
+ const std::string& version);
+
+ void setCheckPeriod(unsigned int seconds);
+ void setBandwidthLimit(U64 bytesPerSecond);
+
+ void startChecking(bool install_if_ready = false);
+ void stopChecking();
+ bool isChecking();
+ eUpdaterState getState();
+
+ typedef boost::function<void (void)> app_exit_callback_t;
+ template <typename F>
+ void setAppExitCallback(F const &callable)
+ {
+ app_exit_callback_t aecb = callable;
+ setImplAppExitCallback(aecb);
+ }
+
+ // If an update is or has been downloaded, this method will return the
+ // version string for that update. An empty string will be returned
+ // otherwise.
+ std::string updatedVersion(void);
+
+private:
+ boost::shared_ptr<LLUpdaterServiceImpl> mImpl;
+ void setImplAppExitCallback(app_exit_callback_t aecb);
+};
+
+// Returns the full version as a string.
+std::string const & ll_get_version(void);
+
+#endif // LL_UPDATERSERVICE_H
diff --git a/indra/viewer_components/updater/scripts/darwin/update_install b/indra/viewer_components/updater/scripts/darwin/update_install
new file mode 100644
index 0000000000..6a95f96d86
--- /dev/null
+++ b/indra/viewer_components/updater/scripts/darwin/update_install
@@ -0,0 +1,10 @@
+#! /bin/bash
+
+#
+# The first argument contains the path to the installer app. The second a path
+# to a marker file which should be created if the installer fails.q
+#
+
+cd "$(dirname "$0")"
+(../Resources/mac-updater.app/Contents/MacOS/mac-updater -dmg "$1" -name "Second Life Viewer 2"; if [ $? -ne 0 ]; then echo $3 >> "$2"; fi;) &
+exit 0
diff --git a/indra/viewer_components/updater/scripts/linux/update_install b/indra/viewer_components/updater/scripts/linux/update_install
new file mode 100644
index 0000000000..88451340ec
--- /dev/null
+++ b/indra/viewer_components/updater/scripts/linux/update_install
@@ -0,0 +1,10 @@
+#! /bin/bash
+INSTALL_DIR=$(cd "$(dirname "$0")/.." ; pwd)
+export LD_LIBRARY_PATH="$INSTALL_DIR/lib"
+bin/linux-updater.bin --file "$1" --dest "$INSTALL_DIR" --name "Second Life Viewer 2" --stringsdir "$INSTALL_DIR/skins/default/xui/en" --stringsfile "strings.xml"
+
+if [ $? -ne 0 ]
+ then echo $3 >> "$2"
+fi
+
+rm -f "$1"
diff --git a/indra/viewer_components/updater/scripts/windows/update_install.bat b/indra/viewer_components/updater/scripts/windows/update_install.bat
new file mode 100644
index 0000000000..96687226a8
--- /dev/null
+++ b/indra/viewer_components/updater/scripts/windows/update_install.bat
@@ -0,0 +1,3 @@
+start /WAIT %1 /SKIP_DIALOGS
+IF ERRORLEVEL 1 ECHO %3 > %2
+DEL %1
diff --git a/indra/viewer_components/updater/tests/llupdaterservice_test.cpp b/indra/viewer_components/updater/tests/llupdaterservice_test.cpp
new file mode 100644
index 0000000000..e19d5724f1
--- /dev/null
+++ b/indra/viewer_components/updater/tests/llupdaterservice_test.cpp
@@ -0,0 +1,194 @@
+/**
+ * @file llupdaterservice_test.cpp
+ * @brief Tests of llupdaterservice.cpp.
+ *
+ * $LicenseInfo:firstyear=2010&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$
+ */
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "../llupdaterservice.h"
+#include "../llupdatechecker.h"
+#include "../llupdatedownloader.h"
+#include "../llupdateinstaller.h"
+
+#include "../../../test/lltut.h"
+//#define DEBUG_ON
+#include "../../../test/debug.h"
+
+#include "llevents.h"
+#include "lldir.h"
+
+/*****************************************************************************
+* MOCK'd
+*****************************************************************************/
+LLUpdateChecker::LLUpdateChecker(LLUpdateChecker::Client & client)
+{}
+void LLUpdateChecker::check(std::string const & protocolVersion, std::string const & hostUrl,
+ std::string const & servicePath, std::string channel, std::string version)
+{}
+LLUpdateDownloader::LLUpdateDownloader(Client & ) {}
+void LLUpdateDownloader::download(LLURI const & , std::string const &, std::string const &, bool){}
+
+class LLDir_Mock : public LLDir
+{
+ void initAppDirs(const std::string &app_name,
+ const std::string& app_read_only_data_dir = "") {}
+ U32 countFilesInDir(const std::string &dirname, const std::string &mask)
+ {
+ return 0;
+ }
+
+ void getRandomFileInDir(const std::string &dirname,
+ const std::string &mask,
+ std::string &fname) {}
+ std::string getCurPath() { return ""; }
+ BOOL fileExists(const std::string &filename) const { return false; }
+ std::string getLLPluginLauncher() { return ""; }
+ std::string getLLPluginFilename(std::string base_name) { return ""; }
+
+} gDirUtil;
+LLDir* gDirUtilp = &gDirUtil;
+LLDir::LLDir() {}
+LLDir::~LLDir() {}
+S32 LLDir::deleteFilesInDir(const std::string &dirname,
+ const std::string &mask)
+{ return 0; }
+
+void LLDir::setChatLogsDir(const std::string &path){}
+void LLDir::setPerAccountChatLogsDir(const std::string &username){}
+void LLDir::setLindenUserDir(const std::string &username){}
+void LLDir::setSkinFolder(const std::string &skin_folder){}
+bool LLDir::setCacheDir(const std::string &path){ return true; }
+void LLDir::dumpCurrentDirectories() {}
+
+std::string LLDir::getExpandedFilename(ELLPath location,
+ const std::string &filename) const
+{
+ return "";
+}
+
+std::string LLUpdateDownloader::downloadMarkerPath(void)
+{
+ return "";
+}
+
+void LLUpdateDownloader::resume(void) {}
+void LLUpdateDownloader::cancel(void) {}
+void LLUpdateDownloader::setBandwidthLimit(U64 bytesPerSecond) {}
+
+int ll_install_update(std::string const &, std::string const &, bool, LLInstallScriptMode)
+{
+ return 0;
+}
+
+std::string const & ll_install_failed_marker_path()
+{
+ static std::string wubba;
+ return wubba;
+}
+
+/*
+#pragma warning(disable: 4273)
+llus_mock_llifstream::llus_mock_llifstream(const std::string& _Filename,
+ ios_base::openmode _Mode,
+ int _Prot) :
+ std::basic_istream<char,std::char_traits< char > >(NULL,true)
+{}
+
+llus_mock_llifstream::~llus_mock_llifstream() {}
+bool llus_mock_llifstream::is_open() const {return true;}
+void llus_mock_llifstream::close() {}
+*/
+
+/*****************************************************************************
+* TUT
+*****************************************************************************/
+namespace tut
+{
+ struct llupdaterservice_data
+ {
+ llupdaterservice_data() :
+ pumps(LLEventPumps::instance()),
+ test_url("dummy_url"),
+ test_channel("dummy_channel"),
+ test_version("dummy_version")
+ {}
+ LLEventPumps& pumps;
+ std::string test_url;
+ std::string test_channel;
+ std::string test_version;
+ };
+
+ typedef test_group<llupdaterservice_data> llupdaterservice_group;
+ typedef llupdaterservice_group::object llupdaterservice_object;
+ llupdaterservice_group llupdaterservicegrp("LLUpdaterService");
+
+ template<> template<>
+ void llupdaterservice_object::test<1>()
+ {
+ DEBUG;
+ LLUpdaterService updater;
+ bool got_usage_error = false;
+ try
+ {
+ updater.startChecking();
+ }
+ catch(LLUpdaterService::UsageError)
+ {
+ got_usage_error = true;
+ }
+ ensure("Caught start before params", got_usage_error);
+ }
+
+ template<> template<>
+ void llupdaterservice_object::test<2>()
+ {
+ DEBUG;
+ LLUpdaterService updater;
+ bool got_usage_error = false;
+ try
+ {
+ updater.initialize("1.0",test_url, "update" ,test_channel, test_version);
+ updater.startChecking();
+ updater.initialize("1.0", "other_url", "update", test_channel, test_version);
+ }
+ catch(LLUpdaterService::UsageError)
+ {
+ got_usage_error = true;
+ }
+ ensure("Caught params while running", got_usage_error);
+ }
+
+ template<> template<>
+ void llupdaterservice_object::test<3>()
+ {
+ DEBUG;
+ LLUpdaterService updater;
+ updater.initialize("1.0", test_url, "update", test_channel, test_version);
+ updater.startChecking();
+ ensure(updater.isChecking());
+ updater.stopChecking();
+ ensure(!updater.isChecking());
+ }
+}
diff --git a/indra/win_crash_logger/llcrashloggerwindows.cpp b/indra/win_crash_logger/llcrashloggerwindows.cpp
index 354b7e6cc3..51ff754c27 100644
--- a/indra/win_crash_logger/llcrashloggerwindows.cpp
+++ b/indra/win_crash_logger/llcrashloggerwindows.cpp
@@ -34,7 +34,6 @@
#include "boost/tokenizer.hpp"
-#include "dbghelp.h"
#include "indra_constants.h" // CRASH_BEHAVIOR_ASK, CRASH_SETTING_NAME
#include "llerror.h"
#include "llfile.h"