From b10770103552de583f0457528d298769c8fa3beb Mon Sep 17 00:00:00 2001
From: Rye Mutt <rye@alchemyviewer.org>
Date: Sat, 14 Dec 2019 01:27:55 -0500
Subject: [PATCH] =?UTF-8?q?=F0=9F=94=A5=20Line=20Ending=20Sadness?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .gitattributes                                |    9 +
 .../InstallRequiredSystemLibrariesAL.cmake    | 1466 +--
 indra/deps/CMakeLists.txt                     |  120 +-
 indra/llcommon/llsdserialize.cpp              | 4696 +++++-----
 indra/llmessage/llmessageprecompiled.cpp      |   54 +-
 indra/llmessage/llmessageprecompiled.h        |   86 +-
 indra/llui/lluiprecompiled.cpp                |   54 +-
 indra/llui/lluiprecompiled.h                  |  148 +-
 indra/llwindow/llwindowsdl2.cpp               |    2 +-
 .../installers/windows/installer_template.nsi | 1284 +--
 indra/newview/installers/windows/lang_da.nsi  |  112 +-
 indra/newview/installers/windows/lang_de.nsi  |  112 +-
 .../newview/installers/windows/lang_en-us.nsi |  112 +-
 indra/newview/installers/windows/lang_es.nsi  |  112 +-
 indra/newview/installers/windows/lang_fr.nsi  |  112 +-
 indra/newview/installers/windows/lang_it.nsi  |  112 +-
 indra/newview/installers/windows/lang_ja.nsi  |  112 +-
 indra/newview/installers/windows/lang_pl.nsi  |  112 +-
 .../newview/installers/windows/lang_pt-br.nsi |  112 +-
 indra/newview/installers/windows/lang_ru.nsi  |  112 +-
 indra/newview/installers/windows/lang_tr.nsi  |  112 +-
 indra/newview/installers/windows/lang_zh.nsi  |  112 +-
 indra/newview/lldrawpoolavatar.cpp            | 4678 ++++-----
 indra/newview/llmaterialmgr.h                 |    6 +-
 indra/newview/llspatialpartition.cpp          | 8326 ++++++++---------
 indra/newview/llviewerbuildconfig.h.in        |   98 +-
 .../default/xui/en/floater_group_profile.xml  |   54 +-
 .../default/xui/en/floater_legacy_profile.xml |   54 +-
 .../default/xui/en/panel_people_friends.xml   |  306 +-
 .../default/xui/en/panel_people_groups.xml    |  250 +-
 .../default/xui/en/panel_people_nearby.xml    |  304 +-
 .../default/xui/en/panel_people_recent.xml    |  220 +-
 32 files changed, 11784 insertions(+), 11775 deletions(-)

diff --git a/.gitattributes b/.gitattributes
index bfbd414682..3188bae730 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,5 +1,9 @@
 * text eol=lf
 
+# Viewer Files
+*.db2 binary
+*.llm binary
+
 *.sln text eol=crlf
 *.vcproj text eol=crlf
 *.vcxproj text eol=crlf
@@ -9,5 +13,10 @@
 *.tga binary
 *.jpg binary
 *.j2k binary
+*.j2c binary
+*.ico binary
+*.icns binary
+*.bmp binary
+*.BMP binary
 
 /indra/tools/manifests/compatibility.manifest text eol=crlf
\ No newline at end of file
diff --git a/indra/cmake/InstallRequiredSystemLibrariesAL.cmake b/indra/cmake/InstallRequiredSystemLibrariesAL.cmake
index 6dd525a21d..c13d04b2e5 100644
--- a/indra/cmake/InstallRequiredSystemLibrariesAL.cmake
+++ b/indra/cmake/InstallRequiredSystemLibrariesAL.cmake
@@ -1,733 +1,733 @@
-# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
-# file Copyright.txt or https://cmake.org/licensing for details.
-
-#[=======================================================================[.rst:
-InstallRequiredSystemLibraries
-------------------------------
-
-Include this module to search for compiler-provided system runtime
-libraries and add install rules for them.  Some optional variables
-may be set prior to including the module to adjust behavior:
-
-``CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS``
-  Specify additional runtime libraries that may not be detected.
-  After inclusion any detected libraries will be appended to this.
-
-``CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP``
-  Set to TRUE to skip calling the :command:`install(PROGRAMS)` command to
-  allow the includer to specify its own install rule, using the value of
-  ``CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS`` to get the list of libraries.
-
-``CMAKE_INSTALL_DEBUG_LIBRARIES``
-  Set to TRUE to install the debug runtime libraries when available
-  with MSVC tools.
-
-``CMAKE_INSTALL_DEBUG_LIBRARIES_ONLY``
-  Set to TRUE to install only the debug runtime libraries with MSVC
-  tools even if the release runtime libraries are also available.
-
-``CMAKE_INSTALL_UCRT_LIBRARIES``
-  Set to TRUE to install the Windows Universal CRT libraries for
-  app-local deployment (e.g. to Windows XP).  This is meaningful
-  only with MSVC from Visual Studio 2015 or higher.
-
-  One may set a ``CMAKE_WINDOWS_KITS_10_DIR`` *environment variable*
-  to an absolute path to tell CMake to look for Windows 10 SDKs in
-  a custom location.  The specified directory is expected to contain
-  ``Redist/ucrt/DLLs/*`` directories.
-
-``CMAKE_INSTALL_MFC_LIBRARIES``
-  Set to TRUE to install the MSVC MFC runtime libraries.
-
-``CMAKE_INSTALL_OPENMP_LIBRARIES``
-  Set to TRUE to install the MSVC OpenMP runtime libraries
-
-``CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION``
-  Specify the :command:`install(PROGRAMS)` command ``DESTINATION``
-  option.  If not specified, the default is ``bin`` on Windows
-  and ``lib`` elsewhere.
-
-``CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS``
-  Set to TRUE to disable warnings about required library files that
-  do not exist.  (For example, Visual Studio Express editions may
-  not provide the redistributable files.)
-
-``CMAKE_INSTALL_SYSTEM_RUNTIME_COMPONENT``
-  Specify the :command:`install(PROGRAMS)` command ``COMPONENT``
-  option.  If not specified, no such option will be used.
-#]=======================================================================]
-
-cmake_policy(PUSH)
-cmake_policy(SET CMP0054 NEW) # if() quoted variables not dereferenced
-
-set(_IRSL_HAVE_Intel FALSE)
-set(_IRSL_HAVE_MSVC FALSE)
-foreach(LANG IN ITEMS C CXX Fortran)
-  if("${CMAKE_${LANG}_COMPILER_ID}" STREQUAL "Intel")
-    if(NOT _IRSL_HAVE_Intel)
-      get_filename_component(_Intel_basedir "${CMAKE_${LANG}_COMPILER}" PATH)
-      if(CMAKE_SIZEOF_VOID_P EQUAL 8)
-        set(_Intel_archdir intel64)
-      else()
-        set(_Intel_archdir x86)
-      endif()
-      set(_Intel_compiler_ver ${CMAKE_${LANG}_COMPILER_VERSION})
-      if(WIN32)
-        get_filename_component(_Intel_redistdir "${_Intel_basedir}/../../redist/${_Intel_archdir}/compiler" ABSOLUTE)
-      elseif(APPLE)
-        get_filename_component(_Intel_redistdir "${_Intel_basedir}/../../compiler/lib" ABSOLUTE)
-      else()
-        if(EXISTS "${_Intel_basedir}/../lib/${_Intel_archdir}_lin")
-          get_filename_component(_Intel_redistdir "${_Intel_basedir}/../lib/${_Intel_archdir}" ABSOLUTE)
-        else()
-          get_filename_component(_Intel_redistdir "${_Intel_basedir}/../../compiler/lib/${_Intel_archdir}_lin" ABSOLUTE)
-        endif()
-      endif()
-      set(_IRSL_HAVE_Intel TRUE)
-    endif()
-  elseif("${CMAKE_${LANG}_COMPILER_ID}" STREQUAL "MSVC")
-    set(_IRSL_HAVE_MSVC TRUE)
-  endif()
-endforeach()
-
-if(MSVC)
-  file(TO_CMAKE_PATH "$ENV{SYSTEMROOT}" SYSTEMROOT)
-
-  if(CMAKE_CL_64)
-    if(MSVC_VERSION GREATER 1599)
-      # VS 10 and later:
-      set(CMAKE_MSVC_ARCH x64)
-    else()
-      # VS 9 and earlier:
-      set(CMAKE_MSVC_ARCH amd64)
-    endif()
-  else()
-    set(CMAKE_MSVC_ARCH x86)
-  endif()
-
-  get_filename_component(devenv_dir "${CMAKE_MAKE_PROGRAM}" PATH)
-  get_filename_component(base_dir "${devenv_dir}/../.." ABSOLUTE)
-
-  if(MSVC_VERSION EQUAL 1300)
-    set(__install__libs
-      "${SYSTEMROOT}/system32/msvcp70.dll"
-      "${SYSTEMROOT}/system32/msvcr70.dll"
-      )
-  endif()
-
-  if(MSVC_VERSION EQUAL 1310)
-    set(__install__libs
-      "${SYSTEMROOT}/system32/msvcp71.dll"
-      "${SYSTEMROOT}/system32/msvcr71.dll"
-      )
-  endif()
-
-  if(MSVC_TOOLSET_VERSION EQUAL 80)
-    # Find the runtime library redistribution directory.
-    get_filename_component(msvc_install_dir
-      "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0;InstallDir]" ABSOLUTE)
-    if(DEFINED MSVC80_REDIST_DIR AND EXISTS "${MSVC80_REDIST_DIR}")
-      set(MSVC_REDIST_DIR "${MSVC80_REDIST_DIR}") # use old cache entry
-    endif()
-    find_path(MSVC_REDIST_DIR NAMES ${CMAKE_MSVC_ARCH}/Microsoft.VC80.CRT/Microsoft.VC80.CRT.manifest
-      PATHS
-        "${msvc_install_dir}/../../VC/redist"
-        "${base_dir}/VC/redist"
-      )
-    mark_as_advanced(MSVC_REDIST_DIR)
-    set(MSVC_CRT_DIR "${MSVC_REDIST_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.VC80.CRT")
-
-    # Install the manifest that allows DLLs to be loaded from the
-    # directory containing the executable.
-    if(NOT CMAKE_INSTALL_DEBUG_LIBRARIES_ONLY)
-      set(__install__libs
-        "${MSVC_CRT_DIR}/Microsoft.VC80.CRT.manifest"
-        "${MSVC_CRT_DIR}/msvcm80.dll"
-        "${MSVC_CRT_DIR}/msvcp80.dll"
-        "${MSVC_CRT_DIR}/msvcr80.dll"
-        )
-    else()
-      set(__install__libs)
-    endif()
-
-    if(CMAKE_INSTALL_DEBUG_LIBRARIES)
-      set(MSVC_CRT_DIR
-        "${MSVC_REDIST_DIR}/Debug_NonRedist/${CMAKE_MSVC_ARCH}/Microsoft.VC80.DebugCRT")
-      set(__install__libs ${__install__libs}
-        "${MSVC_CRT_DIR}/Microsoft.VC80.DebugCRT.manifest"
-        "${MSVC_CRT_DIR}/msvcm80d.dll"
-        "${MSVC_CRT_DIR}/msvcp80d.dll"
-        "${MSVC_CRT_DIR}/msvcr80d.dll"
-        )
-    endif()
-  endif()
-
-  if(MSVC_TOOLSET_VERSION EQUAL 90)
-    # Find the runtime library redistribution directory.
-    get_filename_component(msvc_install_dir
-      "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\9.0;InstallDir]" ABSOLUTE)
-    get_filename_component(msvc_express_install_dir
-      "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\9.0;InstallDir]" ABSOLUTE)
-    if(DEFINED MSVC90_REDIST_DIR AND EXISTS "${MSVC90_REDIST_DIR}")
-      set(MSVC_REDIST_DIR "${MSVC90_REDIST_DIR}") # use old cache entry
-    endif()
-    find_path(MSVC_REDIST_DIR NAMES ${CMAKE_MSVC_ARCH}/Microsoft.VC90.CRT/Microsoft.VC90.CRT.manifest
-      PATHS
-        "${msvc_install_dir}/../../VC/redist"
-        "${msvc_express_install_dir}/../../VC/redist"
-        "${base_dir}/VC/redist"
-      )
-    mark_as_advanced(MSVC_REDIST_DIR)
-    set(MSVC_CRT_DIR "${MSVC_REDIST_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.VC90.CRT")
-
-    # Install the manifest that allows DLLs to be loaded from the
-    # directory containing the executable.
-    if(NOT CMAKE_INSTALL_DEBUG_LIBRARIES_ONLY)
-      set(__install__libs
-        "${MSVC_CRT_DIR}/Microsoft.VC90.CRT.manifest"
-        "${MSVC_CRT_DIR}/msvcm90.dll"
-        "${MSVC_CRT_DIR}/msvcp90.dll"
-        "${MSVC_CRT_DIR}/msvcr90.dll"
-        )
-    else()
-      set(__install__libs)
-    endif()
-
-    if(CMAKE_INSTALL_DEBUG_LIBRARIES)
-      set(MSVC_CRT_DIR
-        "${MSVC_REDIST_DIR}/Debug_NonRedist/${CMAKE_MSVC_ARCH}/Microsoft.VC90.DebugCRT")
-      set(__install__libs ${__install__libs}
-        "${MSVC_CRT_DIR}/Microsoft.VC90.DebugCRT.manifest"
-        "${MSVC_CRT_DIR}/msvcm90d.dll"
-        "${MSVC_CRT_DIR}/msvcp90d.dll"
-        "${MSVC_CRT_DIR}/msvcr90d.dll"
-        )
-    endif()
-  endif()
-
-  set(MSVC_REDIST_NAME "")
-  set(_MSVC_DLL_VERSION "")
-  set(_MSVC_IDE_VERSION "")
-  if(MSVC_VERSION GREATER_EQUAL 2000)
-    message(WARNING "MSVC ${MSVC_VERSION} not yet supported.")
-  elseif(MSVC_VERSION_VERSION GREATER_EQUAL 143)
-    message(WARNING "MSVC toolset v${MSVC_VERSION_VERSION} not yet supported.")
-  elseif(MSVC_TOOLSET_VERSION EQUAL 142)
-    set(MSVC_REDIST_NAME VC142)
-    set(_MSVC_DLL_VERSION 140)
-    set(_MSVC_IDE_VERSION 16)
-  elseif(MSVC_TOOLSET_VERSION EQUAL 141)
-    set(MSVC_REDIST_NAME VC142)
-    set(_MSVC_DLL_VERSION 140)
-    set(_MSVC_IDE_VERSION 16)
-  elseif(MSVC_TOOLSET_VERSION)
-    set(MSVC_REDIST_NAME VC${MSVC_TOOLSET_VERSION})
-    math(EXPR _MSVC_DLL_VERSION "${MSVC_TOOLSET_VERSION} / 10 * 10")
-    math(EXPR _MSVC_IDE_VERSION "${MSVC_TOOLSET_VERSION} / 10")
-  endif()
-
-  set(_MSVCRT_DLL_VERSION "")
-  set(_MSVCRT_IDE_VERSION "")
-  if(_MSVC_IDE_VERSION GREATER_EQUAL 10)
-    set(_MSVCRT_DLL_VERSION "${_MSVC_DLL_VERSION}")
-    set(_MSVCRT_IDE_VERSION "${_MSVC_IDE_VERSION}")
-  endif()
-
-  if(_MSVCRT_DLL_VERSION)
-    set(v "${_MSVCRT_DLL_VERSION}")
-    set(vs "${_MSVCRT_IDE_VERSION}")
-
-    # Find the runtime library redistribution directory.
-    if(vs VERSION_LESS 15 AND DEFINED MSVC${vs}_REDIST_DIR AND EXISTS "${MSVC${vs}_REDIST_DIR}")
-      set(MSVC_REDIST_DIR "${MSVC${vs}_REDIST_DIR}") # use old cache entry
-    endif()
-    if(NOT vs VERSION_LESS 15)
-      set(_vs_redist_paths "")
-      cmake_host_system_information(RESULT _vs_dir QUERY VS_${vs}_DIR) # undocumented query
-      if(IS_DIRECTORY "${_vs_dir}")
-        file(GLOB _vs_redist_paths "${_vs_dir}/VC/Redist/MSVC/*")
-      endif()
-      unset(_vs_dir)
-    else()
-      get_filename_component(_vs_dir
-        "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\${vs}.0;InstallDir]" ABSOLUTE)
-      set(programfilesx86 "ProgramFiles(x86)")
-      set(_vs_redist_paths
-        "${_vs_dir}/../../VC/redist"
-        "${base_dir}/VC/redist"
-        "$ENV{ProgramFiles}/Microsoft Visual Studio ${vs}.0/VC/redist"
-        "$ENV{${programfilesx86}}/Microsoft Visual Studio ${vs}.0/VC/redist"
-        )
-      unset(_vs_dir)
-      unset(programfilesx86)
-    endif()
-    find_path(MSVC_REDIST_DIR NAMES ${CMAKE_MSVC_ARCH}/Microsoft.${MSVC_REDIST_NAME}.CRT PATHS ${_vs_redist_paths})
-    unset(_vs_redist_paths)
-    mark_as_advanced(MSVC_REDIST_DIR)
-    set(MSVC_CRT_DIR "${MSVC_REDIST_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.${MSVC_REDIST_NAME}.CRT")
-
-    if(NOT CMAKE_INSTALL_DEBUG_LIBRARIES_ONLY)
-      set(__install__libs
-        "${MSVC_CRT_DIR}/msvcp${v}.dll"
-        )
-      if(NOT vs VERSION_LESS 14)
-        file(GLOB __msvcr_dlls "${MSVC_CRT_DIR}/*.dll")
-        list(APPEND __install__libs ${__msvcr_dlls})
-      else()
-        list(APPEND __install__libs "${MSVC_CRT_DIR}/msvcr${v}.dll")
-      endif()
-    else()
-      set(__install__libs)
-    endif()
-
-    if(CMAKE_INSTALL_DEBUG_LIBRARIES)
-      set(MSVC_CRT_DIR
-        "${MSVC_REDIST_DIR}/Debug_NonRedist/${CMAKE_MSVC_ARCH}/Microsoft.${MSVC_REDIST_NAME}.DebugCRT")
-      set(__install__libs ${__install__libs}
-        "${MSVC_CRT_DIR}/msvcp${v}d.dll"
-        )
-      if(NOT vs VERSION_LESS 14)
-        list(APPEND __install__libs
-            "${MSVC_CRT_DIR}/vcruntime${v}d.dll"
-            "${MSVC_CRT_DIR}/concrt${v}d.dll"
-            )
-      else()
-        list(APPEND __install__libs "${MSVC_CRT_DIR}/msvcr${v}d.dll")
-      endif()
-    endif()
-
-    if(CMAKE_INSTALL_UCRT_LIBRARIES AND NOT vs VERSION_LESS 14)
-      # Find the Windows Kits directory.
-      get_filename_component(windows_kits_dir
-        "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots;KitsRoot10]" ABSOLUTE)
-      set(programfilesx86 "ProgramFiles(x86)")
-      if(";${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION};$ENV{UCRTVersion};$ENV{WindowsSDKVersion};" MATCHES [=[;(10\.[0-9.]+)[;\]]=])
-        set(__ucrt_version "${CMAKE_MATCH_1}/")
-      else()
-        set(__ucrt_version "")
-      endif()
-      find_path(WINDOWS_KITS_DIR
-        NAMES
-          Redist/${__ucrt_version}ucrt/DLLs/${CMAKE_MSVC_ARCH}/ucrtbase.dll
-          Redist/ucrt/DLLs/${CMAKE_MSVC_ARCH}/ucrtbase.dll
-        PATHS
-        $ENV{CMAKE_WINDOWS_KITS_10_DIR}
-        "${windows_kits_dir}"
-        "$ENV{ProgramFiles}/Windows Kits/10"
-        "$ENV{${programfilesx86}}/Windows Kits/10"
-        )
-      mark_as_advanced(WINDOWS_KITS_DIR)
-
-      # Glob the list of UCRT DLLs.
-      if(NOT CMAKE_INSTALL_DEBUG_LIBRARIES_ONLY)
-        if(EXISTS "${WINDOWS_KITS_DIR}/Redist/${__ucrt_version}ucrt/DLLs/${CMAKE_MSVC_ARCH}/ucrtbase.dll")
-          file(GLOB __ucrt_dlls "${WINDOWS_KITS_DIR}/Redist/${__ucrt_version}ucrt/DLLs/${CMAKE_MSVC_ARCH}/*.dll")
-        else()
-          file(GLOB __ucrt_dlls "${WINDOWS_KITS_DIR}/Redist/ucrt/DLLs/${CMAKE_MSVC_ARCH}/*.dll")
-        endif()
-        list(APPEND __install__libs ${__ucrt_dlls})
-      endif()
-      if(CMAKE_INSTALL_DEBUG_LIBRARIES)
-        if(EXISTS "${WINDOWS_KITS_DIR}/bin/${__ucrt_version}${CMAKE_MSVC_ARCH}/ucrt/ucrtbased.dll")
-          file(GLOB __ucrt_dlls "${WINDOWS_KITS_DIR}/bin/${__ucrt_version}${CMAKE_MSVC_ARCH}/ucrt/*.dll")
-        else()
-          file(GLOB __ucrt_dlls "${WINDOWS_KITS_DIR}/bin/${CMAKE_MSVC_ARCH}/ucrt/*.dll")
-        endif()
-        list(APPEND __install__libs ${__ucrt_dlls})
-      endif()
-    endif()
-  endif()
-
-  if(CMAKE_INSTALL_MFC_LIBRARIES)
-    if(MSVC_VERSION EQUAL 1300)
-      set(__install__libs ${__install__libs}
-        "${SYSTEMROOT}/system32/mfc70.dll"
-        )
-    endif()
-
-    if(MSVC_VERSION EQUAL 1310)
-      set(__install__libs ${__install__libs}
-        "${SYSTEMROOT}/system32/mfc71.dll"
-        )
-    endif()
-
-    if(MSVC_VERSION EQUAL 1400)
-      if(CMAKE_INSTALL_DEBUG_LIBRARIES)
-        set(MSVC_MFC_DIR
-          "${MSVC_REDIST_DIR}/Debug_NonRedist/${CMAKE_MSVC_ARCH}/Microsoft.VC80.DebugMFC")
-        set(__install__libs ${__install__libs}
-          "${MSVC_MFC_DIR}/Microsoft.VC80.DebugMFC.manifest"
-          "${MSVC_MFC_DIR}/mfc80d.dll"
-          "${MSVC_MFC_DIR}/mfc80ud.dll"
-          "${MSVC_MFC_DIR}/mfcm80d.dll"
-          "${MSVC_MFC_DIR}/mfcm80ud.dll"
-          )
-      endif()
-
-      set(MSVC_MFC_DIR "${MSVC_REDIST_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.VC80.MFC")
-      # Install the manifest that allows DLLs to be loaded from the
-      # directory containing the executable.
-      if(NOT CMAKE_INSTALL_DEBUG_LIBRARIES_ONLY)
-        set(__install__libs ${__install__libs}
-          "${MSVC_MFC_DIR}/Microsoft.VC80.MFC.manifest"
-          "${MSVC_MFC_DIR}/mfc80.dll"
-          "${MSVC_MFC_DIR}/mfc80u.dll"
-          "${MSVC_MFC_DIR}/mfcm80.dll"
-          "${MSVC_MFC_DIR}/mfcm80u.dll"
-          )
-      endif()
-
-      # include the language dll's for vs8 as well as the actual dll's
-      set(MSVC_MFCLOC_DIR "${MSVC_REDIST_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.VC80.MFCLOC")
-      # Install the manifest that allows DLLs to be loaded from the
-      # directory containing the executable.
-      set(__install__libs ${__install__libs}
-        "${MSVC_MFCLOC_DIR}/Microsoft.VC80.MFCLOC.manifest"
-        "${MSVC_MFCLOC_DIR}/mfc80chs.dll"
-        "${MSVC_MFCLOC_DIR}/mfc80cht.dll"
-        "${MSVC_MFCLOC_DIR}/mfc80enu.dll"
-        "${MSVC_MFCLOC_DIR}/mfc80esp.dll"
-        "${MSVC_MFCLOC_DIR}/mfc80deu.dll"
-        "${MSVC_MFCLOC_DIR}/mfc80fra.dll"
-        "${MSVC_MFCLOC_DIR}/mfc80ita.dll"
-        "${MSVC_MFCLOC_DIR}/mfc80jpn.dll"
-        "${MSVC_MFCLOC_DIR}/mfc80kor.dll"
-        )
-    endif()
-
-    if(MSVC_VERSION EQUAL 1500)
-      if(CMAKE_INSTALL_DEBUG_LIBRARIES)
-        set(MSVC_MFC_DIR
-          "${MSVC_REDIST_DIR}/Debug_NonRedist/${CMAKE_MSVC_ARCH}/Microsoft.VC90.DebugMFC")
-        set(__install__libs ${__install__libs}
-          "${MSVC_MFC_DIR}/Microsoft.VC90.DebugMFC.manifest"
-          "${MSVC_MFC_DIR}/mfc90d.dll"
-          "${MSVC_MFC_DIR}/mfc90ud.dll"
-          "${MSVC_MFC_DIR}/mfcm90d.dll"
-          "${MSVC_MFC_DIR}/mfcm90ud.dll"
-          )
-      endif()
-
-      set(MSVC_MFC_DIR "${MSVC_REDIST_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.VC90.MFC")
-      # Install the manifest that allows DLLs to be loaded from the
-      # directory containing the executable.
-      if(NOT CMAKE_INSTALL_DEBUG_LIBRARIES_ONLY)
-        set(__install__libs ${__install__libs}
-          "${MSVC_MFC_DIR}/Microsoft.VC90.MFC.manifest"
-          "${MSVC_MFC_DIR}/mfc90.dll"
-          "${MSVC_MFC_DIR}/mfc90u.dll"
-          "${MSVC_MFC_DIR}/mfcm90.dll"
-          "${MSVC_MFC_DIR}/mfcm90u.dll"
-          )
-      endif()
-
-      # include the language dll's for vs9 as well as the actual dll's
-      set(MSVC_MFCLOC_DIR "${MSVC_REDIST_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.VC90.MFCLOC")
-      # Install the manifest that allows DLLs to be loaded from the
-      # directory containing the executable.
-      set(__install__libs ${__install__libs}
-        "${MSVC_MFCLOC_DIR}/Microsoft.VC90.MFCLOC.manifest"
-        "${MSVC_MFCLOC_DIR}/mfc90chs.dll"
-        "${MSVC_MFCLOC_DIR}/mfc90cht.dll"
-        "${MSVC_MFCLOC_DIR}/mfc90enu.dll"
-        "${MSVC_MFCLOC_DIR}/mfc90esp.dll"
-        "${MSVC_MFCLOC_DIR}/mfc90deu.dll"
-        "${MSVC_MFCLOC_DIR}/mfc90fra.dll"
-        "${MSVC_MFCLOC_DIR}/mfc90ita.dll"
-        "${MSVC_MFCLOC_DIR}/mfc90jpn.dll"
-        "${MSVC_MFCLOC_DIR}/mfc90kor.dll"
-        )
-    endif()
-
-    set(_MFC_DLL_VERSION "")
-    set(_MFC_IDE_VERSION "")
-    if(_MSVC_IDE_VERSION GREATER_EQUAL 10)
-      set(_MFC_DLL_VERSION ${_MSVC_DLL_VERSION})
-      set(_MFC_IDE_VERSION ${_MSVC_IDE_VERSION})
-    endif()
-
-    if(_MFC_DLL_VERSION)
-      set(v "${_MFC_DLL_VERSION}")
-      set(vs "${_MFC_IDE_VERSION}")
-
-      # Starting with VS 15 the MFC DLLs may be in a different directory.
-      if (NOT vs VERSION_LESS 15)
-        file(GLOB _MSVC_REDIST_DIRS "${MSVC_REDIST_DIR}/../*")
-        find_path(MSVC_REDIST_MFC_DIR NAMES ${CMAKE_MSVC_ARCH}/Microsoft.${MSVC_REDIST_NAME}.MFC
-          PATHS ${_MSVC_REDIST_DIRS} NO_DEFAULT_PATH)
-        mark_as_advanced(MSVC_REDIST_MFC_DIR)
-        unset(_MSVC_REDIST_DIRS)
-      else()
-        set(MSVC_REDIST_MFC_DIR "${MSVC_REDIST_DIR}")
-      endif()
-
-      # Multi-Byte Character Set versions of MFC are available as optional
-      # addon since Visual Studio 12.  So for version 12 or higher, check
-      # whether they are available and exclude them if they are not.
-
-      if(CMAKE_INSTALL_DEBUG_LIBRARIES)
-        set(MSVC_MFC_DIR
-          "${MSVC_REDIST_MFC_DIR}/Debug_NonRedist/${CMAKE_MSVC_ARCH}/Microsoft.${MSVC_REDIST_NAME}.DebugMFC")
-        set(__install__libs ${__install__libs}
-          "${MSVC_MFC_DIR}/mfc${v}ud.dll"
-          "${MSVC_MFC_DIR}/mfcm${v}ud.dll"
-          )
-        if("${v}" LESS 12 OR EXISTS "${MSVC_MFC_DIR}/mfc${v}d.dll")
-          set(__install__libs ${__install__libs}
-            "${MSVC_MFC_DIR}/mfc${v}d.dll"
-          )
-        endif()
-        if("${v}" LESS 12 OR EXISTS "${MSVC_MFC_DIR}/mfcm${v}d.dll")
-          set(__install__libs ${__install__libs}
-            "${MSVC_MFC_DIR}/mfcm${v}d.dll"
-          )
-        endif()
-      endif()
-
-      set(MSVC_MFC_DIR "${MSVC_REDIST_MFC_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.${MSVC_REDIST_NAME}.MFC")
-      if(NOT CMAKE_INSTALL_DEBUG_LIBRARIES_ONLY)
-        set(__install__libs ${__install__libs}
-          "${MSVC_MFC_DIR}/mfc${v}u.dll"
-          "${MSVC_MFC_DIR}/mfcm${v}u.dll"
-          )
-        if("${v}" LESS 12 OR EXISTS "${MSVC_MFC_DIR}/mfc${v}.dll")
-          set(__install__libs ${__install__libs}
-            "${MSVC_MFC_DIR}/mfc${v}.dll"
-          )
-        endif()
-        if("${v}" LESS 12 OR EXISTS "${MSVC_MFC_DIR}/mfcm${v}.dll")
-          set(__install__libs ${__install__libs}
-            "${MSVC_MFC_DIR}/mfcm${v}.dll"
-          )
-        endif()
-      endif()
-
-      # include the language dll's as well as the actual dll's
-      set(MSVC_MFCLOC_DIR "${MSVC_REDIST_MFC_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.${MSVC_REDIST_NAME}.MFCLOC")
-      set(__install__libs ${__install__libs}
-        "${MSVC_MFCLOC_DIR}/mfc${v}chs.dll"
-        "${MSVC_MFCLOC_DIR}/mfc${v}cht.dll"
-        "${MSVC_MFCLOC_DIR}/mfc${v}deu.dll"
-        "${MSVC_MFCLOC_DIR}/mfc${v}enu.dll"
-        "${MSVC_MFCLOC_DIR}/mfc${v}esn.dll"
-        "${MSVC_MFCLOC_DIR}/mfc${v}fra.dll"
-        "${MSVC_MFCLOC_DIR}/mfc${v}ita.dll"
-        "${MSVC_MFCLOC_DIR}/mfc${v}jpn.dll"
-        "${MSVC_MFCLOC_DIR}/mfc${v}kor.dll"
-        "${MSVC_MFCLOC_DIR}/mfc${v}rus.dll"
-        )
-    endif()
-  endif()
-
-  # MSVC 8 was the first version with OpenMP
-  # Furthermore, there is no debug version of this
-  if(CMAKE_INSTALL_OPENMP_LIBRARIES AND _IRSL_HAVE_MSVC)
-    set(_MSOMP_DLL_VERSION ${_MSVC_DLL_VERSION})
-    set(_MSOMP_IDE_VERSION ${_MSVC_IDE_VERSION})
-
-    if(_MSOMP_DLL_VERSION)
-      set(v "${_MSOMP_DLL_VERSION}")
-      set(vs "${_MSOMP_IDE_VERSION}")
-      set(MSVC_OPENMP_DIR "${MSVC_REDIST_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.${MSVC_REDIST_NAME}.OPENMP")
-
-      if(NOT CMAKE_INSTALL_DEBUG_LIBRARIES_ONLY)
-        set(__install__libs ${__install__libs}
-          "${MSVC_OPENMP_DIR}/vcomp${v}.dll")
-      endif()
-    endif()
-  endif()
-
-  foreach(lib
-      ${__install__libs}
-      )
-    if(EXISTS ${lib})
-      set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS
-        ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS} ${lib})
-    else()
-      if(NOT CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS)
-        message(WARNING "system runtime library file does not exist: '${lib}'")
-        # This warning indicates an incomplete Visual Studio installation
-        # or a bug somewhere above here in this file.
-        # If you would like to avoid this warning, fix the real problem, or
-        # set CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS before including
-        # this file.
-      endif()
-    endif()
-  endforeach()
-endif()
-
-if(_IRSL_HAVE_Intel)
-  unset(__install_libs)
-  if(CMAKE_INSTALL_OPENMP_LIBRARIES)
-    if(WIN32)
-      list(APPEND __install_libs "${_Intel_redistdir}/libiomp5md.dll" "${_Intel_redistdir}/libiompstubs5md.dll")
-    elseif(APPLE)
-      list(APPEND __install_libs "${_Intel_redistdir}/libiomp5.dylib" "${_Intel_redistdir}/libiompstubs5.dylib")
-    else()
-      list(APPEND __install_libs "${_Intel_redistdir}/libiomp5.so" "${_Intel_redistdir}/libiompstubs5.so")
-      if(_Intel_compiler_ver VERSION_LESS 17)
-        list(APPEND __install_libs "${_Intel_redistdir}/libomp_db.so")
-      endif()
-      if(_Intel_compiler_ver VERSION_LESS 13)
-        list(APPEND __install_libs "${_Intel_redistdir}/libiompprof5.so")
-      endif()
-    endif()
-  endif()
-  if(WIN32)
-    set(__install_dirs "${_Intel_redistdir}/1033")
-    if(EXISTS "${_Intel_redistdir}/1041")
-      list(APPEND __install_dirs "${_Intel_redistdir}/1041")
-    endif()
-    if(_Intel_compiler_ver VERSION_LESS 18)
-      list(APPEND __install_dirs "${_Intel_redistdir}/irml" "${_Intel_redistdir}/irml_c")
-    endif()
-    foreach(__Intel_lib IN ITEMS cilkrts20.dll libchkp.dll libioffload_host.dll libirngmd.dll
-      libmmd.dll libmmdd.dll libmpx.dll liboffload.dll svml_dispmd.dll)
-
-      list(APPEND __install_libs "${_Intel_redistdir}/${__Intel_lib}")
-    endforeach()
-    if(CMAKE_C_COMPILER_ID STREQUAL Intel OR CMAKE_CXX_COMPILER_ID STREQUAL Intel)
-      list(APPEND __install_libs "${_Intel_redistdir}/libgfxoffload.dll")
-    endif()
-    if(CMAKE_Fortran_COMPILER_ID STREQUAL Intel)
-      foreach(__Intel_lib IN ITEMS ifdlg100.dll libicaf.dll libifcoremd.dll libifcoremdd.dll libifcorert.dll libifcorertd.dll libifportmd.dll)
-
-        list(APPEND __install_libs "${_Intel_redistdir}/${__Intel_lib}")
-      endforeach()
-    endif()
-  elseif(APPLE)
-    foreach(__Intel_lib IN ITEMS libchkp.dylib libcilkrts.5.dylib libcilkrts.dylib libimf.dylib libintlc.dylib libirc.dylib libirng.dylib libsvml.dylib)
-      list(APPEND __install_libs "${_Intel_redistdir}/${__Intel_lib}")
-    endforeach()
-    if(CMAKE_C_COMPILER_ID STREQUAL Intel OR CMAKE_CXX_COMPILER_ID STREQUAL Intel)
-      if(_Intel_compiler_ver VERSION_LESS 17)
-        list(APPEND __install_libs "${_Intel_redistdir}/libistrconv.dylib")
-      endif()
-    endif()
-    if(CMAKE_Fortran_COMPILER_ID STREQUAL Intel)
-      foreach(__Intel_lib IN ITEMS libifcore.dylib libifcoremt.dylib libifport.dylib libifportmt.dylib)
-
-        list(APPEND __install_libs "${_Intel_redistdir}/${__Intel_lib}")
-      endforeach()
-    endif()
-  else()
-    foreach(__Intel_lib IN ITEMS libchkp.so libcilkrts.so libcilkrts.so.5 libimf.so libintlc.so libintlc.so.5 libirc.so libpdbx.so libpdbx.so.5 libsvml.so)
-
-      list(APPEND __install_libs "${_Intel_redistdir}/${__Intel_lib}")
-    endforeach()
-    if(_Intel_compiler_ver VERSION_GREATER_EQUAL 13)
-      foreach(__Intel_lib IN ITEMS libirng.so liboffload.so liboffload.so.5)
-
-        list(APPEND __install_libs "${_Intel_redistdir}/${__Intel_lib}")
-      endforeach()
-    endif()
-    if(CMAKE_C_COMPILER_ID STREQUAL Intel OR CMAKE_CXX_COMPILER_ID STREQUAL Intel)
-      set(__install_dirs "${_Intel_redistdir}/irml")
-      list(APPEND __install_libs "${_Intel_redistdir}/cilk_db.so")
-      if(_Intel_compiler_ver VERSION_GREATER_EQUAL 15)
-        list(APPEND __install_libs "${_Intel_redistdir}/libistrconv.so" "${_Intel_redistdir}/libgfxoffload.so")
-      endif()
-    endif()
-    if(_Intel_compiler_ver VERSION_GREATER_EQUAL 16)
-      foreach(__Intel_lib IN ITEMS libioffload_host.so libioffload_host.so.5 libioffload_target.so libioffload_target.so.5 libmpx.so offload_main)
-
-        list(APPEND __install_libs "${_Intel_redistdir}/${__Intel_lib}")
-      endforeach()
-    endif()
-    if(_Intel_compiler_ver VERSION_LESS 15)
-      foreach(__Intel_lib IN ITEMS libcxaguard.so libcxaguard.so.5)
-
-        list(APPEND __install_libs "${_Intel_redistdir}/${__Intel_lib}")
-      endforeach()
-    endif()
-    if(CMAKE_Fortran_COMPILER_ID STREQUAL Intel)
-      foreach(__Intel_lib IN ITEMS libicaf.so libifcore.so libifcore.so.5 libifcoremt.so libifcoremt.so.5 libifport.so libifport.so.5)
-
-        list(APPEND __install_libs "${_Intel_redistdir}/${__Intel_lib}")
-      endforeach()
-    endif()
-  endif()
-
-  foreach(lib IN LISTS __install_libs)
-    if(EXISTS ${lib})
-      list(APPEND CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS ${lib})
-    else()
-      if(NOT CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS)
-        message(WARNING "system runtime library file does not exist: '${lib}'")
-      endif()
-    endif()
-  endforeach()
-
-  foreach(dir IN LISTS __install_dirs)
-    if(EXISTS ${dir})
-      list(APPEND CMAKE_INSTALL_SYSTEM_RUNTIME_DIRECTORIES ${dir})
-    else()
-      if(NOT CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS)
-        message(WARNING "system runtime library file does not exist: '${dir}'")
-      endif()
-    endif()
-  endforeach()
-endif()
-
-if(WATCOM)
-  get_filename_component( CompilerPath ${CMAKE_C_COMPILER} PATH )
-  if(CMAKE_C_COMPILER_VERSION)
-    set(_compiler_version ${CMAKE_C_COMPILER_VERSION})
-  else()
-    set(_compiler_version ${CMAKE_CXX_COMPILER_VERSION})
-  endif()
-  string(REGEX MATCHALL "[0-9]+" _watcom_version_list "${_compiler_version}")
-  list(GET _watcom_version_list 0 _watcom_major)
-  list(GET _watcom_version_list 1 _watcom_minor)
-  set( __install__libs
-    ${CompilerPath}/clbr${_watcom_major}${_watcom_minor}.dll
-    ${CompilerPath}/mt7r${_watcom_major}${_watcom_minor}.dll
-    ${CompilerPath}/plbr${_watcom_major}${_watcom_minor}.dll )
-  foreach(lib
-      ${__install__libs}
-      )
-    if(EXISTS ${lib})
-      set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS
-        ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS} ${lib})
-    else()
-      if(NOT CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS)
-        message(WARNING "system runtime library file does not exist: '${lib}'")
-        # This warning indicates an incomplete Watcom installation
-        # or a bug somewhere above here in this file.
-        # If you would like to avoid this warning, fix the real problem, or
-        # set CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS before including
-        # this file.
-      endif()
-    endif()
-  endforeach()
-endif()
-
-
-# Include system runtime libraries in the installation if any are
-# specified by CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS.
-if(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS)
-  if(NOT CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP)
-    if(NOT CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION)
-      if(WIN32)
-        set(CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION bin)
-      else()
-        set(CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION lib)
-      endif()
-    endif()
-    if(CMAKE_INSTALL_SYSTEM_RUNTIME_COMPONENT)
-      set(_CMAKE_INSTALL_SYSTEM_RUNTIME_COMPONENT
-        COMPONENT ${CMAKE_INSTALL_SYSTEM_RUNTIME_COMPONENT})
-    endif()
-    install(PROGRAMS ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS}
-      DESTINATION ${CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION}
-      ${_CMAKE_INSTALL_SYSTEM_RUNTIME_COMPONENT}
-      )
-
-    install(DIRECTORY ${CMAKE_INSTALL_SYSTEM_RUNTIME_DIRECTORIES}
-      DESTINATION ${CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION}
-      ${_CMAKE_INSTALL_SYSTEM_RUNTIME_COMPONENT}
-      )
-  endif()
-endif()
-
-cmake_policy(POP)
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+InstallRequiredSystemLibraries
+------------------------------
+
+Include this module to search for compiler-provided system runtime
+libraries and add install rules for them.  Some optional variables
+may be set prior to including the module to adjust behavior:
+
+``CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS``
+  Specify additional runtime libraries that may not be detected.
+  After inclusion any detected libraries will be appended to this.
+
+``CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP``
+  Set to TRUE to skip calling the :command:`install(PROGRAMS)` command to
+  allow the includer to specify its own install rule, using the value of
+  ``CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS`` to get the list of libraries.
+
+``CMAKE_INSTALL_DEBUG_LIBRARIES``
+  Set to TRUE to install the debug runtime libraries when available
+  with MSVC tools.
+
+``CMAKE_INSTALL_DEBUG_LIBRARIES_ONLY``
+  Set to TRUE to install only the debug runtime libraries with MSVC
+  tools even if the release runtime libraries are also available.
+
+``CMAKE_INSTALL_UCRT_LIBRARIES``
+  Set to TRUE to install the Windows Universal CRT libraries for
+  app-local deployment (e.g. to Windows XP).  This is meaningful
+  only with MSVC from Visual Studio 2015 or higher.
+
+  One may set a ``CMAKE_WINDOWS_KITS_10_DIR`` *environment variable*
+  to an absolute path to tell CMake to look for Windows 10 SDKs in
+  a custom location.  The specified directory is expected to contain
+  ``Redist/ucrt/DLLs/*`` directories.
+
+``CMAKE_INSTALL_MFC_LIBRARIES``
+  Set to TRUE to install the MSVC MFC runtime libraries.
+
+``CMAKE_INSTALL_OPENMP_LIBRARIES``
+  Set to TRUE to install the MSVC OpenMP runtime libraries
+
+``CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION``
+  Specify the :command:`install(PROGRAMS)` command ``DESTINATION``
+  option.  If not specified, the default is ``bin`` on Windows
+  and ``lib`` elsewhere.
+
+``CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS``
+  Set to TRUE to disable warnings about required library files that
+  do not exist.  (For example, Visual Studio Express editions may
+  not provide the redistributable files.)
+
+``CMAKE_INSTALL_SYSTEM_RUNTIME_COMPONENT``
+  Specify the :command:`install(PROGRAMS)` command ``COMPONENT``
+  option.  If not specified, no such option will be used.
+#]=======================================================================]
+
+cmake_policy(PUSH)
+cmake_policy(SET CMP0054 NEW) # if() quoted variables not dereferenced
+
+set(_IRSL_HAVE_Intel FALSE)
+set(_IRSL_HAVE_MSVC FALSE)
+foreach(LANG IN ITEMS C CXX Fortran)
+  if("${CMAKE_${LANG}_COMPILER_ID}" STREQUAL "Intel")
+    if(NOT _IRSL_HAVE_Intel)
+      get_filename_component(_Intel_basedir "${CMAKE_${LANG}_COMPILER}" PATH)
+      if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+        set(_Intel_archdir intel64)
+      else()
+        set(_Intel_archdir x86)
+      endif()
+      set(_Intel_compiler_ver ${CMAKE_${LANG}_COMPILER_VERSION})
+      if(WIN32)
+        get_filename_component(_Intel_redistdir "${_Intel_basedir}/../../redist/${_Intel_archdir}/compiler" ABSOLUTE)
+      elseif(APPLE)
+        get_filename_component(_Intel_redistdir "${_Intel_basedir}/../../compiler/lib" ABSOLUTE)
+      else()
+        if(EXISTS "${_Intel_basedir}/../lib/${_Intel_archdir}_lin")
+          get_filename_component(_Intel_redistdir "${_Intel_basedir}/../lib/${_Intel_archdir}" ABSOLUTE)
+        else()
+          get_filename_component(_Intel_redistdir "${_Intel_basedir}/../../compiler/lib/${_Intel_archdir}_lin" ABSOLUTE)
+        endif()
+      endif()
+      set(_IRSL_HAVE_Intel TRUE)
+    endif()
+  elseif("${CMAKE_${LANG}_COMPILER_ID}" STREQUAL "MSVC")
+    set(_IRSL_HAVE_MSVC TRUE)
+  endif()
+endforeach()
+
+if(MSVC)
+  file(TO_CMAKE_PATH "$ENV{SYSTEMROOT}" SYSTEMROOT)
+
+  if(CMAKE_CL_64)
+    if(MSVC_VERSION GREATER 1599)
+      # VS 10 and later:
+      set(CMAKE_MSVC_ARCH x64)
+    else()
+      # VS 9 and earlier:
+      set(CMAKE_MSVC_ARCH amd64)
+    endif()
+  else()
+    set(CMAKE_MSVC_ARCH x86)
+  endif()
+
+  get_filename_component(devenv_dir "${CMAKE_MAKE_PROGRAM}" PATH)
+  get_filename_component(base_dir "${devenv_dir}/../.." ABSOLUTE)
+
+  if(MSVC_VERSION EQUAL 1300)
+    set(__install__libs
+      "${SYSTEMROOT}/system32/msvcp70.dll"
+      "${SYSTEMROOT}/system32/msvcr70.dll"
+      )
+  endif()
+
+  if(MSVC_VERSION EQUAL 1310)
+    set(__install__libs
+      "${SYSTEMROOT}/system32/msvcp71.dll"
+      "${SYSTEMROOT}/system32/msvcr71.dll"
+      )
+  endif()
+
+  if(MSVC_TOOLSET_VERSION EQUAL 80)
+    # Find the runtime library redistribution directory.
+    get_filename_component(msvc_install_dir
+      "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0;InstallDir]" ABSOLUTE)
+    if(DEFINED MSVC80_REDIST_DIR AND EXISTS "${MSVC80_REDIST_DIR}")
+      set(MSVC_REDIST_DIR "${MSVC80_REDIST_DIR}") # use old cache entry
+    endif()
+    find_path(MSVC_REDIST_DIR NAMES ${CMAKE_MSVC_ARCH}/Microsoft.VC80.CRT/Microsoft.VC80.CRT.manifest
+      PATHS
+        "${msvc_install_dir}/../../VC/redist"
+        "${base_dir}/VC/redist"
+      )
+    mark_as_advanced(MSVC_REDIST_DIR)
+    set(MSVC_CRT_DIR "${MSVC_REDIST_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.VC80.CRT")
+
+    # Install the manifest that allows DLLs to be loaded from the
+    # directory containing the executable.
+    if(NOT CMAKE_INSTALL_DEBUG_LIBRARIES_ONLY)
+      set(__install__libs
+        "${MSVC_CRT_DIR}/Microsoft.VC80.CRT.manifest"
+        "${MSVC_CRT_DIR}/msvcm80.dll"
+        "${MSVC_CRT_DIR}/msvcp80.dll"
+        "${MSVC_CRT_DIR}/msvcr80.dll"
+        )
+    else()
+      set(__install__libs)
+    endif()
+
+    if(CMAKE_INSTALL_DEBUG_LIBRARIES)
+      set(MSVC_CRT_DIR
+        "${MSVC_REDIST_DIR}/Debug_NonRedist/${CMAKE_MSVC_ARCH}/Microsoft.VC80.DebugCRT")
+      set(__install__libs ${__install__libs}
+        "${MSVC_CRT_DIR}/Microsoft.VC80.DebugCRT.manifest"
+        "${MSVC_CRT_DIR}/msvcm80d.dll"
+        "${MSVC_CRT_DIR}/msvcp80d.dll"
+        "${MSVC_CRT_DIR}/msvcr80d.dll"
+        )
+    endif()
+  endif()
+
+  if(MSVC_TOOLSET_VERSION EQUAL 90)
+    # Find the runtime library redistribution directory.
+    get_filename_component(msvc_install_dir
+      "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\9.0;InstallDir]" ABSOLUTE)
+    get_filename_component(msvc_express_install_dir
+      "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\9.0;InstallDir]" ABSOLUTE)
+    if(DEFINED MSVC90_REDIST_DIR AND EXISTS "${MSVC90_REDIST_DIR}")
+      set(MSVC_REDIST_DIR "${MSVC90_REDIST_DIR}") # use old cache entry
+    endif()
+    find_path(MSVC_REDIST_DIR NAMES ${CMAKE_MSVC_ARCH}/Microsoft.VC90.CRT/Microsoft.VC90.CRT.manifest
+      PATHS
+        "${msvc_install_dir}/../../VC/redist"
+        "${msvc_express_install_dir}/../../VC/redist"
+        "${base_dir}/VC/redist"
+      )
+    mark_as_advanced(MSVC_REDIST_DIR)
+    set(MSVC_CRT_DIR "${MSVC_REDIST_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.VC90.CRT")
+
+    # Install the manifest that allows DLLs to be loaded from the
+    # directory containing the executable.
+    if(NOT CMAKE_INSTALL_DEBUG_LIBRARIES_ONLY)
+      set(__install__libs
+        "${MSVC_CRT_DIR}/Microsoft.VC90.CRT.manifest"
+        "${MSVC_CRT_DIR}/msvcm90.dll"
+        "${MSVC_CRT_DIR}/msvcp90.dll"
+        "${MSVC_CRT_DIR}/msvcr90.dll"
+        )
+    else()
+      set(__install__libs)
+    endif()
+
+    if(CMAKE_INSTALL_DEBUG_LIBRARIES)
+      set(MSVC_CRT_DIR
+        "${MSVC_REDIST_DIR}/Debug_NonRedist/${CMAKE_MSVC_ARCH}/Microsoft.VC90.DebugCRT")
+      set(__install__libs ${__install__libs}
+        "${MSVC_CRT_DIR}/Microsoft.VC90.DebugCRT.manifest"
+        "${MSVC_CRT_DIR}/msvcm90d.dll"
+        "${MSVC_CRT_DIR}/msvcp90d.dll"
+        "${MSVC_CRT_DIR}/msvcr90d.dll"
+        )
+    endif()
+  endif()
+
+  set(MSVC_REDIST_NAME "")
+  set(_MSVC_DLL_VERSION "")
+  set(_MSVC_IDE_VERSION "")
+  if(MSVC_VERSION GREATER_EQUAL 2000)
+    message(WARNING "MSVC ${MSVC_VERSION} not yet supported.")
+  elseif(MSVC_VERSION_VERSION GREATER_EQUAL 143)
+    message(WARNING "MSVC toolset v${MSVC_VERSION_VERSION} not yet supported.")
+  elseif(MSVC_TOOLSET_VERSION EQUAL 142)
+    set(MSVC_REDIST_NAME VC142)
+    set(_MSVC_DLL_VERSION 140)
+    set(_MSVC_IDE_VERSION 16)
+  elseif(MSVC_TOOLSET_VERSION EQUAL 141)
+    set(MSVC_REDIST_NAME VC142)
+    set(_MSVC_DLL_VERSION 140)
+    set(_MSVC_IDE_VERSION 16)
+  elseif(MSVC_TOOLSET_VERSION)
+    set(MSVC_REDIST_NAME VC${MSVC_TOOLSET_VERSION})
+    math(EXPR _MSVC_DLL_VERSION "${MSVC_TOOLSET_VERSION} / 10 * 10")
+    math(EXPR _MSVC_IDE_VERSION "${MSVC_TOOLSET_VERSION} / 10")
+  endif()
+
+  set(_MSVCRT_DLL_VERSION "")
+  set(_MSVCRT_IDE_VERSION "")
+  if(_MSVC_IDE_VERSION GREATER_EQUAL 10)
+    set(_MSVCRT_DLL_VERSION "${_MSVC_DLL_VERSION}")
+    set(_MSVCRT_IDE_VERSION "${_MSVC_IDE_VERSION}")
+  endif()
+
+  if(_MSVCRT_DLL_VERSION)
+    set(v "${_MSVCRT_DLL_VERSION}")
+    set(vs "${_MSVCRT_IDE_VERSION}")
+
+    # Find the runtime library redistribution directory.
+    if(vs VERSION_LESS 15 AND DEFINED MSVC${vs}_REDIST_DIR AND EXISTS "${MSVC${vs}_REDIST_DIR}")
+      set(MSVC_REDIST_DIR "${MSVC${vs}_REDIST_DIR}") # use old cache entry
+    endif()
+    if(NOT vs VERSION_LESS 15)
+      set(_vs_redist_paths "")
+      cmake_host_system_information(RESULT _vs_dir QUERY VS_${vs}_DIR) # undocumented query
+      if(IS_DIRECTORY "${_vs_dir}")
+        file(GLOB _vs_redist_paths "${_vs_dir}/VC/Redist/MSVC/*")
+      endif()
+      unset(_vs_dir)
+    else()
+      get_filename_component(_vs_dir
+        "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\${vs}.0;InstallDir]" ABSOLUTE)
+      set(programfilesx86 "ProgramFiles(x86)")
+      set(_vs_redist_paths
+        "${_vs_dir}/../../VC/redist"
+        "${base_dir}/VC/redist"
+        "$ENV{ProgramFiles}/Microsoft Visual Studio ${vs}.0/VC/redist"
+        "$ENV{${programfilesx86}}/Microsoft Visual Studio ${vs}.0/VC/redist"
+        )
+      unset(_vs_dir)
+      unset(programfilesx86)
+    endif()
+    find_path(MSVC_REDIST_DIR NAMES ${CMAKE_MSVC_ARCH}/Microsoft.${MSVC_REDIST_NAME}.CRT PATHS ${_vs_redist_paths})
+    unset(_vs_redist_paths)
+    mark_as_advanced(MSVC_REDIST_DIR)
+    set(MSVC_CRT_DIR "${MSVC_REDIST_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.${MSVC_REDIST_NAME}.CRT")
+
+    if(NOT CMAKE_INSTALL_DEBUG_LIBRARIES_ONLY)
+      set(__install__libs
+        "${MSVC_CRT_DIR}/msvcp${v}.dll"
+        )
+      if(NOT vs VERSION_LESS 14)
+        file(GLOB __msvcr_dlls "${MSVC_CRT_DIR}/*.dll")
+        list(APPEND __install__libs ${__msvcr_dlls})
+      else()
+        list(APPEND __install__libs "${MSVC_CRT_DIR}/msvcr${v}.dll")
+      endif()
+    else()
+      set(__install__libs)
+    endif()
+
+    if(CMAKE_INSTALL_DEBUG_LIBRARIES)
+      set(MSVC_CRT_DIR
+        "${MSVC_REDIST_DIR}/Debug_NonRedist/${CMAKE_MSVC_ARCH}/Microsoft.${MSVC_REDIST_NAME}.DebugCRT")
+      set(__install__libs ${__install__libs}
+        "${MSVC_CRT_DIR}/msvcp${v}d.dll"
+        )
+      if(NOT vs VERSION_LESS 14)
+        list(APPEND __install__libs
+            "${MSVC_CRT_DIR}/vcruntime${v}d.dll"
+            "${MSVC_CRT_DIR}/concrt${v}d.dll"
+            )
+      else()
+        list(APPEND __install__libs "${MSVC_CRT_DIR}/msvcr${v}d.dll")
+      endif()
+    endif()
+
+    if(CMAKE_INSTALL_UCRT_LIBRARIES AND NOT vs VERSION_LESS 14)
+      # Find the Windows Kits directory.
+      get_filename_component(windows_kits_dir
+        "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots;KitsRoot10]" ABSOLUTE)
+      set(programfilesx86 "ProgramFiles(x86)")
+      if(";${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION};$ENV{UCRTVersion};$ENV{WindowsSDKVersion};" MATCHES [=[;(10\.[0-9.]+)[;\]]=])
+        set(__ucrt_version "${CMAKE_MATCH_1}/")
+      else()
+        set(__ucrt_version "")
+      endif()
+      find_path(WINDOWS_KITS_DIR
+        NAMES
+          Redist/${__ucrt_version}ucrt/DLLs/${CMAKE_MSVC_ARCH}/ucrtbase.dll
+          Redist/ucrt/DLLs/${CMAKE_MSVC_ARCH}/ucrtbase.dll
+        PATHS
+        $ENV{CMAKE_WINDOWS_KITS_10_DIR}
+        "${windows_kits_dir}"
+        "$ENV{ProgramFiles}/Windows Kits/10"
+        "$ENV{${programfilesx86}}/Windows Kits/10"
+        )
+      mark_as_advanced(WINDOWS_KITS_DIR)
+
+      # Glob the list of UCRT DLLs.
+      if(NOT CMAKE_INSTALL_DEBUG_LIBRARIES_ONLY)
+        if(EXISTS "${WINDOWS_KITS_DIR}/Redist/${__ucrt_version}ucrt/DLLs/${CMAKE_MSVC_ARCH}/ucrtbase.dll")
+          file(GLOB __ucrt_dlls "${WINDOWS_KITS_DIR}/Redist/${__ucrt_version}ucrt/DLLs/${CMAKE_MSVC_ARCH}/*.dll")
+        else()
+          file(GLOB __ucrt_dlls "${WINDOWS_KITS_DIR}/Redist/ucrt/DLLs/${CMAKE_MSVC_ARCH}/*.dll")
+        endif()
+        list(APPEND __install__libs ${__ucrt_dlls})
+      endif()
+      if(CMAKE_INSTALL_DEBUG_LIBRARIES)
+        if(EXISTS "${WINDOWS_KITS_DIR}/bin/${__ucrt_version}${CMAKE_MSVC_ARCH}/ucrt/ucrtbased.dll")
+          file(GLOB __ucrt_dlls "${WINDOWS_KITS_DIR}/bin/${__ucrt_version}${CMAKE_MSVC_ARCH}/ucrt/*.dll")
+        else()
+          file(GLOB __ucrt_dlls "${WINDOWS_KITS_DIR}/bin/${CMAKE_MSVC_ARCH}/ucrt/*.dll")
+        endif()
+        list(APPEND __install__libs ${__ucrt_dlls})
+      endif()
+    endif()
+  endif()
+
+  if(CMAKE_INSTALL_MFC_LIBRARIES)
+    if(MSVC_VERSION EQUAL 1300)
+      set(__install__libs ${__install__libs}
+        "${SYSTEMROOT}/system32/mfc70.dll"
+        )
+    endif()
+
+    if(MSVC_VERSION EQUAL 1310)
+      set(__install__libs ${__install__libs}
+        "${SYSTEMROOT}/system32/mfc71.dll"
+        )
+    endif()
+
+    if(MSVC_VERSION EQUAL 1400)
+      if(CMAKE_INSTALL_DEBUG_LIBRARIES)
+        set(MSVC_MFC_DIR
+          "${MSVC_REDIST_DIR}/Debug_NonRedist/${CMAKE_MSVC_ARCH}/Microsoft.VC80.DebugMFC")
+        set(__install__libs ${__install__libs}
+          "${MSVC_MFC_DIR}/Microsoft.VC80.DebugMFC.manifest"
+          "${MSVC_MFC_DIR}/mfc80d.dll"
+          "${MSVC_MFC_DIR}/mfc80ud.dll"
+          "${MSVC_MFC_DIR}/mfcm80d.dll"
+          "${MSVC_MFC_DIR}/mfcm80ud.dll"
+          )
+      endif()
+
+      set(MSVC_MFC_DIR "${MSVC_REDIST_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.VC80.MFC")
+      # Install the manifest that allows DLLs to be loaded from the
+      # directory containing the executable.
+      if(NOT CMAKE_INSTALL_DEBUG_LIBRARIES_ONLY)
+        set(__install__libs ${__install__libs}
+          "${MSVC_MFC_DIR}/Microsoft.VC80.MFC.manifest"
+          "${MSVC_MFC_DIR}/mfc80.dll"
+          "${MSVC_MFC_DIR}/mfc80u.dll"
+          "${MSVC_MFC_DIR}/mfcm80.dll"
+          "${MSVC_MFC_DIR}/mfcm80u.dll"
+          )
+      endif()
+
+      # include the language dll's for vs8 as well as the actual dll's
+      set(MSVC_MFCLOC_DIR "${MSVC_REDIST_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.VC80.MFCLOC")
+      # Install the manifest that allows DLLs to be loaded from the
+      # directory containing the executable.
+      set(__install__libs ${__install__libs}
+        "${MSVC_MFCLOC_DIR}/Microsoft.VC80.MFCLOC.manifest"
+        "${MSVC_MFCLOC_DIR}/mfc80chs.dll"
+        "${MSVC_MFCLOC_DIR}/mfc80cht.dll"
+        "${MSVC_MFCLOC_DIR}/mfc80enu.dll"
+        "${MSVC_MFCLOC_DIR}/mfc80esp.dll"
+        "${MSVC_MFCLOC_DIR}/mfc80deu.dll"
+        "${MSVC_MFCLOC_DIR}/mfc80fra.dll"
+        "${MSVC_MFCLOC_DIR}/mfc80ita.dll"
+        "${MSVC_MFCLOC_DIR}/mfc80jpn.dll"
+        "${MSVC_MFCLOC_DIR}/mfc80kor.dll"
+        )
+    endif()
+
+    if(MSVC_VERSION EQUAL 1500)
+      if(CMAKE_INSTALL_DEBUG_LIBRARIES)
+        set(MSVC_MFC_DIR
+          "${MSVC_REDIST_DIR}/Debug_NonRedist/${CMAKE_MSVC_ARCH}/Microsoft.VC90.DebugMFC")
+        set(__install__libs ${__install__libs}
+          "${MSVC_MFC_DIR}/Microsoft.VC90.DebugMFC.manifest"
+          "${MSVC_MFC_DIR}/mfc90d.dll"
+          "${MSVC_MFC_DIR}/mfc90ud.dll"
+          "${MSVC_MFC_DIR}/mfcm90d.dll"
+          "${MSVC_MFC_DIR}/mfcm90ud.dll"
+          )
+      endif()
+
+      set(MSVC_MFC_DIR "${MSVC_REDIST_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.VC90.MFC")
+      # Install the manifest that allows DLLs to be loaded from the
+      # directory containing the executable.
+      if(NOT CMAKE_INSTALL_DEBUG_LIBRARIES_ONLY)
+        set(__install__libs ${__install__libs}
+          "${MSVC_MFC_DIR}/Microsoft.VC90.MFC.manifest"
+          "${MSVC_MFC_DIR}/mfc90.dll"
+          "${MSVC_MFC_DIR}/mfc90u.dll"
+          "${MSVC_MFC_DIR}/mfcm90.dll"
+          "${MSVC_MFC_DIR}/mfcm90u.dll"
+          )
+      endif()
+
+      # include the language dll's for vs9 as well as the actual dll's
+      set(MSVC_MFCLOC_DIR "${MSVC_REDIST_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.VC90.MFCLOC")
+      # Install the manifest that allows DLLs to be loaded from the
+      # directory containing the executable.
+      set(__install__libs ${__install__libs}
+        "${MSVC_MFCLOC_DIR}/Microsoft.VC90.MFCLOC.manifest"
+        "${MSVC_MFCLOC_DIR}/mfc90chs.dll"
+        "${MSVC_MFCLOC_DIR}/mfc90cht.dll"
+        "${MSVC_MFCLOC_DIR}/mfc90enu.dll"
+        "${MSVC_MFCLOC_DIR}/mfc90esp.dll"
+        "${MSVC_MFCLOC_DIR}/mfc90deu.dll"
+        "${MSVC_MFCLOC_DIR}/mfc90fra.dll"
+        "${MSVC_MFCLOC_DIR}/mfc90ita.dll"
+        "${MSVC_MFCLOC_DIR}/mfc90jpn.dll"
+        "${MSVC_MFCLOC_DIR}/mfc90kor.dll"
+        )
+    endif()
+
+    set(_MFC_DLL_VERSION "")
+    set(_MFC_IDE_VERSION "")
+    if(_MSVC_IDE_VERSION GREATER_EQUAL 10)
+      set(_MFC_DLL_VERSION ${_MSVC_DLL_VERSION})
+      set(_MFC_IDE_VERSION ${_MSVC_IDE_VERSION})
+    endif()
+
+    if(_MFC_DLL_VERSION)
+      set(v "${_MFC_DLL_VERSION}")
+      set(vs "${_MFC_IDE_VERSION}")
+
+      # Starting with VS 15 the MFC DLLs may be in a different directory.
+      if (NOT vs VERSION_LESS 15)
+        file(GLOB _MSVC_REDIST_DIRS "${MSVC_REDIST_DIR}/../*")
+        find_path(MSVC_REDIST_MFC_DIR NAMES ${CMAKE_MSVC_ARCH}/Microsoft.${MSVC_REDIST_NAME}.MFC
+          PATHS ${_MSVC_REDIST_DIRS} NO_DEFAULT_PATH)
+        mark_as_advanced(MSVC_REDIST_MFC_DIR)
+        unset(_MSVC_REDIST_DIRS)
+      else()
+        set(MSVC_REDIST_MFC_DIR "${MSVC_REDIST_DIR}")
+      endif()
+
+      # Multi-Byte Character Set versions of MFC are available as optional
+      # addon since Visual Studio 12.  So for version 12 or higher, check
+      # whether they are available and exclude them if they are not.
+
+      if(CMAKE_INSTALL_DEBUG_LIBRARIES)
+        set(MSVC_MFC_DIR
+          "${MSVC_REDIST_MFC_DIR}/Debug_NonRedist/${CMAKE_MSVC_ARCH}/Microsoft.${MSVC_REDIST_NAME}.DebugMFC")
+        set(__install__libs ${__install__libs}
+          "${MSVC_MFC_DIR}/mfc${v}ud.dll"
+          "${MSVC_MFC_DIR}/mfcm${v}ud.dll"
+          )
+        if("${v}" LESS 12 OR EXISTS "${MSVC_MFC_DIR}/mfc${v}d.dll")
+          set(__install__libs ${__install__libs}
+            "${MSVC_MFC_DIR}/mfc${v}d.dll"
+          )
+        endif()
+        if("${v}" LESS 12 OR EXISTS "${MSVC_MFC_DIR}/mfcm${v}d.dll")
+          set(__install__libs ${__install__libs}
+            "${MSVC_MFC_DIR}/mfcm${v}d.dll"
+          )
+        endif()
+      endif()
+
+      set(MSVC_MFC_DIR "${MSVC_REDIST_MFC_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.${MSVC_REDIST_NAME}.MFC")
+      if(NOT CMAKE_INSTALL_DEBUG_LIBRARIES_ONLY)
+        set(__install__libs ${__install__libs}
+          "${MSVC_MFC_DIR}/mfc${v}u.dll"
+          "${MSVC_MFC_DIR}/mfcm${v}u.dll"
+          )
+        if("${v}" LESS 12 OR EXISTS "${MSVC_MFC_DIR}/mfc${v}.dll")
+          set(__install__libs ${__install__libs}
+            "${MSVC_MFC_DIR}/mfc${v}.dll"
+          )
+        endif()
+        if("${v}" LESS 12 OR EXISTS "${MSVC_MFC_DIR}/mfcm${v}.dll")
+          set(__install__libs ${__install__libs}
+            "${MSVC_MFC_DIR}/mfcm${v}.dll"
+          )
+        endif()
+      endif()
+
+      # include the language dll's as well as the actual dll's
+      set(MSVC_MFCLOC_DIR "${MSVC_REDIST_MFC_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.${MSVC_REDIST_NAME}.MFCLOC")
+      set(__install__libs ${__install__libs}
+        "${MSVC_MFCLOC_DIR}/mfc${v}chs.dll"
+        "${MSVC_MFCLOC_DIR}/mfc${v}cht.dll"
+        "${MSVC_MFCLOC_DIR}/mfc${v}deu.dll"
+        "${MSVC_MFCLOC_DIR}/mfc${v}enu.dll"
+        "${MSVC_MFCLOC_DIR}/mfc${v}esn.dll"
+        "${MSVC_MFCLOC_DIR}/mfc${v}fra.dll"
+        "${MSVC_MFCLOC_DIR}/mfc${v}ita.dll"
+        "${MSVC_MFCLOC_DIR}/mfc${v}jpn.dll"
+        "${MSVC_MFCLOC_DIR}/mfc${v}kor.dll"
+        "${MSVC_MFCLOC_DIR}/mfc${v}rus.dll"
+        )
+    endif()
+  endif()
+
+  # MSVC 8 was the first version with OpenMP
+  # Furthermore, there is no debug version of this
+  if(CMAKE_INSTALL_OPENMP_LIBRARIES AND _IRSL_HAVE_MSVC)
+    set(_MSOMP_DLL_VERSION ${_MSVC_DLL_VERSION})
+    set(_MSOMP_IDE_VERSION ${_MSVC_IDE_VERSION})
+
+    if(_MSOMP_DLL_VERSION)
+      set(v "${_MSOMP_DLL_VERSION}")
+      set(vs "${_MSOMP_IDE_VERSION}")
+      set(MSVC_OPENMP_DIR "${MSVC_REDIST_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.${MSVC_REDIST_NAME}.OPENMP")
+
+      if(NOT CMAKE_INSTALL_DEBUG_LIBRARIES_ONLY)
+        set(__install__libs ${__install__libs}
+          "${MSVC_OPENMP_DIR}/vcomp${v}.dll")
+      endif()
+    endif()
+  endif()
+
+  foreach(lib
+      ${__install__libs}
+      )
+    if(EXISTS ${lib})
+      set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS
+        ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS} ${lib})
+    else()
+      if(NOT CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS)
+        message(WARNING "system runtime library file does not exist: '${lib}'")
+        # This warning indicates an incomplete Visual Studio installation
+        # or a bug somewhere above here in this file.
+        # If you would like to avoid this warning, fix the real problem, or
+        # set CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS before including
+        # this file.
+      endif()
+    endif()
+  endforeach()
+endif()
+
+if(_IRSL_HAVE_Intel)
+  unset(__install_libs)
+  if(CMAKE_INSTALL_OPENMP_LIBRARIES)
+    if(WIN32)
+      list(APPEND __install_libs "${_Intel_redistdir}/libiomp5md.dll" "${_Intel_redistdir}/libiompstubs5md.dll")
+    elseif(APPLE)
+      list(APPEND __install_libs "${_Intel_redistdir}/libiomp5.dylib" "${_Intel_redistdir}/libiompstubs5.dylib")
+    else()
+      list(APPEND __install_libs "${_Intel_redistdir}/libiomp5.so" "${_Intel_redistdir}/libiompstubs5.so")
+      if(_Intel_compiler_ver VERSION_LESS 17)
+        list(APPEND __install_libs "${_Intel_redistdir}/libomp_db.so")
+      endif()
+      if(_Intel_compiler_ver VERSION_LESS 13)
+        list(APPEND __install_libs "${_Intel_redistdir}/libiompprof5.so")
+      endif()
+    endif()
+  endif()
+  if(WIN32)
+    set(__install_dirs "${_Intel_redistdir}/1033")
+    if(EXISTS "${_Intel_redistdir}/1041")
+      list(APPEND __install_dirs "${_Intel_redistdir}/1041")
+    endif()
+    if(_Intel_compiler_ver VERSION_LESS 18)
+      list(APPEND __install_dirs "${_Intel_redistdir}/irml" "${_Intel_redistdir}/irml_c")
+    endif()
+    foreach(__Intel_lib IN ITEMS cilkrts20.dll libchkp.dll libioffload_host.dll libirngmd.dll
+      libmmd.dll libmmdd.dll libmpx.dll liboffload.dll svml_dispmd.dll)
+
+      list(APPEND __install_libs "${_Intel_redistdir}/${__Intel_lib}")
+    endforeach()
+    if(CMAKE_C_COMPILER_ID STREQUAL Intel OR CMAKE_CXX_COMPILER_ID STREQUAL Intel)
+      list(APPEND __install_libs "${_Intel_redistdir}/libgfxoffload.dll")
+    endif()
+    if(CMAKE_Fortran_COMPILER_ID STREQUAL Intel)
+      foreach(__Intel_lib IN ITEMS ifdlg100.dll libicaf.dll libifcoremd.dll libifcoremdd.dll libifcorert.dll libifcorertd.dll libifportmd.dll)
+
+        list(APPEND __install_libs "${_Intel_redistdir}/${__Intel_lib}")
+      endforeach()
+    endif()
+  elseif(APPLE)
+    foreach(__Intel_lib IN ITEMS libchkp.dylib libcilkrts.5.dylib libcilkrts.dylib libimf.dylib libintlc.dylib libirc.dylib libirng.dylib libsvml.dylib)
+      list(APPEND __install_libs "${_Intel_redistdir}/${__Intel_lib}")
+    endforeach()
+    if(CMAKE_C_COMPILER_ID STREQUAL Intel OR CMAKE_CXX_COMPILER_ID STREQUAL Intel)
+      if(_Intel_compiler_ver VERSION_LESS 17)
+        list(APPEND __install_libs "${_Intel_redistdir}/libistrconv.dylib")
+      endif()
+    endif()
+    if(CMAKE_Fortran_COMPILER_ID STREQUAL Intel)
+      foreach(__Intel_lib IN ITEMS libifcore.dylib libifcoremt.dylib libifport.dylib libifportmt.dylib)
+
+        list(APPEND __install_libs "${_Intel_redistdir}/${__Intel_lib}")
+      endforeach()
+    endif()
+  else()
+    foreach(__Intel_lib IN ITEMS libchkp.so libcilkrts.so libcilkrts.so.5 libimf.so libintlc.so libintlc.so.5 libirc.so libpdbx.so libpdbx.so.5 libsvml.so)
+
+      list(APPEND __install_libs "${_Intel_redistdir}/${__Intel_lib}")
+    endforeach()
+    if(_Intel_compiler_ver VERSION_GREATER_EQUAL 13)
+      foreach(__Intel_lib IN ITEMS libirng.so liboffload.so liboffload.so.5)
+
+        list(APPEND __install_libs "${_Intel_redistdir}/${__Intel_lib}")
+      endforeach()
+    endif()
+    if(CMAKE_C_COMPILER_ID STREQUAL Intel OR CMAKE_CXX_COMPILER_ID STREQUAL Intel)
+      set(__install_dirs "${_Intel_redistdir}/irml")
+      list(APPEND __install_libs "${_Intel_redistdir}/cilk_db.so")
+      if(_Intel_compiler_ver VERSION_GREATER_EQUAL 15)
+        list(APPEND __install_libs "${_Intel_redistdir}/libistrconv.so" "${_Intel_redistdir}/libgfxoffload.so")
+      endif()
+    endif()
+    if(_Intel_compiler_ver VERSION_GREATER_EQUAL 16)
+      foreach(__Intel_lib IN ITEMS libioffload_host.so libioffload_host.so.5 libioffload_target.so libioffload_target.so.5 libmpx.so offload_main)
+
+        list(APPEND __install_libs "${_Intel_redistdir}/${__Intel_lib}")
+      endforeach()
+    endif()
+    if(_Intel_compiler_ver VERSION_LESS 15)
+      foreach(__Intel_lib IN ITEMS libcxaguard.so libcxaguard.so.5)
+
+        list(APPEND __install_libs "${_Intel_redistdir}/${__Intel_lib}")
+      endforeach()
+    endif()
+    if(CMAKE_Fortran_COMPILER_ID STREQUAL Intel)
+      foreach(__Intel_lib IN ITEMS libicaf.so libifcore.so libifcore.so.5 libifcoremt.so libifcoremt.so.5 libifport.so libifport.so.5)
+
+        list(APPEND __install_libs "${_Intel_redistdir}/${__Intel_lib}")
+      endforeach()
+    endif()
+  endif()
+
+  foreach(lib IN LISTS __install_libs)
+    if(EXISTS ${lib})
+      list(APPEND CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS ${lib})
+    else()
+      if(NOT CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS)
+        message(WARNING "system runtime library file does not exist: '${lib}'")
+      endif()
+    endif()
+  endforeach()
+
+  foreach(dir IN LISTS __install_dirs)
+    if(EXISTS ${dir})
+      list(APPEND CMAKE_INSTALL_SYSTEM_RUNTIME_DIRECTORIES ${dir})
+    else()
+      if(NOT CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS)
+        message(WARNING "system runtime library file does not exist: '${dir}'")
+      endif()
+    endif()
+  endforeach()
+endif()
+
+if(WATCOM)
+  get_filename_component( CompilerPath ${CMAKE_C_COMPILER} PATH )
+  if(CMAKE_C_COMPILER_VERSION)
+    set(_compiler_version ${CMAKE_C_COMPILER_VERSION})
+  else()
+    set(_compiler_version ${CMAKE_CXX_COMPILER_VERSION})
+  endif()
+  string(REGEX MATCHALL "[0-9]+" _watcom_version_list "${_compiler_version}")
+  list(GET _watcom_version_list 0 _watcom_major)
+  list(GET _watcom_version_list 1 _watcom_minor)
+  set( __install__libs
+    ${CompilerPath}/clbr${_watcom_major}${_watcom_minor}.dll
+    ${CompilerPath}/mt7r${_watcom_major}${_watcom_minor}.dll
+    ${CompilerPath}/plbr${_watcom_major}${_watcom_minor}.dll )
+  foreach(lib
+      ${__install__libs}
+      )
+    if(EXISTS ${lib})
+      set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS
+        ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS} ${lib})
+    else()
+      if(NOT CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS)
+        message(WARNING "system runtime library file does not exist: '${lib}'")
+        # This warning indicates an incomplete Watcom installation
+        # or a bug somewhere above here in this file.
+        # If you would like to avoid this warning, fix the real problem, or
+        # set CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS before including
+        # this file.
+      endif()
+    endif()
+  endforeach()
+endif()
+
+
+# Include system runtime libraries in the installation if any are
+# specified by CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS.
+if(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS)
+  if(NOT CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP)
+    if(NOT CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION)
+      if(WIN32)
+        set(CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION bin)
+      else()
+        set(CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION lib)
+      endif()
+    endif()
+    if(CMAKE_INSTALL_SYSTEM_RUNTIME_COMPONENT)
+      set(_CMAKE_INSTALL_SYSTEM_RUNTIME_COMPONENT
+        COMPONENT ${CMAKE_INSTALL_SYSTEM_RUNTIME_COMPONENT})
+    endif()
+    install(PROGRAMS ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS}
+      DESTINATION ${CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION}
+      ${_CMAKE_INSTALL_SYSTEM_RUNTIME_COMPONENT}
+      )
+
+    install(DIRECTORY ${CMAKE_INSTALL_SYSTEM_RUNTIME_DIRECTORIES}
+      DESTINATION ${CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION}
+      ${_CMAKE_INSTALL_SYSTEM_RUNTIME_COMPONENT}
+      )
+  endif()
+endif()
+
+cmake_policy(POP)
diff --git a/indra/deps/CMakeLists.txt b/indra/deps/CMakeLists.txt
index 764e3a733f..1c8354ad4a 100644
--- a/indra/deps/CMakeLists.txt
+++ b/indra/deps/CMakeLists.txt
@@ -1,60 +1,60 @@
-project(deps)
-
-include(FetchContent)
-
-set(CMAKE_FOLDER "Third Party")
-set(CMAKE_POSITION_INDEPENDENT_CODE ON)
-
-FetchContent_Declare(
-  Catch2
-  GIT_REPOSITORY https://github.com/catchorg/Catch2.git
-  GIT_TAG        v2.11.0
-  )
-FetchContent_Declare(
-  fmt
-  GIT_REPOSITORY https://github.com/fmtlib/fmt.git
-  GIT_TAG        6.1.2
-  )
-FetchContent_Declare(
-  nlohmann_json
-  GIT_REPOSITORY https://github.com/nlohmann/json.git
-  GIT_TAG        v3.7.3
-  )
-FetchContent_Declare(
-  absl
-  GIT_REPOSITORY https://git.alchemyviewer.org/alchemy/thirdparty/abseil-cpp.git
-  GIT_TAG        9b9a2536d1c212d792db9eb26b670b30397ee14c
-)
-
-# This is a hack because absl has dumb cmake
-set(OLD_BUILD_TEST ${BUILD_TESTING})
-set(BUILD_TESTING OFF)
-FetchContent_MakeAvailable(absl)
-set(BUILD_TESTING ${OLD_BUILD_TEST})
-
-# Supress warnings inside abseil under MSVC
-if(WINDOWS)
-  target_compile_options(absl_strings PRIVATE /wd4018)
-  target_compile_options(absl_str_format_internal PRIVATE /wd4018)
-  target_compile_options(absl_flags_usage_internal PRIVATE /wd4018)
-endif()
-
-
-if (BUILD_TESTING)
-  FetchContent_MakeAvailable(Catch2)
-endif()
-
-#Download the rest of the libraries
-FetchContent_MakeAvailable(fmt)
-
-# Typically you don't care so much for a third party library's tests to be
-# run from your own project's code.
-set(JSON_BuildTests OFF CACHE INTERNAL "")
-
-# If you only include this third party in PRIVATE source files, you do not
-# need to install it when your main project gets installed.
-set(JSON_Install OFF CACHE INTERNAL "")
-FetchContent_MakeAvailable(nlohmann_json)
-
-unset(CMAKE_FOLDER)
-unset(CMAKE_POSITION_INDEPENDENT_CODE)
+project(deps)
+
+include(FetchContent)
+
+set(CMAKE_FOLDER "Third Party")
+set(CMAKE_POSITION_INDEPENDENT_CODE ON)
+
+FetchContent_Declare(
+  Catch2
+  GIT_REPOSITORY https://github.com/catchorg/Catch2.git
+  GIT_TAG        v2.11.0
+  )
+FetchContent_Declare(
+  fmt
+  GIT_REPOSITORY https://github.com/fmtlib/fmt.git
+  GIT_TAG        6.1.2
+  )
+FetchContent_Declare(
+  nlohmann_json
+  GIT_REPOSITORY https://github.com/nlohmann/json.git
+  GIT_TAG        v3.7.3
+  )
+FetchContent_Declare(
+  absl
+  GIT_REPOSITORY https://git.alchemyviewer.org/alchemy/thirdparty/abseil-cpp.git
+  GIT_TAG        9b9a2536d1c212d792db9eb26b670b30397ee14c
+)
+
+# This is a hack because absl has dumb cmake
+set(OLD_BUILD_TEST ${BUILD_TESTING})
+set(BUILD_TESTING OFF)
+FetchContent_MakeAvailable(absl)
+set(BUILD_TESTING ${OLD_BUILD_TEST})
+
+# Supress warnings inside abseil under MSVC
+if(WINDOWS)
+  target_compile_options(absl_strings PRIVATE /wd4018)
+  target_compile_options(absl_str_format_internal PRIVATE /wd4018)
+  target_compile_options(absl_flags_usage_internal PRIVATE /wd4018)
+endif()
+
+
+if (BUILD_TESTING)
+  FetchContent_MakeAvailable(Catch2)
+endif()
+
+#Download the rest of the libraries
+FetchContent_MakeAvailable(fmt)
+
+# Typically you don't care so much for a third party library's tests to be
+# run from your own project's code.
+set(JSON_BuildTests OFF CACHE INTERNAL "")
+
+# If you only include this third party in PRIVATE source files, you do not
+# need to install it when your main project gets installed.
+set(JSON_Install OFF CACHE INTERNAL "")
+FetchContent_MakeAvailable(nlohmann_json)
+
+unset(CMAKE_FOLDER)
+unset(CMAKE_POSITION_INDEPENDENT_CODE)
diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp
index fea1d4907f..38e392ff6c 100644
--- a/indra/llcommon/llsdserialize.cpp
+++ b/indra/llcommon/llsdserialize.cpp
@@ -1,2348 +1,2348 @@
-/** 
- * @file llsdserialize.cpp
- * @author Phoenix
- * @date 2006-03-05
- * @brief Implementation of LLSD parsers and formatters
- *
- * $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 "llsdserialize.h"
-#include "llwin32headerslean.h"
-#include "llpointer.h"
-#include "llstreamtools.h" // for fullread
-#include "llbase64.h"
-
-#include <iostream>
-
-#include <boost/iostreams/device/array.hpp>
-#include <boost/iostreams/stream.hpp>
-
-#ifdef LL_USESYSTEMLIBS
-# 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
-
-#include "lldate.h"
-#include "llsd.h"
-#include "llstring.h"
-#include "lluri.h"
-
-// File constants
-static const int MAX_HDR_LEN = 20;
-static const S32 UNZIP_LLSD_MAX_DEPTH = 96;
-static const char LEGACY_NON_HEADER[] = "<llsd>";
-const std::string LLSD_BINARY_HEADER("LLSD/Binary");
-const std::string LLSD_XML_HEADER("LLSD/XML");
-
-//used to deflate a gzipped asset (currently used for navmeshes)
-#define windowBits 15
-#define ENABLE_ZLIB_GZIP 32
-
-/**
- * LLSDSerialize
- */
-
-// static
-void LLSDSerialize::serialize(const LLSD& sd, std::ostream& str, ELLSD_Serialize type, U32 options)
-{
-	LLPointer<LLSDFormatter> f = NULL;
-
-	switch (type)
-	{
-	case LLSD_BINARY:
-		str << "<? " << LLSD_BINARY_HEADER << " ?>\n";
-		f = new LLSDBinaryFormatter;
-		break;
-
-	case LLSD_XML:
-		str << "<? " << LLSD_XML_HEADER << " ?>\n";
-		f = new LLSDXMLFormatter;
-		break;
-
-	default:
-		LL_WARNS() << "serialize request for unknown ELLSD_Serialize" << LL_ENDL;
-	}
-
-	if (f.notNull())
-	{
-		f->format(sd, str, options);
-	}
-}
-
-// static
-bool LLSDSerialize::deserialize(LLSD& sd, std::istream& str, S32 max_bytes)
-{
-	LLPointer<LLSDParser> p = NULL;
-	char hdr_buf[MAX_HDR_LEN + 1] = ""; /* Flawfinder: ignore */
-	int i;
-	int inbuf = 0;
-	bool legacy_no_header = false;
-	bool fail_if_not_legacy = false;
-	std::string header;
-
-	/*
-	 * Get the first line before anything.
-	 */
-	str.get(hdr_buf, MAX_HDR_LEN, '\n');
-	if (str.fail())
-	{
-		str.clear();
-		fail_if_not_legacy = true;
-	}
-
-	if (!strnicmp(LEGACY_NON_HEADER, hdr_buf, strlen(LEGACY_NON_HEADER))) /* Flawfinder: ignore */
-	{
-		legacy_no_header = true;
-		inbuf = (int)str.gcount();
-	}
-	else
-	{
-		if (fail_if_not_legacy)
-			goto fail;
-		/*
-		* Remove the newline chars
-		*/
-		for (i = 0; i < MAX_HDR_LEN; i++)
-		{
-			if (hdr_buf[i] == 0 || hdr_buf[i] == '\r' ||
-				hdr_buf[i] == '\n')
-			{
-				hdr_buf[i] = 0;
-				break;
-			}
-		}
-		header = hdr_buf;
-
-		std::string::size_type start = header.find_first_not_of("<? ");
-		std::string::size_type end = std::string::npos;
-		if (start != std::string::npos)
-		{
-			end = header.find_first_of(" ?", start);
-		}
-		if ((start == std::string::npos) || (end == std::string::npos))
-			goto fail;
-
-		header = header.substr(start, end - start);
-		ws(str);
-	}
-	/*
-	 * Create the parser as appropriate
-	 */
-	if (legacy_no_header)
-	{	// Create a LLSD XML parser, and parse the first chunk read above
-		LLSDXMLParser* x = new LLSDXMLParser();
-		x->parsePart(hdr_buf, inbuf);	// Parse the first part that was already read
-		x->parseLines(str, sd);			// Parse the rest of it
-		delete x;
-		return true;
-	}
-
-	if (header == LLSD_BINARY_HEADER)
-	{
-		p = new LLSDBinaryParser;
-	}
-	else if (header == LLSD_XML_HEADER)
-	{
-		p = new LLSDXMLParser;
-	}
-	else
-	{
-		LL_WARNS() << "deserialize request for unknown ELLSD_Serialize" << LL_ENDL;
-	}
-
-	if (p.notNull())
-	{
-		p->parse(str, sd, max_bytes);
-		return true;
-	}
-
-fail:
-	LL_WARNS() << "deserialize LLSD parse failure" << LL_ENDL;
-	return false;
-}
-
-/**
- * Endian handlers
- */
-#if LL_BIG_ENDIAN
-U64 ll_htonll(U64 hostlonglong) { return hostlonglong; }
-U64 ll_ntohll(U64 netlonglong) { return netlonglong; }
-F64 ll_htond(F64 hostlonglong) { return hostlonglong; }
-F64 ll_ntohd(F64 netlonglong) { return netlonglong; }
-#else
-// I read some comments one a indicating that doing an integer add
-// here would be faster than a bitwise or. For now, the or has
-// programmer clarity, since the intended outcome matches the
-// operation.
-U64 ll_htonll(U64 hostlonglong)
-{
-	return ((U64)(htonl((U32)((hostlonglong >> 32) & 0xFFFFFFFF))) |
-			((U64)(htonl((U32)(hostlonglong & 0xFFFFFFFF))) << 32));
-}
-U64 ll_ntohll(U64 netlonglong)
-{
-	return ((U64)(ntohl((U32)((netlonglong >> 32) & 0xFFFFFFFF))) |
-			((U64)(ntohl((U32)(netlonglong & 0xFFFFFFFF))) << 32));
-}
-union LLEndianSwapper
-{
-	F64 d;
-	U64 i;
-};
-F64 ll_htond(F64 hostdouble)
-{
-	LLEndianSwapper tmp;
-	tmp.d = hostdouble;
-	tmp.i = ll_htonll(tmp.i);
-	return tmp.d;
-}
-F64 ll_ntohd(F64 netdouble)
-{
-	LLEndianSwapper tmp;
-	tmp.d = netdouble;
-	tmp.i = ll_ntohll(tmp.i);
-	return tmp.d;
-}
-#endif
-
-/**
- * Local functions.
- */
-/**
- * @brief Figure out what kind of string it is (raw or delimited) and handoff.
- *
- * @param istr The stream to read from.
- * @param value [out] The string which was found.
- * @param max_bytes The maximum possible length of the string. Passing in
- * a negative value will skip this check.
- * @return Returns number of bytes read off of the stream. Returns
- * PARSE_FAILURE (-1) on failure.
- */
-int deserialize_string(std::istream& istr, std::string& value, S32 max_bytes);
-
-/**
- * @brief Parse a delimited string. 
- *
- * @param istr The stream to read from, with the delimiter already popped.
- * @param value [out] The string which was found.
- * @param d The delimiter to use.
- * @return Returns number of bytes read off of the stream. Returns
- * PARSE_FAILURE (-1) on failure.
- */
-int deserialize_string_delim(std::istream& istr, std::string& value, char d);
-
-/**
- * @brief Read a raw string off the stream.
- *
- * @param istr The stream to read from, with the (len) parameter
- * leading the stream.
- * @param value [out] The string which was found.
- * @param d The delimiter to use.
- * @param max_bytes The maximum possible length of the string. Passing in
- * a negative value will skip this check.
- * @return Returns number of bytes read off of the stream. Returns
- * PARSE_FAILURE (-1) on failure.
- */
-int deserialize_string_raw(
-	std::istream& istr,
-	std::string& value,
-	S32 max_bytes);
-
-/**
- * @brief helper method for dealing with the different notation boolean format.
- *
- * @param istr The stream to read from with the leading character stripped.
- * @param data [out] the result of the parse.
- * @param compare The string to compare the boolean against
- * @param vale The value to assign to data if the parse succeeds.
- * @return Returns number of bytes read off of the stream. Returns
- * PARSE_FAILURE (-1) on failure.
- */
-int deserialize_boolean(
-	std::istream& istr,
-	LLSD& data,
-	const std::string& compare,
-	bool value);
-
-/**
- * @brief Do notation escaping of a string to an ostream.
- *
- * @param value The string to escape and serialize
- * @param str The stream to serialize to.
- */
-void serialize_string(const std::string& value, std::ostream& str);
-
-
-/**
- * Local constants.
- */
-static const std::string NOTATION_TRUE_SERIAL("true");
-static const std::string NOTATION_FALSE_SERIAL("false");
-
-static const char BINARY_TRUE_SERIAL = '1';
-static const char BINARY_FALSE_SERIAL = '0';
-
-
-/**
- * LLSDParser
- */
-LLSDParser::LLSDParser()
-	: mCheckLimits(true), mMaxBytesLeft(0), mParseLines(false)
-{
-}
-
-// virtual
-LLSDParser::~LLSDParser()
-{ }
-
-S32 LLSDParser::parse(std::istream& istr, LLSD& data, S32 max_bytes, S32 max_depth)
-{
-	mCheckLimits = (LLSDSerialize::SIZE_UNLIMITED == max_bytes) ? false : true;
-	mMaxBytesLeft = max_bytes;
-	return doParse(istr, data, max_depth);
-}
-
-
-// Parse using routine to get() lines, faster than parse()
-S32 LLSDParser::parseLines(std::istream& istr, LLSD& data)
-{
-	mCheckLimits = false;
-	mParseLines = true;
-	return doParse(istr, data);
-}
-
-
-int LLSDParser::get(std::istream& istr) const
-{
-	if(mCheckLimits) --mMaxBytesLeft;
-	return istr.get();
-}
-
-std::istream& LLSDParser::get(
-	std::istream& istr,
-	char* s,
-	std::streamsize n,
-	char delim) const
-{
-	istr.get(s, n, delim);
-	if(mCheckLimits) mMaxBytesLeft -= (int)istr.gcount();
-	return istr;
-}
-
-std::istream& LLSDParser::get(
-		std::istream& istr,
-		std::streambuf& sb,
-		char delim) const		
-{
-	istr.get(sb, delim);
-	if(mCheckLimits) mMaxBytesLeft -= (int)istr.gcount();
-	return istr;
-}
-
-std::istream& LLSDParser::ignore(std::istream& istr) const
-{
-	istr.ignore();
-	if(mCheckLimits) --mMaxBytesLeft;
-	return istr;
-}
-
-std::istream& LLSDParser::putback(std::istream& istr, char c) const
-{
-	istr.putback(c);
-	if(mCheckLimits) ++mMaxBytesLeft;
-	return istr;
-}
-
-std::istream& LLSDParser::read(
-	std::istream& istr,
-	char* s,
-	std::streamsize n) const
-{
-	istr.read(s, n);
-	if(mCheckLimits) mMaxBytesLeft -= (int)istr.gcount();
-	return istr;
-}
-
-void LLSDParser::account(S32 bytes) const
-{
-	if(mCheckLimits) mMaxBytesLeft -= bytes;
-}
-
-
-/**
- * LLSDNotationParser
- */
-LLSDNotationParser::LLSDNotationParser()
-{
-}	
-
-// virtual
-LLSDNotationParser::~LLSDNotationParser()
-{ }
-
-// virtual
-S32 LLSDNotationParser::doParse(std::istream& istr, LLSD& data, S32 max_depth) const
-{
-	// map: { string:object, string:object }
-	// array: [ object, object, object ]
-	// undef: !
-	// boolean: true | false | 1 | 0 | T | F | t | f | TRUE | FALSE
-	// integer: i####
-	// real: r####
-	// uuid: u####
-	// string: "g'day" | 'have a "nice" day' | s(size)"raw data"
-	// uri: l"escaped"
-	// date: d"YYYY-MM-DDTHH:MM:SS.FFZ"
-	// binary: b##"ff3120ab1" | b(size)"raw data"
-	char c;
-	c = istr.peek();
-	if (max_depth == 0)
-	{
-		return PARSE_FAILURE;
-	}
-	while(isspace(c))
-	{
-		// pop the whitespace.
-		c = get(istr);
-		c = istr.peek();
-		continue;
-	}
-	if(!istr.good())
-	{
-		return 0;
-	}
-	S32 parse_count = 1;
-	switch(c)
-	{
-	case '{':
-	{
-		S32 child_count = parseMap(istr, data, max_depth - 1);
-		if((child_count == PARSE_FAILURE) || data.isUndefined())
-		{
-			parse_count = PARSE_FAILURE;
-		}
-		else
-		{
-			parse_count += child_count;
-		}
-		if(istr.fail())
-		{
-			LL_INFOS() << "STREAM FAILURE reading map." << LL_ENDL;
-			parse_count = PARSE_FAILURE;
-		}
-		break;
-	}
-
-	case '[':
-	{
-		S32 child_count = parseArray(istr, data, max_depth - 1);
-		if((child_count == PARSE_FAILURE) || data.isUndefined())
-		{
-			parse_count = PARSE_FAILURE;
-		}
-		else
-		{
-			parse_count += child_count;
-		}
-		if(istr.fail())
-		{
-			LL_INFOS() << "STREAM FAILURE reading array." << LL_ENDL;
-			parse_count = PARSE_FAILURE;
-		}
-		break;
-	}
-
-	case '!':
-		c = get(istr);
-		data.clear();
-		break;
-
-	case '0':
-		c = get(istr);
-		data = false;
-		break;
-
-	case 'F':
-	case 'f':
-		ignore(istr);
-		c = istr.peek();
-		if(isalpha(c))
-		{
-			int cnt = deserialize_boolean(
-				istr,
-				data,
-				NOTATION_FALSE_SERIAL,
-				false);
-			if(PARSE_FAILURE == cnt) parse_count = cnt;
-			else account(cnt);
-		}
-		else
-		{
-			data = false;
-		}
-		if(istr.fail())
-		{
-			LL_INFOS() << "STREAM FAILURE reading boolean." << LL_ENDL;
-			parse_count = PARSE_FAILURE;
-		}
-		break;
-
-	case '1':
-		c = get(istr);
-		data = true;
-		break;
-
-	case 'T':
-	case 't':
-		ignore(istr);
-		c = istr.peek();
-		if(isalpha(c))
-		{
-			int cnt = deserialize_boolean(istr,data,NOTATION_TRUE_SERIAL,true);
-			if(PARSE_FAILURE == cnt) parse_count = cnt;
-			else account(cnt);
-		}
-		else
-		{
-			data = true;
-		}
-		if(istr.fail())
-		{
-			LL_INFOS() << "STREAM FAILURE reading boolean." << LL_ENDL;
-			parse_count = PARSE_FAILURE;
-		}
-		break;
-
-	case 'i':
-	{
-		c = get(istr);
-		S32 integer = 0;
-		istr >> integer;
-		data = integer;
-		if(istr.fail())
-		{
-			LL_INFOS() << "STREAM FAILURE reading integer." << LL_ENDL;
-			parse_count = PARSE_FAILURE;
-		}
-		break;
-	}
-
-	case 'r':
-	{
-		c = get(istr);
-		F64 real = 0.0;
-		istr >> real;
-		data = real;
-		if(istr.fail())
-		{
-			LL_INFOS() << "STREAM FAILURE reading real." << LL_ENDL;
-			parse_count = PARSE_FAILURE;
-		}
-		break;
-	}
-
-	case 'u':
-	{
-		c = get(istr);
-		LLUUID id;
-		istr >> id;
-		data = id;
-		if(istr.fail())
-		{
-			LL_INFOS() << "STREAM FAILURE reading uuid." << LL_ENDL;
-			parse_count = PARSE_FAILURE;
-		}
-		break;
-	}
-
-	case '\"':
-	case '\'':
-	case 's':
-		if(!parseString(istr, data))
-		{
-			parse_count = PARSE_FAILURE;
-		}
-		if(istr.fail())
-		{
-			LL_INFOS() << "STREAM FAILURE reading string." << LL_ENDL;
-			parse_count = PARSE_FAILURE;
-		}
-		break;
-
-	case 'l':
-	{
-		c = get(istr); // pop the 'l'
-		c = get(istr); // pop the delimiter
-		std::string str;
-		int cnt = deserialize_string_delim(istr, str, c);
-		if(PARSE_FAILURE == cnt)
-		{
-			parse_count = PARSE_FAILURE;
-		}
-		else
-		{
-			data = LLURI(str);
-			account(cnt);
-		}
-		if(istr.fail())
-		{
-			LL_INFOS() << "STREAM FAILURE reading link." << LL_ENDL;
-			parse_count = PARSE_FAILURE;
-		}
-		break;
-	}
-
-	case 'd':
-	{
-		c = get(istr); // pop the 'd'
-		c = get(istr); // pop the delimiter
-		std::string str;
-		int cnt = deserialize_string_delim(istr, str, c);
-		if(PARSE_FAILURE == cnt)
-		{
-			parse_count = PARSE_FAILURE;
-		}
-		else
-		{
-			data = LLDate(str);
-			account(cnt);
-		}
-		if(istr.fail())
-		{
-			LL_INFOS() << "STREAM FAILURE reading date." << LL_ENDL;
-			parse_count = PARSE_FAILURE;
-		}
-		break;
-	}
-
-	case 'b':
-		if(!parseBinary(istr, data))
-		{
-			parse_count = PARSE_FAILURE;
-		}
-		if(istr.fail())
-		{
-			LL_INFOS() << "STREAM FAILURE reading data." << LL_ENDL;
-			parse_count = PARSE_FAILURE;
-		}
-		break;
-
-	default:
-		parse_count = PARSE_FAILURE;
-		LL_INFOS() << "Unrecognized character while parsing: int(" << (int)c
-			<< ")" << LL_ENDL;
-		break;
-	}
-	if(PARSE_FAILURE == parse_count)
-	{
-		data.clear();
-	}
-	return parse_count;
-}
-
-S32 LLSDNotationParser::parseMap(std::istream& istr, LLSD& map, S32 max_depth) const
-{
-	// map: { string:object, string:object }
-	map = LLSD::emptyMap();
-	S32 parse_count = 0;
-	char c = get(istr);
-	if(c == '{')
-	{
-		// eat commas, white
-		bool found_name = false;
-		std::string name;
-		c = get(istr);
-		while(c != '}' && istr.good())
-		{
-			if(!found_name)
-			{
-				if((c == '\"') || (c == '\'') || (c == 's'))
-				{
-					putback(istr, c);
-					found_name = true;
-					int count = deserialize_string(istr, name, mMaxBytesLeft);
-					if(PARSE_FAILURE == count) return PARSE_FAILURE;
-					account(count);
-				}
-				c = get(istr);
-			}
-			else
-			{
-				if(isspace(c) || (c == ':'))
-				{
-					c = get(istr);
-					continue;
-				}
-				putback(istr, c);
-				LLSD child;
-				S32 count = doParse(istr, child, max_depth);
-				if(count > 0)
-				{
-					// There must be a value for every key, thus
-					// child_count must be greater than 0.
-					parse_count += count;
-					map.insert(name, child);
-				}
-				else
-				{
-					return PARSE_FAILURE;
-				}
-				found_name = false;
-				c = get(istr);
-			}
-		}
-		if(c != '}')
-		{
-			map.clear();
-			return PARSE_FAILURE;
-		}
-	}
-	return parse_count;
-}
-
-S32 LLSDNotationParser::parseArray(std::istream& istr, LLSD& array, S32 max_depth) const
-{
-	// array: [ object, object, object ]
-	array = LLSD::emptyArray();
-	S32 parse_count = 0;
-	char c = get(istr);
-	if(c == '[')
-	{
-		// eat commas, white
-		c = get(istr);
-		while((c != ']') && istr.good())
-		{
-			LLSD child;
-			if(isspace(c) || (c == ','))
-			{
-				c = get(istr);
-				continue;
-			}
-			putback(istr, c);
-			S32 count = doParse(istr, child, max_depth);
-			if(PARSE_FAILURE == count)
-			{
-				return PARSE_FAILURE;
-			}
-			else
-			{
-				parse_count += count;
-				array.append(child);
-			}
-			c = get(istr);
-		}
-		if(c != ']')
-		{
-			return PARSE_FAILURE;
-		}
-	}
-	return parse_count;
-}
-
-bool LLSDNotationParser::parseString(std::istream& istr, LLSD& data) const
-{
-	std::string value;
-	int count = deserialize_string(istr, value, mMaxBytesLeft);
-	if(PARSE_FAILURE == count) return false;
-	account(count);
-	data = value;
-	return true;
-}
-
-bool LLSDNotationParser::parseBinary(std::istream& istr, LLSD& data) const
-{
-	// binary: b##"ff3120ab1"
-	// or: b(len)"..."
-
-	// I want to manually control those values here to make sure the
-	// parser doesn't break when someone changes a constant somewhere
-	// else.
-	const U32 BINARY_BUFFER_SIZE = 256;
-	const U32 STREAM_GET_COUNT = 255;
-
-	// need to read the base out.
-	char buf[BINARY_BUFFER_SIZE];		/* Flawfinder: ignore */
-	get(istr, buf, STREAM_GET_COUNT, '"');
-	char c = get(istr);
-	if(c != '"') return false;
-	if(0 == strncmp("b(", buf, 2))
-	{
-		// We probably have a valid raw binary stream. determine
-		// the size, and read it.
-		S32 len = strtol(buf + 2, NULL, 0);
-		if(mCheckLimits && (len > mMaxBytesLeft)) return false;
-		std::vector<U8> value;
-		if(len)
-		{
-			value.resize(len);
-			account((int)fullread(istr, (char *)&value[0], len));
-		}
-		c = get(istr); // strip off the trailing double-quote
-		data = value;
-	}
-	else if(0 == strncmp("b64", buf, 3))
-	{
-		// *FIX: A bit inefficient, but works for now. To make the
-		// format better, I would need to add a hint into the
-		// serialization format that indicated how long it was.
-		std::stringstream coded_stream;
-		get(istr, *(coded_stream.rdbuf()), '\"');
-		c = get(istr);
-		std::string encoded(coded_stream.str());
-		size_t len = LLBase64::requiredDecryptionSpace(encoded);
-		std::vector<U8> value;
-		if(len)
-		{
-			value.resize(len);
-			len = LLBase64::decode(encoded, &value[0], len);
-			value.resize(len);
-		}
-		data = value;
-	}
-	else if(0 == strncmp("b16", buf, 3))
-	{
-		// yay, base 16. We pop the next character which is either a
-		// double quote or base 16 data. If it's a double quote, we're
-		// done parsing. If it's not, put the data back, and read the
-		// stream until the next double quote.
-		char* read;	 /*Flawfinder: ignore*/
-		U8 byte;
-		U8 byte_buffer[BINARY_BUFFER_SIZE];
-		U8* write;
-		std::vector<U8> value;
-		c = get(istr);
-		while(c != '"')
-		{
-			putback(istr, c);
-			read = buf;
-			write = byte_buffer;
-			get(istr, buf, STREAM_GET_COUNT, '"');
-			c = get(istr);
-			while(*read != '\0')	 /*Flawfinder: ignore*/
-			{
-				byte = hex_as_nybble(*read++);
-				byte = byte << 4;
-				byte |= hex_as_nybble(*read++);
-				*write++ = byte;
-			}
-			// copy the data out of the byte buffer
-			value.insert(value.end(), byte_buffer, write);
-		}
-		data = value;
-	}
-	else
-	{
-		return false;
-	}
-	return true;
-}
-
-
-/**
- * LLSDBinaryParser
- */
-
-// virtual
-S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data, S32 max_depth) const
-{
-/**
- * Undefined: '!'<br>
- * Boolean: '1' for true '0' for false<br>
- * Integer: 'i' + 4 bytes network byte order<br>
- * Real: 'r' + 8 bytes IEEE double<br>
- * UUID: 'u' + 16 byte unsigned integer<br>
- * String: 's' + 4 byte integer size + string<br>
- *  strings also secretly support the notation format
- * Date: 'd' + 8 byte IEEE double for seconds since epoch<br>
- * URI: 'l' + 4 byte integer size + string uri<br>
- * Binary: 'b' + 4 byte integer size + binary data<br>
- * Array: '[' + 4 byte integer size  + all values + ']'<br>
- * Map: '{' + 4 byte integer size  every(key + value) + '}'<br>
- *  map keys are serialized as s + 4 byte integer size + string or in the
- *  notation format.
- */
-	char c;
-	c = get(istr);
-	if(!istr.good())
-	{
-		return 0;
-	}
-	if (max_depth == 0)
-	{
-		return PARSE_FAILURE;
-	}
-	S32 parse_count = 1;
-	switch(c)
-	{
-	case '{':
-	{
-		S32 child_count = parseMap(istr, data, max_depth - 1);
-		if((child_count == PARSE_FAILURE) || data.isUndefined())
-		{
-			parse_count = PARSE_FAILURE;
-		}
-		else
-		{
-			parse_count += child_count;
-		}
-		if(istr.fail())
-		{
-			LL_INFOS() << "STREAM FAILURE reading binary map." << LL_ENDL;
-			parse_count = PARSE_FAILURE;
-		}
-		break;
-	}
-
-	case '[':
-	{
-		S32 child_count = parseArray(istr, data, max_depth - 1);
-		if((child_count == PARSE_FAILURE) || data.isUndefined())
-		{
-			parse_count = PARSE_FAILURE;
-		}
-		else
-		{
-			parse_count += child_count;
-		}
-		if(istr.fail())
-		{
-			LL_INFOS() << "STREAM FAILURE reading binary array." << LL_ENDL;
-			parse_count = PARSE_FAILURE;
-		}
-		break;
-	}
-
-	case '!':
-		data.clear();
-		break;
-
-	case '0':
-		data = false;
-		break;
-
-	case '1':
-		data = true;
-		break;
-
-	case 'i':
-	{
-		U32 value_nbo = 0;
-		read(istr, (char*)&value_nbo, sizeof(U32));	 /*Flawfinder: ignore*/
-		data = (S32)ntohl(value_nbo);
-		if(istr.fail())
-		{
-			LL_INFOS() << "STREAM FAILURE reading binary integer." << LL_ENDL;
-		}
-		break;
-	}
-
-	case 'r':
-	{
-		F64 real_nbo = 0.0;
-		read(istr, (char*)&real_nbo, sizeof(F64));	 /*Flawfinder: ignore*/
-		data = ll_ntohd(real_nbo);
-		if(istr.fail())
-		{
-			LL_INFOS() << "STREAM FAILURE reading binary real." << LL_ENDL;
-		}
-		break;
-	}
-
-	case 'u':
-	{
-		LLUUID id;
-		read(istr, (char*)(&id.mData), UUID_BYTES);	 /*Flawfinder: ignore*/
-		data = id;
-		if(istr.fail())
-		{
-			LL_INFOS() << "STREAM FAILURE reading binary uuid." << LL_ENDL;
-		}
-		break;
-	}
-
-	case '\'':
-	case '"':
-	{
-		std::string value;
-		int cnt = deserialize_string_delim(istr, value, c);
-		if(PARSE_FAILURE == cnt)
-		{
-			parse_count = PARSE_FAILURE;
-		}
-		else
-		{
-			data = value;
-			account(cnt);
-		}
-		if(istr.fail())
-		{
-			LL_INFOS() << "STREAM FAILURE reading binary (notation-style) string."
-				<< LL_ENDL;
-			parse_count = PARSE_FAILURE;
-		}
-		break;
-	}
-
-	case 's':
-	{
-		std::string value;
-		if(parseString(istr, value))
-		{
-			data = value;
-		}
-		else
-		{
-			parse_count = PARSE_FAILURE;
-		}
-		if(istr.fail())
-		{
-			LL_INFOS() << "STREAM FAILURE reading binary string." << LL_ENDL;
-			parse_count = PARSE_FAILURE;
-		}
-		break;
-	}
-
-	case 'l':
-	{
-		std::string value;
-		if(parseString(istr, value))
-		{
-			data = LLURI(value);
-		}
-		else
-		{
-			parse_count = PARSE_FAILURE;
-		}
-		if(istr.fail())
-		{
-			LL_INFOS() << "STREAM FAILURE reading binary link." << LL_ENDL;
-			parse_count = PARSE_FAILURE;
-		}
-		break;
-	}
-
-	case 'd':
-	{
-		F64 real = 0.0;
-		read(istr, (char*)&real, sizeof(F64));	 /*Flawfinder: ignore*/
-		data = LLDate(real);
-		if(istr.fail())
-		{
-			LL_INFOS() << "STREAM FAILURE reading binary date." << LL_ENDL;
-			parse_count = PARSE_FAILURE;
-		}
-		break;
-	}
-
-	case 'b':
-	{
-		// We probably have a valid raw binary stream. determine
-		// the size, and read it.
-		U32 size_nbo = 0;
-		read(istr, (char*)&size_nbo, sizeof(U32));	/*Flawfinder: ignore*/
-		S32 size = (S32)ntohl(size_nbo);
-		if(mCheckLimits && (size > mMaxBytesLeft))
-		{
-			parse_count = PARSE_FAILURE;
-		}
-		else
-		{
-			std::vector<U8> value;
-			if(size > 0)
-			{
-				value.resize(size);
-				account((int)fullread(istr, (char*)&value[0], size));
-			}
-			data = value;
-		}
-		if(istr.fail())
-		{
-			LL_INFOS() << "STREAM FAILURE reading binary." << LL_ENDL;
-			parse_count = PARSE_FAILURE;
-		}
-		break;
-	}
-
-	default:
-		parse_count = PARSE_FAILURE;
-		LL_INFOS() << "Unrecognized character while parsing: int(" << (int)c
-			<< ")" << LL_ENDL;
-		break;
-	}
-	if(PARSE_FAILURE == parse_count)
-	{
-		data.clear();
-	}
-	return parse_count;
-}
-
-S32 LLSDBinaryParser::parseMap(std::istream& istr, LLSD& map, S32 max_depth) const
-{
-	map = LLSD::emptyMap();
-	U32 value_nbo = 0;
-	read(istr, (char*)&value_nbo, sizeof(U32));		 /*Flawfinder: ignore*/
-	S32 size = (S32)ntohl(value_nbo);
-	S32 parse_count = 0;
-	S32 count = 0;
-	char c = get(istr);
-	while(c != '}' && (count < size) && istr.good())
-	{
-		std::string name;
-		switch(c)
-		{
-		case 'k':
-			if(!parseString(istr, name))
-			{
-				return PARSE_FAILURE;
-			}
-			break;
-		case '\'':
-		case '"':
-		{
-			int cnt = deserialize_string_delim(istr, name, c);
-			if(PARSE_FAILURE == cnt) return PARSE_FAILURE;
-			account(cnt);
-			break;
-		}
-		}
-		LLSD child;
-		S32 child_count = doParse(istr, child, max_depth);
-		if(child_count > 0)
-		{
-			// There must be a value for every key, thus child_count
-			// must be greater than 0.
-			parse_count += child_count;
-			map.insert(name, child);
-		}
-		else
-		{
-			return PARSE_FAILURE;
-		}
-		++count;
-		c = get(istr);
-	}
-	if((c != '}') || (count < size))
-	{
-		// Make sure it is correctly terminated and we parsed as many
-		// as were said to be there.
-		return PARSE_FAILURE;
-	}
-	return parse_count;
-}
-
-S32 LLSDBinaryParser::parseArray(std::istream& istr, LLSD& array, S32 max_depth) const
-{
-	array = LLSD::emptyArray();
-	U32 value_nbo = 0;
-	read(istr, (char*)&value_nbo, sizeof(U32));		 /*Flawfinder: ignore*/
-	S32 size = (S32)ntohl(value_nbo);
-
-	// *FIX: This would be a good place to reserve some space in the
-	// array...
-
-	S32 parse_count = 0;
-	S32 count = 0;
-	char c = istr.peek();
-	while((c != ']') && (count < size) && istr.good())
-	{
-		LLSD child;
-		S32 child_count = doParse(istr, child, max_depth);
-		if(PARSE_FAILURE == child_count)
-		{
-			return PARSE_FAILURE;
-		}
-		if(child_count)
-		{
-			parse_count += child_count;
-			array.append(child);
-		}
-		++count;
-		c = istr.peek();
-	}
-	c = get(istr);
-	if((c != ']') || (count < size))
-	{
-		// Make sure it is correctly terminated and we parsed as many
-		// as were said to be there.
-		return PARSE_FAILURE;
-	}
-	return parse_count;
-}
-
-bool LLSDBinaryParser::parseString(
-	std::istream& istr,
-	std::string& value) const
-{
-	// *FIX: This is memory inefficient.
-	U32 value_nbo = 0;
-	read(istr, (char*)&value_nbo, sizeof(U32));		 /*Flawfinder: ignore*/
-	S32 size = (S32)ntohl(value_nbo);
-	if(mCheckLimits && (size > mMaxBytesLeft)) return false;
-	if(size < 0) return false;
-	std::vector<char> buf;
-	if(size)
-	{
-		buf.resize(size);
-		account((int)fullread(istr, &buf[0], size));
-		value.assign(buf.begin(), buf.end());
-	}
-	return true;
-}
-
-
-/**
- * LLSDFormatter
- */
-LLSDFormatter::LLSDFormatter() :
-	mBoolAlpha(false)
-{
-}
-
-// virtual
-LLSDFormatter::~LLSDFormatter()
-{ }
-
-void LLSDFormatter::boolalpha(bool alpha)
-{
-	mBoolAlpha = alpha;
-}
-
-void LLSDFormatter::realFormat(const std::string& format)
-{
-	mRealFormat = format;
-}
-
-void LLSDFormatter::formatReal(LLSD::Real real, std::ostream& ostr) const
-{
-	std::string buffer = llformat(mRealFormat.c_str(), real);
-	ostr << buffer;
-}
-
-/**
- * LLSDNotationFormatter
- */
-LLSDNotationFormatter::LLSDNotationFormatter()
-{
-}
-
-// virtual
-LLSDNotationFormatter::~LLSDNotationFormatter()
-{ }
-
-// static
-std::string LLSDNotationFormatter::escapeString(const std::string& in)
-{
-	std::ostringstream ostr;
-	serialize_string(in, ostr);
-	return ostr.str();
-}
-
-// virtual
-S32 LLSDNotationFormatter::format(const LLSD& data, std::ostream& ostr, U32 options) const
-{
-	S32 rv = format_impl(data, ostr, options, 0);
-	return rv;
-}
-
-S32 LLSDNotationFormatter::format_impl(const LLSD& data, std::ostream& ostr, U32 options, U32 level) const
-{
-	S32 format_count = 1;
-	std::string pre;
-	std::string post;
-
-	if (options & LLSDFormatter::OPTIONS_PRETTY)
-	{
-		for (U32 i = 0; i < level; i++)
-		{
-			pre += "    ";
-		}
-		post = "\n";
-	}
-
-	switch(data.type())
-	{
-	case LLSD::TypeMap:
-	{
-		if (0 != level) ostr << post << pre;
-		ostr << "{";
-		std::string inner_pre;
-		if (options & LLSDFormatter::OPTIONS_PRETTY)
-		{
-			inner_pre = pre + "    ";
-		}
-
-		bool need_comma = false;
-        auto iter = data.beginMap();
-        auto end = data.endMap();
-		for(; iter != end; ++iter)
-		{
-			if(need_comma) ostr << ",";
-			need_comma = true;
-			ostr << post << inner_pre << '\'';
-			serialize_string((*iter).first, ostr);
-			ostr << "':";
-			format_count += format_impl((*iter).second, ostr, options, level + 2);
-		}
-		ostr << post << pre << "}";
-		break;
-	}
-
-	case LLSD::TypeArray:
-	{
-		ostr << post << pre << "[";
-		bool need_comma = false;
-        auto iter = data.beginArray();
-        auto end = data.endArray();
-		for(; iter != end; ++iter)
-		{
-			if(need_comma) ostr << ",";
-			need_comma = true;
-			format_count += format_impl(*iter, ostr, options, level + 1);
-		}
-		ostr << "]";
-		break;
-	}
-
-	case LLSD::TypeUndefined:
-		ostr << "!";
-		break;
-
-	case LLSD::TypeBoolean:
-		if(mBoolAlpha ||
-#if( LL_WINDOWS || __GNUC__ > 2)
-		   (ostr.flags() & std::ios::boolalpha)
-#else
-		   (ostr.flags() & 0x0100)
-#endif
-			)
-		{
-			ostr << (data.asBoolean()
-					 ? NOTATION_TRUE_SERIAL : NOTATION_FALSE_SERIAL);
-		}
-		else
-		{
-			ostr << (data.asBoolean() ? 1 : 0);
-		}
-		break;
-
-	case LLSD::TypeInteger:
-		ostr << "i" << data.asInteger();
-		break;
-
-	case LLSD::TypeReal:
-		ostr << "r";
-		if(mRealFormat.empty())
-		{
-			ostr << data.asReal();
-		}
-		else
-		{
-			formatReal(data.asReal(), ostr);
-		}
-		break;
-
-	case LLSD::TypeUUID:
-		ostr << "u" << data.asUUID();
-		break;
-
-	case LLSD::TypeString:
-		ostr << '\'';
-		serialize_string(data.asStringRef(), ostr);
-		ostr << '\'';
-		break;
-
-	case LLSD::TypeDate:
-		ostr << "d\"" << data.asDate() << "\"";
-		break;
-
-	case LLSD::TypeURI:
-		ostr << "l\"";
-		serialize_string(data.asString(), ostr);
-		ostr << "\"";
-		break;
-
-	case LLSD::TypeBinary:
-	{
-		// *FIX: memory inefficient.
-		const std::vector<U8>& buffer = data.asBinary();
-		ostr << "b(" << buffer.size() << ")\"";
-		if(!buffer.empty())
-		{
-			if (options & LLSDFormatter::OPTIONS_PRETTY_BINARY)
-			{
-				std::ios_base::fmtflags old_flags = ostr.flags();
-				ostr.setf( std::ios::hex, std::ios::basefield );
-				ostr << "0x";
-				for (unsigned char i : buffer)
-                {
-					ostr << static_cast<int>(i);
-				}
-				ostr.flags(old_flags);
-			}
-			else
-			{
-				ostr.write(reinterpret_cast<const char*>(&buffer[0]), buffer.size());
-			}
-		}
-		ostr << "\"";
-		break;
-	}
-
-	default:
-		// *NOTE: This should never happen.
-		ostr << "!";
-		break;
-	}
-	return format_count;
-}
-
-
-/**
- * LLSDBinaryFormatter
- */
-LLSDBinaryFormatter::LLSDBinaryFormatter()
-{
-}
-
-// virtual
-LLSDBinaryFormatter::~LLSDBinaryFormatter()
-{ }
-
-// virtual
-S32 LLSDBinaryFormatter::format(const LLSD& data, std::ostream& ostr, U32 options) const
-{
-	S32 format_count = 1;
-	switch(data.type())
-	{
-	case LLSD::TypeMap:
-	{
-		ostr.put('{');
-		U32 size_nbo = htonl(data.size());
-		ostr.write(reinterpret_cast<const char*>(&size_nbo), sizeof(U32));
-        auto iter = data.beginMap();
-        auto end = data.endMap();
-		for(; iter != end; ++iter)
-		{
-			ostr.put('k');
-			formatString((*iter).first, ostr);
-			format_count += format((*iter).second, ostr);
-		}
-		ostr.put('}');
-		break;
-	}
-
-	case LLSD::TypeArray:
-	{
-		ostr.put('[');
-		U32 size_nbo = htonl(data.size());
-		ostr.write(reinterpret_cast<const char*>(&size_nbo), sizeof(U32));
-        auto iter = data.beginArray();
-        auto end = data.endArray();
-		for(; iter != end; ++iter)
-		{
-			format_count += format(*iter, ostr);
-		}
-		ostr.put(']');
-		break;
-	}
-
-	case LLSD::TypeUndefined:
-		ostr.put('!');
-		break;
-
-	case LLSD::TypeBoolean:
-		if(data.asBoolean()) ostr.put(BINARY_TRUE_SERIAL);
-		else ostr.put(BINARY_FALSE_SERIAL);
-		break;
-
-	case LLSD::TypeInteger:
-	{
-		ostr.put('i');
-		U32 value_nbo = htonl(data.asInteger());
-		ostr.write((const char*)(&value_nbo), sizeof(U32));
-		break;
-	}
-
-	case LLSD::TypeReal:
-	{
-		ostr.put('r');
-		F64 value_nbo = ll_htond(data.asReal());
-		ostr.write((const char*)(&value_nbo), sizeof(F64));
-		break;
-	}
-
-	case LLSD::TypeUUID:
-	{
-		ostr.put('u');
-		LLUUID temp = data.asUUID();
-		ostr.write((const char*)(&(temp.mData)), UUID_BYTES);
-		break;
-	}
-
-	case LLSD::TypeString:
-		ostr.put('s');
-		formatString(data.asStringRef(), ostr);
-		break;
-
-	case LLSD::TypeDate:
-	{
-		ostr.put('d');
-		F64 value = data.asReal();
-		ostr.write((const char*)(&value), sizeof(F64));
-		break;
-	}
-
-	case LLSD::TypeURI:
-		ostr.put('l');
-		formatString(data.asString(), ostr);
-		break;
-
-	case LLSD::TypeBinary:
-	{
-		ostr.put('b');
-		const std::vector<U8>& buffer = data.asBinary();
-		U32 size_nbo = htonl(buffer.size());
-		ostr.write((const char*)(&size_nbo), sizeof(U32));
-		if(!buffer.empty()) ostr.write((const char*)&buffer[0], buffer.size());
-		break;
-	}
-
-	default:
-		// *NOTE: This should never happen.
-		ostr.put('!');
-		break;
-	}
-	return format_count;
-}
-
-void LLSDBinaryFormatter::formatString(
-	const std::string& string,
-	std::ostream& ostr) const
-{
-	U32 size_nbo = htonl(string.size());
-	ostr.write((const char*)(&size_nbo), sizeof(U32));
-	ostr.write(string.c_str(), string.size());
-}
-
-/**
- * local functions
- */
-int deserialize_string(std::istream& istr, std::string& value, S32 max_bytes)
-{
-	int c = istr.get();
-	if(istr.fail())
-	{
-		// No data in stream, bail out but mention the character we
-		// grabbed.
-		return LLSDParser::PARSE_FAILURE;
-	}
-
-	int rv = LLSDParser::PARSE_FAILURE;
-	switch(c)
-	{
-	case '\'':
-	case '"':
-		rv = deserialize_string_delim(istr, value, c);
-		break;
-	case 's':
-		// technically, less than max_bytes, but this is just meant to
-		// catch egregious protocol errors. parse errors will be
-		// caught in the case of incorrect counts.
-		rv = deserialize_string_raw(istr, value, max_bytes);
-		break;
-	default:
-		break;
-	}
-	if(LLSDParser::PARSE_FAILURE == rv) return rv;
-	return rv + 1; // account for the character grabbed at the top.
-}
-
-int deserialize_string_delim(
-	std::istream& istr,
-	std::string& value,
-	char delim)
-{
-	std::ostringstream write_buffer;
-	bool found_escape = false;
-	bool found_hex = false;
-	bool found_digit = false;
-	U8 byte = 0;
-	int count = 0;
-
-	while (true)
-	{
-		int next_byte = istr.get();
-		++count;
-
-		if(istr.fail())
-		{
-			// If our stream is empty, break out
-			value = write_buffer.str();
-			return LLSDParser::PARSE_FAILURE;
-		}
-
-		char next_char = (char)next_byte; // Now that we know it's not EOF
-		
-		if(found_escape)
-		{
-			// next character(s) is a special sequence.
-			if(found_hex)
-			{
-				if(found_digit)
-				{
-					found_digit = false;
-					found_hex = false;
-					found_escape = false;
-					byte = byte << 4;
-					byte |= hex_as_nybble(next_char);
-					write_buffer << byte;
-					byte = 0;
-				}
-				else
-				{
-					// next character is the first nybble of
-					//
-					found_digit = true;
-					byte = hex_as_nybble(next_char);
-				}
-			}
-			else if(next_char == 'x')
-			{
-				found_hex = true;
-			}
-			else
-			{
-				switch(next_char)
-				{
-				case 'a':
-					write_buffer << '\a';
-					break;
-				case 'b':
-					write_buffer << '\b';
-					break;
-				case 'f':
-					write_buffer << '\f';
-					break;
-				case 'n':
-					write_buffer << '\n';
-					break;
-				case 'r':
-					write_buffer << '\r';
-					break;
-				case 't':
-					write_buffer << '\t';
-					break;
-				case 'v':
-					write_buffer << '\v';
-					break;
-				default:
-					write_buffer << next_char;
-					break;
-				}
-				found_escape = false;
-			}
-		}
-		else if(next_char == '\\')
-		{
-			found_escape = true;
-		}
-		else if(next_char == delim)
-		{
-			break;
-		}
-		else
-		{
-			write_buffer << next_char;
-		}
-	}
-
-	value = write_buffer.str();
-	return count;
-}
-
-int deserialize_string_raw(
-	std::istream& istr,
-	std::string& value,
-	S32 max_bytes)
-{
-	int count = 0;
-	const S32 BUF_LEN = 20;
-	char buf[BUF_LEN];		/* Flawfinder: ignore */
-	istr.get(buf, BUF_LEN - 1, ')');
-	count += (int)istr.gcount();
-	int c = istr.get();
-	c = istr.get();
-	count += 2;
-	if(((c == '"') || (c == '\'')) && (buf[0] == '('))
-	{
-		// We probably have a valid raw string. determine
-		// the size, and read it.
-		// *FIX: This is memory inefficient.
-		S32 len = strtol(buf + 1, NULL, 0);
-		if((max_bytes>0)&&(len>max_bytes)) return LLSDParser::PARSE_FAILURE;
-		std::vector<char> buf2;
-		if(len)
-		{
-			buf2.resize(len);
-			count += (int)fullread(istr, (char *)&buf2[0], len);
-			value.assign(buf2.begin(), buf2.end());
-		}
-		c = istr.get();
-		++count;
-		if(!((c == '"') || (c == '\'')))
-		{
-			return LLSDParser::PARSE_FAILURE;
-		}
-	}
-	else
-	{
-		return LLSDParser::PARSE_FAILURE;
-	}
-	return count;
-}
-
-static const char* NOTATION_STRING_CHARACTERS[256] =
-{
-	"\\x00",	// 0
-	"\\x01",	// 1
-	"\\x02",	// 2
-	"\\x03",	// 3
-	"\\x04",	// 4
-	"\\x05",	// 5
-	"\\x06",	// 6
-	"\\a",		// 7
-	"\\b",		// 8
-	"\\t",		// 9
-	"\\n",		// 10
-	"\\v",		// 11
-	"\\f",		// 12
-	"\\r",		// 13
-	"\\x0e",	// 14
-	"\\x0f",	// 15
-	"\\x10",	// 16
-	"\\x11",	// 17
-	"\\x12",	// 18
-	"\\x13",	// 19
-	"\\x14",	// 20
-	"\\x15",	// 21
-	"\\x16",	// 22
-	"\\x17",	// 23
-	"\\x18",	// 24
-	"\\x19",	// 25
-	"\\x1a",	// 26
-	"\\x1b",	// 27
-	"\\x1c",	// 28
-	"\\x1d",	// 29
-	"\\x1e",	// 30
-	"\\x1f",	// 31
-	" ",		// 32
-	"!",		// 33
-	"\"",		// 34
-	"#",		// 35
-	"$",		// 36
-	"%",		// 37
-	"&",		// 38
-	"\\'",		// 39
-	"(",		// 40
-	")",		// 41
-	"*",		// 42
-	"+",		// 43
-	",",		// 44
-	"-",		// 45
-	".",		// 46
-	"/",		// 47
-	"0",		// 48
-	"1",		// 49
-	"2",		// 50
-	"3",		// 51
-	"4",		// 52
-	"5",		// 53
-	"6",		// 54
-	"7",		// 55
-	"8",		// 56
-	"9",		// 57
-	":",		// 58
-	";",		// 59
-	"<",		// 60
-	"=",		// 61
-	">",		// 62
-	"?",		// 63
-	"@",		// 64
-	"A",		// 65
-	"B",		// 66
-	"C",		// 67
-	"D",		// 68
-	"E",		// 69
-	"F",		// 70
-	"G",		// 71
-	"H",		// 72
-	"I",		// 73
-	"J",		// 74
-	"K",		// 75
-	"L",		// 76
-	"M",		// 77
-	"N",		// 78
-	"O",		// 79
-	"P",		// 80
-	"Q",		// 81
-	"R",		// 82
-	"S",		// 83
-	"T",		// 84
-	"U",		// 85
-	"V",		// 86
-	"W",		// 87
-	"X",		// 88
-	"Y",		// 89
-	"Z",		// 90
-	"[",		// 91
-	"\\\\",		// 92
-	"]",		// 93
-	"^",		// 94
-	"_",		// 95
-	"`",		// 96
-	"a",		// 97
-	"b",		// 98
-	"c",		// 99
-	"d",		// 100
-	"e",		// 101
-	"f",		// 102
-	"g",		// 103
-	"h",		// 104
-	"i",		// 105
-	"j",		// 106
-	"k",		// 107
-	"l",		// 108
-	"m",		// 109
-	"n",		// 110
-	"o",		// 111
-	"p",		// 112
-	"q",		// 113
-	"r",		// 114
-	"s",		// 115
-	"t",		// 116
-	"u",		// 117
-	"v",		// 118
-	"w",		// 119
-	"x",		// 120
-	"y",		// 121
-	"z",		// 122
-	"{",		// 123
-	"|",		// 124
-	"}",		// 125
-	"~",		// 126
-	"\\x7f",	// 127
-	"\\x80",	// 128
-	"\\x81",	// 129
-	"\\x82",	// 130
-	"\\x83",	// 131
-	"\\x84",	// 132
-	"\\x85",	// 133
-	"\\x86",	// 134
-	"\\x87",	// 135
-	"\\x88",	// 136
-	"\\x89",	// 137
-	"\\x8a",	// 138
-	"\\x8b",	// 139
-	"\\x8c",	// 140
-	"\\x8d",	// 141
-	"\\x8e",	// 142
-	"\\x8f",	// 143
-	"\\x90",	// 144
-	"\\x91",	// 145
-	"\\x92",	// 146
-	"\\x93",	// 147
-	"\\x94",	// 148
-	"\\x95",	// 149
-	"\\x96",	// 150
-	"\\x97",	// 151
-	"\\x98",	// 152
-	"\\x99",	// 153
-	"\\x9a",	// 154
-	"\\x9b",	// 155
-	"\\x9c",	// 156
-	"\\x9d",	// 157
-	"\\x9e",	// 158
-	"\\x9f",	// 159
-	"\\xa0",	// 160
-	"\\xa1",	// 161
-	"\\xa2",	// 162
-	"\\xa3",	// 163
-	"\\xa4",	// 164
-	"\\xa5",	// 165
-	"\\xa6",	// 166
-	"\\xa7",	// 167
-	"\\xa8",	// 168
-	"\\xa9",	// 169
-	"\\xaa",	// 170
-	"\\xab",	// 171
-	"\\xac",	// 172
-	"\\xad",	// 173
-	"\\xae",	// 174
-	"\\xaf",	// 175
-	"\\xb0",	// 176
-	"\\xb1",	// 177
-	"\\xb2",	// 178
-	"\\xb3",	// 179
-	"\\xb4",	// 180
-	"\\xb5",	// 181
-	"\\xb6",	// 182
-	"\\xb7",	// 183
-	"\\xb8",	// 184
-	"\\xb9",	// 185
-	"\\xba",	// 186
-	"\\xbb",	// 187
-	"\\xbc",	// 188
-	"\\xbd",	// 189
-	"\\xbe",	// 190
-	"\\xbf",	// 191
-	"\\xc0",	// 192
-	"\\xc1",	// 193
-	"\\xc2",	// 194
-	"\\xc3",	// 195
-	"\\xc4",	// 196
-	"\\xc5",	// 197
-	"\\xc6",	// 198
-	"\\xc7",	// 199
-	"\\xc8",	// 200
-	"\\xc9",	// 201
-	"\\xca",	// 202
-	"\\xcb",	// 203
-	"\\xcc",	// 204
-	"\\xcd",	// 205
-	"\\xce",	// 206
-	"\\xcf",	// 207
-	"\\xd0",	// 208
-	"\\xd1",	// 209
-	"\\xd2",	// 210
-	"\\xd3",	// 211
-	"\\xd4",	// 212
-	"\\xd5",	// 213
-	"\\xd6",	// 214
-	"\\xd7",	// 215
-	"\\xd8",	// 216
-	"\\xd9",	// 217
-	"\\xda",	// 218
-	"\\xdb",	// 219
-	"\\xdc",	// 220
-	"\\xdd",	// 221
-	"\\xde",	// 222
-	"\\xdf",	// 223
-	"\\xe0",	// 224
-	"\\xe1",	// 225
-	"\\xe2",	// 226
-	"\\xe3",	// 227
-	"\\xe4",	// 228
-	"\\xe5",	// 229
-	"\\xe6",	// 230
-	"\\xe7",	// 231
-	"\\xe8",	// 232
-	"\\xe9",	// 233
-	"\\xea",	// 234
-	"\\xeb",	// 235
-	"\\xec",	// 236
-	"\\xed",	// 237
-	"\\xee",	// 238
-	"\\xef",	// 239
-	"\\xf0",	// 240
-	"\\xf1",	// 241
-	"\\xf2",	// 242
-	"\\xf3",	// 243
-	"\\xf4",	// 244
-	"\\xf5",	// 245
-	"\\xf6",	// 246
-	"\\xf7",	// 247
-	"\\xf8",	// 248
-	"\\xf9",	// 249
-	"\\xfa",	// 250
-	"\\xfb",	// 251
-	"\\xfc",	// 252
-	"\\xfd",	// 253
-	"\\xfe",	// 254
-	"\\xff"		// 255
-};
-
-void serialize_string(const std::string& value, std::ostream& str)
-{
-	std::string::const_iterator it = value.begin();
-	std::string::const_iterator end = value.end();
-	U8 c;
-	for(; it != end; ++it)
-	{
-		c = (U8)(*it);
-		str << NOTATION_STRING_CHARACTERS[c];
-	}
-}
-
-int deserialize_boolean(
-	std::istream& istr,
-	LLSD& data,
-	const std::string& compare,
-	bool value)
-{
-	//
-	// this method is a little goofy, because it gets the stream at
-	// the point where the t or f has already been
-	// consumed. Basically, parse for a patch to the string passed in
-	// starting at index 1. If it's a match:
-	//  * assign data to value
-	//  * return the number of bytes read
-	// otherwise:
-	//  * set data to LLSD::null
-	//  * return LLSDParser::PARSE_FAILURE (-1)
-	//
-	int bytes_read = 0;
-	std::string::size_type ii = 0;
-	char c = istr.peek();
-	while((++ii < compare.size())
-		  && (tolower(c) == (int)compare[ii])
-		  && istr.good())
-	{
-		istr.ignore();
-		++bytes_read;
-		c = istr.peek();
-	}
-	if(compare.size() != ii)
-	{
-		data.clear();
-		return LLSDParser::PARSE_FAILURE;
-	}
-	data = value;
-	return bytes_read;
-}
-
-std::ostream& operator<<(std::ostream& s, const LLSD& llsd)
-{
-	s << LLSDNotationStreamer(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)
-	{
-		LL_WARNS() << "Failed to compress LLSD block." << LL_ENDL;
-		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)
-			{
-				free(output);
-				LL_WARNS() << "Failed to compress LLSD block." << LL_ENDL;
-				return std::string();
-			}
-
-			have = CHUNK-strm.avail_out;
-			U8* new_output = (U8*) realloc(output, cur_size+have);
-			if (new_output == NULL)
-			{
-				LL_WARNS() << "Failed to compress LLSD block: can't reallocate memory, current size: " << cur_size << " bytes; requested " << cur_size + have << " bytes." << LL_ENDL;
-				deflateEnd(&strm);
-				if (output)
-				{
-					free(output);
-				}
-				return std::string();
-			}
-			output = new_output;
-			memcpy(output+cur_size, out, have);
-			cur_size += have;
-		}
-		else 
-		{
-			free(output);
-			LL_WARNS() << "Failed to compress LLSD block." << LL_ENDL;
-			return std::string();
-		}
-	}
-	while (ret == Z_OK);
-
-	std::string::size_type size = cur_size;
-
-	std::string result((char*) output, size);
-	deflateEnd(&strm);
-	free(output);
-
-	return result;
-}
-
-// <alchemy>
-//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
-LLUZipHelper::EZipRresult LLUZipHelper::unzip_llsd(LLSD& data, std::istream& is, S32 size)
-{
-	std::unique_ptr<U8 []> in;
-	try
-	{
-		in = std::make_unique<U8 []>(size);
-	}
-	catch (const std::bad_alloc&)
-	{
-		return ZR_MEM_ERROR;
-	}
-	is.read((char*)in.get(), size);
-
-	return unzip_llsd(data, in.get(), size);
-}
-
-LLUZipHelper::EZipRresult LLUZipHelper::unzip_llsd(LLSD& data, U8* in, S32 size)
-{
-	U8* result = NULL;
-	U32 cur_size = 0;
-	z_stream strm;
-		
-	const U32 CHUNK = 65536;
-
-	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);
-		
-		switch (ret)
-		{
-		case Z_NEED_DICT:
-			ret = Z_DATA_ERROR;
-		case Z_DATA_ERROR:
-		case Z_MEM_ERROR:
-		case Z_STREAM_ERROR:
-			inflateEnd(&strm);
-			free(result);
-			return ZR_MEM_ERROR;
-			break;
-		}
-
-		U32 have = CHUNK-strm.avail_out;
-
-		U8* new_result = (U8*)realloc(result, cur_size + have);
-		if (new_result == NULL)
-		{
-			LL_WARNS() << "Failed to unzip LLSD block: can't reallocate memory, current size: " << cur_size << " bytes; requested " << cur_size + have << " bytes." << LL_ENDL;
-			inflateEnd(&strm);
-			if (result)
-			{
-				free(result);
-			}
-			return ZR_MEM_ERROR;
-		}
-		result = new_result;
-		memcpy(result+cur_size, out, have);
-		cur_size += have;
-
-	} while (ret == Z_OK);
-
-	inflateEnd(&strm);
-
-	if (ret != Z_STREAM_END)
-	{
-		free(result);
-		return ZR_DATA_ERROR;
-	}
-
-	//result now points to the decompressed LLSD block
-	{
-		char* result_ptr = strip_deprecated_header((char*)result, cur_size);
-
-		boost::iostreams::stream<boost::iostreams::array_source> istrm(result_ptr, cur_size);
-		
-		if (!LLSDSerialize::fromBinary(data, istrm, cur_size, UNZIP_LLSD_MAX_DEPTH))
-		{
-			LL_WARNS() << "Failed to unzip LLSD block" << LL_ENDL;
-			free(result);
-			return ZR_PARSE_ERROR;
-		}
-	}
-
-	free(result);
-	return ZR_OK;
-}
-
-//This unzip function will only work with a gzip header and trailer - while the contents
-//of the actual compressed data is the same for either format (gzip vs zlib ), the headers
-//and trailers are different for the formats.
-U8* unzip_llsdNavMesh(bool& valid, unsigned int& outsize, std::istream& is, S32 size)
-{
-	if (size == 0)
-	{
-		LL_WARNS() << "No data to unzip." << LL_ENDL;
-		return NULL;
-	}
-	auto in = std::make_unique<U8[]>(size);
-	is.read((char*)in.get(), size);
-	return unzip_llsdNavMesh(valid, outsize, in.get(), size);
-}
-
-U8* unzip_llsdNavMesh( bool& valid, unsigned int& outsize, U8* in, S32 size )
-{
-	if (size == 0)
-	{
-		LL_WARNS() << "No data to unzip." << LL_ENDL;
-		return NULL;
-	}
-	U8* result = NULL;
-	U32 cur_size = 0;
-	z_stream strm;
-		
-	const U32 CHUNK = 0x4000;
-
-	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 = inflateInit2(&strm,  windowBits | ENABLE_ZLIB_GZIP );
-	do
-	{
-		strm.avail_out = CHUNK;
-		strm.next_out = out;
-		ret = inflate(&strm, Z_NO_FLUSH);
-		switch (ret)
-		{
-		case Z_NEED_DICT:
-			ret = Z_DATA_ERROR;
-		case Z_DATA_ERROR:
-		case Z_MEM_ERROR:
-		case Z_STREAM_ERROR:
-			inflateEnd(&strm);
-			free(result);
-			valid = false;
-			return NULL;
-		}
-		U32 have = CHUNK-strm.avail_out;
-
-		U8* new_result = (U8*) realloc(result, cur_size + have);
-		if (new_result == NULL)
-		{
-			LL_WARNS() << "Failed to unzip LLSD NavMesh block: can't reallocate memory, current size: " << cur_size
-				<< " bytes; requested " << cur_size + have
-				<< " bytes; total syze: ." << size << " bytes."
-				<< LL_ENDL;
-			inflateEnd(&strm);
-			if (result)
-			{
-				free(result);
-			}
-			valid = false;
-			return NULL;
-		}
-		result = new_result;
-		memcpy(result+cur_size, out, have);
-		cur_size += have;
-
-	} while (ret == Z_OK);
-
-	inflateEnd(&strm);
-
-	if (ret != Z_STREAM_END)
-	{
-		free(result);
-		valid = false;
-		return NULL;
-	}
-
-	//result now points to the decompressed LLSD block
-	{
-		outsize= cur_size;
-		valid = true;		
-	}
-
-	return result;
-}
-
-char* strip_deprecated_header(char* in, U32& cur_size, U32* header_size)
-{
-	const char* deprecated_header = "<? LLSD/Binary ?>";
-	constexpr size_t deprecated_header_size = 17;
-
-	if (cur_size > deprecated_header_size
-		&& memcmp(in, deprecated_header, deprecated_header_size) == 0)
-	{
-		in = in + deprecated_header_size;
-		cur_size = cur_size - deprecated_header_size;
-		if (header_size)
-		{
-			*header_size = deprecated_header_size + 1;
-		}
-	}
-
-	return in;
-}
-// </alchemy>
-
+/** 
+ * @file llsdserialize.cpp
+ * @author Phoenix
+ * @date 2006-03-05
+ * @brief Implementation of LLSD parsers and formatters
+ *
+ * $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 "llsdserialize.h"
+#include "llwin32headerslean.h"
+#include "llpointer.h"
+#include "llstreamtools.h" // for fullread
+#include "llbase64.h"
+
+#include <iostream>
+
+#include <boost/iostreams/device/array.hpp>
+#include <boost/iostreams/stream.hpp>
+
+#ifdef LL_USESYSTEMLIBS
+# 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
+
+#include "lldate.h"
+#include "llsd.h"
+#include "llstring.h"
+#include "lluri.h"
+
+// File constants
+static const int MAX_HDR_LEN = 20;
+static const S32 UNZIP_LLSD_MAX_DEPTH = 96;
+static const char LEGACY_NON_HEADER[] = "<llsd>";
+const std::string LLSD_BINARY_HEADER("LLSD/Binary");
+const std::string LLSD_XML_HEADER("LLSD/XML");
+
+//used to deflate a gzipped asset (currently used for navmeshes)
+#define windowBits 15
+#define ENABLE_ZLIB_GZIP 32
+
+/**
+ * LLSDSerialize
+ */
+
+// static
+void LLSDSerialize::serialize(const LLSD& sd, std::ostream& str, ELLSD_Serialize type, U32 options)
+{
+	LLPointer<LLSDFormatter> f = NULL;
+
+	switch (type)
+	{
+	case LLSD_BINARY:
+		str << "<? " << LLSD_BINARY_HEADER << " ?>\n";
+		f = new LLSDBinaryFormatter;
+		break;
+
+	case LLSD_XML:
+		str << "<? " << LLSD_XML_HEADER << " ?>\n";
+		f = new LLSDXMLFormatter;
+		break;
+
+	default:
+		LL_WARNS() << "serialize request for unknown ELLSD_Serialize" << LL_ENDL;
+	}
+
+	if (f.notNull())
+	{
+		f->format(sd, str, options);
+	}
+}
+
+// static
+bool LLSDSerialize::deserialize(LLSD& sd, std::istream& str, S32 max_bytes)
+{
+	LLPointer<LLSDParser> p = NULL;
+	char hdr_buf[MAX_HDR_LEN + 1] = ""; /* Flawfinder: ignore */
+	int i;
+	int inbuf = 0;
+	bool legacy_no_header = false;
+	bool fail_if_not_legacy = false;
+	std::string header;
+
+	/*
+	 * Get the first line before anything.
+	 */
+	str.get(hdr_buf, MAX_HDR_LEN, '\n');
+	if (str.fail())
+	{
+		str.clear();
+		fail_if_not_legacy = true;
+	}
+
+	if (!strnicmp(LEGACY_NON_HEADER, hdr_buf, strlen(LEGACY_NON_HEADER))) /* Flawfinder: ignore */
+	{
+		legacy_no_header = true;
+		inbuf = (int)str.gcount();
+	}
+	else
+	{
+		if (fail_if_not_legacy)
+			goto fail;
+		/*
+		* Remove the newline chars
+		*/
+		for (i = 0; i < MAX_HDR_LEN; i++)
+		{
+			if (hdr_buf[i] == 0 || hdr_buf[i] == '\r' ||
+				hdr_buf[i] == '\n')
+			{
+				hdr_buf[i] = 0;
+				break;
+			}
+		}
+		header = hdr_buf;
+
+		std::string::size_type start = header.find_first_not_of("<? ");
+		std::string::size_type end = std::string::npos;
+		if (start != std::string::npos)
+		{
+			end = header.find_first_of(" ?", start);
+		}
+		if ((start == std::string::npos) || (end == std::string::npos))
+			goto fail;
+
+		header = header.substr(start, end - start);
+		ws(str);
+	}
+	/*
+	 * Create the parser as appropriate
+	 */
+	if (legacy_no_header)
+	{	// Create a LLSD XML parser, and parse the first chunk read above
+		LLSDXMLParser* x = new LLSDXMLParser();
+		x->parsePart(hdr_buf, inbuf);	// Parse the first part that was already read
+		x->parseLines(str, sd);			// Parse the rest of it
+		delete x;
+		return true;
+	}
+
+	if (header == LLSD_BINARY_HEADER)
+	{
+		p = new LLSDBinaryParser;
+	}
+	else if (header == LLSD_XML_HEADER)
+	{
+		p = new LLSDXMLParser;
+	}
+	else
+	{
+		LL_WARNS() << "deserialize request for unknown ELLSD_Serialize" << LL_ENDL;
+	}
+
+	if (p.notNull())
+	{
+		p->parse(str, sd, max_bytes);
+		return true;
+	}
+
+fail:
+	LL_WARNS() << "deserialize LLSD parse failure" << LL_ENDL;
+	return false;
+}
+
+/**
+ * Endian handlers
+ */
+#if LL_BIG_ENDIAN
+U64 ll_htonll(U64 hostlonglong) { return hostlonglong; }
+U64 ll_ntohll(U64 netlonglong) { return netlonglong; }
+F64 ll_htond(F64 hostlonglong) { return hostlonglong; }
+F64 ll_ntohd(F64 netlonglong) { return netlonglong; }
+#else
+// I read some comments one a indicating that doing an integer add
+// here would be faster than a bitwise or. For now, the or has
+// programmer clarity, since the intended outcome matches the
+// operation.
+U64 ll_htonll(U64 hostlonglong)
+{
+	return ((U64)(htonl((U32)((hostlonglong >> 32) & 0xFFFFFFFF))) |
+			((U64)(htonl((U32)(hostlonglong & 0xFFFFFFFF))) << 32));
+}
+U64 ll_ntohll(U64 netlonglong)
+{
+	return ((U64)(ntohl((U32)((netlonglong >> 32) & 0xFFFFFFFF))) |
+			((U64)(ntohl((U32)(netlonglong & 0xFFFFFFFF))) << 32));
+}
+union LLEndianSwapper
+{
+	F64 d;
+	U64 i;
+};
+F64 ll_htond(F64 hostdouble)
+{
+	LLEndianSwapper tmp;
+	tmp.d = hostdouble;
+	tmp.i = ll_htonll(tmp.i);
+	return tmp.d;
+}
+F64 ll_ntohd(F64 netdouble)
+{
+	LLEndianSwapper tmp;
+	tmp.d = netdouble;
+	tmp.i = ll_ntohll(tmp.i);
+	return tmp.d;
+}
+#endif
+
+/**
+ * Local functions.
+ */
+/**
+ * @brief Figure out what kind of string it is (raw or delimited) and handoff.
+ *
+ * @param istr The stream to read from.
+ * @param value [out] The string which was found.
+ * @param max_bytes The maximum possible length of the string. Passing in
+ * a negative value will skip this check.
+ * @return Returns number of bytes read off of the stream. Returns
+ * PARSE_FAILURE (-1) on failure.
+ */
+int deserialize_string(std::istream& istr, std::string& value, S32 max_bytes);
+
+/**
+ * @brief Parse a delimited string. 
+ *
+ * @param istr The stream to read from, with the delimiter already popped.
+ * @param value [out] The string which was found.
+ * @param d The delimiter to use.
+ * @return Returns number of bytes read off of the stream. Returns
+ * PARSE_FAILURE (-1) on failure.
+ */
+int deserialize_string_delim(std::istream& istr, std::string& value, char d);
+
+/**
+ * @brief Read a raw string off the stream.
+ *
+ * @param istr The stream to read from, with the (len) parameter
+ * leading the stream.
+ * @param value [out] The string which was found.
+ * @param d The delimiter to use.
+ * @param max_bytes The maximum possible length of the string. Passing in
+ * a negative value will skip this check.
+ * @return Returns number of bytes read off of the stream. Returns
+ * PARSE_FAILURE (-1) on failure.
+ */
+int deserialize_string_raw(
+	std::istream& istr,
+	std::string& value,
+	S32 max_bytes);
+
+/**
+ * @brief helper method for dealing with the different notation boolean format.
+ *
+ * @param istr The stream to read from with the leading character stripped.
+ * @param data [out] the result of the parse.
+ * @param compare The string to compare the boolean against
+ * @param vale The value to assign to data if the parse succeeds.
+ * @return Returns number of bytes read off of the stream. Returns
+ * PARSE_FAILURE (-1) on failure.
+ */
+int deserialize_boolean(
+	std::istream& istr,
+	LLSD& data,
+	const std::string& compare,
+	bool value);
+
+/**
+ * @brief Do notation escaping of a string to an ostream.
+ *
+ * @param value The string to escape and serialize
+ * @param str The stream to serialize to.
+ */
+void serialize_string(const std::string& value, std::ostream& str);
+
+
+/**
+ * Local constants.
+ */
+static const std::string NOTATION_TRUE_SERIAL("true");
+static const std::string NOTATION_FALSE_SERIAL("false");
+
+static const char BINARY_TRUE_SERIAL = '1';
+static const char BINARY_FALSE_SERIAL = '0';
+
+
+/**
+ * LLSDParser
+ */
+LLSDParser::LLSDParser()
+	: mCheckLimits(true), mMaxBytesLeft(0), mParseLines(false)
+{
+}
+
+// virtual
+LLSDParser::~LLSDParser()
+{ }
+
+S32 LLSDParser::parse(std::istream& istr, LLSD& data, S32 max_bytes, S32 max_depth)
+{
+	mCheckLimits = (LLSDSerialize::SIZE_UNLIMITED == max_bytes) ? false : true;
+	mMaxBytesLeft = max_bytes;
+	return doParse(istr, data, max_depth);
+}
+
+
+// Parse using routine to get() lines, faster than parse()
+S32 LLSDParser::parseLines(std::istream& istr, LLSD& data)
+{
+	mCheckLimits = false;
+	mParseLines = true;
+	return doParse(istr, data);
+}
+
+
+int LLSDParser::get(std::istream& istr) const
+{
+	if(mCheckLimits) --mMaxBytesLeft;
+	return istr.get();
+}
+
+std::istream& LLSDParser::get(
+	std::istream& istr,
+	char* s,
+	std::streamsize n,
+	char delim) const
+{
+	istr.get(s, n, delim);
+	if(mCheckLimits) mMaxBytesLeft -= (int)istr.gcount();
+	return istr;
+}
+
+std::istream& LLSDParser::get(
+		std::istream& istr,
+		std::streambuf& sb,
+		char delim) const		
+{
+	istr.get(sb, delim);
+	if(mCheckLimits) mMaxBytesLeft -= (int)istr.gcount();
+	return istr;
+}
+
+std::istream& LLSDParser::ignore(std::istream& istr) const
+{
+	istr.ignore();
+	if(mCheckLimits) --mMaxBytesLeft;
+	return istr;
+}
+
+std::istream& LLSDParser::putback(std::istream& istr, char c) const
+{
+	istr.putback(c);
+	if(mCheckLimits) ++mMaxBytesLeft;
+	return istr;
+}
+
+std::istream& LLSDParser::read(
+	std::istream& istr,
+	char* s,
+	std::streamsize n) const
+{
+	istr.read(s, n);
+	if(mCheckLimits) mMaxBytesLeft -= (int)istr.gcount();
+	return istr;
+}
+
+void LLSDParser::account(S32 bytes) const
+{
+	if(mCheckLimits) mMaxBytesLeft -= bytes;
+}
+
+
+/**
+ * LLSDNotationParser
+ */
+LLSDNotationParser::LLSDNotationParser()
+{
+}	
+
+// virtual
+LLSDNotationParser::~LLSDNotationParser()
+{ }
+
+// virtual
+S32 LLSDNotationParser::doParse(std::istream& istr, LLSD& data, S32 max_depth) const
+{
+	// map: { string:object, string:object }
+	// array: [ object, object, object ]
+	// undef: !
+	// boolean: true | false | 1 | 0 | T | F | t | f | TRUE | FALSE
+	// integer: i####
+	// real: r####
+	// uuid: u####
+	// string: "g'day" | 'have a "nice" day' | s(size)"raw data"
+	// uri: l"escaped"
+	// date: d"YYYY-MM-DDTHH:MM:SS.FFZ"
+	// binary: b##"ff3120ab1" | b(size)"raw data"
+	char c;
+	c = istr.peek();
+	if (max_depth == 0)
+	{
+		return PARSE_FAILURE;
+	}
+	while(isspace(c))
+	{
+		// pop the whitespace.
+		c = get(istr);
+		c = istr.peek();
+		continue;
+	}
+	if(!istr.good())
+	{
+		return 0;
+	}
+	S32 parse_count = 1;
+	switch(c)
+	{
+	case '{':
+	{
+		S32 child_count = parseMap(istr, data, max_depth - 1);
+		if((child_count == PARSE_FAILURE) || data.isUndefined())
+		{
+			parse_count = PARSE_FAILURE;
+		}
+		else
+		{
+			parse_count += child_count;
+		}
+		if(istr.fail())
+		{
+			LL_INFOS() << "STREAM FAILURE reading map." << LL_ENDL;
+			parse_count = PARSE_FAILURE;
+		}
+		break;
+	}
+
+	case '[':
+	{
+		S32 child_count = parseArray(istr, data, max_depth - 1);
+		if((child_count == PARSE_FAILURE) || data.isUndefined())
+		{
+			parse_count = PARSE_FAILURE;
+		}
+		else
+		{
+			parse_count += child_count;
+		}
+		if(istr.fail())
+		{
+			LL_INFOS() << "STREAM FAILURE reading array." << LL_ENDL;
+			parse_count = PARSE_FAILURE;
+		}
+		break;
+	}
+
+	case '!':
+		c = get(istr);
+		data.clear();
+		break;
+
+	case '0':
+		c = get(istr);
+		data = false;
+		break;
+
+	case 'F':
+	case 'f':
+		ignore(istr);
+		c = istr.peek();
+		if(isalpha(c))
+		{
+			int cnt = deserialize_boolean(
+				istr,
+				data,
+				NOTATION_FALSE_SERIAL,
+				false);
+			if(PARSE_FAILURE == cnt) parse_count = cnt;
+			else account(cnt);
+		}
+		else
+		{
+			data = false;
+		}
+		if(istr.fail())
+		{
+			LL_INFOS() << "STREAM FAILURE reading boolean." << LL_ENDL;
+			parse_count = PARSE_FAILURE;
+		}
+		break;
+
+	case '1':
+		c = get(istr);
+		data = true;
+		break;
+
+	case 'T':
+	case 't':
+		ignore(istr);
+		c = istr.peek();
+		if(isalpha(c))
+		{
+			int cnt = deserialize_boolean(istr,data,NOTATION_TRUE_SERIAL,true);
+			if(PARSE_FAILURE == cnt) parse_count = cnt;
+			else account(cnt);
+		}
+		else
+		{
+			data = true;
+		}
+		if(istr.fail())
+		{
+			LL_INFOS() << "STREAM FAILURE reading boolean." << LL_ENDL;
+			parse_count = PARSE_FAILURE;
+		}
+		break;
+
+	case 'i':
+	{
+		c = get(istr);
+		S32 integer = 0;
+		istr >> integer;
+		data = integer;
+		if(istr.fail())
+		{
+			LL_INFOS() << "STREAM FAILURE reading integer." << LL_ENDL;
+			parse_count = PARSE_FAILURE;
+		}
+		break;
+	}
+
+	case 'r':
+	{
+		c = get(istr);
+		F64 real = 0.0;
+		istr >> real;
+		data = real;
+		if(istr.fail())
+		{
+			LL_INFOS() << "STREAM FAILURE reading real." << LL_ENDL;
+			parse_count = PARSE_FAILURE;
+		}
+		break;
+	}
+
+	case 'u':
+	{
+		c = get(istr);
+		LLUUID id;
+		istr >> id;
+		data = id;
+		if(istr.fail())
+		{
+			LL_INFOS() << "STREAM FAILURE reading uuid." << LL_ENDL;
+			parse_count = PARSE_FAILURE;
+		}
+		break;
+	}
+
+	case '\"':
+	case '\'':
+	case 's':
+		if(!parseString(istr, data))
+		{
+			parse_count = PARSE_FAILURE;
+		}
+		if(istr.fail())
+		{
+			LL_INFOS() << "STREAM FAILURE reading string." << LL_ENDL;
+			parse_count = PARSE_FAILURE;
+		}
+		break;
+
+	case 'l':
+	{
+		c = get(istr); // pop the 'l'
+		c = get(istr); // pop the delimiter
+		std::string str;
+		int cnt = deserialize_string_delim(istr, str, c);
+		if(PARSE_FAILURE == cnt)
+		{
+			parse_count = PARSE_FAILURE;
+		}
+		else
+		{
+			data = LLURI(str);
+			account(cnt);
+		}
+		if(istr.fail())
+		{
+			LL_INFOS() << "STREAM FAILURE reading link." << LL_ENDL;
+			parse_count = PARSE_FAILURE;
+		}
+		break;
+	}
+
+	case 'd':
+	{
+		c = get(istr); // pop the 'd'
+		c = get(istr); // pop the delimiter
+		std::string str;
+		int cnt = deserialize_string_delim(istr, str, c);
+		if(PARSE_FAILURE == cnt)
+		{
+			parse_count = PARSE_FAILURE;
+		}
+		else
+		{
+			data = LLDate(str);
+			account(cnt);
+		}
+		if(istr.fail())
+		{
+			LL_INFOS() << "STREAM FAILURE reading date." << LL_ENDL;
+			parse_count = PARSE_FAILURE;
+		}
+		break;
+	}
+
+	case 'b':
+		if(!parseBinary(istr, data))
+		{
+			parse_count = PARSE_FAILURE;
+		}
+		if(istr.fail())
+		{
+			LL_INFOS() << "STREAM FAILURE reading data." << LL_ENDL;
+			parse_count = PARSE_FAILURE;
+		}
+		break;
+
+	default:
+		parse_count = PARSE_FAILURE;
+		LL_INFOS() << "Unrecognized character while parsing: int(" << (int)c
+			<< ")" << LL_ENDL;
+		break;
+	}
+	if(PARSE_FAILURE == parse_count)
+	{
+		data.clear();
+	}
+	return parse_count;
+}
+
+S32 LLSDNotationParser::parseMap(std::istream& istr, LLSD& map, S32 max_depth) const
+{
+	// map: { string:object, string:object }
+	map = LLSD::emptyMap();
+	S32 parse_count = 0;
+	char c = get(istr);
+	if(c == '{')
+	{
+		// eat commas, white
+		bool found_name = false;
+		std::string name;
+		c = get(istr);
+		while(c != '}' && istr.good())
+		{
+			if(!found_name)
+			{
+				if((c == '\"') || (c == '\'') || (c == 's'))
+				{
+					putback(istr, c);
+					found_name = true;
+					int count = deserialize_string(istr, name, mMaxBytesLeft);
+					if(PARSE_FAILURE == count) return PARSE_FAILURE;
+					account(count);
+				}
+				c = get(istr);
+			}
+			else
+			{
+				if(isspace(c) || (c == ':'))
+				{
+					c = get(istr);
+					continue;
+				}
+				putback(istr, c);
+				LLSD child;
+				S32 count = doParse(istr, child, max_depth);
+				if(count > 0)
+				{
+					// There must be a value for every key, thus
+					// child_count must be greater than 0.
+					parse_count += count;
+					map.insert(name, child);
+				}
+				else
+				{
+					return PARSE_FAILURE;
+				}
+				found_name = false;
+				c = get(istr);
+			}
+		}
+		if(c != '}')
+		{
+			map.clear();
+			return PARSE_FAILURE;
+		}
+	}
+	return parse_count;
+}
+
+S32 LLSDNotationParser::parseArray(std::istream& istr, LLSD& array, S32 max_depth) const
+{
+	// array: [ object, object, object ]
+	array = LLSD::emptyArray();
+	S32 parse_count = 0;
+	char c = get(istr);
+	if(c == '[')
+	{
+		// eat commas, white
+		c = get(istr);
+		while((c != ']') && istr.good())
+		{
+			LLSD child;
+			if(isspace(c) || (c == ','))
+			{
+				c = get(istr);
+				continue;
+			}
+			putback(istr, c);
+			S32 count = doParse(istr, child, max_depth);
+			if(PARSE_FAILURE == count)
+			{
+				return PARSE_FAILURE;
+			}
+			else
+			{
+				parse_count += count;
+				array.append(child);
+			}
+			c = get(istr);
+		}
+		if(c != ']')
+		{
+			return PARSE_FAILURE;
+		}
+	}
+	return parse_count;
+}
+
+bool LLSDNotationParser::parseString(std::istream& istr, LLSD& data) const
+{
+	std::string value;
+	int count = deserialize_string(istr, value, mMaxBytesLeft);
+	if(PARSE_FAILURE == count) return false;
+	account(count);
+	data = value;
+	return true;
+}
+
+bool LLSDNotationParser::parseBinary(std::istream& istr, LLSD& data) const
+{
+	// binary: b##"ff3120ab1"
+	// or: b(len)"..."
+
+	// I want to manually control those values here to make sure the
+	// parser doesn't break when someone changes a constant somewhere
+	// else.
+	const U32 BINARY_BUFFER_SIZE = 256;
+	const U32 STREAM_GET_COUNT = 255;
+
+	// need to read the base out.
+	char buf[BINARY_BUFFER_SIZE];		/* Flawfinder: ignore */
+	get(istr, buf, STREAM_GET_COUNT, '"');
+	char c = get(istr);
+	if(c != '"') return false;
+	if(0 == strncmp("b(", buf, 2))
+	{
+		// We probably have a valid raw binary stream. determine
+		// the size, and read it.
+		S32 len = strtol(buf + 2, NULL, 0);
+		if(mCheckLimits && (len > mMaxBytesLeft)) return false;
+		std::vector<U8> value;
+		if(len)
+		{
+			value.resize(len);
+			account((int)fullread(istr, (char *)&value[0], len));
+		}
+		c = get(istr); // strip off the trailing double-quote
+		data = value;
+	}
+	else if(0 == strncmp("b64", buf, 3))
+	{
+		// *FIX: A bit inefficient, but works for now. To make the
+		// format better, I would need to add a hint into the
+		// serialization format that indicated how long it was.
+		std::stringstream coded_stream;
+		get(istr, *(coded_stream.rdbuf()), '\"');
+		c = get(istr);
+		std::string encoded(coded_stream.str());
+		size_t len = LLBase64::requiredDecryptionSpace(encoded);
+		std::vector<U8> value;
+		if(len)
+		{
+			value.resize(len);
+			len = LLBase64::decode(encoded, &value[0], len);
+			value.resize(len);
+		}
+		data = value;
+	}
+	else if(0 == strncmp("b16", buf, 3))
+	{
+		// yay, base 16. We pop the next character which is either a
+		// double quote or base 16 data. If it's a double quote, we're
+		// done parsing. If it's not, put the data back, and read the
+		// stream until the next double quote.
+		char* read;	 /*Flawfinder: ignore*/
+		U8 byte;
+		U8 byte_buffer[BINARY_BUFFER_SIZE];
+		U8* write;
+		std::vector<U8> value;
+		c = get(istr);
+		while(c != '"')
+		{
+			putback(istr, c);
+			read = buf;
+			write = byte_buffer;
+			get(istr, buf, STREAM_GET_COUNT, '"');
+			c = get(istr);
+			while(*read != '\0')	 /*Flawfinder: ignore*/
+			{
+				byte = hex_as_nybble(*read++);
+				byte = byte << 4;
+				byte |= hex_as_nybble(*read++);
+				*write++ = byte;
+			}
+			// copy the data out of the byte buffer
+			value.insert(value.end(), byte_buffer, write);
+		}
+		data = value;
+	}
+	else
+	{
+		return false;
+	}
+	return true;
+}
+
+
+/**
+ * LLSDBinaryParser
+ */
+
+// virtual
+S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data, S32 max_depth) const
+{
+/**
+ * Undefined: '!'<br>
+ * Boolean: '1' for true '0' for false<br>
+ * Integer: 'i' + 4 bytes network byte order<br>
+ * Real: 'r' + 8 bytes IEEE double<br>
+ * UUID: 'u' + 16 byte unsigned integer<br>
+ * String: 's' + 4 byte integer size + string<br>
+ *  strings also secretly support the notation format
+ * Date: 'd' + 8 byte IEEE double for seconds since epoch<br>
+ * URI: 'l' + 4 byte integer size + string uri<br>
+ * Binary: 'b' + 4 byte integer size + binary data<br>
+ * Array: '[' + 4 byte integer size  + all values + ']'<br>
+ * Map: '{' + 4 byte integer size  every(key + value) + '}'<br>
+ *  map keys are serialized as s + 4 byte integer size + string or in the
+ *  notation format.
+ */
+	char c;
+	c = get(istr);
+	if(!istr.good())
+	{
+		return 0;
+	}
+	if (max_depth == 0)
+	{
+		return PARSE_FAILURE;
+	}
+	S32 parse_count = 1;
+	switch(c)
+	{
+	case '{':
+	{
+		S32 child_count = parseMap(istr, data, max_depth - 1);
+		if((child_count == PARSE_FAILURE) || data.isUndefined())
+		{
+			parse_count = PARSE_FAILURE;
+		}
+		else
+		{
+			parse_count += child_count;
+		}
+		if(istr.fail())
+		{
+			LL_INFOS() << "STREAM FAILURE reading binary map." << LL_ENDL;
+			parse_count = PARSE_FAILURE;
+		}
+		break;
+	}
+
+	case '[':
+	{
+		S32 child_count = parseArray(istr, data, max_depth - 1);
+		if((child_count == PARSE_FAILURE) || data.isUndefined())
+		{
+			parse_count = PARSE_FAILURE;
+		}
+		else
+		{
+			parse_count += child_count;
+		}
+		if(istr.fail())
+		{
+			LL_INFOS() << "STREAM FAILURE reading binary array." << LL_ENDL;
+			parse_count = PARSE_FAILURE;
+		}
+		break;
+	}
+
+	case '!':
+		data.clear();
+		break;
+
+	case '0':
+		data = false;
+		break;
+
+	case '1':
+		data = true;
+		break;
+
+	case 'i':
+	{
+		U32 value_nbo = 0;
+		read(istr, (char*)&value_nbo, sizeof(U32));	 /*Flawfinder: ignore*/
+		data = (S32)ntohl(value_nbo);
+		if(istr.fail())
+		{
+			LL_INFOS() << "STREAM FAILURE reading binary integer." << LL_ENDL;
+		}
+		break;
+	}
+
+	case 'r':
+	{
+		F64 real_nbo = 0.0;
+		read(istr, (char*)&real_nbo, sizeof(F64));	 /*Flawfinder: ignore*/
+		data = ll_ntohd(real_nbo);
+		if(istr.fail())
+		{
+			LL_INFOS() << "STREAM FAILURE reading binary real." << LL_ENDL;
+		}
+		break;
+	}
+
+	case 'u':
+	{
+		LLUUID id;
+		read(istr, (char*)(&id.mData), UUID_BYTES);	 /*Flawfinder: ignore*/
+		data = id;
+		if(istr.fail())
+		{
+			LL_INFOS() << "STREAM FAILURE reading binary uuid." << LL_ENDL;
+		}
+		break;
+	}
+
+	case '\'':
+	case '"':
+	{
+		std::string value;
+		int cnt = deserialize_string_delim(istr, value, c);
+		if(PARSE_FAILURE == cnt)
+		{
+			parse_count = PARSE_FAILURE;
+		}
+		else
+		{
+			data = value;
+			account(cnt);
+		}
+		if(istr.fail())
+		{
+			LL_INFOS() << "STREAM FAILURE reading binary (notation-style) string."
+				<< LL_ENDL;
+			parse_count = PARSE_FAILURE;
+		}
+		break;
+	}
+
+	case 's':
+	{
+		std::string value;
+		if(parseString(istr, value))
+		{
+			data = value;
+		}
+		else
+		{
+			parse_count = PARSE_FAILURE;
+		}
+		if(istr.fail())
+		{
+			LL_INFOS() << "STREAM FAILURE reading binary string." << LL_ENDL;
+			parse_count = PARSE_FAILURE;
+		}
+		break;
+	}
+
+	case 'l':
+	{
+		std::string value;
+		if(parseString(istr, value))
+		{
+			data = LLURI(value);
+		}
+		else
+		{
+			parse_count = PARSE_FAILURE;
+		}
+		if(istr.fail())
+		{
+			LL_INFOS() << "STREAM FAILURE reading binary link." << LL_ENDL;
+			parse_count = PARSE_FAILURE;
+		}
+		break;
+	}
+
+	case 'd':
+	{
+		F64 real = 0.0;
+		read(istr, (char*)&real, sizeof(F64));	 /*Flawfinder: ignore*/
+		data = LLDate(real);
+		if(istr.fail())
+		{
+			LL_INFOS() << "STREAM FAILURE reading binary date." << LL_ENDL;
+			parse_count = PARSE_FAILURE;
+		}
+		break;
+	}
+
+	case 'b':
+	{
+		// We probably have a valid raw binary stream. determine
+		// the size, and read it.
+		U32 size_nbo = 0;
+		read(istr, (char*)&size_nbo, sizeof(U32));	/*Flawfinder: ignore*/
+		S32 size = (S32)ntohl(size_nbo);
+		if(mCheckLimits && (size > mMaxBytesLeft))
+		{
+			parse_count = PARSE_FAILURE;
+		}
+		else
+		{
+			std::vector<U8> value;
+			if(size > 0)
+			{
+				value.resize(size);
+				account((int)fullread(istr, (char*)&value[0], size));
+			}
+			data = value;
+		}
+		if(istr.fail())
+		{
+			LL_INFOS() << "STREAM FAILURE reading binary." << LL_ENDL;
+			parse_count = PARSE_FAILURE;
+		}
+		break;
+	}
+
+	default:
+		parse_count = PARSE_FAILURE;
+		LL_INFOS() << "Unrecognized character while parsing: int(" << (int)c
+			<< ")" << LL_ENDL;
+		break;
+	}
+	if(PARSE_FAILURE == parse_count)
+	{
+		data.clear();
+	}
+	return parse_count;
+}
+
+S32 LLSDBinaryParser::parseMap(std::istream& istr, LLSD& map, S32 max_depth) const
+{
+	map = LLSD::emptyMap();
+	U32 value_nbo = 0;
+	read(istr, (char*)&value_nbo, sizeof(U32));		 /*Flawfinder: ignore*/
+	S32 size = (S32)ntohl(value_nbo);
+	S32 parse_count = 0;
+	S32 count = 0;
+	char c = get(istr);
+	while(c != '}' && (count < size) && istr.good())
+	{
+		std::string name;
+		switch(c)
+		{
+		case 'k':
+			if(!parseString(istr, name))
+			{
+				return PARSE_FAILURE;
+			}
+			break;
+		case '\'':
+		case '"':
+		{
+			int cnt = deserialize_string_delim(istr, name, c);
+			if(PARSE_FAILURE == cnt) return PARSE_FAILURE;
+			account(cnt);
+			break;
+		}
+		}
+		LLSD child;
+		S32 child_count = doParse(istr, child, max_depth);
+		if(child_count > 0)
+		{
+			// There must be a value for every key, thus child_count
+			// must be greater than 0.
+			parse_count += child_count;
+			map.insert(name, child);
+		}
+		else
+		{
+			return PARSE_FAILURE;
+		}
+		++count;
+		c = get(istr);
+	}
+	if((c != '}') || (count < size))
+	{
+		// Make sure it is correctly terminated and we parsed as many
+		// as were said to be there.
+		return PARSE_FAILURE;
+	}
+	return parse_count;
+}
+
+S32 LLSDBinaryParser::parseArray(std::istream& istr, LLSD& array, S32 max_depth) const
+{
+	array = LLSD::emptyArray();
+	U32 value_nbo = 0;
+	read(istr, (char*)&value_nbo, sizeof(U32));		 /*Flawfinder: ignore*/
+	S32 size = (S32)ntohl(value_nbo);
+
+	// *FIX: This would be a good place to reserve some space in the
+	// array...
+
+	S32 parse_count = 0;
+	S32 count = 0;
+	char c = istr.peek();
+	while((c != ']') && (count < size) && istr.good())
+	{
+		LLSD child;
+		S32 child_count = doParse(istr, child, max_depth);
+		if(PARSE_FAILURE == child_count)
+		{
+			return PARSE_FAILURE;
+		}
+		if(child_count)
+		{
+			parse_count += child_count;
+			array.append(child);
+		}
+		++count;
+		c = istr.peek();
+	}
+	c = get(istr);
+	if((c != ']') || (count < size))
+	{
+		// Make sure it is correctly terminated and we parsed as many
+		// as were said to be there.
+		return PARSE_FAILURE;
+	}
+	return parse_count;
+}
+
+bool LLSDBinaryParser::parseString(
+	std::istream& istr,
+	std::string& value) const
+{
+	// *FIX: This is memory inefficient.
+	U32 value_nbo = 0;
+	read(istr, (char*)&value_nbo, sizeof(U32));		 /*Flawfinder: ignore*/
+	S32 size = (S32)ntohl(value_nbo);
+	if(mCheckLimits && (size > mMaxBytesLeft)) return false;
+	if(size < 0) return false;
+	std::vector<char> buf;
+	if(size)
+	{
+		buf.resize(size);
+		account((int)fullread(istr, &buf[0], size));
+		value.assign(buf.begin(), buf.end());
+	}
+	return true;
+}
+
+
+/**
+ * LLSDFormatter
+ */
+LLSDFormatter::LLSDFormatter() :
+	mBoolAlpha(false)
+{
+}
+
+// virtual
+LLSDFormatter::~LLSDFormatter()
+{ }
+
+void LLSDFormatter::boolalpha(bool alpha)
+{
+	mBoolAlpha = alpha;
+}
+
+void LLSDFormatter::realFormat(const std::string& format)
+{
+	mRealFormat = format;
+}
+
+void LLSDFormatter::formatReal(LLSD::Real real, std::ostream& ostr) const
+{
+	std::string buffer = llformat(mRealFormat.c_str(), real);
+	ostr << buffer;
+}
+
+/**
+ * LLSDNotationFormatter
+ */
+LLSDNotationFormatter::LLSDNotationFormatter()
+{
+}
+
+// virtual
+LLSDNotationFormatter::~LLSDNotationFormatter()
+{ }
+
+// static
+std::string LLSDNotationFormatter::escapeString(const std::string& in)
+{
+	std::ostringstream ostr;
+	serialize_string(in, ostr);
+	return ostr.str();
+}
+
+// virtual
+S32 LLSDNotationFormatter::format(const LLSD& data, std::ostream& ostr, U32 options) const
+{
+	S32 rv = format_impl(data, ostr, options, 0);
+	return rv;
+}
+
+S32 LLSDNotationFormatter::format_impl(const LLSD& data, std::ostream& ostr, U32 options, U32 level) const
+{
+	S32 format_count = 1;
+	std::string pre;
+	std::string post;
+
+	if (options & LLSDFormatter::OPTIONS_PRETTY)
+	{
+		for (U32 i = 0; i < level; i++)
+		{
+			pre += "    ";
+		}
+		post = "\n";
+	}
+
+	switch(data.type())
+	{
+	case LLSD::TypeMap:
+	{
+		if (0 != level) ostr << post << pre;
+		ostr << "{";
+		std::string inner_pre;
+		if (options & LLSDFormatter::OPTIONS_PRETTY)
+		{
+			inner_pre = pre + "    ";
+		}
+
+		bool need_comma = false;
+        auto iter = data.beginMap();
+        auto end = data.endMap();
+		for(; iter != end; ++iter)
+		{
+			if(need_comma) ostr << ",";
+			need_comma = true;
+			ostr << post << inner_pre << '\'';
+			serialize_string((*iter).first, ostr);
+			ostr << "':";
+			format_count += format_impl((*iter).second, ostr, options, level + 2);
+		}
+		ostr << post << pre << "}";
+		break;
+	}
+
+	case LLSD::TypeArray:
+	{
+		ostr << post << pre << "[";
+		bool need_comma = false;
+        auto iter = data.beginArray();
+        auto end = data.endArray();
+		for(; iter != end; ++iter)
+		{
+			if(need_comma) ostr << ",";
+			need_comma = true;
+			format_count += format_impl(*iter, ostr, options, level + 1);
+		}
+		ostr << "]";
+		break;
+	}
+
+	case LLSD::TypeUndefined:
+		ostr << "!";
+		break;
+
+	case LLSD::TypeBoolean:
+		if(mBoolAlpha ||
+#if( LL_WINDOWS || __GNUC__ > 2)
+		   (ostr.flags() & std::ios::boolalpha)
+#else
+		   (ostr.flags() & 0x0100)
+#endif
+			)
+		{
+			ostr << (data.asBoolean()
+					 ? NOTATION_TRUE_SERIAL : NOTATION_FALSE_SERIAL);
+		}
+		else
+		{
+			ostr << (data.asBoolean() ? 1 : 0);
+		}
+		break;
+
+	case LLSD::TypeInteger:
+		ostr << "i" << data.asInteger();
+		break;
+
+	case LLSD::TypeReal:
+		ostr << "r";
+		if(mRealFormat.empty())
+		{
+			ostr << data.asReal();
+		}
+		else
+		{
+			formatReal(data.asReal(), ostr);
+		}
+		break;
+
+	case LLSD::TypeUUID:
+		ostr << "u" << data.asUUID();
+		break;
+
+	case LLSD::TypeString:
+		ostr << '\'';
+		serialize_string(data.asStringRef(), ostr);
+		ostr << '\'';
+		break;
+
+	case LLSD::TypeDate:
+		ostr << "d\"" << data.asDate() << "\"";
+		break;
+
+	case LLSD::TypeURI:
+		ostr << "l\"";
+		serialize_string(data.asString(), ostr);
+		ostr << "\"";
+		break;
+
+	case LLSD::TypeBinary:
+	{
+		// *FIX: memory inefficient.
+		const std::vector<U8>& buffer = data.asBinary();
+		ostr << "b(" << buffer.size() << ")\"";
+		if(!buffer.empty())
+		{
+			if (options & LLSDFormatter::OPTIONS_PRETTY_BINARY)
+			{
+				std::ios_base::fmtflags old_flags = ostr.flags();
+				ostr.setf( std::ios::hex, std::ios::basefield );
+				ostr << "0x";
+				for (unsigned char i : buffer)
+                {
+					ostr << static_cast<int>(i);
+				}
+				ostr.flags(old_flags);
+			}
+			else
+			{
+				ostr.write(reinterpret_cast<const char*>(&buffer[0]), buffer.size());
+			}
+		}
+		ostr << "\"";
+		break;
+	}
+
+	default:
+		// *NOTE: This should never happen.
+		ostr << "!";
+		break;
+	}
+	return format_count;
+}
+
+
+/**
+ * LLSDBinaryFormatter
+ */
+LLSDBinaryFormatter::LLSDBinaryFormatter()
+{
+}
+
+// virtual
+LLSDBinaryFormatter::~LLSDBinaryFormatter()
+{ }
+
+// virtual
+S32 LLSDBinaryFormatter::format(const LLSD& data, std::ostream& ostr, U32 options) const
+{
+	S32 format_count = 1;
+	switch(data.type())
+	{
+	case LLSD::TypeMap:
+	{
+		ostr.put('{');
+		U32 size_nbo = htonl(data.size());
+		ostr.write(reinterpret_cast<const char*>(&size_nbo), sizeof(U32));
+        auto iter = data.beginMap();
+        auto end = data.endMap();
+		for(; iter != end; ++iter)
+		{
+			ostr.put('k');
+			formatString((*iter).first, ostr);
+			format_count += format((*iter).second, ostr);
+		}
+		ostr.put('}');
+		break;
+	}
+
+	case LLSD::TypeArray:
+	{
+		ostr.put('[');
+		U32 size_nbo = htonl(data.size());
+		ostr.write(reinterpret_cast<const char*>(&size_nbo), sizeof(U32));
+        auto iter = data.beginArray();
+        auto end = data.endArray();
+		for(; iter != end; ++iter)
+		{
+			format_count += format(*iter, ostr);
+		}
+		ostr.put(']');
+		break;
+	}
+
+	case LLSD::TypeUndefined:
+		ostr.put('!');
+		break;
+
+	case LLSD::TypeBoolean:
+		if(data.asBoolean()) ostr.put(BINARY_TRUE_SERIAL);
+		else ostr.put(BINARY_FALSE_SERIAL);
+		break;
+
+	case LLSD::TypeInteger:
+	{
+		ostr.put('i');
+		U32 value_nbo = htonl(data.asInteger());
+		ostr.write((const char*)(&value_nbo), sizeof(U32));
+		break;
+	}
+
+	case LLSD::TypeReal:
+	{
+		ostr.put('r');
+		F64 value_nbo = ll_htond(data.asReal());
+		ostr.write((const char*)(&value_nbo), sizeof(F64));
+		break;
+	}
+
+	case LLSD::TypeUUID:
+	{
+		ostr.put('u');
+		LLUUID temp = data.asUUID();
+		ostr.write((const char*)(&(temp.mData)), UUID_BYTES);
+		break;
+	}
+
+	case LLSD::TypeString:
+		ostr.put('s');
+		formatString(data.asStringRef(), ostr);
+		break;
+
+	case LLSD::TypeDate:
+	{
+		ostr.put('d');
+		F64 value = data.asReal();
+		ostr.write((const char*)(&value), sizeof(F64));
+		break;
+	}
+
+	case LLSD::TypeURI:
+		ostr.put('l');
+		formatString(data.asString(), ostr);
+		break;
+
+	case LLSD::TypeBinary:
+	{
+		ostr.put('b');
+		const std::vector<U8>& buffer = data.asBinary();
+		U32 size_nbo = htonl(buffer.size());
+		ostr.write((const char*)(&size_nbo), sizeof(U32));
+		if(!buffer.empty()) ostr.write((const char*)&buffer[0], buffer.size());
+		break;
+	}
+
+	default:
+		// *NOTE: This should never happen.
+		ostr.put('!');
+		break;
+	}
+	return format_count;
+}
+
+void LLSDBinaryFormatter::formatString(
+	const std::string& string,
+	std::ostream& ostr) const
+{
+	U32 size_nbo = htonl(string.size());
+	ostr.write((const char*)(&size_nbo), sizeof(U32));
+	ostr.write(string.c_str(), string.size());
+}
+
+/**
+ * local functions
+ */
+int deserialize_string(std::istream& istr, std::string& value, S32 max_bytes)
+{
+	int c = istr.get();
+	if(istr.fail())
+	{
+		// No data in stream, bail out but mention the character we
+		// grabbed.
+		return LLSDParser::PARSE_FAILURE;
+	}
+
+	int rv = LLSDParser::PARSE_FAILURE;
+	switch(c)
+	{
+	case '\'':
+	case '"':
+		rv = deserialize_string_delim(istr, value, c);
+		break;
+	case 's':
+		// technically, less than max_bytes, but this is just meant to
+		// catch egregious protocol errors. parse errors will be
+		// caught in the case of incorrect counts.
+		rv = deserialize_string_raw(istr, value, max_bytes);
+		break;
+	default:
+		break;
+	}
+	if(LLSDParser::PARSE_FAILURE == rv) return rv;
+	return rv + 1; // account for the character grabbed at the top.
+}
+
+int deserialize_string_delim(
+	std::istream& istr,
+	std::string& value,
+	char delim)
+{
+	std::ostringstream write_buffer;
+	bool found_escape = false;
+	bool found_hex = false;
+	bool found_digit = false;
+	U8 byte = 0;
+	int count = 0;
+
+	while (true)
+	{
+		int next_byte = istr.get();
+		++count;
+
+		if(istr.fail())
+		{
+			// If our stream is empty, break out
+			value = write_buffer.str();
+			return LLSDParser::PARSE_FAILURE;
+		}
+
+		char next_char = (char)next_byte; // Now that we know it's not EOF
+		
+		if(found_escape)
+		{
+			// next character(s) is a special sequence.
+			if(found_hex)
+			{
+				if(found_digit)
+				{
+					found_digit = false;
+					found_hex = false;
+					found_escape = false;
+					byte = byte << 4;
+					byte |= hex_as_nybble(next_char);
+					write_buffer << byte;
+					byte = 0;
+				}
+				else
+				{
+					// next character is the first nybble of
+					//
+					found_digit = true;
+					byte = hex_as_nybble(next_char);
+				}
+			}
+			else if(next_char == 'x')
+			{
+				found_hex = true;
+			}
+			else
+			{
+				switch(next_char)
+				{
+				case 'a':
+					write_buffer << '\a';
+					break;
+				case 'b':
+					write_buffer << '\b';
+					break;
+				case 'f':
+					write_buffer << '\f';
+					break;
+				case 'n':
+					write_buffer << '\n';
+					break;
+				case 'r':
+					write_buffer << '\r';
+					break;
+				case 't':
+					write_buffer << '\t';
+					break;
+				case 'v':
+					write_buffer << '\v';
+					break;
+				default:
+					write_buffer << next_char;
+					break;
+				}
+				found_escape = false;
+			}
+		}
+		else if(next_char == '\\')
+		{
+			found_escape = true;
+		}
+		else if(next_char == delim)
+		{
+			break;
+		}
+		else
+		{
+			write_buffer << next_char;
+		}
+	}
+
+	value = write_buffer.str();
+	return count;
+}
+
+int deserialize_string_raw(
+	std::istream& istr,
+	std::string& value,
+	S32 max_bytes)
+{
+	int count = 0;
+	const S32 BUF_LEN = 20;
+	char buf[BUF_LEN];		/* Flawfinder: ignore */
+	istr.get(buf, BUF_LEN - 1, ')');
+	count += (int)istr.gcount();
+	int c = istr.get();
+	c = istr.get();
+	count += 2;
+	if(((c == '"') || (c == '\'')) && (buf[0] == '('))
+	{
+		// We probably have a valid raw string. determine
+		// the size, and read it.
+		// *FIX: This is memory inefficient.
+		S32 len = strtol(buf + 1, NULL, 0);
+		if((max_bytes>0)&&(len>max_bytes)) return LLSDParser::PARSE_FAILURE;
+		std::vector<char> buf2;
+		if(len)
+		{
+			buf2.resize(len);
+			count += (int)fullread(istr, (char *)&buf2[0], len);
+			value.assign(buf2.begin(), buf2.end());
+		}
+		c = istr.get();
+		++count;
+		if(!((c == '"') || (c == '\'')))
+		{
+			return LLSDParser::PARSE_FAILURE;
+		}
+	}
+	else
+	{
+		return LLSDParser::PARSE_FAILURE;
+	}
+	return count;
+}
+
+static const char* NOTATION_STRING_CHARACTERS[256] =
+{
+	"\\x00",	// 0
+	"\\x01",	// 1
+	"\\x02",	// 2
+	"\\x03",	// 3
+	"\\x04",	// 4
+	"\\x05",	// 5
+	"\\x06",	// 6
+	"\\a",		// 7
+	"\\b",		// 8
+	"\\t",		// 9
+	"\\n",		// 10
+	"\\v",		// 11
+	"\\f",		// 12
+	"\\r",		// 13
+	"\\x0e",	// 14
+	"\\x0f",	// 15
+	"\\x10",	// 16
+	"\\x11",	// 17
+	"\\x12",	// 18
+	"\\x13",	// 19
+	"\\x14",	// 20
+	"\\x15",	// 21
+	"\\x16",	// 22
+	"\\x17",	// 23
+	"\\x18",	// 24
+	"\\x19",	// 25
+	"\\x1a",	// 26
+	"\\x1b",	// 27
+	"\\x1c",	// 28
+	"\\x1d",	// 29
+	"\\x1e",	// 30
+	"\\x1f",	// 31
+	" ",		// 32
+	"!",		// 33
+	"\"",		// 34
+	"#",		// 35
+	"$",		// 36
+	"%",		// 37
+	"&",		// 38
+	"\\'",		// 39
+	"(",		// 40
+	")",		// 41
+	"*",		// 42
+	"+",		// 43
+	",",		// 44
+	"-",		// 45
+	".",		// 46
+	"/",		// 47
+	"0",		// 48
+	"1",		// 49
+	"2",		// 50
+	"3",		// 51
+	"4",		// 52
+	"5",		// 53
+	"6",		// 54
+	"7",		// 55
+	"8",		// 56
+	"9",		// 57
+	":",		// 58
+	";",		// 59
+	"<",		// 60
+	"=",		// 61
+	">",		// 62
+	"?",		// 63
+	"@",		// 64
+	"A",		// 65
+	"B",		// 66
+	"C",		// 67
+	"D",		// 68
+	"E",		// 69
+	"F",		// 70
+	"G",		// 71
+	"H",		// 72
+	"I",		// 73
+	"J",		// 74
+	"K",		// 75
+	"L",		// 76
+	"M",		// 77
+	"N",		// 78
+	"O",		// 79
+	"P",		// 80
+	"Q",		// 81
+	"R",		// 82
+	"S",		// 83
+	"T",		// 84
+	"U",		// 85
+	"V",		// 86
+	"W",		// 87
+	"X",		// 88
+	"Y",		// 89
+	"Z",		// 90
+	"[",		// 91
+	"\\\\",		// 92
+	"]",		// 93
+	"^",		// 94
+	"_",		// 95
+	"`",		// 96
+	"a",		// 97
+	"b",		// 98
+	"c",		// 99
+	"d",		// 100
+	"e",		// 101
+	"f",		// 102
+	"g",		// 103
+	"h",		// 104
+	"i",		// 105
+	"j",		// 106
+	"k",		// 107
+	"l",		// 108
+	"m",		// 109
+	"n",		// 110
+	"o",		// 111
+	"p",		// 112
+	"q",		// 113
+	"r",		// 114
+	"s",		// 115
+	"t",		// 116
+	"u",		// 117
+	"v",		// 118
+	"w",		// 119
+	"x",		// 120
+	"y",		// 121
+	"z",		// 122
+	"{",		// 123
+	"|",		// 124
+	"}",		// 125
+	"~",		// 126
+	"\\x7f",	// 127
+	"\\x80",	// 128
+	"\\x81",	// 129
+	"\\x82",	// 130
+	"\\x83",	// 131
+	"\\x84",	// 132
+	"\\x85",	// 133
+	"\\x86",	// 134
+	"\\x87",	// 135
+	"\\x88",	// 136
+	"\\x89",	// 137
+	"\\x8a",	// 138
+	"\\x8b",	// 139
+	"\\x8c",	// 140
+	"\\x8d",	// 141
+	"\\x8e",	// 142
+	"\\x8f",	// 143
+	"\\x90",	// 144
+	"\\x91",	// 145
+	"\\x92",	// 146
+	"\\x93",	// 147
+	"\\x94",	// 148
+	"\\x95",	// 149
+	"\\x96",	// 150
+	"\\x97",	// 151
+	"\\x98",	// 152
+	"\\x99",	// 153
+	"\\x9a",	// 154
+	"\\x9b",	// 155
+	"\\x9c",	// 156
+	"\\x9d",	// 157
+	"\\x9e",	// 158
+	"\\x9f",	// 159
+	"\\xa0",	// 160
+	"\\xa1",	// 161
+	"\\xa2",	// 162
+	"\\xa3",	// 163
+	"\\xa4",	// 164
+	"\\xa5",	// 165
+	"\\xa6",	// 166
+	"\\xa7",	// 167
+	"\\xa8",	// 168
+	"\\xa9",	// 169
+	"\\xaa",	// 170
+	"\\xab",	// 171
+	"\\xac",	// 172
+	"\\xad",	// 173
+	"\\xae",	// 174
+	"\\xaf",	// 175
+	"\\xb0",	// 176
+	"\\xb1",	// 177
+	"\\xb2",	// 178
+	"\\xb3",	// 179
+	"\\xb4",	// 180
+	"\\xb5",	// 181
+	"\\xb6",	// 182
+	"\\xb7",	// 183
+	"\\xb8",	// 184
+	"\\xb9",	// 185
+	"\\xba",	// 186
+	"\\xbb",	// 187
+	"\\xbc",	// 188
+	"\\xbd",	// 189
+	"\\xbe",	// 190
+	"\\xbf",	// 191
+	"\\xc0",	// 192
+	"\\xc1",	// 193
+	"\\xc2",	// 194
+	"\\xc3",	// 195
+	"\\xc4",	// 196
+	"\\xc5",	// 197
+	"\\xc6",	// 198
+	"\\xc7",	// 199
+	"\\xc8",	// 200
+	"\\xc9",	// 201
+	"\\xca",	// 202
+	"\\xcb",	// 203
+	"\\xcc",	// 204
+	"\\xcd",	// 205
+	"\\xce",	// 206
+	"\\xcf",	// 207
+	"\\xd0",	// 208
+	"\\xd1",	// 209
+	"\\xd2",	// 210
+	"\\xd3",	// 211
+	"\\xd4",	// 212
+	"\\xd5",	// 213
+	"\\xd6",	// 214
+	"\\xd7",	// 215
+	"\\xd8",	// 216
+	"\\xd9",	// 217
+	"\\xda",	// 218
+	"\\xdb",	// 219
+	"\\xdc",	// 220
+	"\\xdd",	// 221
+	"\\xde",	// 222
+	"\\xdf",	// 223
+	"\\xe0",	// 224
+	"\\xe1",	// 225
+	"\\xe2",	// 226
+	"\\xe3",	// 227
+	"\\xe4",	// 228
+	"\\xe5",	// 229
+	"\\xe6",	// 230
+	"\\xe7",	// 231
+	"\\xe8",	// 232
+	"\\xe9",	// 233
+	"\\xea",	// 234
+	"\\xeb",	// 235
+	"\\xec",	// 236
+	"\\xed",	// 237
+	"\\xee",	// 238
+	"\\xef",	// 239
+	"\\xf0",	// 240
+	"\\xf1",	// 241
+	"\\xf2",	// 242
+	"\\xf3",	// 243
+	"\\xf4",	// 244
+	"\\xf5",	// 245
+	"\\xf6",	// 246
+	"\\xf7",	// 247
+	"\\xf8",	// 248
+	"\\xf9",	// 249
+	"\\xfa",	// 250
+	"\\xfb",	// 251
+	"\\xfc",	// 252
+	"\\xfd",	// 253
+	"\\xfe",	// 254
+	"\\xff"		// 255
+};
+
+void serialize_string(const std::string& value, std::ostream& str)
+{
+	std::string::const_iterator it = value.begin();
+	std::string::const_iterator end = value.end();
+	U8 c;
+	for(; it != end; ++it)
+	{
+		c = (U8)(*it);
+		str << NOTATION_STRING_CHARACTERS[c];
+	}
+}
+
+int deserialize_boolean(
+	std::istream& istr,
+	LLSD& data,
+	const std::string& compare,
+	bool value)
+{
+	//
+	// this method is a little goofy, because it gets the stream at
+	// the point where the t or f has already been
+	// consumed. Basically, parse for a patch to the string passed in
+	// starting at index 1. If it's a match:
+	//  * assign data to value
+	//  * return the number of bytes read
+	// otherwise:
+	//  * set data to LLSD::null
+	//  * return LLSDParser::PARSE_FAILURE (-1)
+	//
+	int bytes_read = 0;
+	std::string::size_type ii = 0;
+	char c = istr.peek();
+	while((++ii < compare.size())
+		  && (tolower(c) == (int)compare[ii])
+		  && istr.good())
+	{
+		istr.ignore();
+		++bytes_read;
+		c = istr.peek();
+	}
+	if(compare.size() != ii)
+	{
+		data.clear();
+		return LLSDParser::PARSE_FAILURE;
+	}
+	data = value;
+	return bytes_read;
+}
+
+std::ostream& operator<<(std::ostream& s, const LLSD& llsd)
+{
+	s << LLSDNotationStreamer(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)
+	{
+		LL_WARNS() << "Failed to compress LLSD block." << LL_ENDL;
+		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)
+			{
+				free(output);
+				LL_WARNS() << "Failed to compress LLSD block." << LL_ENDL;
+				return std::string();
+			}
+
+			have = CHUNK-strm.avail_out;
+			U8* new_output = (U8*) realloc(output, cur_size+have);
+			if (new_output == NULL)
+			{
+				LL_WARNS() << "Failed to compress LLSD block: can't reallocate memory, current size: " << cur_size << " bytes; requested " << cur_size + have << " bytes." << LL_ENDL;
+				deflateEnd(&strm);
+				if (output)
+				{
+					free(output);
+				}
+				return std::string();
+			}
+			output = new_output;
+			memcpy(output+cur_size, out, have);
+			cur_size += have;
+		}
+		else 
+		{
+			free(output);
+			LL_WARNS() << "Failed to compress LLSD block." << LL_ENDL;
+			return std::string();
+		}
+	}
+	while (ret == Z_OK);
+
+	std::string::size_type size = cur_size;
+
+	std::string result((char*) output, size);
+	deflateEnd(&strm);
+	free(output);
+
+	return result;
+}
+
+// <alchemy>
+//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
+LLUZipHelper::EZipRresult LLUZipHelper::unzip_llsd(LLSD& data, std::istream& is, S32 size)
+{
+	std::unique_ptr<U8 []> in;
+	try
+	{
+		in = std::make_unique<U8 []>(size);
+	}
+	catch (const std::bad_alloc&)
+	{
+		return ZR_MEM_ERROR;
+	}
+	is.read((char*)in.get(), size);
+
+	return unzip_llsd(data, in.get(), size);
+}
+
+LLUZipHelper::EZipRresult LLUZipHelper::unzip_llsd(LLSD& data, U8* in, S32 size)
+{
+	U8* result = NULL;
+	U32 cur_size = 0;
+	z_stream strm;
+		
+	const U32 CHUNK = 65536;
+
+	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);
+		
+		switch (ret)
+		{
+		case Z_NEED_DICT:
+			ret = Z_DATA_ERROR;
+		case Z_DATA_ERROR:
+		case Z_MEM_ERROR:
+		case Z_STREAM_ERROR:
+			inflateEnd(&strm);
+			free(result);
+			return ZR_MEM_ERROR;
+			break;
+		}
+
+		U32 have = CHUNK-strm.avail_out;
+
+		U8* new_result = (U8*)realloc(result, cur_size + have);
+		if (new_result == NULL)
+		{
+			LL_WARNS() << "Failed to unzip LLSD block: can't reallocate memory, current size: " << cur_size << " bytes; requested " << cur_size + have << " bytes." << LL_ENDL;
+			inflateEnd(&strm);
+			if (result)
+			{
+				free(result);
+			}
+			return ZR_MEM_ERROR;
+		}
+		result = new_result;
+		memcpy(result+cur_size, out, have);
+		cur_size += have;
+
+	} while (ret == Z_OK);
+
+	inflateEnd(&strm);
+
+	if (ret != Z_STREAM_END)
+	{
+		free(result);
+		return ZR_DATA_ERROR;
+	}
+
+	//result now points to the decompressed LLSD block
+	{
+		char* result_ptr = strip_deprecated_header((char*)result, cur_size);
+
+		boost::iostreams::stream<boost::iostreams::array_source> istrm(result_ptr, cur_size);
+		
+		if (!LLSDSerialize::fromBinary(data, istrm, cur_size, UNZIP_LLSD_MAX_DEPTH))
+		{
+			LL_WARNS() << "Failed to unzip LLSD block" << LL_ENDL;
+			free(result);
+			return ZR_PARSE_ERROR;
+		}
+	}
+
+	free(result);
+	return ZR_OK;
+}
+
+//This unzip function will only work with a gzip header and trailer - while the contents
+//of the actual compressed data is the same for either format (gzip vs zlib ), the headers
+//and trailers are different for the formats.
+U8* unzip_llsdNavMesh(bool& valid, unsigned int& outsize, std::istream& is, S32 size)
+{
+	if (size == 0)
+	{
+		LL_WARNS() << "No data to unzip." << LL_ENDL;
+		return NULL;
+	}
+	auto in = std::make_unique<U8[]>(size);
+	is.read((char*)in.get(), size);
+	return unzip_llsdNavMesh(valid, outsize, in.get(), size);
+}
+
+U8* unzip_llsdNavMesh( bool& valid, unsigned int& outsize, U8* in, S32 size )
+{
+	if (size == 0)
+	{
+		LL_WARNS() << "No data to unzip." << LL_ENDL;
+		return NULL;
+	}
+	U8* result = NULL;
+	U32 cur_size = 0;
+	z_stream strm;
+		
+	const U32 CHUNK = 0x4000;
+
+	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 = inflateInit2(&strm,  windowBits | ENABLE_ZLIB_GZIP );
+	do
+	{
+		strm.avail_out = CHUNK;
+		strm.next_out = out;
+		ret = inflate(&strm, Z_NO_FLUSH);
+		switch (ret)
+		{
+		case Z_NEED_DICT:
+			ret = Z_DATA_ERROR;
+		case Z_DATA_ERROR:
+		case Z_MEM_ERROR:
+		case Z_STREAM_ERROR:
+			inflateEnd(&strm);
+			free(result);
+			valid = false;
+			return NULL;
+		}
+		U32 have = CHUNK-strm.avail_out;
+
+		U8* new_result = (U8*) realloc(result, cur_size + have);
+		if (new_result == NULL)
+		{
+			LL_WARNS() << "Failed to unzip LLSD NavMesh block: can't reallocate memory, current size: " << cur_size
+				<< " bytes; requested " << cur_size + have
+				<< " bytes; total syze: ." << size << " bytes."
+				<< LL_ENDL;
+			inflateEnd(&strm);
+			if (result)
+			{
+				free(result);
+			}
+			valid = false;
+			return NULL;
+		}
+		result = new_result;
+		memcpy(result+cur_size, out, have);
+		cur_size += have;
+
+	} while (ret == Z_OK);
+
+	inflateEnd(&strm);
+
+	if (ret != Z_STREAM_END)
+	{
+		free(result);
+		valid = false;
+		return NULL;
+	}
+
+	//result now points to the decompressed LLSD block
+	{
+		outsize= cur_size;
+		valid = true;		
+	}
+
+	return result;
+}
+
+char* strip_deprecated_header(char* in, U32& cur_size, U32* header_size)
+{
+	const char* deprecated_header = "<? LLSD/Binary ?>";
+	constexpr size_t deprecated_header_size = 17;
+
+	if (cur_size > deprecated_header_size
+		&& memcmp(in, deprecated_header, deprecated_header_size) == 0)
+	{
+		in = in + deprecated_header_size;
+		cur_size = cur_size - deprecated_header_size;
+		if (header_size)
+		{
+			*header_size = deprecated_header_size + 1;
+		}
+	}
+
+	return in;
+}
+// </alchemy>
+
diff --git a/indra/llmessage/llmessageprecompiled.cpp b/indra/llmessage/llmessageprecompiled.cpp
index 4c43c94f03..3ee59cdbb9 100644
--- a/indra/llmessage/llmessageprecompiled.cpp
+++ b/indra/llmessage/llmessageprecompiled.cpp
@@ -1,27 +1,27 @@
-/**
- * @file llmessageprecompiled.cpp
- * @brief Includes common headers
- *
- * $LicenseInfo:firstyear=2019&license=viewerlgpl$
- * Alchemy Viewer Source Code
- * Copyright (C) 2019, Alchemy Viewer Project, 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 "llmessageprecompiled.h"
+/**
+ * @file llmessageprecompiled.cpp
+ * @brief Includes common headers
+ *
+ * $LicenseInfo:firstyear=2019&license=viewerlgpl$
+ * Alchemy Viewer Source Code
+ * Copyright (C) 2019, Alchemy Viewer Project, 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 "llmessageprecompiled.h"
diff --git a/indra/llmessage/llmessageprecompiled.h b/indra/llmessage/llmessageprecompiled.h
index 3aef589ac5..12679d7830 100644
--- a/indra/llmessage/llmessageprecompiled.h
+++ b/indra/llmessage/llmessageprecompiled.h
@@ -1,43 +1,43 @@
-/**
- * @file llmessageprecompiled.h
- * @brief Includes common headers
- *
- * $LicenseInfo:firstyear=2019&license=viewerlgpl$
- * Alchemy Viewer Source Code
- * Copyright (C) 2019, Alchemy Viewer Project, 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_LLMESSAGEPRECOMPILED_H
-#define LL_LLMESSAGEPRECOMPILED_H
-
-#include "linden_common.h"
-
-#include "llwin32headerslean.h"
-
-#include "llapr.h"
-#include "llsd.h"
-#include "llsingleton.h"
-#include "llstring.h"
-#include "llstringtable.h"
-#include "llstl.h"
-#include "lltimer.h"
-
-#endif // LL_LLMESSAGEPRECOMPILED_H
-
+/**
+ * @file llmessageprecompiled.h
+ * @brief Includes common headers
+ *
+ * $LicenseInfo:firstyear=2019&license=viewerlgpl$
+ * Alchemy Viewer Source Code
+ * Copyright (C) 2019, Alchemy Viewer Project, 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_LLMESSAGEPRECOMPILED_H
+#define LL_LLMESSAGEPRECOMPILED_H
+
+#include "linden_common.h"
+
+#include "llwin32headerslean.h"
+
+#include "llapr.h"
+#include "llsd.h"
+#include "llsingleton.h"
+#include "llstring.h"
+#include "llstringtable.h"
+#include "llstl.h"
+#include "lltimer.h"
+
+#endif // LL_LLMESSAGEPRECOMPILED_H
+
diff --git a/indra/llui/lluiprecompiled.cpp b/indra/llui/lluiprecompiled.cpp
index 9a722ae709..6043343642 100644
--- a/indra/llui/lluiprecompiled.cpp
+++ b/indra/llui/lluiprecompiled.cpp
@@ -1,27 +1,27 @@
-/**
- * @file lluiprecompiled.cpp
- * @brief Includes common headers
- *
- * $LicenseInfo:firstyear=2019&license=viewerlgpl$
- * Alchemy Viewer Source Code
- * Copyright (C) 2019, Alchemy Viewer Project, 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 "lluiprecompiled.h"
+/**
+ * @file lluiprecompiled.cpp
+ * @brief Includes common headers
+ *
+ * $LicenseInfo:firstyear=2019&license=viewerlgpl$
+ * Alchemy Viewer Source Code
+ * Copyright (C) 2019, Alchemy Viewer Project, 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 "lluiprecompiled.h"
diff --git a/indra/llui/lluiprecompiled.h b/indra/llui/lluiprecompiled.h
index b112559582..adc541809f 100644
--- a/indra/llui/lluiprecompiled.h
+++ b/indra/llui/lluiprecompiled.h
@@ -1,74 +1,74 @@
-/**
- * @file lluiprecompiled.h
- * @brief Includes common headers
- *
- * $LicenseInfo:firstyear=2019&license=viewerlgpl$
- * Alchemy Viewer Source Code
- * Copyright (C) 2019, Alchemy Viewer Project, 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_LLUIPRECOMPILED_H
-#define LL_LLUIPRECOMPILED_H
-
-#include "linden_common.h"
-
-#include <functional>
-#include <map>
-#include <limits>
-#include <list>
-#include <memory>
-#include <queue>
-#include <vector>
-
-#include "absl/container/node_hash_map.h"
-#include <absl/container/flat_hash_map.h>
-
-#include "llhandle.h"
-#include "llfasttimer.h"
-#include "llframetimer.h"
-#include "llheteromap.h"
-#include "llinitparam.h"
-#include "llinstancetracker.h"
-#include "llpointer.h"
-#include "llregistry.h"
-#include "llsd.h"
-#include "llsingleton.h"
-#include "llstl.h"
-#include "llstring.h"
-#include "lltreeiterators.h"
-
-#include "llcoord.h"
-#include "llrect.h"
-#include "llquaternion.h"
-#include "v2math.h"
-#include "v4color.h"
-#include "m3math.h"
-
-#include "lldir.h"
-
-#include "llgl.h"
-#include "llfontgl.h"
-#include "llglslshader.h"
-#include "llrender2dutils.h"
-
-#include "llcontrol.h"
-#include "llxmlnode.h"
-
-#endif // LL_LLUIPRECOMPILED_H
+/**
+ * @file lluiprecompiled.h
+ * @brief Includes common headers
+ *
+ * $LicenseInfo:firstyear=2019&license=viewerlgpl$
+ * Alchemy Viewer Source Code
+ * Copyright (C) 2019, Alchemy Viewer Project, 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_LLUIPRECOMPILED_H
+#define LL_LLUIPRECOMPILED_H
+
+#include "linden_common.h"
+
+#include <functional>
+#include <map>
+#include <limits>
+#include <list>
+#include <memory>
+#include <queue>
+#include <vector>
+
+#include "absl/container/node_hash_map.h"
+#include <absl/container/flat_hash_map.h>
+
+#include "llhandle.h"
+#include "llfasttimer.h"
+#include "llframetimer.h"
+#include "llheteromap.h"
+#include "llinitparam.h"
+#include "llinstancetracker.h"
+#include "llpointer.h"
+#include "llregistry.h"
+#include "llsd.h"
+#include "llsingleton.h"
+#include "llstl.h"
+#include "llstring.h"
+#include "lltreeiterators.h"
+
+#include "llcoord.h"
+#include "llrect.h"
+#include "llquaternion.h"
+#include "v2math.h"
+#include "v4color.h"
+#include "m3math.h"
+
+#include "lldir.h"
+
+#include "llgl.h"
+#include "llfontgl.h"
+#include "llglslshader.h"
+#include "llrender2dutils.h"
+
+#include "llcontrol.h"
+#include "llxmlnode.h"
+
+#endif // LL_LLUIPRECOMPILED_H
diff --git a/indra/llwindow/llwindowsdl2.cpp b/indra/llwindow/llwindowsdl2.cpp
index 9ed1581272..5519582069 100644
--- a/indra/llwindow/llwindowsdl2.cpp
+++ b/indra/llwindow/llwindowsdl2.cpp
@@ -46,7 +46,7 @@
 #include "SDL2/SDL_syswm.h"
 
 #if LL_WINDOWS
-#include <commdlg.h>
+#include <commdlg.h>
 #include <shellapi.h>
 #include "../newview/res/resource.h"
 #endif
diff --git a/indra/newview/installers/windows/installer_template.nsi b/indra/newview/installers/windows/installer_template.nsi
index 6d4a92e2f6..ffae438d9b 100644
--- a/indra/newview/installers/windows/installer_template.nsi
+++ b/indra/newview/installers/windows/installer_template.nsi
@@ -1,642 +1,642 @@
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; secondlife setup.nsi
-;; Copyright 2004-2011, Linden Research, Inc.
-;; Copyright 2013-2015 Alchemy Viewer Project
-;;
-;; 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
-;;
-;; NSIS 3 or higher required for Unicode support
-;;
-;; Author: James Cook, Don Kjer, Callum Prentice, Drake Arconis
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;--------------------------------
-;Unicode
-  Unicode true
-
-;--------------------------------
-;Include Modern UI
-
-  !include "LogicLib.nsh"
-  !include "StdUtils.nsh"
-  !include "FileFunc.nsh"
-  !insertmacro GetParameters
-  !insertmacro GetOptions
-  !include "x64.nsh"
-  !include "WinVer.nsh"
-  !include "MUI2.nsh"
-
-;-------------------------------
-;Global Variables
-  ; These will be replaced by manifest scripts
-  %%INST_VARS%%
-  %%WIN64_BIN_BUILD%%
-
-  Var INSTEXE
-  Var INSTPROG
-  Var VIEWER_EXE
-  Var INSTSHORTCUT
-  Var AUTOSTART
-  Var COMMANDLINE         ; command line passed to this installer, set in .onInit
-  Var SHORTCUT_LANG_PARAM ; "--set InstallLanguage de", passes language to viewer
-  Var SKIP_DIALOGS        ; set from command line in  .onInit. autoinstall 
-                          ; GUI and the defaults.
-  Var STARTMENUFOLDER
-
-;--------------------------------
-;Registry Keys
-  !define ALCHEMY_KEY      "SOFTWARE\${VENDORSTR}"
-  !define INSTNAME_KEY    "${ALCHEMY_KEY}\${APPNAMEONEWORD}"
-  !define MSCURRVER_KEY   "SOFTWARE\Microsoft\Windows\CurrentVersion"
-  !define MSNTCURRVER_KEY "SOFTWARE\Microsoft\Windows NT\CurrentVersion"
-  !define MSUNINSTALL_KEY "${MSCURRVER_KEY}\Uninstall\${APPNAMEONEWORD}"
-
-;--------------------------------
-;General
-
-  ;Name and file
-  Name "${APPNAME}"
-  OutFile "${INSTOUTFILE}"
-  Caption "${CAPTIONSTR}"
-  BrandingText "${VENDORSTR}"
-
-  ;Default installation folder
-!ifdef WIN64_BIN_BUILD
-  InstallDir "$PROGRAMFILES64\${APPNAMEONEWORD}"
-!else
-  InstallDir "$PROGRAMFILES\${APPNAMEONEWORD}"
-!endif
-
-  ;Get installation folder from registry if available and 32bit otherwise do it in init
-!ifndef WIN64_BIN_BUILD
-  InstallDirRegKey HKLM "${INSTNAME_KEY}" ""
-!endif
-
-  ;Request application privileges for Windows UAC
-  RequestExecutionLevel admin
-  
-  ;Compression
-  SetCompress auto			; compress to saves space
-  SetCompressor /solid /final lzma	; compress whole installer as one block
-  
-  ;File Handling
-  SetOverwrite on
-
-  ;Verify CRC
-  CRCCheck on
-
-;--------------------------------
-;Version Information
-
-  VIProductVersion "${VERSION_LONG}"
-  VIAddVersionKey "ProductName" "${APPNAME} Installer"
-  VIAddVersionKey "Comments" "A viewer for the meta-verse!"
-  VIAddVersionKey "CompanyName" "Alchemy Viewer Project"
-  VIAddVersionKey "LegalCopyright" "Copyright © 2013-2019, Alchemy Viewer Project"
-  VIAddVersionKey "FileDescription" "${APPNAME} Installer"
-  VIAddVersionKey "ProductVersion" "${VERSION_LONG}"
-  VIAddVersionKey "FileVersion" "${VERSION_LONG}"
-
-;--------------------------------
-;Interface Settings
-
-  ;Show Details
-  ShowInstDetails hide
-  ShowUninstDetails hide
-
-  !define MUI_ICON "%%SOURCE%%\installers\windows\install_icon.ico"
-  !define MUI_UNICON "%%SOURCE%%\installers\windows\uninstall_icon.ico"
-  !define MUI_WELCOMEFINISHPAGE_BITMAP "%%SOURCE%%\installers\windows\install_welcome.bmp"
-  !define MUI_UNWELCOMEFINISHPAGE_BITMAP "%%SOURCE%%\installers\windows\uninstall_welcome.bmp"
-  !define MUI_ABORTWARNING
-
-;--------------------------------
-;Language Selection Dialog Settings
-
-  ;Show all languages, despite user's codepage
-  !define MUI_LANGDLL_ALLLANGUAGES
-
-  ;Remember the installer language
-  !define MUI_LANGDLL_REGISTRY_ROOT "HKLM" 
-  !define MUI_LANGDLL_REGISTRY_KEY "${INSTNAME_KEY}" 
-  !define MUI_LANGDLL_REGISTRY_VALUENAME "InstallerLanguage"
-  
-  ;Always show the dialog
-  !define MUI_LANGDLL_ALWAYSSHOW
-
-;--------------------------------
-;Install Pages
-
-  !define MUI_PAGE_CUSTOMFUNCTION_PRE check_skip
-  !insertmacro MUI_PAGE_WELCOME
-  
-  ;License Page
-  !define MUI_PAGE_CUSTOMFUNCTION_PRE check_skip
-  !insertmacro MUI_PAGE_LICENSE "%%SOURCE%%\..\..\doc\LGPL-licence.txt"
-
-  ;Directory Page
-  !define MUI_PAGE_CUSTOMFUNCTION_PRE check_skip
-  !insertmacro MUI_PAGE_DIRECTORY
-
-  ;Start Menu Folder Page
-  !define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKLM" 
-  !define MUI_STARTMENUPAGE_REGISTRY_KEY "${INSTNAME_KEY}" 
-  !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder"
-  !define MUI_PAGE_CUSTOMFUNCTION_PRE check_skip
-  !insertmacro MUI_PAGE_STARTMENU Application $STARTMENUFOLDER
-
-  ;Install Progress Page
-  !define MUI_PAGE_CUSTOMFUNCTION_LEAVE CheckWindowsServPack
-  !insertmacro MUI_PAGE_INSTFILES
-
-  ; Finish Page
-  !define MUI_PAGE_CUSTOMFUNCTION_PRE check_skip_finish
-  !define MUI_FINISHPAGE_RUN
-  !define MUI_FINISHPAGE_RUN_FUNCTION launch_viewer
-  !define MUI_FINISHPAGE_SHOWREADME
-  !define MUI_FINISHPAGE_SHOWREADME_TEXT "Create Desktop Shortcut"
-  !define MUI_FINISHPAGE_SHOWREADME_NOTCHECKED
-  !define MUI_FINISHPAGE_SHOWREADME_FUNCTION create_desktop_shortcut
-  !define MUI_FINISHPAGE_NOREBOOTSUPPORT
-  !insertmacro MUI_PAGE_FINISH
-
-;--------------------------------
-;Uninstall Pages
-
-  !insertmacro MUI_UNPAGE_WELCOME
-  !insertmacro MUI_UNPAGE_CONFIRM
-  !insertmacro MUI_UNPAGE_INSTFILES
-  !insertmacro MUI_UNPAGE_FINISH
-
-;--------------------------------
-;Languages
-
-  !include "%%SOURCE%%\installers\windows\lang_en-us.nsi"
-  !include "%%SOURCE%%\installers\windows\lang_de.nsi"
-  !include "%%SOURCE%%\installers\windows\lang_es.nsi"
-  !include "%%SOURCE%%\installers\windows\lang_fr.nsi"
-  !include "%%SOURCE%%\installers\windows\lang_ja.nsi"
-  !include "%%SOURCE%%\installers\windows\lang_it.nsi"
-  !include "%%SOURCE%%\installers\windows\lang_pt-br.nsi"
-  !include "%%SOURCE%%\installers\windows\lang_ru.nsi"
-  !include "%%SOURCE%%\installers\windows\lang_tr.nsi"
-  !include "%%SOURCE%%\installers\windows\lang_zh.nsi"
-
-;--------------------------------
-;Reserve Files
-  
-  ;If you are using solid compression, files that are required before
-  ;the actual installation should be stored first in the data block,
-  ;because this will make your installer start faster.
-  
-  !insertmacro MUI_RESERVEFILE_LANGDLL
-  ReserveFile "${NSISDIR}\Plugins\x86-unicode\NSISdl.dll"
-  ReserveFile "${NSISDIR}\Plugins\x86-unicode\nsDialogs.dll"
-  ReserveFile "${NSISDIR}\Plugins\x86-unicode\StartMenu.dll"
-  ReserveFile "${NSISDIR}\Plugins\x86-unicode\StdUtils.dll"
-  ReserveFile "${NSISDIR}\Plugins\x86-unicode\System.dll"
-  ReserveFile "${NSISDIR}\Plugins\x86-unicode\UserInfo.dll"
-
-;--------------------------------
-; Local Functions
-
-;Page pre-checks for skip conditions
-Function check_skip
-  StrCmp $SKIP_DIALOGS "true" 0 +2
-  Abort
-FunctionEnd
-
-Function check_skip_finish
-  StrCmp $SKIP_DIALOGS "true" 0 +4
-  StrCmp $AUTOSTART "true" 0 +3
-  Call launch_viewer
-  Abort
-FunctionEnd
-
-Function launch_viewer
-  ${StdUtils.ExecShellAsUser} $0 "$INSTDIR\$INSTEXE" "open" "precheck $INSTDIR\$VIEWER_EXE $SHORTCUT_LANG_PARAM"
-FunctionEnd
-
-Function create_desktop_shortcut
-  CreateShortCut "$DESKTOP\$INSTSHORTCUT.lnk" "$INSTDIR\$VIEWER_EXE" "$SHORTCUT_LANG_PARAM" "$INSTDIR\$VIEWER_EXE"
-FunctionEnd
-
-;Check version compatibility
-Function CheckWindowsVersion
-!ifdef WIN64_BIN_BUILD
-  ${IfNot} ${RunningX64}
-    MessageBox MB_OK|MB_ICONSTOP "This version requires a 64 bit operating system."
-    Quit
-  ${EndIf}
-!endif
-
-  ${If} ${AtMostWinVista}
-    MessageBox MB_OK $(CheckWindowsVersionMB)
-    Quit
-  ${EndIf}
-FunctionEnd
-
-;Check service pack compatibility and suggest upgrade
-Function CheckWindowsServPack
-  ${If} ${IsWin7}
-  ${AndIfNot} ${IsServicePack} 1
-    MessageBox MB_OK $(CheckWindowsServPackMB)
-    DetailPrint $(UseLatestServPackDP)
-    Return
-  ${EndIf}
-
-  ${If} ${IsWin2008R2}
-  ${AndIfNot} ${IsServicePack} 1
-    MessageBox MB_OK $(CheckWindowsServPackMB)
-    DetailPrint $(UseLatestServPackDP)
-    Return
-  ${EndIf}
-FunctionEnd
-
-;Make sure the user can install/uninstall
-Function CheckIfAdministrator
-  DetailPrint $(CheckAdministratorInstDP)
-  UserInfo::GetAccountType
-  Pop $R0
-  StrCmp $R0 "Admin" lbl_is_admin
-    MessageBox MB_OK $(CheckAdministratorInstMB)
-    Quit
-lbl_is_admin:
-  Return
-FunctionEnd
-
-Function un.CheckIfAdministrator
-  DetailPrint $(CheckAdministratorUnInstDP)
-  UserInfo::GetAccountType
-  Pop $R0
-  StrCmp $R0 "Admin" lbl_is_admin
-    MessageBox MB_OK $(CheckAdministratorUnInstMB)
-    Quit
-lbl_is_admin:
-  Return
-FunctionEnd
-
-;Checks for CPU compatibility
-Function CheckCPUFlags
-  Push $1
-  System::Call 'kernel32::IsProcessorFeaturePresent(i) i(10) .r1'
-  IntCmp $1 1 OK_SSE2
-  MessageBox MB_OKCANCEL $(MissingSSE2) /SD IDOK IDOK OK_SSE2
-  Quit
-
-  OK_SSE2:
-  Pop $1
-  Return
-FunctionEnd
-
-;Checks if installed version is same as installer and offers to cancel
-Function CheckIfAlreadyCurrent
-!ifdef WIN64_BIN_BUILD
-  SetRegView 64
-!endif
-  Push $0
-  ReadRegStr $0 HKLM "SOFTWARE\${VENDORSTR}\$INSTPROG" "Version"
-  StrCmp $0 ${VERSION_LONG} 0 continue_install
-  StrCmp $SKIP_DIALOGS "true" continue_install
-  MessageBox MB_OKCANCEL $(CheckIfCurrentMB) /SD IDOK IDOK continue_install
-  Quit
-continue_install:
-  Pop $0
-  Return
-FunctionEnd
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-; Close the program, if running. Modifies no variables.
-; Allows user to bail out of install process.
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-Function CloseSecondLife
-  Push $0
-  FindWindow $0 "Alchemy" ""
-  IntCmp $0 0 DONE
-  
-  StrCmp $SKIP_DIALOGS "true" CLOSE
-    MessageBox MB_OKCANCEL $(CloseSecondLifeInstMB) IDOK CLOSE IDCANCEL CANCEL_INSTALL
-
-  CANCEL_INSTALL:
-    Quit
-
-  CLOSE:
-    DetailPrint $(CloseSecondLifeInstDP)
-    SendMessage $0 16 0 0
-
-  LOOP:
-	FindWindow $0 "Alchemy" ""
-	IntCmp $0 0 DONE
-	Sleep 500
-	Goto LOOP
-
-  DONE:
-    Pop $0
-    Return
-FunctionEnd
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-; Close the program, if running. Modifies no variables.
-; Allows user to bail out of uninstall process.
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-Function un.CloseSecondLife
-  Push $0
-  FindWindow $0 "Alchemy" ""
-  IntCmp $0 0 DONE
-  MessageBox MB_OKCANCEL $(CloseSecondLifeUnInstMB) IDOK CLOSE IDCANCEL CANCEL_UNINSTALL
-
-  CANCEL_UNINSTALL:
-    Quit
-
-  CLOSE:
-    DetailPrint $(CloseSecondLifeUnInstDP)
-    SendMessage $0 16 0 0
-
-  LOOP:
-    FindWindow $0 "Alchemy" ""
-    IntCmp $0 0 DONE
-    Sleep 500
-    Goto LOOP
-
-  DONE:
-    Pop $0
-    Return
-FunctionEnd
-
-
-
-;--------------------------------
-;Installer Sections
-
-Section "Viewer"
-  SectionIn RO
-  SetShellVarContext all
-!ifdef WIN64_BIN_BUILD
-  SetRegView 64
-!endif
-  ;Start with some default values.
-  StrCpy $INSTPROG "${APPNAMEONEWORD}"
-  StrCpy $INSTEXE "${INSTEXE}"
-  StrCpy $VIEWER_EXE "${VIEWER_EXE}"
-  StrCpy $INSTSHORTCUT "${APPNAME}"
-
-  Call CheckIfAlreadyCurrent
-  Call CloseSecondLife			    ; Make sure we're not running
-
-  SetOutPath "$INSTDIR"  
-  ;Remove all old files first to prevent incorrect installation
-  ;RMDir /r "$INSTDIR\*"
-  RMDir /r "$INSTDIR\app_settings"
-  RMDir /r "$INSTDIR\llplugin"
-  RMDir /r "$INSTDIR\skins"
-  RMDir /r "$INSTDIR\voice"
-  
-  ;This placeholder is replaced by the complete list of all the files in the installer, by viewer_manifest.py
-  %%INSTALL_FILES%%
-  
-  ;Pass the installer's language to the client to use as a default
-  StrCpy $SHORTCUT_LANG_PARAM "--set InstallLanguage $(LanguageCode)"
-  
-  ;Create startmenu shortcuts
-  !insertmacro MUI_STARTMENU_WRITE_BEGIN Application
-    CreateDirectory "$SMPROGRAMS\$STARTMENUFOLDER"
-!ifdef WIN64_BIN_BUILD
-    CreateShortCut	"$SMPROGRAMS\$STARTMENUFOLDER\$INSTSHORTCUT x64.lnk" "$INSTDIR\$VIEWER_EXE" "$SHORTCUT_LANG_PARAM" "$INSTDIR\$VIEWER_EXE"
-    CreateShortCut	"$SMPROGRAMS\$STARTMENUFOLDER\Uninstall $INSTSHORTCUT x64.lnk" "$\"$INSTDIR\uninst.exe$\"" ""
-!else
-    CreateShortCut	"$SMPROGRAMS\$STARTMENUFOLDER\$INSTSHORTCUT.lnk" "$INSTDIR\$VIEWER_EXE" "$SHORTCUT_LANG_PARAM" "$INSTDIR\$VIEWER_EXE"
-    CreateShortCut	"$SMPROGRAMS\$STARTMENUFOLDER\Uninstall $INSTSHORTCUT.lnk" "$INSTDIR\uninst.exe" ""
-!endif
-    WriteINIStr		"$SMPROGRAMS\$STARTMENUFOLDER\SL Create Account.url" "InternetShortcut" "URL" "http://join.secondlife.com/"
-    WriteINIStr		"$SMPROGRAMS\$STARTMENUFOLDER\SL Your Account.url"	"InternetShortcut" "URL" "http://www.secondlife.com/account/"
-    WriteINIStr		"$SMPROGRAMS\$STARTMENUFOLDER\SL Scripting Language Help.url" "InternetShortcut" "URL" "http://wiki.secondlife.com/wiki/LSL_Portal"
-
-  !insertmacro MUI_STARTMENU_WRITE_END
-
-  ;Other shortcuts
-  SetOutPath "$INSTDIR"
-  CreateShortCut "$INSTDIR\$INSTSHORTCUT.lnk" "$INSTDIR\$VIEWER_EXE" "$SHORTCUT_LANG_PARAM" "$INSTDIR\$VIEWER_EXE"
-  CreateShortCut "$INSTDIR\Uninstall $INSTSHORTCUT.lnk" "$INSTDIR\uninst.exe" ""
-    
-  ;Write registry
-  WriteRegStr HKLM "${INSTNAME_KEY}" "" "$INSTDIR"
-  WriteRegStr HKLM "${INSTNAME_KEY}" "Version" "${VERSION_LONG}"
-  WriteRegStr HKLM "${INSTNAME_KEY}" "Shortcut" "$INSTSHORTCUT"
-  WriteRegStr HKLM "${INSTNAME_KEY}" "Exe" "$VIEWER_EXE"
-  WriteRegStr HKLM "${MSUNINSTALL_KEY}" "Comments" "A viewer for the meta-verse!"
-!ifdef WIN64_BIN_BUILD
-  WriteRegStr HKLM "${MSUNINSTALL_KEY}" "DisplayName" "$INSTSHORTCUT x64"
-!else
-  WriteRegStr HKLM "${MSUNINSTALL_KEY}" "DisplayName" "$INSTSHORTCUT"
-!endif
-  WriteRegStr HKLM "${MSUNINSTALL_KEY}" "DisplayIcon" "$INSTDIR\$VIEWER_EXE"
-  WriteRegStr HKLM "${MSUNINSTALL_KEY}" "DisplayVersion" "${VERSION_LONG}"
-  WriteRegStr HKLM "${MSUNINSTALL_KEY}" "InstallLocation" "$INSTDIR"
-  WriteRegStr HKLM "${MSUNINSTALL_KEY}" "InstallSource" "$EXEDIR\"
-  WriteRegStr HKLM "${MSUNINSTALL_KEY}" "HelpLink" "https://www.alchemyviewer.org"
-  WriteRegDWORD HKLM "${MSUNINSTALL_KEY}" "NoModify" 1
-  WriteRegDWORD HKLM "${MSUNINSTALL_KEY}" "NoRepair" 1
-  WriteRegStr HKLM "${MSUNINSTALL_KEY}" "Publisher" "${VENDORSTR}"
-  WriteRegStr HKLM "${MSUNINSTALL_KEY}" "URLInfoAbout" "https://www.alchemyviewer.org"
-  WriteRegStr HKLM "${MSUNINSTALL_KEY}" "URLUpdateInfo" "https://www.alchemyviewer.org/p/downloads.html"
-  WriteRegStr HKLM "${MSUNINSTALL_KEY}" "UninstallString" "$\"$INSTDIR\uninst.exe$\""
-  WriteRegStr HKLM "${MSUNINSTALL_KEY}" "QuietUninstallString" "$\"$INSTDIR\uninst.exe$\" /S"
-  ${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2
-  IntFmt $0 "0x%08X" $0
-  WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "EstimatedSize" "$0"
-
-
-  ;Write URL registry info
-  DeleteRegKey HKEY_CLASSES_ROOT "${URLNAME}"
-  WriteRegStr HKEY_CLASSES_ROOT "${URLNAME}" "" "URL:Second Life"
-  WriteRegStr HKEY_CLASSES_ROOT "${URLNAME}" "URL Protocol" ""
-  WriteRegStr HKEY_CLASSES_ROOT "${URLNAME}\DefaultIcon" "" "$INSTDIR\$VIEWER_EXE"
-  ;; URL param must be last item passed to viewer, it ignores subsequent params
-  ;; to avoid parameter injection attacks.
-  WriteRegStr HKEY_CLASSES_ROOT "${URLNAME}\shell" "" "open"
-!ifdef WIN64_BIN_BUILD
-  WriteRegStr HKEY_CLASSES_ROOT "${URLNAME}\shell\open" "FriendlyAppName" "$INSTSHORTCUT x64"
-!else
-  WriteRegStr HKEY_CLASSES_ROOT "${URLNAME}\shell\open" "FriendlyAppName" "$INSTSHORTCUT"
-!endif
-  WriteRegExpandStr HKEY_CLASSES_ROOT "${URLNAME}\shell\open\command" "" "$\"$INSTDIR\$VIEWER_EXE$\" -url $\"%1$\""
-
-  DeleteRegKey HKEY_CLASSES_ROOT "x-grid-info"
-  WriteRegStr HKEY_CLASSES_ROOT "x-grid-info" "" "URL:Hypergrid"
-  WriteRegStr HKEY_CLASSES_ROOT "x-grid-info" "URL Protocol" ""
-  WriteRegStr HKEY_CLASSES_ROOT "x-grid-info\DefaultIcon" "" "$INSTDIR\$VIEWER_EXE"
-  ;; URL param must be last item passed to viewer, it ignores subsequent params
-  ;; to avoid parameter injection attacks.
-  WriteRegStr HKEY_CLASSES_ROOT "x-grid-info\shell" "" "open"
-!ifdef WIN64_BIN_BUILD
-  WriteRegStr HKEY_CLASSES_ROOT "x-grid-info\shell\open" "FriendlyAppName" "$INSTSHORTCUT x64"
-!else
-  WriteRegStr HKEY_CLASSES_ROOT "x-grid-info\shell\open" "FriendlyAppName" "$INSTSHORTCUT"
-!endif
-  WriteRegExpandStr HKEY_CLASSES_ROOT "x-grid-info\shell\open\command" "" "$\"$INSTDIR\$VIEWER_EXE$\" -url $\"%1$\""
-
-  DeleteRegKey HKEY_CLASSES_ROOT "x-grid-location-info}"
-  WriteRegStr HKEY_CLASSES_ROOT "x-grid-location-info" "" "URL:Hypergrid legacy"
-  WriteRegStr HKEY_CLASSES_ROOT "x-grid-location-info" "URL Protocol" ""
-  WriteRegStr HKEY_CLASSES_ROOT "x-grid-location-info\DefaultIcon" "" "$INSTDIR\$VIEWER_EXE"
-  ;; URL param must be last item passed to viewer, it ignores subsequent params
-  ;; to avoid parameter injection attacks.
-  WriteRegStr HKEY_CLASSES_ROOT "x-grid-location-info\shell" "" "open"
-!ifdef WIN64_BIN_BUILD
-  WriteRegStr HKEY_CLASSES_ROOT "x-grid-location-info\shell\open" "FriendlyAppName" "$INSTSHORTCUT x64"
-!else
-  WriteRegStr HKEY_CLASSES_ROOT "x-grid-location-info\shell\open" "FriendlyAppName" "$INSTSHORTCUT"
-!endif
-  WriteRegExpandStr HKEY_CLASSES_ROOT "x-grid-location-info\shell\open\command" "" "$\"$INSTDIR\$VIEWER_EXE$\" -url $\"%1$\""
-  
-  ;Create uninstaller
-  SetOutPath "$INSTDIR"  
-  WriteUninstaller "$INSTDIR\uninst.exe"
-  
-SectionEnd
-
-;--------------------------------
-;Installer Functions
-Function .onInit
-!ifdef WIN64_BIN_BUILD
-  SetRegView 64
-!endif
-  ;Don't install on unsupported operating systems
-  Call CheckWindowsVersion
-  ;Don't install if not administator
-  Call CheckIfAdministrator
-  ;Don't install if we lack required cpu support
-  Call CheckCPUFlags
-
-  Push $0
-
-  ;Get installation folder from registry if available for 64bit
-  ReadRegStr $0 HKLM "SOFTWARE\${VENDORSTR}\${APPNAMEONEWORD}" ""
-  IfErrors +2 0 ; If error jump past setting the instdir from registry
-  StrCpy $INSTDIR $0
-
-  ${GetParameters} $COMMANDLINE              ; get our command line
-
-  ${GetOptions} $COMMANDLINE "/SKIP_DIALOGS" $0   
-  IfErrors +2 0 ; If error jump past setting SKIP_DIALOGS
-  StrCpy $SKIP_DIALOGS "true"
-
-  ${GetOptions} $COMMANDLINE "/AUTOSTART" $0
-  IfErrors +2 0 ; If error jump past setting AUTOSTART
-  StrCpy $AUTOSTART "true"
-
-
-  ${GetOptions} $COMMANDLINE "/LANGID=" $0   ; /LANGID=1033 implies US English
-  ; If no language (error), then proceed
-  IfErrors lbl_configure_default_lang
-  ; No error means we got a language, so use it
-  StrCpy $LANGUAGE $0
-  Goto lbl_return
-  
-lbl_configure_default_lang:
-  ;For silent installs, no language prompt, use default
-  IfSilent lbl_return
-  StrCmp $SKIP_DIALOGS "true" lbl_return
- 
-  !insertmacro MUI_LANGDLL_DISPLAY
-
-lbl_return:
-  Pop $0
-  Return
-FunctionEnd
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; After install completes, launch app
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-Function .onInstSuccess
-        Push $R0
-        Push $0
-        ;; MAINT-7812: Only write nsis.winstall file with /marker switch
-        ${GetParameters} $R0
-        ${GetOptionsS} $R0 "/marker" $0
-        ;; If no /marker switch, skip to ClearErrors
-        IfErrors +4 0
-        ;; $EXEDIR is where we find the installer file
-        ;; Put a marker file there so VMP will know we're done
-        ;; and it can delete the download directory next time.
-        ;; http://nsis.sourceforge.net/Write_text_to_a_file
-        FileOpen $0 "$EXEDIR\nsis.winstall" w
-        FileWrite $0 "NSIS done$\n"
-        FileClose $0
-
-        ClearErrors
-        Pop $0
-        Pop $R0
-FunctionEnd
-
-;--------------------------------
-;Uninstaller Section
-
-Section "Uninstall"
-  SectionIn RO
-  SetShellVarContext all
-!ifdef WIN64_BIN_BUILD
-  SetRegView 64
-!endif
-  
-  StrCpy $INSTPROG "${APPNAMEONEWORD}"
-  StrCpy $INSTSHORTCUT "${APPNAME}"
-
-  Call un.CloseSecondLife
-  
-  !insertmacro MUI_STARTMENU_GETFOLDER Application $STARTMENUFOLDER
-  RMDir /r "$SMPROGRAMS\$STARTMENUFOLDER"
-
-  # This placeholder is replaced by the complete list of files to uninstall by viewer_manifest.py
-  %%DELETE_FILES%%
-
-  ;Optional/obsolete files.  Delete won't fail if they don't exist.
-  Delete "$INSTDIR\message_template.msg"
-  Delete "$INSTDIR\VivoxVoiceService-*.log"
-
-  ;Shortcuts in install directory
-  Delete "$INSTDIR\$INSTSHORTCUT.lnk"
-  Delete "$INSTDIR\Uninstall $INSTSHORTCUT.lnk"
-
-  Delete "$INSTDIR\uninst.exe"
-  RMDir "$INSTDIR"
-  
-  IfFileExists "$INSTDIR" FOLDERFOUND NOFOLDER
-
-FOLDERFOUND:
-  ;Silent uninstall always removes all files (/SD IDYES)
-  MessageBox MB_YESNO $(DeleteProgramFilesMB) /SD IDYES IDNO NOFOLDER
-  RMDir /r "$INSTDIR"
-
-NOFOLDER:
-  DeleteRegKey HKLM "SOFTWARE\${VENDORSTR}\$INSTPROG"
-  DeleteRegKey /ifempty HKLM "SOFTWARE\${VENDORSTR}"
-  DeleteRegKey HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG"
- 
-SectionEnd
-
-;--------------------------------
-;Uninstaller Functions
-
-Function un.onInit
-!ifdef WIN64_BIN_BUILD
-  SetRegView 64
-!endif
-  Call un.CheckIfAdministrator
-
-  !insertmacro MUI_UNGETLANGUAGE
-  
-FunctionEnd
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; secondlife setup.nsi
+;; Copyright 2004-2011, Linden Research, Inc.
+;; Copyright 2013-2015 Alchemy Viewer Project
+;;
+;; 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
+;;
+;; NSIS 3 or higher required for Unicode support
+;;
+;; Author: James Cook, Don Kjer, Callum Prentice, Drake Arconis
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;--------------------------------
+;Unicode
+  Unicode true
+
+;--------------------------------
+;Include Modern UI
+
+  !include "LogicLib.nsh"
+  !include "StdUtils.nsh"
+  !include "FileFunc.nsh"
+  !insertmacro GetParameters
+  !insertmacro GetOptions
+  !include "x64.nsh"
+  !include "WinVer.nsh"
+  !include "MUI2.nsh"
+
+;-------------------------------
+;Global Variables
+  ; These will be replaced by manifest scripts
+  %%INST_VARS%%
+  %%WIN64_BIN_BUILD%%
+
+  Var INSTEXE
+  Var INSTPROG
+  Var VIEWER_EXE
+  Var INSTSHORTCUT
+  Var AUTOSTART
+  Var COMMANDLINE         ; command line passed to this installer, set in .onInit
+  Var SHORTCUT_LANG_PARAM ; "--set InstallLanguage de", passes language to viewer
+  Var SKIP_DIALOGS        ; set from command line in  .onInit. autoinstall 
+                          ; GUI and the defaults.
+  Var STARTMENUFOLDER
+
+;--------------------------------
+;Registry Keys
+  !define ALCHEMY_KEY      "SOFTWARE\${VENDORSTR}"
+  !define INSTNAME_KEY    "${ALCHEMY_KEY}\${APPNAMEONEWORD}"
+  !define MSCURRVER_KEY   "SOFTWARE\Microsoft\Windows\CurrentVersion"
+  !define MSNTCURRVER_KEY "SOFTWARE\Microsoft\Windows NT\CurrentVersion"
+  !define MSUNINSTALL_KEY "${MSCURRVER_KEY}\Uninstall\${APPNAMEONEWORD}"
+
+;--------------------------------
+;General
+
+  ;Name and file
+  Name "${APPNAME}"
+  OutFile "${INSTOUTFILE}"
+  Caption "${CAPTIONSTR}"
+  BrandingText "${VENDORSTR}"
+
+  ;Default installation folder
+!ifdef WIN64_BIN_BUILD
+  InstallDir "$PROGRAMFILES64\${APPNAMEONEWORD}"
+!else
+  InstallDir "$PROGRAMFILES\${APPNAMEONEWORD}"
+!endif
+
+  ;Get installation folder from registry if available and 32bit otherwise do it in init
+!ifndef WIN64_BIN_BUILD
+  InstallDirRegKey HKLM "${INSTNAME_KEY}" ""
+!endif
+
+  ;Request application privileges for Windows UAC
+  RequestExecutionLevel admin
+  
+  ;Compression
+  SetCompress auto			; compress to saves space
+  SetCompressor /solid /final lzma	; compress whole installer as one block
+  
+  ;File Handling
+  SetOverwrite on
+
+  ;Verify CRC
+  CRCCheck on
+
+;--------------------------------
+;Version Information
+
+  VIProductVersion "${VERSION_LONG}"
+  VIAddVersionKey "ProductName" "${APPNAME} Installer"
+  VIAddVersionKey "Comments" "A viewer for the meta-verse!"
+  VIAddVersionKey "CompanyName" "Alchemy Viewer Project"
+  VIAddVersionKey "LegalCopyright" "Copyright © 2013-2019, Alchemy Viewer Project"
+  VIAddVersionKey "FileDescription" "${APPNAME} Installer"
+  VIAddVersionKey "ProductVersion" "${VERSION_LONG}"
+  VIAddVersionKey "FileVersion" "${VERSION_LONG}"
+
+;--------------------------------
+;Interface Settings
+
+  ;Show Details
+  ShowInstDetails hide
+  ShowUninstDetails hide
+
+  !define MUI_ICON "%%SOURCE%%\installers\windows\install_icon.ico"
+  !define MUI_UNICON "%%SOURCE%%\installers\windows\uninstall_icon.ico"
+  !define MUI_WELCOMEFINISHPAGE_BITMAP "%%SOURCE%%\installers\windows\install_welcome.bmp"
+  !define MUI_UNWELCOMEFINISHPAGE_BITMAP "%%SOURCE%%\installers\windows\uninstall_welcome.bmp"
+  !define MUI_ABORTWARNING
+
+;--------------------------------
+;Language Selection Dialog Settings
+
+  ;Show all languages, despite user's codepage
+  !define MUI_LANGDLL_ALLLANGUAGES
+
+  ;Remember the installer language
+  !define MUI_LANGDLL_REGISTRY_ROOT "HKLM" 
+  !define MUI_LANGDLL_REGISTRY_KEY "${INSTNAME_KEY}" 
+  !define MUI_LANGDLL_REGISTRY_VALUENAME "InstallerLanguage"
+  
+  ;Always show the dialog
+  !define MUI_LANGDLL_ALWAYSSHOW
+
+;--------------------------------
+;Install Pages
+
+  !define MUI_PAGE_CUSTOMFUNCTION_PRE check_skip
+  !insertmacro MUI_PAGE_WELCOME
+  
+  ;License Page
+  !define MUI_PAGE_CUSTOMFUNCTION_PRE check_skip
+  !insertmacro MUI_PAGE_LICENSE "%%SOURCE%%\..\..\doc\LGPL-licence.txt"
+
+  ;Directory Page
+  !define MUI_PAGE_CUSTOMFUNCTION_PRE check_skip
+  !insertmacro MUI_PAGE_DIRECTORY
+
+  ;Start Menu Folder Page
+  !define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKLM" 
+  !define MUI_STARTMENUPAGE_REGISTRY_KEY "${INSTNAME_KEY}" 
+  !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder"
+  !define MUI_PAGE_CUSTOMFUNCTION_PRE check_skip
+  !insertmacro MUI_PAGE_STARTMENU Application $STARTMENUFOLDER
+
+  ;Install Progress Page
+  !define MUI_PAGE_CUSTOMFUNCTION_LEAVE CheckWindowsServPack
+  !insertmacro MUI_PAGE_INSTFILES
+
+  ; Finish Page
+  !define MUI_PAGE_CUSTOMFUNCTION_PRE check_skip_finish
+  !define MUI_FINISHPAGE_RUN
+  !define MUI_FINISHPAGE_RUN_FUNCTION launch_viewer
+  !define MUI_FINISHPAGE_SHOWREADME
+  !define MUI_FINISHPAGE_SHOWREADME_TEXT "Create Desktop Shortcut"
+  !define MUI_FINISHPAGE_SHOWREADME_NOTCHECKED
+  !define MUI_FINISHPAGE_SHOWREADME_FUNCTION create_desktop_shortcut
+  !define MUI_FINISHPAGE_NOREBOOTSUPPORT
+  !insertmacro MUI_PAGE_FINISH
+
+;--------------------------------
+;Uninstall Pages
+
+  !insertmacro MUI_UNPAGE_WELCOME
+  !insertmacro MUI_UNPAGE_CONFIRM
+  !insertmacro MUI_UNPAGE_INSTFILES
+  !insertmacro MUI_UNPAGE_FINISH
+
+;--------------------------------
+;Languages
+
+  !include "%%SOURCE%%\installers\windows\lang_en-us.nsi"
+  !include "%%SOURCE%%\installers\windows\lang_de.nsi"
+  !include "%%SOURCE%%\installers\windows\lang_es.nsi"
+  !include "%%SOURCE%%\installers\windows\lang_fr.nsi"
+  !include "%%SOURCE%%\installers\windows\lang_ja.nsi"
+  !include "%%SOURCE%%\installers\windows\lang_it.nsi"
+  !include "%%SOURCE%%\installers\windows\lang_pt-br.nsi"
+  !include "%%SOURCE%%\installers\windows\lang_ru.nsi"
+  !include "%%SOURCE%%\installers\windows\lang_tr.nsi"
+  !include "%%SOURCE%%\installers\windows\lang_zh.nsi"
+
+;--------------------------------
+;Reserve Files
+  
+  ;If you are using solid compression, files that are required before
+  ;the actual installation should be stored first in the data block,
+  ;because this will make your installer start faster.
+  
+  !insertmacro MUI_RESERVEFILE_LANGDLL
+  ReserveFile "${NSISDIR}\Plugins\x86-unicode\NSISdl.dll"
+  ReserveFile "${NSISDIR}\Plugins\x86-unicode\nsDialogs.dll"
+  ReserveFile "${NSISDIR}\Plugins\x86-unicode\StartMenu.dll"
+  ReserveFile "${NSISDIR}\Plugins\x86-unicode\StdUtils.dll"
+  ReserveFile "${NSISDIR}\Plugins\x86-unicode\System.dll"
+  ReserveFile "${NSISDIR}\Plugins\x86-unicode\UserInfo.dll"
+
+;--------------------------------
+; Local Functions
+
+;Page pre-checks for skip conditions
+Function check_skip
+  StrCmp $SKIP_DIALOGS "true" 0 +2
+  Abort
+FunctionEnd
+
+Function check_skip_finish
+  StrCmp $SKIP_DIALOGS "true" 0 +4
+  StrCmp $AUTOSTART "true" 0 +3
+  Call launch_viewer
+  Abort
+FunctionEnd
+
+Function launch_viewer
+  ${StdUtils.ExecShellAsUser} $0 "$INSTDIR\$INSTEXE" "open" "precheck $INSTDIR\$VIEWER_EXE $SHORTCUT_LANG_PARAM"
+FunctionEnd
+
+Function create_desktop_shortcut
+  CreateShortCut "$DESKTOP\$INSTSHORTCUT.lnk" "$INSTDIR\$VIEWER_EXE" "$SHORTCUT_LANG_PARAM" "$INSTDIR\$VIEWER_EXE"
+FunctionEnd
+
+;Check version compatibility
+Function CheckWindowsVersion
+!ifdef WIN64_BIN_BUILD
+  ${IfNot} ${RunningX64}
+    MessageBox MB_OK|MB_ICONSTOP "This version requires a 64 bit operating system."
+    Quit
+  ${EndIf}
+!endif
+
+  ${If} ${AtMostWinVista}
+    MessageBox MB_OK $(CheckWindowsVersionMB)
+    Quit
+  ${EndIf}
+FunctionEnd
+
+;Check service pack compatibility and suggest upgrade
+Function CheckWindowsServPack
+  ${If} ${IsWin7}
+  ${AndIfNot} ${IsServicePack} 1
+    MessageBox MB_OK $(CheckWindowsServPackMB)
+    DetailPrint $(UseLatestServPackDP)
+    Return
+  ${EndIf}
+
+  ${If} ${IsWin2008R2}
+  ${AndIfNot} ${IsServicePack} 1
+    MessageBox MB_OK $(CheckWindowsServPackMB)
+    DetailPrint $(UseLatestServPackDP)
+    Return
+  ${EndIf}
+FunctionEnd
+
+;Make sure the user can install/uninstall
+Function CheckIfAdministrator
+  DetailPrint $(CheckAdministratorInstDP)
+  UserInfo::GetAccountType
+  Pop $R0
+  StrCmp $R0 "Admin" lbl_is_admin
+    MessageBox MB_OK $(CheckAdministratorInstMB)
+    Quit
+lbl_is_admin:
+  Return
+FunctionEnd
+
+Function un.CheckIfAdministrator
+  DetailPrint $(CheckAdministratorUnInstDP)
+  UserInfo::GetAccountType
+  Pop $R0
+  StrCmp $R0 "Admin" lbl_is_admin
+    MessageBox MB_OK $(CheckAdministratorUnInstMB)
+    Quit
+lbl_is_admin:
+  Return
+FunctionEnd
+
+;Checks for CPU compatibility
+Function CheckCPUFlags
+  Push $1
+  System::Call 'kernel32::IsProcessorFeaturePresent(i) i(10) .r1'
+  IntCmp $1 1 OK_SSE2
+  MessageBox MB_OKCANCEL $(MissingSSE2) /SD IDOK IDOK OK_SSE2
+  Quit
+
+  OK_SSE2:
+  Pop $1
+  Return
+FunctionEnd
+
+;Checks if installed version is same as installer and offers to cancel
+Function CheckIfAlreadyCurrent
+!ifdef WIN64_BIN_BUILD
+  SetRegView 64
+!endif
+  Push $0
+  ReadRegStr $0 HKLM "SOFTWARE\${VENDORSTR}\$INSTPROG" "Version"
+  StrCmp $0 ${VERSION_LONG} 0 continue_install
+  StrCmp $SKIP_DIALOGS "true" continue_install
+  MessageBox MB_OKCANCEL $(CheckIfCurrentMB) /SD IDOK IDOK continue_install
+  Quit
+continue_install:
+  Pop $0
+  Return
+FunctionEnd
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Close the program, if running. Modifies no variables.
+; Allows user to bail out of install process.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+Function CloseSecondLife
+  Push $0
+  FindWindow $0 "Alchemy" ""
+  IntCmp $0 0 DONE
+  
+  StrCmp $SKIP_DIALOGS "true" CLOSE
+    MessageBox MB_OKCANCEL $(CloseSecondLifeInstMB) IDOK CLOSE IDCANCEL CANCEL_INSTALL
+
+  CANCEL_INSTALL:
+    Quit
+
+  CLOSE:
+    DetailPrint $(CloseSecondLifeInstDP)
+    SendMessage $0 16 0 0
+
+  LOOP:
+	FindWindow $0 "Alchemy" ""
+	IntCmp $0 0 DONE
+	Sleep 500
+	Goto LOOP
+
+  DONE:
+    Pop $0
+    Return
+FunctionEnd
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Close the program, if running. Modifies no variables.
+; Allows user to bail out of uninstall process.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+Function un.CloseSecondLife
+  Push $0
+  FindWindow $0 "Alchemy" ""
+  IntCmp $0 0 DONE
+  MessageBox MB_OKCANCEL $(CloseSecondLifeUnInstMB) IDOK CLOSE IDCANCEL CANCEL_UNINSTALL
+
+  CANCEL_UNINSTALL:
+    Quit
+
+  CLOSE:
+    DetailPrint $(CloseSecondLifeUnInstDP)
+    SendMessage $0 16 0 0
+
+  LOOP:
+    FindWindow $0 "Alchemy" ""
+    IntCmp $0 0 DONE
+    Sleep 500
+    Goto LOOP
+
+  DONE:
+    Pop $0
+    Return
+FunctionEnd
+
+
+
+;--------------------------------
+;Installer Sections
+
+Section "Viewer"
+  SectionIn RO
+  SetShellVarContext all
+!ifdef WIN64_BIN_BUILD
+  SetRegView 64
+!endif
+  ;Start with some default values.
+  StrCpy $INSTPROG "${APPNAMEONEWORD}"
+  StrCpy $INSTEXE "${INSTEXE}"
+  StrCpy $VIEWER_EXE "${VIEWER_EXE}"
+  StrCpy $INSTSHORTCUT "${APPNAME}"
+
+  Call CheckIfAlreadyCurrent
+  Call CloseSecondLife			    ; Make sure we're not running
+
+  SetOutPath "$INSTDIR"  
+  ;Remove all old files first to prevent incorrect installation
+  ;RMDir /r "$INSTDIR\*"
+  RMDir /r "$INSTDIR\app_settings"
+  RMDir /r "$INSTDIR\llplugin"
+  RMDir /r "$INSTDIR\skins"
+  RMDir /r "$INSTDIR\voice"
+  
+  ;This placeholder is replaced by the complete list of all the files in the installer, by viewer_manifest.py
+  %%INSTALL_FILES%%
+  
+  ;Pass the installer's language to the client to use as a default
+  StrCpy $SHORTCUT_LANG_PARAM "--set InstallLanguage $(LanguageCode)"
+  
+  ;Create startmenu shortcuts
+  !insertmacro MUI_STARTMENU_WRITE_BEGIN Application
+    CreateDirectory "$SMPROGRAMS\$STARTMENUFOLDER"
+!ifdef WIN64_BIN_BUILD
+    CreateShortCut	"$SMPROGRAMS\$STARTMENUFOLDER\$INSTSHORTCUT x64.lnk" "$INSTDIR\$VIEWER_EXE" "$SHORTCUT_LANG_PARAM" "$INSTDIR\$VIEWER_EXE"
+    CreateShortCut	"$SMPROGRAMS\$STARTMENUFOLDER\Uninstall $INSTSHORTCUT x64.lnk" "$\"$INSTDIR\uninst.exe$\"" ""
+!else
+    CreateShortCut	"$SMPROGRAMS\$STARTMENUFOLDER\$INSTSHORTCUT.lnk" "$INSTDIR\$VIEWER_EXE" "$SHORTCUT_LANG_PARAM" "$INSTDIR\$VIEWER_EXE"
+    CreateShortCut	"$SMPROGRAMS\$STARTMENUFOLDER\Uninstall $INSTSHORTCUT.lnk" "$INSTDIR\uninst.exe" ""
+!endif
+    WriteINIStr		"$SMPROGRAMS\$STARTMENUFOLDER\SL Create Account.url" "InternetShortcut" "URL" "http://join.secondlife.com/"
+    WriteINIStr		"$SMPROGRAMS\$STARTMENUFOLDER\SL Your Account.url"	"InternetShortcut" "URL" "http://www.secondlife.com/account/"
+    WriteINIStr		"$SMPROGRAMS\$STARTMENUFOLDER\SL Scripting Language Help.url" "InternetShortcut" "URL" "http://wiki.secondlife.com/wiki/LSL_Portal"
+
+  !insertmacro MUI_STARTMENU_WRITE_END
+
+  ;Other shortcuts
+  SetOutPath "$INSTDIR"
+  CreateShortCut "$INSTDIR\$INSTSHORTCUT.lnk" "$INSTDIR\$VIEWER_EXE" "$SHORTCUT_LANG_PARAM" "$INSTDIR\$VIEWER_EXE"
+  CreateShortCut "$INSTDIR\Uninstall $INSTSHORTCUT.lnk" "$INSTDIR\uninst.exe" ""
+    
+  ;Write registry
+  WriteRegStr HKLM "${INSTNAME_KEY}" "" "$INSTDIR"
+  WriteRegStr HKLM "${INSTNAME_KEY}" "Version" "${VERSION_LONG}"
+  WriteRegStr HKLM "${INSTNAME_KEY}" "Shortcut" "$INSTSHORTCUT"
+  WriteRegStr HKLM "${INSTNAME_KEY}" "Exe" "$VIEWER_EXE"
+  WriteRegStr HKLM "${MSUNINSTALL_KEY}" "Comments" "A viewer for the meta-verse!"
+!ifdef WIN64_BIN_BUILD
+  WriteRegStr HKLM "${MSUNINSTALL_KEY}" "DisplayName" "$INSTSHORTCUT x64"
+!else
+  WriteRegStr HKLM "${MSUNINSTALL_KEY}" "DisplayName" "$INSTSHORTCUT"
+!endif
+  WriteRegStr HKLM "${MSUNINSTALL_KEY}" "DisplayIcon" "$INSTDIR\$VIEWER_EXE"
+  WriteRegStr HKLM "${MSUNINSTALL_KEY}" "DisplayVersion" "${VERSION_LONG}"
+  WriteRegStr HKLM "${MSUNINSTALL_KEY}" "InstallLocation" "$INSTDIR"
+  WriteRegStr HKLM "${MSUNINSTALL_KEY}" "InstallSource" "$EXEDIR\"
+  WriteRegStr HKLM "${MSUNINSTALL_KEY}" "HelpLink" "https://www.alchemyviewer.org"
+  WriteRegDWORD HKLM "${MSUNINSTALL_KEY}" "NoModify" 1
+  WriteRegDWORD HKLM "${MSUNINSTALL_KEY}" "NoRepair" 1
+  WriteRegStr HKLM "${MSUNINSTALL_KEY}" "Publisher" "${VENDORSTR}"
+  WriteRegStr HKLM "${MSUNINSTALL_KEY}" "URLInfoAbout" "https://www.alchemyviewer.org"
+  WriteRegStr HKLM "${MSUNINSTALL_KEY}" "URLUpdateInfo" "https://www.alchemyviewer.org/p/downloads.html"
+  WriteRegStr HKLM "${MSUNINSTALL_KEY}" "UninstallString" "$\"$INSTDIR\uninst.exe$\""
+  WriteRegStr HKLM "${MSUNINSTALL_KEY}" "QuietUninstallString" "$\"$INSTDIR\uninst.exe$\" /S"
+  ${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2
+  IntFmt $0 "0x%08X" $0
+  WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "EstimatedSize" "$0"
+
+
+  ;Write URL registry info
+  DeleteRegKey HKEY_CLASSES_ROOT "${URLNAME}"
+  WriteRegStr HKEY_CLASSES_ROOT "${URLNAME}" "" "URL:Second Life"
+  WriteRegStr HKEY_CLASSES_ROOT "${URLNAME}" "URL Protocol" ""
+  WriteRegStr HKEY_CLASSES_ROOT "${URLNAME}\DefaultIcon" "" "$INSTDIR\$VIEWER_EXE"
+  ;; URL param must be last item passed to viewer, it ignores subsequent params
+  ;; to avoid parameter injection attacks.
+  WriteRegStr HKEY_CLASSES_ROOT "${URLNAME}\shell" "" "open"
+!ifdef WIN64_BIN_BUILD
+  WriteRegStr HKEY_CLASSES_ROOT "${URLNAME}\shell\open" "FriendlyAppName" "$INSTSHORTCUT x64"
+!else
+  WriteRegStr HKEY_CLASSES_ROOT "${URLNAME}\shell\open" "FriendlyAppName" "$INSTSHORTCUT"
+!endif
+  WriteRegExpandStr HKEY_CLASSES_ROOT "${URLNAME}\shell\open\command" "" "$\"$INSTDIR\$VIEWER_EXE$\" -url $\"%1$\""
+
+  DeleteRegKey HKEY_CLASSES_ROOT "x-grid-info"
+  WriteRegStr HKEY_CLASSES_ROOT "x-grid-info" "" "URL:Hypergrid"
+  WriteRegStr HKEY_CLASSES_ROOT "x-grid-info" "URL Protocol" ""
+  WriteRegStr HKEY_CLASSES_ROOT "x-grid-info\DefaultIcon" "" "$INSTDIR\$VIEWER_EXE"
+  ;; URL param must be last item passed to viewer, it ignores subsequent params
+  ;; to avoid parameter injection attacks.
+  WriteRegStr HKEY_CLASSES_ROOT "x-grid-info\shell" "" "open"
+!ifdef WIN64_BIN_BUILD
+  WriteRegStr HKEY_CLASSES_ROOT "x-grid-info\shell\open" "FriendlyAppName" "$INSTSHORTCUT x64"
+!else
+  WriteRegStr HKEY_CLASSES_ROOT "x-grid-info\shell\open" "FriendlyAppName" "$INSTSHORTCUT"
+!endif
+  WriteRegExpandStr HKEY_CLASSES_ROOT "x-grid-info\shell\open\command" "" "$\"$INSTDIR\$VIEWER_EXE$\" -url $\"%1$\""
+
+  DeleteRegKey HKEY_CLASSES_ROOT "x-grid-location-info}"
+  WriteRegStr HKEY_CLASSES_ROOT "x-grid-location-info" "" "URL:Hypergrid legacy"
+  WriteRegStr HKEY_CLASSES_ROOT "x-grid-location-info" "URL Protocol" ""
+  WriteRegStr HKEY_CLASSES_ROOT "x-grid-location-info\DefaultIcon" "" "$INSTDIR\$VIEWER_EXE"
+  ;; URL param must be last item passed to viewer, it ignores subsequent params
+  ;; to avoid parameter injection attacks.
+  WriteRegStr HKEY_CLASSES_ROOT "x-grid-location-info\shell" "" "open"
+!ifdef WIN64_BIN_BUILD
+  WriteRegStr HKEY_CLASSES_ROOT "x-grid-location-info\shell\open" "FriendlyAppName" "$INSTSHORTCUT x64"
+!else
+  WriteRegStr HKEY_CLASSES_ROOT "x-grid-location-info\shell\open" "FriendlyAppName" "$INSTSHORTCUT"
+!endif
+  WriteRegExpandStr HKEY_CLASSES_ROOT "x-grid-location-info\shell\open\command" "" "$\"$INSTDIR\$VIEWER_EXE$\" -url $\"%1$\""
+  
+  ;Create uninstaller
+  SetOutPath "$INSTDIR"  
+  WriteUninstaller "$INSTDIR\uninst.exe"
+  
+SectionEnd
+
+;--------------------------------
+;Installer Functions
+Function .onInit
+!ifdef WIN64_BIN_BUILD
+  SetRegView 64
+!endif
+  ;Don't install on unsupported operating systems
+  Call CheckWindowsVersion
+  ;Don't install if not administator
+  Call CheckIfAdministrator
+  ;Don't install if we lack required cpu support
+  Call CheckCPUFlags
+
+  Push $0
+
+  ;Get installation folder from registry if available for 64bit
+  ReadRegStr $0 HKLM "SOFTWARE\${VENDORSTR}\${APPNAMEONEWORD}" ""
+  IfErrors +2 0 ; If error jump past setting the instdir from registry
+  StrCpy $INSTDIR $0
+
+  ${GetParameters} $COMMANDLINE              ; get our command line
+
+  ${GetOptions} $COMMANDLINE "/SKIP_DIALOGS" $0   
+  IfErrors +2 0 ; If error jump past setting SKIP_DIALOGS
+  StrCpy $SKIP_DIALOGS "true"
+
+  ${GetOptions} $COMMANDLINE "/AUTOSTART" $0
+  IfErrors +2 0 ; If error jump past setting AUTOSTART
+  StrCpy $AUTOSTART "true"
+
+
+  ${GetOptions} $COMMANDLINE "/LANGID=" $0   ; /LANGID=1033 implies US English
+  ; If no language (error), then proceed
+  IfErrors lbl_configure_default_lang
+  ; No error means we got a language, so use it
+  StrCpy $LANGUAGE $0
+  Goto lbl_return
+  
+lbl_configure_default_lang:
+  ;For silent installs, no language prompt, use default
+  IfSilent lbl_return
+  StrCmp $SKIP_DIALOGS "true" lbl_return
+ 
+  !insertmacro MUI_LANGDLL_DISPLAY
+
+lbl_return:
+  Pop $0
+  Return
+FunctionEnd
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; After install completes, launch app
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+Function .onInstSuccess
+        Push $R0
+        Push $0
+        ;; MAINT-7812: Only write nsis.winstall file with /marker switch
+        ${GetParameters} $R0
+        ${GetOptionsS} $R0 "/marker" $0
+        ;; If no /marker switch, skip to ClearErrors
+        IfErrors +4 0
+        ;; $EXEDIR is where we find the installer file
+        ;; Put a marker file there so VMP will know we're done
+        ;; and it can delete the download directory next time.
+        ;; http://nsis.sourceforge.net/Write_text_to_a_file
+        FileOpen $0 "$EXEDIR\nsis.winstall" w
+        FileWrite $0 "NSIS done$\n"
+        FileClose $0
+
+        ClearErrors
+        Pop $0
+        Pop $R0
+FunctionEnd
+
+;--------------------------------
+;Uninstaller Section
+
+Section "Uninstall"
+  SectionIn RO
+  SetShellVarContext all
+!ifdef WIN64_BIN_BUILD
+  SetRegView 64
+!endif
+  
+  StrCpy $INSTPROG "${APPNAMEONEWORD}"
+  StrCpy $INSTSHORTCUT "${APPNAME}"
+
+  Call un.CloseSecondLife
+  
+  !insertmacro MUI_STARTMENU_GETFOLDER Application $STARTMENUFOLDER
+  RMDir /r "$SMPROGRAMS\$STARTMENUFOLDER"
+
+  # This placeholder is replaced by the complete list of files to uninstall by viewer_manifest.py
+  %%DELETE_FILES%%
+
+  ;Optional/obsolete files.  Delete won't fail if they don't exist.
+  Delete "$INSTDIR\message_template.msg"
+  Delete "$INSTDIR\VivoxVoiceService-*.log"
+
+  ;Shortcuts in install directory
+  Delete "$INSTDIR\$INSTSHORTCUT.lnk"
+  Delete "$INSTDIR\Uninstall $INSTSHORTCUT.lnk"
+
+  Delete "$INSTDIR\uninst.exe"
+  RMDir "$INSTDIR"
+  
+  IfFileExists "$INSTDIR" FOLDERFOUND NOFOLDER
+
+FOLDERFOUND:
+  ;Silent uninstall always removes all files (/SD IDYES)
+  MessageBox MB_YESNO $(DeleteProgramFilesMB) /SD IDYES IDNO NOFOLDER
+  RMDir /r "$INSTDIR"
+
+NOFOLDER:
+  DeleteRegKey HKLM "SOFTWARE\${VENDORSTR}\$INSTPROG"
+  DeleteRegKey /ifempty HKLM "SOFTWARE\${VENDORSTR}"
+  DeleteRegKey HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG"
+ 
+SectionEnd
+
+;--------------------------------
+;Uninstaller Functions
+
+Function un.onInit
+!ifdef WIN64_BIN_BUILD
+  SetRegView 64
+!endif
+  Call un.CheckIfAdministrator
+
+  !insertmacro MUI_UNGETLANGUAGE
+  
+FunctionEnd
diff --git a/indra/newview/installers/windows/lang_da.nsi b/indra/newview/installers/windows/lang_da.nsi
index 756e275f69..e4458ce408 100644
--- a/indra/newview/installers/windows/lang_da.nsi
+++ b/indra/newview/installers/windows/lang_da.nsi
@@ -1,56 +1,56 @@
-; First is default
-!insertmacro MUI_LANGUAGE "Danish"
-
-; Language string
-LangString LanguageCode ${LANG_DANISH}   "da"
-
-; Language selection dialog
-LangString SelectInstallerLanguage  ${LANG_DANISH} "Vælg venligst sprog til installation"
-
-; installation directory text
-LangString DirectoryChooseTitle ${LANG_DANISH} "Installationsmappe" 
-LangString DirectoryChooseUpdate ${LANG_DANISH} "Vælg ${APPNAME} mappe til opdatering til version ${VERSION_LONG}.(XXX):"
-LangString DirectoryChooseSetup ${LANG_DANISH} "Vælg mappe hvor ${APPNAME} skal installeres:"
-
-; CheckStartupParams message box
-LangString CheckStartupParamsMB ${LANG_DANISH} "Kunne ikke finde programmet '$INSTPROG'. Baggrundsopdatering fejlede."
-
-; check windows version
-LangString CheckWindowsVersionDP ${LANG_DANISH} "Checker Windows version..."
-LangString CheckWindowsVersionMB ${LANG_DANISH} '${APPNAME} supporterer kun Windows XP.$\n$\nForsøg på installation på Windows $R0 kan resultere i nedbrud og datatab.$\n$\n'
-LangString CheckWindowsServPackMB ${LANG_DANISH} "It is recomended to run ${APPNAME} on the latest service pack for your operating system.$\nThis will help with performance and stability of the program."
-LangString UseLatestServPackDP ${LANG_DANISH} "Please use Windows Update to install the latest Service Pack."
-
-; checkifadministrator function (install)
-LangString CheckAdministratorInstDP ${LANG_DANISH} "Checker rettigheder til installation..."
-LangString CheckAdministratorInstMB ${LANG_DANISH} 'Det ser ud til at du benytter en konto med begrænsninger.$\nDu skal have "administrator" rettigheder for at installere ${APPNAME}.'
-
-; checkifadministrator function (uninstall)
-LangString CheckAdministratorUnInstDP ${LANG_DANISH} "Checker rettigheder til at afinstallere..."
-LangString CheckAdministratorUnInstMB ${LANG_DANISH} 'Det ser ud til at du benytter en konto med begrænsninger.$\nDu skal have "administrator" rettigheder for at afinstallere ${APPNAME}.'
-
-; checkifalreadycurrent
-LangString CheckIfCurrentMB ${LANG_DANISH} "Det ser ud til at ${APPNAME} ${VERSION_LONG} allerede er installeret.$\n$\nØnsker du at installere igen?"
-
-; checkcpuflags
-LangString MissingSSE2 ${LANG_DANISH} "This machine may not have a CPU with SSE2 support, which is required to run ${APPNAME} ${VERSION_LONG}. Do you want to continue?"
-
-; closesecondlife function (install)
-LangString CloseSecondLifeInstDP ${LANG_DANISH} "Venter på at Alchemy skal lukke ned..."
-LangString CloseSecondLifeInstMB ${LANG_DANISH} "Alchemy kan ikke installeres mens programmet kører.$\n$\nAfslut programmet for at fortsætte.$\nVælg ANNULÉR for at afbryde installation."
-
-; closesecondlife function (uninstall)
-LangString CloseSecondLifeUnInstDP ${LANG_DANISH} "Venter på at Alchemy skal lukke ned..."
-LangString CloseSecondLifeUnInstMB ${LANG_DANISH} "Alchemy kan ikke afinstalleres mens programmet kører.$\n$\nAfslut programmet for at fortsætte.$\nVælg ANNULÉR for at afbryde installation."
-
-; CheckNetworkConnection
-LangString CheckNetworkConnectionDP ${LANG_DANISH} "Checker netværksforbindelse..."
-
-; removecachefiles
-LangString RemoveCacheFilesDP ${LANG_DANISH} "Sletter cache filer i dokument mappen"
-
-; delete program files
-LangString DeleteProgramFilesMB ${LANG_DANISH} "Der er stadig filer i ${APPNAME} program mappen.$\n$\nDette er sandsynligvis filer du har oprettet eller flyttet til :$\n$INSTDIR$\n$\nØnsker du at fjerne disse filer?"
-
-; uninstall text
-LangString UninstallTextMsg ${LANG_DANISH} "Dette vil afinstallere ${APPNAME} ${VERSION_LONG} fra dit system."
+; First is default
+!insertmacro MUI_LANGUAGE "Danish"
+
+; Language string
+LangString LanguageCode ${LANG_DANISH}   "da"
+
+; Language selection dialog
+LangString SelectInstallerLanguage  ${LANG_DANISH} "Vælg venligst sprog til installation"
+
+; installation directory text
+LangString DirectoryChooseTitle ${LANG_DANISH} "Installationsmappe" 
+LangString DirectoryChooseUpdate ${LANG_DANISH} "Vælg ${APPNAME} mappe til opdatering til version ${VERSION_LONG}.(XXX):"
+LangString DirectoryChooseSetup ${LANG_DANISH} "Vælg mappe hvor ${APPNAME} skal installeres:"
+
+; CheckStartupParams message box
+LangString CheckStartupParamsMB ${LANG_DANISH} "Kunne ikke finde programmet '$INSTPROG'. Baggrundsopdatering fejlede."
+
+; check windows version
+LangString CheckWindowsVersionDP ${LANG_DANISH} "Checker Windows version..."
+LangString CheckWindowsVersionMB ${LANG_DANISH} '${APPNAME} supporterer kun Windows XP.$\n$\nForsøg på installation på Windows $R0 kan resultere i nedbrud og datatab.$\n$\n'
+LangString CheckWindowsServPackMB ${LANG_DANISH} "It is recomended to run ${APPNAME} on the latest service pack for your operating system.$\nThis will help with performance and stability of the program."
+LangString UseLatestServPackDP ${LANG_DANISH} "Please use Windows Update to install the latest Service Pack."
+
+; checkifadministrator function (install)
+LangString CheckAdministratorInstDP ${LANG_DANISH} "Checker rettigheder til installation..."
+LangString CheckAdministratorInstMB ${LANG_DANISH} 'Det ser ud til at du benytter en konto med begrænsninger.$\nDu skal have "administrator" rettigheder for at installere ${APPNAME}.'
+
+; checkifadministrator function (uninstall)
+LangString CheckAdministratorUnInstDP ${LANG_DANISH} "Checker rettigheder til at afinstallere..."
+LangString CheckAdministratorUnInstMB ${LANG_DANISH} 'Det ser ud til at du benytter en konto med begrænsninger.$\nDu skal have "administrator" rettigheder for at afinstallere ${APPNAME}.'
+
+; checkifalreadycurrent
+LangString CheckIfCurrentMB ${LANG_DANISH} "Det ser ud til at ${APPNAME} ${VERSION_LONG} allerede er installeret.$\n$\nØnsker du at installere igen?"
+
+; checkcpuflags
+LangString MissingSSE2 ${LANG_DANISH} "This machine may not have a CPU with SSE2 support, which is required to run ${APPNAME} ${VERSION_LONG}. Do you want to continue?"
+
+; closesecondlife function (install)
+LangString CloseSecondLifeInstDP ${LANG_DANISH} "Venter på at Alchemy skal lukke ned..."
+LangString CloseSecondLifeInstMB ${LANG_DANISH} "Alchemy kan ikke installeres mens programmet kører.$\n$\nAfslut programmet for at fortsætte.$\nVælg ANNULÉR for at afbryde installation."
+
+; closesecondlife function (uninstall)
+LangString CloseSecondLifeUnInstDP ${LANG_DANISH} "Venter på at Alchemy skal lukke ned..."
+LangString CloseSecondLifeUnInstMB ${LANG_DANISH} "Alchemy kan ikke afinstalleres mens programmet kører.$\n$\nAfslut programmet for at fortsætte.$\nVælg ANNULÉR for at afbryde installation."
+
+; CheckNetworkConnection
+LangString CheckNetworkConnectionDP ${LANG_DANISH} "Checker netværksforbindelse..."
+
+; removecachefiles
+LangString RemoveCacheFilesDP ${LANG_DANISH} "Sletter cache filer i dokument mappen"
+
+; delete program files
+LangString DeleteProgramFilesMB ${LANG_DANISH} "Der er stadig filer i ${APPNAME} program mappen.$\n$\nDette er sandsynligvis filer du har oprettet eller flyttet til :$\n$INSTDIR$\n$\nØnsker du at fjerne disse filer?"
+
+; uninstall text
+LangString UninstallTextMsg ${LANG_DANISH} "Dette vil afinstallere ${APPNAME} ${VERSION_LONG} fra dit system."
diff --git a/indra/newview/installers/windows/lang_de.nsi b/indra/newview/installers/windows/lang_de.nsi
index b2e9299bd2..2351f705ab 100755
--- a/indra/newview/installers/windows/lang_de.nsi
+++ b/indra/newview/installers/windows/lang_de.nsi
@@ -1,56 +1,56 @@
-; First is default
-!insertmacro MUI_LANGUAGE "German"
-
-; Language string
-LangString LanguageCode ${LANG_GERMAN}   "de"
-
-; Language selection dialog
-LangString SelectInstallerLanguage  ${LANG_GERMAN} "Bitte wählen Sie die Installationssprache"
-
-; installation directory text
-LangString DirectoryChooseTitle ${LANG_GERMAN} "Installations-Ordner"
-LangString DirectoryChooseUpdate ${LANG_GERMAN} "Wählen Sie den ${APPNAME} Ordner für dieses Update:"
-LangString DirectoryChooseSetup ${LANG_GERMAN} "Pfad in dem ${APPNAME} installiert werden soll:"
-
-; CheckStartupParams message box
-LangString CheckStartupParamsMB ${LANG_GERMAN} "Konnte Programm '$INSTPROG' nicht finden. Stilles Update fehlgeschlagen."
-
-; check windows version
-LangString CheckWindowsVersionDP ${LANG_GERMAN} "Überprüfung der Windows Version ..."
-LangString CheckWindowsVersionMB ${LANG_GERMAN} '${APPNAME} unterstützt nur Windows XP.$\n$\nDer Versuch es auf Windows $R0 zu installieren, könnte zu unvorhersehbaren Abstürzen und Datenverlust führen.$\n$\nTrotzdem installieren?'
-LangString CheckWindowsServPackMB ${LANG_GERMAN} "Es wird empfohlen, das aktuellste Service Pack des Betriebssystems für ${APPNAME} zu verwenden.$\nEs ist hilftreich für Performance und Stabilität des Programms."
-LangString UseLatestServPackDP ${LANG_GERMAN} "Bitte Windows Update benutzen, um das aktuellste Service Pack zu installieren."
-
-; checkifadministrator function (install)
-LangString CheckAdministratorInstDP ${LANG_GERMAN} "Überprüfung der Installations-Berechtigungen ..."
-LangString CheckAdministratorInstMB ${LANG_GERMAN} 'Sie besitzen ungenügende Berechtigungen.$\nSie müssen ein "administrator" sein, um ${APPNAME} installieren zu können.'
-
-; checkifadministrator function (uninstall)
-LangString CheckAdministratorUnInstDP ${LANG_GERMAN} "Überprüfung der Entfernungs-Berechtigungen ..."
-LangString CheckAdministratorUnInstMB ${LANG_GERMAN} 'Sie besitzen ungenügende Berechtigungen.$\nSie müssen ein "administrator" sein, um ${APPNAME} entfernen zu können..'
-
-; checkifalreadycurrent
-LangString CheckIfCurrentMB ${LANG_GERMAN} "Anscheinend ist ${APPNAME} ${VERSION_LONG} bereits installiert.$\n$\nWürden Sie es gerne erneut installieren?"
-
-; checkcpuflags
-LangString MissingSSE2 ${LANG_GERMAN} "Dieser PC besitzt möglicherweise keinen Prozessor mit SSE2-Unterstützung, die für die Ausführung von ${APPNAME} ${VERSION_LONG} benötigt wird. Trotzdem installieren?"
-
-; closesecondlife function (install)
-LangString CloseSecondLifeInstDP ${LANG_GERMAN} "Warten auf die Beendigung von Alchemy ..."
-LangString CloseSecondLifeInstMB ${LANG_GERMAN} "Alchemy kann nicht installiert oder ersetzt werden, wenn es bereits läuft.$\n$\nBeenden Sie, was Sie gerade tun und klicken Sie OK, um Alchemy zu beenden.$\nKlicken Sie CANCEL, um die Installation abzubrechen."
-
-; closesecondlife function (uninstall)
-LangString CloseSecondLifeUnInstDP ${LANG_GERMAN} "Warten auf die Beendigung von Alchemy ..."
-LangString CloseSecondLifeUnInstMB ${LANG_GERMAN} "Alchemy kann nicht entfernt werden, wenn es bereits läuft.$\n$\nBeenden Sie, was Sie gerade tun und klicken Sie OK, um Alchemy zu beenden.$\nKlicken Sie CANCEL, um abzubrechen."
-
-; CheckNetworkConnection
-LangString CheckNetworkConnectionDP ${LANG_GERMAN} "Prüfe Netzwerkverbindung..."
-
-; removecachefiles
-LangString RemoveCacheFilesDP ${LANG_GERMAN} "Löschung aller Cache Dateien in Dokumente und Einstellungen."
-
-; delete program files
-LangString DeleteProgramFilesMB ${LANG_GERMAN} "Es existieren weiterhin Dateien in Ihrem SecondLife Programm Ordner.$\n$\nDies sind möglicherweise Dateien, die sie modifiziert oder bewegt haben:$\n$INSTDIR$\n$\nMöchten Sie diese ebenfalls löschen?"
-
-; uninstall text
-LangString UninstallTextMsg ${LANG_GERMAN} "Dies wird ${APPNAME} ${VERSION_LONG} von Ihrem System entfernen."
+; First is default
+!insertmacro MUI_LANGUAGE "German"
+
+; Language string
+LangString LanguageCode ${LANG_GERMAN}   "de"
+
+; Language selection dialog
+LangString SelectInstallerLanguage  ${LANG_GERMAN} "Bitte wählen Sie die Installationssprache"
+
+; installation directory text
+LangString DirectoryChooseTitle ${LANG_GERMAN} "Installations-Ordner"
+LangString DirectoryChooseUpdate ${LANG_GERMAN} "Wählen Sie den ${APPNAME} Ordner für dieses Update:"
+LangString DirectoryChooseSetup ${LANG_GERMAN} "Pfad in dem ${APPNAME} installiert werden soll:"
+
+; CheckStartupParams message box
+LangString CheckStartupParamsMB ${LANG_GERMAN} "Konnte Programm '$INSTPROG' nicht finden. Stilles Update fehlgeschlagen."
+
+; check windows version
+LangString CheckWindowsVersionDP ${LANG_GERMAN} "Überprüfung der Windows Version ..."
+LangString CheckWindowsVersionMB ${LANG_GERMAN} '${APPNAME} unterstützt nur Windows XP.$\n$\nDer Versuch es auf Windows $R0 zu installieren, könnte zu unvorhersehbaren Abstürzen und Datenverlust führen.$\n$\nTrotzdem installieren?'
+LangString CheckWindowsServPackMB ${LANG_GERMAN} "Es wird empfohlen, das aktuellste Service Pack des Betriebssystems für ${APPNAME} zu verwenden.$\nEs ist hilftreich für Performance und Stabilität des Programms."
+LangString UseLatestServPackDP ${LANG_GERMAN} "Bitte Windows Update benutzen, um das aktuellste Service Pack zu installieren."
+
+; checkifadministrator function (install)
+LangString CheckAdministratorInstDP ${LANG_GERMAN} "Überprüfung der Installations-Berechtigungen ..."
+LangString CheckAdministratorInstMB ${LANG_GERMAN} 'Sie besitzen ungenügende Berechtigungen.$\nSie müssen ein "administrator" sein, um ${APPNAME} installieren zu können.'
+
+; checkifadministrator function (uninstall)
+LangString CheckAdministratorUnInstDP ${LANG_GERMAN} "Überprüfung der Entfernungs-Berechtigungen ..."
+LangString CheckAdministratorUnInstMB ${LANG_GERMAN} 'Sie besitzen ungenügende Berechtigungen.$\nSie müssen ein "administrator" sein, um ${APPNAME} entfernen zu können..'
+
+; checkifalreadycurrent
+LangString CheckIfCurrentMB ${LANG_GERMAN} "Anscheinend ist ${APPNAME} ${VERSION_LONG} bereits installiert.$\n$\nWürden Sie es gerne erneut installieren?"
+
+; checkcpuflags
+LangString MissingSSE2 ${LANG_GERMAN} "Dieser PC besitzt möglicherweise keinen Prozessor mit SSE2-Unterstützung, die für die Ausführung von ${APPNAME} ${VERSION_LONG} benötigt wird. Trotzdem installieren?"
+
+; closesecondlife function (install)
+LangString CloseSecondLifeInstDP ${LANG_GERMAN} "Warten auf die Beendigung von Alchemy ..."
+LangString CloseSecondLifeInstMB ${LANG_GERMAN} "Alchemy kann nicht installiert oder ersetzt werden, wenn es bereits läuft.$\n$\nBeenden Sie, was Sie gerade tun und klicken Sie OK, um Alchemy zu beenden.$\nKlicken Sie CANCEL, um die Installation abzubrechen."
+
+; closesecondlife function (uninstall)
+LangString CloseSecondLifeUnInstDP ${LANG_GERMAN} "Warten auf die Beendigung von Alchemy ..."
+LangString CloseSecondLifeUnInstMB ${LANG_GERMAN} "Alchemy kann nicht entfernt werden, wenn es bereits läuft.$\n$\nBeenden Sie, was Sie gerade tun und klicken Sie OK, um Alchemy zu beenden.$\nKlicken Sie CANCEL, um abzubrechen."
+
+; CheckNetworkConnection
+LangString CheckNetworkConnectionDP ${LANG_GERMAN} "Prüfe Netzwerkverbindung..."
+
+; removecachefiles
+LangString RemoveCacheFilesDP ${LANG_GERMAN} "Löschung aller Cache Dateien in Dokumente und Einstellungen."
+
+; delete program files
+LangString DeleteProgramFilesMB ${LANG_GERMAN} "Es existieren weiterhin Dateien in Ihrem SecondLife Programm Ordner.$\n$\nDies sind möglicherweise Dateien, die sie modifiziert oder bewegt haben:$\n$INSTDIR$\n$\nMöchten Sie diese ebenfalls löschen?"
+
+; uninstall text
+LangString UninstallTextMsg ${LANG_GERMAN} "Dies wird ${APPNAME} ${VERSION_LONG} von Ihrem System entfernen."
diff --git a/indra/newview/installers/windows/lang_en-us.nsi b/indra/newview/installers/windows/lang_en-us.nsi
index 6da77ef0a4..dd1719c7b9 100644
--- a/indra/newview/installers/windows/lang_en-us.nsi
+++ b/indra/newview/installers/windows/lang_en-us.nsi
@@ -1,56 +1,56 @@
-; First is default
-!insertmacro MUI_LANGUAGE "English"
-
-; Language string
-LangString LanguageCode ${LANG_ENGLISH}  "en"
-
-; Language selection dialog
-LangString SelectInstallerLanguage  ${LANG_ENGLISH} "Please select the language of the installer"
-
-; installation directory text
-LangString DirectoryChooseTitle ${LANG_ENGLISH} "Installation Directory" 
-LangString DirectoryChooseUpdate ${LANG_ENGLISH} "Select the ${APPNAME} directory to update to version ${VERSION_LONG}.(XXX):"
-LangString DirectoryChooseSetup ${LANG_ENGLISH} "Select the directory to install ${APPNAME} in:"
-
-; CheckStartupParams message box
-LangString CheckStartupParamsMB ${LANG_ENGLISH} "Could not find the program '$INSTPROG'. Silent update failed."
-
-; check windows version
-LangString CheckWindowsVersionDP ${LANG_ENGLISH} "Checking Windows version..."
-LangString CheckWindowsVersionMB ${LANG_ENGLISH} "${APPNAME} only supports Windows 7 with Service Pack 1 and later.$\nInstallation on this Operating System is not supported. Quitting."
-LangString CheckWindowsServPackMB ${LANG_ENGLISH} "It is recomended to run ${APPNAME} on the latest service pack for your operating system.$\nThis will help with performance and stability of the program."
-LangString UseLatestServPackDP ${LANG_ENGLISH} "Please use Windows Update to install the latest Service Pack."
-
-; checkifadministrator function (install)
-LangString CheckAdministratorInstDP ${LANG_ENGLISH} "Checking for permission to install..."
-LangString CheckAdministratorInstMB ${LANG_ENGLISH} 'You appear to be using a "limited" account.$\nYou must be an "administrator" to install ${APPNAME}.'
-
-; checkifadministrator function (uninstall)
-LangString CheckAdministratorUnInstDP ${LANG_ENGLISH} "Checking for permission to uninstall..."
-LangString CheckAdministratorUnInstMB ${LANG_ENGLISH} 'You appear to be using a "limited" account.$\nYou must be an "administrator" to uninstall ${APPNAME}.'
-
-; checkifalreadycurrent
-LangString CheckIfCurrentMB ${LANG_ENGLISH} "It appears that ${APPNAME} ${VERSION_LONG} is already installed.$\n$\nWould you like to install it again?"
-
-; checkcpuflags
-LangString MissingSSE2 ${LANG_ENGLISH} "This machine may not have a CPU with SSE2 support, which is required to run ${APPNAME} ${VERSION_LONG}. Do you want to continue?"
-
-; closesecondlife function (install)
-LangString CloseSecondLifeInstDP ${LANG_ENGLISH} "Waiting for Alchemy to shut down..."
-LangString CloseSecondLifeInstMB ${LANG_ENGLISH} "Alchemy can't be installed while it is already running.$\n$\nFinish what you're doing then select OK to close Alchemy and continue.$\nSelect CANCEL to cancel installation."
-
-; closesecondlife function (uninstall)
-LangString CloseSecondLifeUnInstDP ${LANG_ENGLISH} "Waiting for Alchemy to shut down..."
-LangString CloseSecondLifeUnInstMB ${LANG_ENGLISH} "Alchemy can't be uninstalled while it is already running.$\n$\nFinish what you're doing then select OK to close Alchemy and continue.$\nSelect CANCEL to cancel."
-
-; CheckNetworkConnection
-LangString CheckNetworkConnectionDP ${LANG_ENGLISH} "Checking network connection..."
-
-; removecachefiles
-LangString RemoveCacheFilesDP ${LANG_ENGLISH} "Deleting cache files in Documents and Settings folder"
-
-; delete program files
-LangString DeleteProgramFilesMB ${LANG_ENGLISH} "There are still files in your ${APPNAME} program directory.$\n$\nThese are possibly files you created or moved to:$\n$INSTDIR$\n$\nDo you want to remove them?"
-
-; uninstall text
-LangString UninstallTextMsg ${LANG_ENGLISH} "This will uninstall ${APPNAME} ${VERSION_LONG} from your system. Click Uninstall to start the uninstallation."
+; First is default
+!insertmacro MUI_LANGUAGE "English"
+
+; Language string
+LangString LanguageCode ${LANG_ENGLISH}  "en"
+
+; Language selection dialog
+LangString SelectInstallerLanguage  ${LANG_ENGLISH} "Please select the language of the installer"
+
+; installation directory text
+LangString DirectoryChooseTitle ${LANG_ENGLISH} "Installation Directory" 
+LangString DirectoryChooseUpdate ${LANG_ENGLISH} "Select the ${APPNAME} directory to update to version ${VERSION_LONG}.(XXX):"
+LangString DirectoryChooseSetup ${LANG_ENGLISH} "Select the directory to install ${APPNAME} in:"
+
+; CheckStartupParams message box
+LangString CheckStartupParamsMB ${LANG_ENGLISH} "Could not find the program '$INSTPROG'. Silent update failed."
+
+; check windows version
+LangString CheckWindowsVersionDP ${LANG_ENGLISH} "Checking Windows version..."
+LangString CheckWindowsVersionMB ${LANG_ENGLISH} "${APPNAME} only supports Windows 7 with Service Pack 1 and later.$\nInstallation on this Operating System is not supported. Quitting."
+LangString CheckWindowsServPackMB ${LANG_ENGLISH} "It is recomended to run ${APPNAME} on the latest service pack for your operating system.$\nThis will help with performance and stability of the program."
+LangString UseLatestServPackDP ${LANG_ENGLISH} "Please use Windows Update to install the latest Service Pack."
+
+; checkifadministrator function (install)
+LangString CheckAdministratorInstDP ${LANG_ENGLISH} "Checking for permission to install..."
+LangString CheckAdministratorInstMB ${LANG_ENGLISH} 'You appear to be using a "limited" account.$\nYou must be an "administrator" to install ${APPNAME}.'
+
+; checkifadministrator function (uninstall)
+LangString CheckAdministratorUnInstDP ${LANG_ENGLISH} "Checking for permission to uninstall..."
+LangString CheckAdministratorUnInstMB ${LANG_ENGLISH} 'You appear to be using a "limited" account.$\nYou must be an "administrator" to uninstall ${APPNAME}.'
+
+; checkifalreadycurrent
+LangString CheckIfCurrentMB ${LANG_ENGLISH} "It appears that ${APPNAME} ${VERSION_LONG} is already installed.$\n$\nWould you like to install it again?"
+
+; checkcpuflags
+LangString MissingSSE2 ${LANG_ENGLISH} "This machine may not have a CPU with SSE2 support, which is required to run ${APPNAME} ${VERSION_LONG}. Do you want to continue?"
+
+; closesecondlife function (install)
+LangString CloseSecondLifeInstDP ${LANG_ENGLISH} "Waiting for Alchemy to shut down..."
+LangString CloseSecondLifeInstMB ${LANG_ENGLISH} "Alchemy can't be installed while it is already running.$\n$\nFinish what you're doing then select OK to close Alchemy and continue.$\nSelect CANCEL to cancel installation."
+
+; closesecondlife function (uninstall)
+LangString CloseSecondLifeUnInstDP ${LANG_ENGLISH} "Waiting for Alchemy to shut down..."
+LangString CloseSecondLifeUnInstMB ${LANG_ENGLISH} "Alchemy can't be uninstalled while it is already running.$\n$\nFinish what you're doing then select OK to close Alchemy and continue.$\nSelect CANCEL to cancel."
+
+; CheckNetworkConnection
+LangString CheckNetworkConnectionDP ${LANG_ENGLISH} "Checking network connection..."
+
+; removecachefiles
+LangString RemoveCacheFilesDP ${LANG_ENGLISH} "Deleting cache files in Documents and Settings folder"
+
+; delete program files
+LangString DeleteProgramFilesMB ${LANG_ENGLISH} "There are still files in your ${APPNAME} program directory.$\n$\nThese are possibly files you created or moved to:$\n$INSTDIR$\n$\nDo you want to remove them?"
+
+; uninstall text
+LangString UninstallTextMsg ${LANG_ENGLISH} "This will uninstall ${APPNAME} ${VERSION_LONG} from your system. Click Uninstall to start the uninstallation."
diff --git a/indra/newview/installers/windows/lang_es.nsi b/indra/newview/installers/windows/lang_es.nsi
index b3f57380db..4c8531d15d 100755
--- a/indra/newview/installers/windows/lang_es.nsi
+++ b/indra/newview/installers/windows/lang_es.nsi
@@ -1,56 +1,56 @@
-; First is default
-!insertmacro MUI_LANGUAGE "Spanish"
-
-; Language string
-LangString LanguageCode ${LANG_SPANISH}  "es"
-
-; Language selection dialog
-LangString SelectInstallerLanguage  ${LANG_SPANISH} "Por favor seleccione el idioma de su instalador"
-
-; installation directory text
-LangString DirectoryChooseTitle ${LANG_SPANISH} "Directorio de instalación" 
-LangString DirectoryChooseUpdate ${LANG_SPANISH} "Seleccione el directorio de ${APPNAME} para actualizar el programa a la versión ${VERSION_LONG}.(XXX):"
-LangString DirectoryChooseSetup ${LANG_SPANISH} "Seleccione el directorio en el que instalar ${APPNAME}:"
-
-; CheckStartupParams message box
-LangString CheckStartupParamsMB ${LANG_SPANISH} "No se pudo encontrar el programa '$INSTPROG'. Error al realizar la actualización desatendida."
-
-; check windows version
-LangString CheckWindowsVersionDP ${LANG_SPANISH} "Comprobando la versión de Windows..."
-LangString CheckWindowsVersionMB ${LANG_SPANISH} '${APPNAME} sólo se puede ejecutar en Windows XP.$\n$\nSi intenta instalar el programa en Windows $R0, es posible que el sistema se bloquee y se pierdan datos.$\n$\n'
-LangString CheckWindowsServPackMB ${LANG_SPANISH} "It is recomended to run ${APPNAME} on the latest service pack for your operating system.$\nThis will help with performance and stability of the program."
-LangString UseLatestServPackDP ${LANG_SPANISH} "Please use Windows Update to install the latest Service Pack."
-
-; checkifadministrator function (install)
-LangString CheckAdministratorInstDP ${LANG_SPANISH} "Comprobando los permisos para la instalación..."
-LangString CheckAdministratorInstMB ${LANG_SPANISH} 'Parece que está usando una cuenta "limitada".$\nDebe iniciar sesión como "administrador" para instalar ${APPNAME}.'
-
-; checkifadministrator function (uninstall)
-LangString CheckAdministratorUnInstDP ${LANG_SPANISH} "Comprobando los permisos para la desinstalación..."
-LangString CheckAdministratorUnInstMB ${LANG_SPANISH} 'Parece que está usando una cuenta "limitada".$\nDebe iniciar sesión como "administrador" para desinstalar ${APPNAME}.'
-
-; checkifalreadycurrent
-LangString CheckIfCurrentMB ${LANG_SPANISH} "Parece que ${APPNAME} ${VERSION_LONG} ya está instalado.$\n$\n¿Desea volver a instalarlo?"
-
-; checkcpuflags
-LangString MissingSSE2 ${LANG_SPANISH} "This machine may not have a CPU with SSE2 support, which is required to run ${APPNAME} ${VERSION_LONG}. Do you want to continue?"
-
-; closesecondlife function (install)
-LangString CloseSecondLifeInstDP ${LANG_SPANISH} "Esperando que Alchemy se cierre..."
-LangString CloseSecondLifeInstMB ${LANG_SPANISH} "Alchemy no se puede instalar mientras esté en ejecución.$\n$\nTermine lo que esté haciendo y seleccione Aceptar (OK) para cerrar Alchemy y continuar el proceso.$\nSeleccione Cancelar (CANCEL) para cancelar la instalación."
-
-; closesecondlife function (uninstall)
-LangString CloseSecondLifeUnInstDP ${LANG_SPANISH} "Esperando que Alchemy se cierre..."
-LangString CloseSecondLifeUnInstMB ${LANG_SPANISH} "Alchemy no se puede desinstalar mientras esté en ejecución.$\n$\nTermine lo que esté haciendo y seleccione Aceptar (OK) para cerrar Alchemy y continuar el proceso.$\nSeleccione Cancelar (CANCEL) para cancelar la desinstalación."
-
-; CheckNetworkConnection
-LangString CheckNetworkConnectionDP ${LANG_SPANISH} "Comprobando la conexión de red..."
-
-; removecachefiles
-LangString RemoveCacheFilesDP ${LANG_SPANISH} "Eliminando los archivos de caché almacenados en la carpeta Documents and Settings..."
-
-; delete program files
-LangString DeleteProgramFilesMB ${LANG_SPANISH} "Aún hay archivos en su directorio de programa de ${APPNAME}.$\n$\nPosiblemente son archivos que ha creado o movido a:$\n$INSTDIR$\n$\n¿Desea eliminarlos?"
-
-; uninstall text
-LangString UninstallTextMsg ${LANG_SPANISH} "Este proceso desinstalará ${APPNAME} ${VERSION_LONG} de su sistema."
+; First is default
+!insertmacro MUI_LANGUAGE "Spanish"
+
+; Language string
+LangString LanguageCode ${LANG_SPANISH}  "es"
+
+; Language selection dialog
+LangString SelectInstallerLanguage  ${LANG_SPANISH} "Por favor seleccione el idioma de su instalador"
+
+; installation directory text
+LangString DirectoryChooseTitle ${LANG_SPANISH} "Directorio de instalación" 
+LangString DirectoryChooseUpdate ${LANG_SPANISH} "Seleccione el directorio de ${APPNAME} para actualizar el programa a la versión ${VERSION_LONG}.(XXX):"
+LangString DirectoryChooseSetup ${LANG_SPANISH} "Seleccione el directorio en el que instalar ${APPNAME}:"
+
+; CheckStartupParams message box
+LangString CheckStartupParamsMB ${LANG_SPANISH} "No se pudo encontrar el programa '$INSTPROG'. Error al realizar la actualización desatendida."
+
+; check windows version
+LangString CheckWindowsVersionDP ${LANG_SPANISH} "Comprobando la versión de Windows..."
+LangString CheckWindowsVersionMB ${LANG_SPANISH} '${APPNAME} sólo se puede ejecutar en Windows XP.$\n$\nSi intenta instalar el programa en Windows $R0, es posible que el sistema se bloquee y se pierdan datos.$\n$\n'
+LangString CheckWindowsServPackMB ${LANG_SPANISH} "It is recomended to run ${APPNAME} on the latest service pack for your operating system.$\nThis will help with performance and stability of the program."
+LangString UseLatestServPackDP ${LANG_SPANISH} "Please use Windows Update to install the latest Service Pack."
+
+; checkifadministrator function (install)
+LangString CheckAdministratorInstDP ${LANG_SPANISH} "Comprobando los permisos para la instalación..."
+LangString CheckAdministratorInstMB ${LANG_SPANISH} 'Parece que está usando una cuenta "limitada".$\nDebe iniciar sesión como "administrador" para instalar ${APPNAME}.'
+
+; checkifadministrator function (uninstall)
+LangString CheckAdministratorUnInstDP ${LANG_SPANISH} "Comprobando los permisos para la desinstalación..."
+LangString CheckAdministratorUnInstMB ${LANG_SPANISH} 'Parece que está usando una cuenta "limitada".$\nDebe iniciar sesión como "administrador" para desinstalar ${APPNAME}.'
+
+; checkifalreadycurrent
+LangString CheckIfCurrentMB ${LANG_SPANISH} "Parece que ${APPNAME} ${VERSION_LONG} ya está instalado.$\n$\n¿Desea volver a instalarlo?"
+
+; checkcpuflags
+LangString MissingSSE2 ${LANG_SPANISH} "This machine may not have a CPU with SSE2 support, which is required to run ${APPNAME} ${VERSION_LONG}. Do you want to continue?"
+
+; closesecondlife function (install)
+LangString CloseSecondLifeInstDP ${LANG_SPANISH} "Esperando que Alchemy se cierre..."
+LangString CloseSecondLifeInstMB ${LANG_SPANISH} "Alchemy no se puede instalar mientras esté en ejecución.$\n$\nTermine lo que esté haciendo y seleccione Aceptar (OK) para cerrar Alchemy y continuar el proceso.$\nSeleccione Cancelar (CANCEL) para cancelar la instalación."
+
+; closesecondlife function (uninstall)
+LangString CloseSecondLifeUnInstDP ${LANG_SPANISH} "Esperando que Alchemy se cierre..."
+LangString CloseSecondLifeUnInstMB ${LANG_SPANISH} "Alchemy no se puede desinstalar mientras esté en ejecución.$\n$\nTermine lo que esté haciendo y seleccione Aceptar (OK) para cerrar Alchemy y continuar el proceso.$\nSeleccione Cancelar (CANCEL) para cancelar la desinstalación."
+
+; CheckNetworkConnection
+LangString CheckNetworkConnectionDP ${LANG_SPANISH} "Comprobando la conexión de red..."
+
+; removecachefiles
+LangString RemoveCacheFilesDP ${LANG_SPANISH} "Eliminando los archivos de caché almacenados en la carpeta Documents and Settings..."
+
+; delete program files
+LangString DeleteProgramFilesMB ${LANG_SPANISH} "Aún hay archivos en su directorio de programa de ${APPNAME}.$\n$\nPosiblemente son archivos que ha creado o movido a:$\n$INSTDIR$\n$\n¿Desea eliminarlos?"
+
+; uninstall text
+LangString UninstallTextMsg ${LANG_SPANISH} "Este proceso desinstalará ${APPNAME} ${VERSION_LONG} de su sistema."
diff --git a/indra/newview/installers/windows/lang_fr.nsi b/indra/newview/installers/windows/lang_fr.nsi
index a45392ea13..74cdc072de 100755
--- a/indra/newview/installers/windows/lang_fr.nsi
+++ b/indra/newview/installers/windows/lang_fr.nsi
@@ -1,56 +1,56 @@
-; First is default
-!insertmacro MUI_LANGUAGE "French"
-
-; Language string
-LangString LanguageCode ${LANG_FRENCH}   "fr"
-
-; Language selection dialog
-LangString SelectInstallerLanguage  ${LANG_FRENCH} "Veuillez sélectionner la langue du programme d’installation"
-
-; installation directory text
-LangString DirectoryChooseTitle ${LANG_FRENCH} "Répertoire d'installation" 
-LangString DirectoryChooseUpdate ${LANG_FRENCH} "Sélectionnez le répertoire de ${APPNAME} pour installer la nouvelle version ${VERSION_LONG}. (XXX) :"
-LangString DirectoryChooseSetup ${LANG_FRENCH} "Sélectionnez le répertoire dans lequel installer ${APPNAME} :"
-
-; CheckStartupParams message box
-LangString CheckStartupParamsMB ${LANG_FRENCH} "Impossible de trouver le programme '$INSTPROG'. La mise à jour silencieuse a échoué."
-
-; check windows version
-LangString CheckWindowsVersionDP ${LANG_FRENCH} "Vérification de la version de Windows en cours..."
-LangString CheckWindowsVersionMB ${LANG_FRENCH} "${APPNAME} prend uniquement en charge Windows XP.$\n$\nToute tentative d'installation sous Windows $R0 peut causer des crashs et des pertes de données.$\n$\n"
-LangString CheckWindowsServPackMB ${LANG_FRENCH} "It is recomended to run ${APPNAME} on the latest service pack for your operating system.$\nThis will help with performance and stability of the program."
-LangString UseLatestServPackDP ${LANG_FRENCH} "Please use Windows Update to install the latest Service Pack."
-
-; checkifadministrator function (install)
-LangString CheckAdministratorInstDP ${LANG_FRENCH} "Vérification de la permission pour effectuer l'installation en cours..."
-LangString CheckAdministratorInstMB ${LANG_FRENCH} "Il semblerait que votre compte soit « limité ».$\nPour installer ${APPNAME}, vous devez avoir un compte « administrateur »."
-
-; checkifadministrator function (uninstall)
-LangString CheckAdministratorUnInstDP ${LANG_FRENCH} "Vérification de la permission pour effectuer la désinstallation en cours..."
-LangString CheckAdministratorUnInstMB ${LANG_FRENCH} "Il semblerait que votre compte soit « limité ».$\nPour désinstaller ${APPNAME}, vous devez avoir un compte « administrateur »."
-
-; checkifalreadycurrent
-LangString CheckIfCurrentMB ${LANG_FRENCH} "Il semblerait que vous ayez déjà installé ${APPNAME} ${VERSION_LONG}.$\n$\nSouhaitez-vous procéder à une nouvelle installation ?"
-
-; checkcpuflags
-LangString MissingSSE2 ${LANG_FRENCH} "This machine may not have a CPU with SSE2 support, which is required to run ${APPNAME} ${VERSION_LONG}. Do you want to continue?"
-
-; closesecondlife function (install)
-LangString CloseSecondLifeInstDP ${LANG_FRENCH} "En attente de la fermeture de Alchemy..."
-LangString CloseSecondLifeInstMB ${LANG_FRENCH} "Alchemy ne peut pas être installé si l'application est déjà lancée..$\n$\nFinissez ce que vous faites puis sélectionnez OK pour fermer Alchemy et continuer.$\nSélectionnez ANNULER pour annuler l'installation."
-
-; closesecondlife function (uninstall)
-LangString CloseSecondLifeUnInstDP ${LANG_FRENCH} "En attente de la fermeture de Alchemy..."
-LangString CloseSecondLifeUnInstMB ${LANG_FRENCH} "Alchemy ne peut pas être désinstallé si l'application est déjà lancée.$\n$\nFinissez ce que vous faites puis sélectionnez OK pour fermer Alchemy et continuer.$\nSélectionnez ANNULER pour annuler la désinstallation."
-
-; CheckNetworkConnection
-LangString CheckNetworkConnectionDP ${LANG_FRENCH} "Connexion au réseau en cours de vérification..."
-
-; removecachefiles
-LangString RemoveCacheFilesDP ${LANG_FRENCH} "Suppression des fichiers du cache dans le dossier Documents et Paramètres"
-
-; delete program files
-LangString DeleteProgramFilesMB ${LANG_FRENCH} "Il y a encore des fichiers dans votre répertoire ${APPNAME}.$\n$\nIl est possible que vous ayez créé ou déplacé ces dossiers vers : $\n$INSTDIR$\n$\nVoulez-vous les supprimer ?"
-
-; uninstall text
-LangString UninstallTextMsg ${LANG_FRENCH} "Cela désinstallera ${APPNAME} ${VERSION_LONG} de votre système."
+; First is default
+!insertmacro MUI_LANGUAGE "French"
+
+; Language string
+LangString LanguageCode ${LANG_FRENCH}   "fr"
+
+; Language selection dialog
+LangString SelectInstallerLanguage  ${LANG_FRENCH} "Veuillez sélectionner la langue du programme d’installation"
+
+; installation directory text
+LangString DirectoryChooseTitle ${LANG_FRENCH} "Répertoire d'installation" 
+LangString DirectoryChooseUpdate ${LANG_FRENCH} "Sélectionnez le répertoire de ${APPNAME} pour installer la nouvelle version ${VERSION_LONG}. (XXX) :"
+LangString DirectoryChooseSetup ${LANG_FRENCH} "Sélectionnez le répertoire dans lequel installer ${APPNAME} :"
+
+; CheckStartupParams message box
+LangString CheckStartupParamsMB ${LANG_FRENCH} "Impossible de trouver le programme '$INSTPROG'. La mise à jour silencieuse a échoué."
+
+; check windows version
+LangString CheckWindowsVersionDP ${LANG_FRENCH} "Vérification de la version de Windows en cours..."
+LangString CheckWindowsVersionMB ${LANG_FRENCH} "${APPNAME} prend uniquement en charge Windows XP.$\n$\nToute tentative d'installation sous Windows $R0 peut causer des crashs et des pertes de données.$\n$\n"
+LangString CheckWindowsServPackMB ${LANG_FRENCH} "It is recomended to run ${APPNAME} on the latest service pack for your operating system.$\nThis will help with performance and stability of the program."
+LangString UseLatestServPackDP ${LANG_FRENCH} "Please use Windows Update to install the latest Service Pack."
+
+; checkifadministrator function (install)
+LangString CheckAdministratorInstDP ${LANG_FRENCH} "Vérification de la permission pour effectuer l'installation en cours..."
+LangString CheckAdministratorInstMB ${LANG_FRENCH} "Il semblerait que votre compte soit « limité ».$\nPour installer ${APPNAME}, vous devez avoir un compte « administrateur »."
+
+; checkifadministrator function (uninstall)
+LangString CheckAdministratorUnInstDP ${LANG_FRENCH} "Vérification de la permission pour effectuer la désinstallation en cours..."
+LangString CheckAdministratorUnInstMB ${LANG_FRENCH} "Il semblerait que votre compte soit « limité ».$\nPour désinstaller ${APPNAME}, vous devez avoir un compte « administrateur »."
+
+; checkifalreadycurrent
+LangString CheckIfCurrentMB ${LANG_FRENCH} "Il semblerait que vous ayez déjà installé ${APPNAME} ${VERSION_LONG}.$\n$\nSouhaitez-vous procéder à une nouvelle installation ?"
+
+; checkcpuflags
+LangString MissingSSE2 ${LANG_FRENCH} "This machine may not have a CPU with SSE2 support, which is required to run ${APPNAME} ${VERSION_LONG}. Do you want to continue?"
+
+; closesecondlife function (install)
+LangString CloseSecondLifeInstDP ${LANG_FRENCH} "En attente de la fermeture de Alchemy..."
+LangString CloseSecondLifeInstMB ${LANG_FRENCH} "Alchemy ne peut pas être installé si l'application est déjà lancée..$\n$\nFinissez ce que vous faites puis sélectionnez OK pour fermer Alchemy et continuer.$\nSélectionnez ANNULER pour annuler l'installation."
+
+; closesecondlife function (uninstall)
+LangString CloseSecondLifeUnInstDP ${LANG_FRENCH} "En attente de la fermeture de Alchemy..."
+LangString CloseSecondLifeUnInstMB ${LANG_FRENCH} "Alchemy ne peut pas être désinstallé si l'application est déjà lancée.$\n$\nFinissez ce que vous faites puis sélectionnez OK pour fermer Alchemy et continuer.$\nSélectionnez ANNULER pour annuler la désinstallation."
+
+; CheckNetworkConnection
+LangString CheckNetworkConnectionDP ${LANG_FRENCH} "Connexion au réseau en cours de vérification..."
+
+; removecachefiles
+LangString RemoveCacheFilesDP ${LANG_FRENCH} "Suppression des fichiers du cache dans le dossier Documents et Paramètres"
+
+; delete program files
+LangString DeleteProgramFilesMB ${LANG_FRENCH} "Il y a encore des fichiers dans votre répertoire ${APPNAME}.$\n$\nIl est possible que vous ayez créé ou déplacé ces dossiers vers : $\n$INSTDIR$\n$\nVoulez-vous les supprimer ?"
+
+; uninstall text
+LangString UninstallTextMsg ${LANG_FRENCH} "Cela désinstallera ${APPNAME} ${VERSION_LONG} de votre système."
diff --git a/indra/newview/installers/windows/lang_it.nsi b/indra/newview/installers/windows/lang_it.nsi
index 0a77f85172..2163daddf6 100755
--- a/indra/newview/installers/windows/lang_it.nsi
+++ b/indra/newview/installers/windows/lang_it.nsi
@@ -1,56 +1,56 @@
-; First is default
-!insertmacro MUI_LANGUAGE "Italian"
-
-; Language string
-LangString LanguageCode ${LANG_ITALIAN}  "it"
-
-; Language selection dialog
-LangString SelectInstallerLanguage  ${LANG_ITALIAN} "Scegliere per favore il linguaggio del programma di installazione"
-
-; installation directory text
-LangString DirectoryChooseTitle ${LANG_ITALIAN} "Directory di installazione" 
-LangString DirectoryChooseUpdate ${LANG_ITALIAN} "Scegli la directory di ${APPNAME} per l’update alla versione ${VERSION_LONG}.(XXX):"
-LangString DirectoryChooseSetup ${LANG_ITALIAN} "Scegli la directory dove installare ${APPNAME}:"
-
-; CheckStartupParams message box
-LangString CheckStartupParamsMB ${LANG_ITALIAN} "Non riesco a trovare il programma '$INSTPROG'. Silent Update fallito."
-
-; check windows version
-LangString CheckWindowsVersionDP ${LANG_ITALIAN} "Controllo della versione di Windows…"
-LangString CheckWindowsVersionMB ${LANG_ITALIAN} '${APPNAME} supporta solo Windows XP.$\n$\nTentare l’installazione su Windows $R0 può provocare blocchi di sistema e perdita di dati.$\n$\n'
-LangString CheckWindowsServPackMB ${LANG_ITALIAN} "It is recomended to run ${APPNAME} on the latest service pack for your operating system.$\nThis will help with performance and stability of the program."
-LangString UseLatestServPackDP ${LANG_ITALIAN} "Please use Windows Update to install the latest Service Pack."
-
-; checkifadministrator function (install)
-LangString CheckAdministratorInstDP ${LANG_ITALIAN} "Controllo del permesso di installazione…"
-LangString CheckAdministratorInstMB ${LANG_ITALIAN} 'Stai utilizzando un account “limitato”.$\nSolo un “amministratore” può installare ${APPNAME}.'
-
-; checkifadministrator function (uninstall)
-LangString CheckAdministratorUnInstDP ${LANG_ITALIAN} "Controllo del permesso di installazione…"
-LangString CheckAdministratorUnInstMB ${LANG_ITALIAN} 'Stai utilizzando un account “limitato”.$\nSolo un “amministratore” può installare ${APPNAME}.'
-
-; checkifalreadycurrent
-LangString CheckIfCurrentMB ${LANG_ITALIAN} "${APPNAME} ${VERSION_LONG} è stato sia già installato.$\n$\nVuoi ripetere l’installazione?"
-
-; checkcpuflags
-LangString MissingSSE2 ${LANG_ITALIAN} "This machine may not have a CPU with SSE2 support, which is required to run ${APPNAME} ${VERSION_LONG}. Do you want to continue?"
-
-; closesecondlife function (install)
-LangString CloseSecondLifeInstDP ${LANG_ITALIAN} "In attesa che Alchemy chiuda…"
-LangString CloseSecondLifeInstMB ${LANG_ITALIAN} "Non è possibile installare Alchemy se è già in funzione..$\n$\nTermina le operazioni in corso e scegli OK per chiudere Alchemy e continuare.$\nScegli CANCELLA per annullare l’installazione."
-
-; closesecondlife function (uninstall)
-LangString CloseSecondLifeUnInstDP ${LANG_ITALIAN} "In attesa della chiusura di Alchemy…"
-LangString CloseSecondLifeUnInstMB ${LANG_ITALIAN} "Non è possibile installare Alchemy se è già in funzione.$\n$\nTermina le operazioni in corso e scegli OK per chiudere Alchemy e continuare.$\nScegli CANCELLA per annullare."
-
-; CheckNetworkConnection
-LangString CheckNetworkConnectionDP ${LANG_ITALIAN} "Verifica connessione di rete in corso..."
-
-; removecachefiles
-LangString RemoveCacheFilesDP ${LANG_ITALIAN} "Cancellazione dei file cache nella cartella Documents and Settings"
-
-; delete program files
-LangString DeleteProgramFilesMB ${LANG_ITALIAN} "Sono ancora presenti dei file nella directory programmi di ${APPNAME}.$\n$\nPotrebbe trattarsi di file creati o trasferiti in:$\n$INSTDIR$\n$\nVuoi cancellarli?"
-
-; uninstall text
-LangString UninstallTextMsg ${LANG_ITALIAN} "Così facendo ${APPNAME} verrà disinstallato ${VERSION_LONG} dal tuo sistema."
+; First is default
+!insertmacro MUI_LANGUAGE "Italian"
+
+; Language string
+LangString LanguageCode ${LANG_ITALIAN}  "it"
+
+; Language selection dialog
+LangString SelectInstallerLanguage  ${LANG_ITALIAN} "Scegliere per favore il linguaggio del programma di installazione"
+
+; installation directory text
+LangString DirectoryChooseTitle ${LANG_ITALIAN} "Directory di installazione" 
+LangString DirectoryChooseUpdate ${LANG_ITALIAN} "Scegli la directory di ${APPNAME} per l’update alla versione ${VERSION_LONG}.(XXX):"
+LangString DirectoryChooseSetup ${LANG_ITALIAN} "Scegli la directory dove installare ${APPNAME}:"
+
+; CheckStartupParams message box
+LangString CheckStartupParamsMB ${LANG_ITALIAN} "Non riesco a trovare il programma '$INSTPROG'. Silent Update fallito."
+
+; check windows version
+LangString CheckWindowsVersionDP ${LANG_ITALIAN} "Controllo della versione di Windows…"
+LangString CheckWindowsVersionMB ${LANG_ITALIAN} '${APPNAME} supporta solo Windows XP.$\n$\nTentare l’installazione su Windows $R0 può provocare blocchi di sistema e perdita di dati.$\n$\n'
+LangString CheckWindowsServPackMB ${LANG_ITALIAN} "It is recomended to run ${APPNAME} on the latest service pack for your operating system.$\nThis will help with performance and stability of the program."
+LangString UseLatestServPackDP ${LANG_ITALIAN} "Please use Windows Update to install the latest Service Pack."
+
+; checkifadministrator function (install)
+LangString CheckAdministratorInstDP ${LANG_ITALIAN} "Controllo del permesso di installazione…"
+LangString CheckAdministratorInstMB ${LANG_ITALIAN} 'Stai utilizzando un account “limitato”.$\nSolo un “amministratore” può installare ${APPNAME}.'
+
+; checkifadministrator function (uninstall)
+LangString CheckAdministratorUnInstDP ${LANG_ITALIAN} "Controllo del permesso di installazione…"
+LangString CheckAdministratorUnInstMB ${LANG_ITALIAN} 'Stai utilizzando un account “limitato”.$\nSolo un “amministratore” può installare ${APPNAME}.'
+
+; checkifalreadycurrent
+LangString CheckIfCurrentMB ${LANG_ITALIAN} "${APPNAME} ${VERSION_LONG} è stato sia già installato.$\n$\nVuoi ripetere l’installazione?"
+
+; checkcpuflags
+LangString MissingSSE2 ${LANG_ITALIAN} "This machine may not have a CPU with SSE2 support, which is required to run ${APPNAME} ${VERSION_LONG}. Do you want to continue?"
+
+; closesecondlife function (install)
+LangString CloseSecondLifeInstDP ${LANG_ITALIAN} "In attesa che Alchemy chiuda…"
+LangString CloseSecondLifeInstMB ${LANG_ITALIAN} "Non è possibile installare Alchemy se è già in funzione..$\n$\nTermina le operazioni in corso e scegli OK per chiudere Alchemy e continuare.$\nScegli CANCELLA per annullare l’installazione."
+
+; closesecondlife function (uninstall)
+LangString CloseSecondLifeUnInstDP ${LANG_ITALIAN} "In attesa della chiusura di Alchemy…"
+LangString CloseSecondLifeUnInstMB ${LANG_ITALIAN} "Non è possibile installare Alchemy se è già in funzione.$\n$\nTermina le operazioni in corso e scegli OK per chiudere Alchemy e continuare.$\nScegli CANCELLA per annullare."
+
+; CheckNetworkConnection
+LangString CheckNetworkConnectionDP ${LANG_ITALIAN} "Verifica connessione di rete in corso..."
+
+; removecachefiles
+LangString RemoveCacheFilesDP ${LANG_ITALIAN} "Cancellazione dei file cache nella cartella Documents and Settings"
+
+; delete program files
+LangString DeleteProgramFilesMB ${LANG_ITALIAN} "Sono ancora presenti dei file nella directory programmi di ${APPNAME}.$\n$\nPotrebbe trattarsi di file creati o trasferiti in:$\n$INSTDIR$\n$\nVuoi cancellarli?"
+
+; uninstall text
+LangString UninstallTextMsg ${LANG_ITALIAN} "Così facendo ${APPNAME} verrà disinstallato ${VERSION_LONG} dal tuo sistema."
diff --git a/indra/newview/installers/windows/lang_ja.nsi b/indra/newview/installers/windows/lang_ja.nsi
index f4cf3c75cf..1155fa7ebd 100755
--- a/indra/newview/installers/windows/lang_ja.nsi
+++ b/indra/newview/installers/windows/lang_ja.nsi
@@ -1,56 +1,56 @@
-; First is default
-!insertmacro MUI_LANGUAGE "Japanese"
-
-; Language string
-LangString LanguageCode ${LANG_JAPANESE} "ja"
-
-; Language selection dialog
-LangString SelectInstallerLanguage  ${LANG_JAPANESE} "インストーラの言語を選択してください"
-
-; installation directory text
-LangString DirectoryChooseTitle ${LANG_JAPANESE} "インストール・ディレクトリ" 
-LangString DirectoryChooseUpdate ${LANG_JAPANESE} "アップデートするセカンドライフのディレクトリを選択してください。:" 
-LangString DirectoryChooseSetup ${LANG_JAPANESE} "セカンドライフをインストールするディレクトリを選択してください。: " 
-
-; CheckStartupParams message box
-LangString CheckStartupParamsMB ${LANG_JAPANESE} "プログラム名'$INSTPROG'が見つかりません。サイレント・アップデートに失敗しました。" 
-
-; check windows version
-LangString CheckWindowsVersionDP ${LANG_JAPANESE} "ウィンドウズのバージョン情報をチェック中です..." 
-LangString CheckWindowsVersionMB ${LANG_JAPANESE} "Second Life はWindows XPのみをサポートしています。Windows $R0をインストールする事は、データの消失やクラッシュの原因になる可能性があります。インストールを続けますか?" 
-LangString CheckWindowsServPackMB ${LANG_JAPANESE} "It is recomended to run Firestorm on the latest service pack for your operating system.$\nThis will help with performance and stability of the program."
-LangString UseLatestServPackDP ${LANG_JAPANESE} "Please use Windows Update to install the latest Service Pack."
-
-; checkifadministrator function (install)
-LangString CheckAdministratorInstDP ${LANG_JAPANESE} "インストールのための権限をチェック中です..." 
-LangString CheckAdministratorInstMB ${LANG_JAPANESE} "セカンドライフをインストールするには管理者権限が必要です。"
-
-; checkifadministrator function (uninstall)
-LangString CheckAdministratorUnInstDP ${LANG_JAPANESE} "アンインストールのための権限をチェック中です..." 
-LangString CheckAdministratorUnInstMB ${LANG_JAPANESE} "セカンドライフをアンインストールするには管理者権限が必要です。" 
-
-; checkifalreadycurrent
-LangString CheckIfCurrentMB ${LANG_JAPANESE} "セカンドライフ${VERSION_LONG} はインストール済みです。再度インストールしますか? " 
-
-; checkcpuflags
-LangString MissingSSE2 ${LANG_JAPANESE} "This machine may not have a CPU with SSE2 support, which is required to run ${APPNAME} ${VERSION_LONG}. Do you want to continue?"
-
-; closesecondlife function (install)
-LangString CloseSecondLifeInstDP ${LANG_JAPANESE} "セカンドライフを終了中です..." 
-LangString CloseSecondLifeInstMB ${LANG_JAPANESE} "セカンドライフの起動中にインストールは出来ません。直ちにセカンドライフを終了してインストールを開始する場合はOKボタンを押してください。CANCELを押すと中止します。"
-
-; closesecondlife function (uninstall)
-LangString CloseSecondLifeUnInstDP ${LANG_JAPANESE} "セカンドライフを終了中です..." 
-LangString CloseSecondLifeUnInstMB ${LANG_JAPANESE} "セカンドライフの起動中にアンインストールは出来ません。直ちにセカンドライフを終了してアンインストールを開始する場合はOKボタンを押してください。CANCELを押すと中止します。" 
-
-; CheckNetworkConnection
-LangString CheckNetworkConnectionDP ${LANG_JAPANESE} "ネットワークの接続を確認中..." 
-
-; removecachefiles
-LangString RemoveCacheFilesDP ${LANG_JAPANESE} " Documents and Settings フォルダのキャッシュファイルをデリート中です。" 
-
-; delete program files
-LangString DeleteProgramFilesMB ${LANG_JAPANESE} "セカンドライフのディレクトリには、まだファイルが残されています。$\n$INSTDIR$\nにあなたが作成、または移動させたファイルがある可能性があります。全て削除しますか? " 
-
-; uninstall text
-LangString UninstallTextMsg ${LANG_JAPANESE} "セカンドライフ${VERSION_LONG}をアンインストールします。"
+; First is default
+!insertmacro MUI_LANGUAGE "Japanese"
+
+; Language string
+LangString LanguageCode ${LANG_JAPANESE} "ja"
+
+; Language selection dialog
+LangString SelectInstallerLanguage  ${LANG_JAPANESE} "インストーラの言語を選択してください"
+
+; installation directory text
+LangString DirectoryChooseTitle ${LANG_JAPANESE} "インストール・ディレクトリ" 
+LangString DirectoryChooseUpdate ${LANG_JAPANESE} "アップデートするセカンドライフのディレクトリを選択してください。:" 
+LangString DirectoryChooseSetup ${LANG_JAPANESE} "セカンドライフをインストールするディレクトリを選択してください。: " 
+
+; CheckStartupParams message box
+LangString CheckStartupParamsMB ${LANG_JAPANESE} "プログラム名'$INSTPROG'が見つかりません。サイレント・アップデートに失敗しました。" 
+
+; check windows version
+LangString CheckWindowsVersionDP ${LANG_JAPANESE} "ウィンドウズのバージョン情報をチェック中です..." 
+LangString CheckWindowsVersionMB ${LANG_JAPANESE} "Second Life はWindows XPのみをサポートしています。Windows $R0をインストールする事は、データの消失やクラッシュの原因になる可能性があります。インストールを続けますか?" 
+LangString CheckWindowsServPackMB ${LANG_JAPANESE} "It is recomended to run Firestorm on the latest service pack for your operating system.$\nThis will help with performance and stability of the program."
+LangString UseLatestServPackDP ${LANG_JAPANESE} "Please use Windows Update to install the latest Service Pack."
+
+; checkifadministrator function (install)
+LangString CheckAdministratorInstDP ${LANG_JAPANESE} "インストールのための権限をチェック中です..." 
+LangString CheckAdministratorInstMB ${LANG_JAPANESE} "セカンドライフをインストールするには管理者権限が必要です。"
+
+; checkifadministrator function (uninstall)
+LangString CheckAdministratorUnInstDP ${LANG_JAPANESE} "アンインストールのための権限をチェック中です..." 
+LangString CheckAdministratorUnInstMB ${LANG_JAPANESE} "セカンドライフをアンインストールするには管理者権限が必要です。" 
+
+; checkifalreadycurrent
+LangString CheckIfCurrentMB ${LANG_JAPANESE} "セカンドライフ${VERSION_LONG} はインストール済みです。再度インストールしますか? " 
+
+; checkcpuflags
+LangString MissingSSE2 ${LANG_JAPANESE} "This machine may not have a CPU with SSE2 support, which is required to run ${APPNAME} ${VERSION_LONG}. Do you want to continue?"
+
+; closesecondlife function (install)
+LangString CloseSecondLifeInstDP ${LANG_JAPANESE} "セカンドライフを終了中です..." 
+LangString CloseSecondLifeInstMB ${LANG_JAPANESE} "セカンドライフの起動中にインストールは出来ません。直ちにセカンドライフを終了してインストールを開始する場合はOKボタンを押してください。CANCELを押すと中止します。"
+
+; closesecondlife function (uninstall)
+LangString CloseSecondLifeUnInstDP ${LANG_JAPANESE} "セカンドライフを終了中です..." 
+LangString CloseSecondLifeUnInstMB ${LANG_JAPANESE} "セカンドライフの起動中にアンインストールは出来ません。直ちにセカンドライフを終了してアンインストールを開始する場合はOKボタンを押してください。CANCELを押すと中止します。" 
+
+; CheckNetworkConnection
+LangString CheckNetworkConnectionDP ${LANG_JAPANESE} "ネットワークの接続を確認中..." 
+
+; removecachefiles
+LangString RemoveCacheFilesDP ${LANG_JAPANESE} " Documents and Settings フォルダのキャッシュファイルをデリート中です。" 
+
+; delete program files
+LangString DeleteProgramFilesMB ${LANG_JAPANESE} "セカンドライフのディレクトリには、まだファイルが残されています。$\n$INSTDIR$\nにあなたが作成、または移動させたファイルがある可能性があります。全て削除しますか? " 
+
+; uninstall text
+LangString UninstallTextMsg ${LANG_JAPANESE} "セカンドライフ${VERSION_LONG}をアンインストールします。"
diff --git a/indra/newview/installers/windows/lang_pl.nsi b/indra/newview/installers/windows/lang_pl.nsi
index bb99786941..36965146a9 100644
--- a/indra/newview/installers/windows/lang_pl.nsi
+++ b/indra/newview/installers/windows/lang_pl.nsi
@@ -1,56 +1,56 @@
-; First is default
-!insertmacro MUI_LANGUAGE "Polish"
-
-; Language string
-LangString LanguageCode ${LANG_POLISH}   "pl"
-
-; Language selection dialog
-LangString SelectInstallerLanguage  ${LANG_POLISH} "Proszę wybrać język instalatora"
-
-; installation directory text
-LangString DirectoryChooseTitle ${LANG_POLISH} "Katalog instalacji" 
-LangString DirectoryChooseUpdate ${LANG_POLISH} "Wybierz katalog instalacji ${APPNAME} w celu aktualizacji wersji ${VERSION_LONG}.(XXX):"
-LangString DirectoryChooseSetup ${LANG_POLISH} "Wybierz katalog instalacji ${APPNAME} w:"
-
-; CheckStartupParams message box
-LangString CheckStartupParamsMB ${LANG_POLISH} "Nie można odnaleźć programu '$INSTPROG'. Cicha aktualizacja zakończyła się niepowodzeniem."
-
-; check windows version
-LangString CheckWindowsVersionDP ${LANG_POLISH} "Sprawdzanie wersji Windows..."
-LangString CheckWindowsVersionMB ${LANG_POLISH} '${APPNAME} obsługuje tylko Windows XP.$\n$\nPróba zainstalowania na Windows $R0 może spowodować awarie i utratę danych.$\n$\n'
-LangString CheckWindowsServPackMB ${LANG_POLISH} "Zalecane jest uruchamianie ${APPNAME} z najnowszym dostępnym Service Packiem zainstalowanym w systemie.$\nPomaga on w podniesieniu wydajności i stabilności programu."
-LangString UseLatestServPackDP ${LANG_POLISH} "Użyj usługi Windows Update, aby zainstalować najnowszy Service Pack."
-
-; checkifadministrator function (install)
-LangString CheckAdministratorInstDP ${LANG_POLISH} "Sprawdzanie zezwolenia na instalacjÄ™..."
-LangString CheckAdministratorInstMB ${LANG_POLISH} 'Używasz "ograniczonego" konta.$\nMusisz być zalogowany jako "administrator" aby zainstalować ${APPNAME}.'
-
-; checkifadministrator function (uninstall)
-LangString CheckAdministratorUnInstDP ${LANG_POLISH} "Sprawdzanie zezwolenia na odinstalowanie..."
-LangString CheckAdministratorUnInstMB ${LANG_POLISH} 'Używasz "ograniczonego" konta.$\nMusisz być być zalogowany jako "administrator" aby zainstalować ${APPNAME}.'
-
-; checkifalreadycurrent
-LangString CheckIfCurrentMB ${LANG_POLISH} "${APPNAME} ${VERSION_LONG} jest już zainstalowane.$\n$\nCzy chcesz zainstalować ${APPNAME} ponownie?"
-
-; checkcpuflags
-LangString MissingSSE2 ${LANG_POLISH} "Ten komputer może nie mieć procesora z obsługą SSE2, który jest wymagany aby uruchomić ${APPNAME} w wersji ${VERSION_LONG}. Chcesz kontynuować?"
-
-; closesecondlife function (install)
-LangString CloseSecondLifeInstDP ${LANG_POLISH} "Oczekiwanie na zamknięcie Alchemy..."
-LangString CloseSecondLifeInstMB ${LANG_POLISH} "Alchemy nie może zostać zainstalowane, ponieważ jest już włączone.$\n$\nZakończ swoje działania i wybierz OK aby zamknąć Alchemy i kontynuować.$\nWybierz CANCEL aby anulować instalację."
-
-; closesecondlife function (uninstall)
-LangString CloseSecondLifeUnInstDP ${LANG_POLISH} "Oczekiwanie na zamknięcie Alchemy..."
-LangString CloseSecondLifeUnInstMB ${LANG_POLISH} "Alchemy nie może zostać zainstalowane, ponieważ jest już włączone.$\n$\nZakończ swoje działania i wybierz OK aby zamknąć Alchemy i kontynuować.$\nWybierz CANCEL aby anulować."
-
-; CheckNetworkConnection
-LangString CheckNetworkConnectionDP ${LANG_POLISH} "Sprawdzanie połączenia sieciowego..."
-
-; removecachefiles
-LangString RemoveCacheFilesDP ${LANG_POLISH} "Kasowanie plików pamięci podręcznej (cache) w folderze Documents and Settings"
-
-; delete program files
-LangString DeleteProgramFilesMB ${LANG_POLISH} "Nadal istnieją pliki w katalogu instalacyjnym ${APPNAME}.$\n$\nMożliwe, że są to pliki, które stworzyłeś/stworzyłaś lub przeniosłeś/przeniosłaś do:$\n$INSTDIR$\n$\nCzy chcesz je usunąć?"
-
-; uninstall text
-LangString UninstallTextMsg ${LANG_POLISH} "To spowoduje odinstalowanie ${APPNAME} ${VERSION_LONG} z Twojego systemu."
+; First is default
+!insertmacro MUI_LANGUAGE "Polish"
+
+; Language string
+LangString LanguageCode ${LANG_POLISH}   "pl"
+
+; Language selection dialog
+LangString SelectInstallerLanguage  ${LANG_POLISH} "Proszę wybrać język instalatora"
+
+; installation directory text
+LangString DirectoryChooseTitle ${LANG_POLISH} "Katalog instalacji" 
+LangString DirectoryChooseUpdate ${LANG_POLISH} "Wybierz katalog instalacji ${APPNAME} w celu aktualizacji wersji ${VERSION_LONG}.(XXX):"
+LangString DirectoryChooseSetup ${LANG_POLISH} "Wybierz katalog instalacji ${APPNAME} w:"
+
+; CheckStartupParams message box
+LangString CheckStartupParamsMB ${LANG_POLISH} "Nie można odnaleźć programu '$INSTPROG'. Cicha aktualizacja zakończyła się niepowodzeniem."
+
+; check windows version
+LangString CheckWindowsVersionDP ${LANG_POLISH} "Sprawdzanie wersji Windows..."
+LangString CheckWindowsVersionMB ${LANG_POLISH} '${APPNAME} obsługuje tylko Windows XP.$\n$\nPróba zainstalowania na Windows $R0 może spowodować awarie i utratę danych.$\n$\n'
+LangString CheckWindowsServPackMB ${LANG_POLISH} "Zalecane jest uruchamianie ${APPNAME} z najnowszym dostępnym Service Packiem zainstalowanym w systemie.$\nPomaga on w podniesieniu wydajności i stabilności programu."
+LangString UseLatestServPackDP ${LANG_POLISH} "Użyj usługi Windows Update, aby zainstalować najnowszy Service Pack."
+
+; checkifadministrator function (install)
+LangString CheckAdministratorInstDP ${LANG_POLISH} "Sprawdzanie zezwolenia na instalacjÄ™..."
+LangString CheckAdministratorInstMB ${LANG_POLISH} 'Używasz "ograniczonego" konta.$\nMusisz być zalogowany jako "administrator" aby zainstalować ${APPNAME}.'
+
+; checkifadministrator function (uninstall)
+LangString CheckAdministratorUnInstDP ${LANG_POLISH} "Sprawdzanie zezwolenia na odinstalowanie..."
+LangString CheckAdministratorUnInstMB ${LANG_POLISH} 'Używasz "ograniczonego" konta.$\nMusisz być być zalogowany jako "administrator" aby zainstalować ${APPNAME}.'
+
+; checkifalreadycurrent
+LangString CheckIfCurrentMB ${LANG_POLISH} "${APPNAME} ${VERSION_LONG} jest już zainstalowane.$\n$\nCzy chcesz zainstalować ${APPNAME} ponownie?"
+
+; checkcpuflags
+LangString MissingSSE2 ${LANG_POLISH} "Ten komputer może nie mieć procesora z obsługą SSE2, który jest wymagany aby uruchomić ${APPNAME} w wersji ${VERSION_LONG}. Chcesz kontynuować?"
+
+; closesecondlife function (install)
+LangString CloseSecondLifeInstDP ${LANG_POLISH} "Oczekiwanie na zamknięcie Alchemy..."
+LangString CloseSecondLifeInstMB ${LANG_POLISH} "Alchemy nie może zostać zainstalowane, ponieważ jest już włączone.$\n$\nZakończ swoje działania i wybierz OK aby zamknąć Alchemy i kontynuować.$\nWybierz CANCEL aby anulować instalację."
+
+; closesecondlife function (uninstall)
+LangString CloseSecondLifeUnInstDP ${LANG_POLISH} "Oczekiwanie na zamknięcie Alchemy..."
+LangString CloseSecondLifeUnInstMB ${LANG_POLISH} "Alchemy nie może zostać zainstalowane, ponieważ jest już włączone.$\n$\nZakończ swoje działania i wybierz OK aby zamknąć Alchemy i kontynuować.$\nWybierz CANCEL aby anulować."
+
+; CheckNetworkConnection
+LangString CheckNetworkConnectionDP ${LANG_POLISH} "Sprawdzanie połączenia sieciowego..."
+
+; removecachefiles
+LangString RemoveCacheFilesDP ${LANG_POLISH} "Kasowanie plików pamięci podręcznej (cache) w folderze Documents and Settings"
+
+; delete program files
+LangString DeleteProgramFilesMB ${LANG_POLISH} "Nadal istnieją pliki w katalogu instalacyjnym ${APPNAME}.$\n$\nMożliwe, że są to pliki, które stworzyłeś/stworzyłaś lub przeniosłeś/przeniosłaś do:$\n$INSTDIR$\n$\nCzy chcesz je usunąć?"
+
+; uninstall text
+LangString UninstallTextMsg ${LANG_POLISH} "To spowoduje odinstalowanie ${APPNAME} ${VERSION_LONG} z Twojego systemu."
diff --git a/indra/newview/installers/windows/lang_pt-br.nsi b/indra/newview/installers/windows/lang_pt-br.nsi
index d7984a50c6..7b99a65239 100755
--- a/indra/newview/installers/windows/lang_pt-br.nsi
+++ b/indra/newview/installers/windows/lang_pt-br.nsi
@@ -1,56 +1,56 @@
-; First is default
-!insertmacro MUI_LANGUAGE "PortugueseBR"
-
-; Language string
-LangString LanguageCode ${LANG_PORTUGUESEBR} "pt"
-
-; Language selection dialog
-LangString SelectInstallerLanguage  ${LANG_PORTUGUESEBR} "Por favor seleccione a linguagem do instalador"
-
-; installation directory text
-LangString DirectoryChooseTitle ${LANG_PORTUGUESEBR} "Diretório de Instalação" 
-LangString DirectoryChooseUpdate ${LANG_PORTUGUESEBR} "Selecione o diretório do ${APPNAME} para atualizar para a versão ${VERSION_LONG}.(XXX):"
-LangString DirectoryChooseSetup ${LANG_PORTUGUESEBR} "Selecione o diretório para a instalação do ${APPNAME} em:"
-
-; CheckStartupParams message box
-LangString CheckStartupParamsMB ${LANG_PORTUGUESEBR} "Não é possível encontrar o programa '$INSTPROG'. Ocorreu uma falha na atualização silenciosa."
-
-; check windows version
-LangString CheckWindowsVersionDP ${LANG_PORTUGUESEBR} "Verificando a versão do Windows..."
-LangString CheckWindowsVersionMB ${LANG_PORTUGUESEBR} 'O ${APPNAME} suporta apenas Windows XP.$\n$\nA tentativa de instalar no Windows $R0 pode resultar em falhas e perda de dados.$\n$\n'
-LangString CheckWindowsServPackMB ${LANG_PORTUGUESEBR} "It is recomended to run ${APPNAME} on the latest service pack for your operating system.$\nThis will help with performance and stability of the program."
-LangString UseLatestServPackDP ${LANG_PORTUGUESEBR} "Please use Windows Update to install the latest Service Pack."
-
-; checkifadministrator function (install)
-LangString CheckAdministratorInstDP ${LANG_PORTUGUESEBR} "Verificando a permissão para instalação..."
-LangString CheckAdministratorInstMB ${LANG_PORTUGUESEBR} 'Você parece estar usando uma conta "limitada".$\nVocê deve ser um "administrador" para poder instalar o ${APPNAME}.'
-
-; checkifadministrator function (uninstall)
-LangString CheckAdministratorUnInstDP ${LANG_PORTUGUESEBR} "Verificando a permissão para desinstalação..."
-LangString CheckAdministratorUnInstMB ${LANG_PORTUGUESEBR} 'Você parece estar usando uma conta "limitada".$\nVocê deve ser um "administrador" para poder desinstalar o ${APPNAME}.'
-
-; checkifalreadycurrent
-LangString CheckIfCurrentMB ${LANG_PORTUGUESEBR} "Parece que o ${APPNAME} ${VERSION_LONG} já está instalado.$\n$\nDeseja instalar novamente?"
-
-; checkcpuflags
-LangString MissingSSE2 ${LANG_PORTUGUESEBR} "This machine may not have a CPU with SSE2 support, which is required to run ${APPNAME} ${VERSION_LONG}. Do you want to continue?"
-
-; closesecondlife function (install)
-LangString CloseSecondLifeInstDP ${LANG_PORTUGUESEBR} "Esperando o encerramento do Alchemy..."
-LangString CloseSecondLifeInstMB ${LANG_PORTUGUESEBR} "O Alchemy não pode ser instalado enquanto ainda está sendo executado.$\n$\nTermine o que estava fazendo e selecione OK para fechar o Alchemy e continuar.$\nSelecione CANCELAR para cancelar a instalação."
-
-; closesecondlife function (uninstall)
-LangString CloseSecondLifeUnInstDP ${LANG_PORTUGUESEBR} "Esperando o encerramento do Alchemy..."
-LangString CloseSecondLifeUnInstMB ${LANG_PORTUGUESEBR} "O Alchemy não pode ser desinstalado enquanto ainda está sendo executado.$\n$\nTermine o que estava fazendo e selecione OK para fechar o Alchemy e continuar.$\nSelecione CANCELAR para cancelar."
-
-; CheckNetworkConnection
-LangString CheckNetworkConnectionDP ${LANG_PORTUGUESEBR} "Verificando a conexão de rede..."
-
-; removecachefiles
-LangString RemoveCacheFilesDP ${LANG_PORTUGUESEBR} "Excluindo arquivos de cache na pasta Documents and Settings"
-
-; delete program files
-LangString DeleteProgramFilesMB ${LANG_PORTUGUESEBR} "Ainda existem arquivos em seu diretório do programa ${APPNAME}.$\n$\nProvavelmente são arquivos que você criou ou moveu para:$\n$INSTDIR$\n$\nDeseja removê-los?"
-
-; uninstall text
-LangString UninstallTextMsg ${LANG_PORTUGUESEBR} "Isso desinstalará o ${APPNAME} ${VERSION_LONG} do seu sistema."
+; First is default
+!insertmacro MUI_LANGUAGE "PortugueseBR"
+
+; Language string
+LangString LanguageCode ${LANG_PORTUGUESEBR} "pt"
+
+; Language selection dialog
+LangString SelectInstallerLanguage  ${LANG_PORTUGUESEBR} "Por favor seleccione a linguagem do instalador"
+
+; installation directory text
+LangString DirectoryChooseTitle ${LANG_PORTUGUESEBR} "Diretório de Instalação" 
+LangString DirectoryChooseUpdate ${LANG_PORTUGUESEBR} "Selecione o diretório do ${APPNAME} para atualizar para a versão ${VERSION_LONG}.(XXX):"
+LangString DirectoryChooseSetup ${LANG_PORTUGUESEBR} "Selecione o diretório para a instalação do ${APPNAME} em:"
+
+; CheckStartupParams message box
+LangString CheckStartupParamsMB ${LANG_PORTUGUESEBR} "Não é possível encontrar o programa '$INSTPROG'. Ocorreu uma falha na atualização silenciosa."
+
+; check windows version
+LangString CheckWindowsVersionDP ${LANG_PORTUGUESEBR} "Verificando a versão do Windows..."
+LangString CheckWindowsVersionMB ${LANG_PORTUGUESEBR} 'O ${APPNAME} suporta apenas Windows XP.$\n$\nA tentativa de instalar no Windows $R0 pode resultar em falhas e perda de dados.$\n$\n'
+LangString CheckWindowsServPackMB ${LANG_PORTUGUESEBR} "It is recomended to run ${APPNAME} on the latest service pack for your operating system.$\nThis will help with performance and stability of the program."
+LangString UseLatestServPackDP ${LANG_PORTUGUESEBR} "Please use Windows Update to install the latest Service Pack."
+
+; checkifadministrator function (install)
+LangString CheckAdministratorInstDP ${LANG_PORTUGUESEBR} "Verificando a permissão para instalação..."
+LangString CheckAdministratorInstMB ${LANG_PORTUGUESEBR} 'Você parece estar usando uma conta "limitada".$\nVocê deve ser um "administrador" para poder instalar o ${APPNAME}.'
+
+; checkifadministrator function (uninstall)
+LangString CheckAdministratorUnInstDP ${LANG_PORTUGUESEBR} "Verificando a permissão para desinstalação..."
+LangString CheckAdministratorUnInstMB ${LANG_PORTUGUESEBR} 'Você parece estar usando uma conta "limitada".$\nVocê deve ser um "administrador" para poder desinstalar o ${APPNAME}.'
+
+; checkifalreadycurrent
+LangString CheckIfCurrentMB ${LANG_PORTUGUESEBR} "Parece que o ${APPNAME} ${VERSION_LONG} já está instalado.$\n$\nDeseja instalar novamente?"
+
+; checkcpuflags
+LangString MissingSSE2 ${LANG_PORTUGUESEBR} "This machine may not have a CPU with SSE2 support, which is required to run ${APPNAME} ${VERSION_LONG}. Do you want to continue?"
+
+; closesecondlife function (install)
+LangString CloseSecondLifeInstDP ${LANG_PORTUGUESEBR} "Esperando o encerramento do Alchemy..."
+LangString CloseSecondLifeInstMB ${LANG_PORTUGUESEBR} "O Alchemy não pode ser instalado enquanto ainda está sendo executado.$\n$\nTermine o que estava fazendo e selecione OK para fechar o Alchemy e continuar.$\nSelecione CANCELAR para cancelar a instalação."
+
+; closesecondlife function (uninstall)
+LangString CloseSecondLifeUnInstDP ${LANG_PORTUGUESEBR} "Esperando o encerramento do Alchemy..."
+LangString CloseSecondLifeUnInstMB ${LANG_PORTUGUESEBR} "O Alchemy não pode ser desinstalado enquanto ainda está sendo executado.$\n$\nTermine o que estava fazendo e selecione OK para fechar o Alchemy e continuar.$\nSelecione CANCELAR para cancelar."
+
+; CheckNetworkConnection
+LangString CheckNetworkConnectionDP ${LANG_PORTUGUESEBR} "Verificando a conexão de rede..."
+
+; removecachefiles
+LangString RemoveCacheFilesDP ${LANG_PORTUGUESEBR} "Excluindo arquivos de cache na pasta Documents and Settings"
+
+; delete program files
+LangString DeleteProgramFilesMB ${LANG_PORTUGUESEBR} "Ainda existem arquivos em seu diretório do programa ${APPNAME}.$\n$\nProvavelmente são arquivos que você criou ou moveu para:$\n$INSTDIR$\n$\nDeseja removê-los?"
+
+; uninstall text
+LangString UninstallTextMsg ${LANG_PORTUGUESEBR} "Isso desinstalará o ${APPNAME} ${VERSION_LONG} do seu sistema."
diff --git a/indra/newview/installers/windows/lang_ru.nsi b/indra/newview/installers/windows/lang_ru.nsi
index e61d39f560..9236ac6de7 100755
--- a/indra/newview/installers/windows/lang_ru.nsi
+++ b/indra/newview/installers/windows/lang_ru.nsi
@@ -1,56 +1,56 @@
-; First is default
-!insertmacro MUI_LANGUAGE "Russian"
-
-; Language string
-LangString LanguageCode ${LANG_RUSSIAN}  "ru"
-
-; Language selection dialog
-LangString SelectInstallerLanguage  ${LANG_RUSSIAN} "Выберите язык программы установки"
-
-; installation directory text
-LangString DirectoryChooseTitle ${LANG_RUSSIAN} "Каталог установки" 
-LangString DirectoryChooseUpdate ${LANG_RUSSIAN} "Выберите каталог ${APPNAME} для обновления до версии ${VERSION_LONG}.(XXX):"
-LangString DirectoryChooseSetup ${LANG_RUSSIAN} "Выберите каталог для установки ${APPNAME}:"
-
-; CheckStartupParams message box
-LangString CheckStartupParamsMB ${LANG_RUSSIAN} "Не удалось найти программу «$INSTPROG». Автоматическое обновление не выполнено."
-
-; check windows version
-LangString CheckWindowsVersionDP ${LANG_RUSSIAN} "Проверка версии Windows..."
-LangString CheckWindowsVersionMB ${LANG_RUSSIAN} '${APPNAME} может работать только в Windows XP.$\n$\nПопытка установки в Windows $R0 может привести к сбою и потере данных.$\n$\n'
-LangString CheckWindowsServPackMB ${LANG_RUSSIAN} "It is recomended to run ${APPNAME} on the latest service pack for your operating system.$\nThis will help with performance and stability of the program."
-LangString UseLatestServPackDP ${LANG_RUSSIAN} "Please use Windows Update to install the latest Service Pack."
-
-; checkifadministrator function (install)
-LangString CheckAdministratorInstDP ${LANG_RUSSIAN} "Проверка разрешений на установку..."
-LangString CheckAdministratorInstMB ${LANG_RUSSIAN} 'Вероятно, у вас ограниченный аккаунт.$\nДля установки ${APPNAME} необходимы права администратора.'
-
-; checkifadministrator function (uninstall)
-LangString CheckAdministratorUnInstDP ${LANG_RUSSIAN} "Проверка разрешений на удаление..."
-LangString CheckAdministratorUnInstMB ${LANG_RUSSIAN} 'Вероятно, у вас ограниченный аккаунт.$\nДля удаления ${APPNAME} необходимы права администратора.'
-
-; checkifalreadycurrent
-LangString CheckIfCurrentMB ${LANG_RUSSIAN} "Вероятно, версия ${APPNAME} ${VERSION_LONG} уже установлена.$\n$\nУстановить ее снова?"
-
-; checkcpuflags
-LangString MissingSSE2 ${LANG_RUSSIAN} "Возможно, на этом компьютере нет ЦП с поддержкой SSE2, которая необходима для работы ${APPNAME} ${VERSION_LONG}. Продолжить?"
-
-; closesecondlife function (install)
-LangString CloseSecondLifeInstDP ${LANG_RUSSIAN} "Ожидаю завершения работы Alchemy..."
-LangString CloseSecondLifeInstMB ${LANG_RUSSIAN} "Alchemy уже работает, выполнить установку невозможно.$\n$\nЗавершите текущую операцию и нажмите кнопку «OK», чтобы закрыть Alchemy и продолжить установку.$\nНажмите кнопку «ОТМЕНА» для отказа от установки."
-
-; closesecondlife function (uninstall)
-LangString CloseSecondLifeUnInstDP ${LANG_RUSSIAN} "Ожидаю завершения работы Alchemy..."
-LangString CloseSecondLifeUnInstMB ${LANG_RUSSIAN} "Alchemy уже работает, выполнить удаление невозможно.$\n$\nЗавершите текущую операцию и нажмите кнопку «OK», чтобы закрыть Alchemy и продолжить удаление.$\nНажмите кнопку «ОТМЕНА» для отказа от удаления."
-
-; CheckNetworkConnection
-LangString CheckNetworkConnectionDP ${LANG_RUSSIAN} "Проверка подключения к сети..."
-
-; removecachefiles
-LangString RemoveCacheFilesDP ${LANG_RUSSIAN} "Удаление файлов кэша из папки «Documents and Settings»"
-
-; delete program files
-LangString DeleteProgramFilesMB ${LANG_RUSSIAN} "В каталоге программы ${APPNAME} остались файлы.$\n$\nВероятно, это файлы, созданные или перемещенные вами в $\n$INSTDIR$\n$\nУдалить их?"
-
-; uninstall text
-LangString UninstallTextMsg ${LANG_RUSSIAN} "Программа ${APPNAME} ${VERSION_LONG} будет удалена из вашей системы."
+; First is default
+!insertmacro MUI_LANGUAGE "Russian"
+
+; Language string
+LangString LanguageCode ${LANG_RUSSIAN}  "ru"
+
+; Language selection dialog
+LangString SelectInstallerLanguage  ${LANG_RUSSIAN} "Выберите язык программы установки"
+
+; installation directory text
+LangString DirectoryChooseTitle ${LANG_RUSSIAN} "Каталог установки" 
+LangString DirectoryChooseUpdate ${LANG_RUSSIAN} "Выберите каталог ${APPNAME} для обновления до версии ${VERSION_LONG}.(XXX):"
+LangString DirectoryChooseSetup ${LANG_RUSSIAN} "Выберите каталог для установки ${APPNAME}:"
+
+; CheckStartupParams message box
+LangString CheckStartupParamsMB ${LANG_RUSSIAN} "Не удалось найти программу «$INSTPROG». Автоматическое обновление не выполнено."
+
+; check windows version
+LangString CheckWindowsVersionDP ${LANG_RUSSIAN} "Проверка версии Windows..."
+LangString CheckWindowsVersionMB ${LANG_RUSSIAN} '${APPNAME} может работать только в Windows XP.$\n$\nПопытка установки в Windows $R0 может привести к сбою и потере данных.$\n$\n'
+LangString CheckWindowsServPackMB ${LANG_RUSSIAN} "It is recomended to run ${APPNAME} on the latest service pack for your operating system.$\nThis will help with performance and stability of the program."
+LangString UseLatestServPackDP ${LANG_RUSSIAN} "Please use Windows Update to install the latest Service Pack."
+
+; checkifadministrator function (install)
+LangString CheckAdministratorInstDP ${LANG_RUSSIAN} "Проверка разрешений на установку..."
+LangString CheckAdministratorInstMB ${LANG_RUSSIAN} 'Вероятно, у вас ограниченный аккаунт.$\nДля установки ${APPNAME} необходимы права администратора.'
+
+; checkifadministrator function (uninstall)
+LangString CheckAdministratorUnInstDP ${LANG_RUSSIAN} "Проверка разрешений на удаление..."
+LangString CheckAdministratorUnInstMB ${LANG_RUSSIAN} 'Вероятно, у вас ограниченный аккаунт.$\nДля удаления ${APPNAME} необходимы права администратора.'
+
+; checkifalreadycurrent
+LangString CheckIfCurrentMB ${LANG_RUSSIAN} "Вероятно, версия ${APPNAME} ${VERSION_LONG} уже установлена.$\n$\nУстановить ее снова?"
+
+; checkcpuflags
+LangString MissingSSE2 ${LANG_RUSSIAN} "Возможно, на этом компьютере нет ЦП с поддержкой SSE2, которая необходима для работы ${APPNAME} ${VERSION_LONG}. Продолжить?"
+
+; closesecondlife function (install)
+LangString CloseSecondLifeInstDP ${LANG_RUSSIAN} "Ожидаю завершения работы Alchemy..."
+LangString CloseSecondLifeInstMB ${LANG_RUSSIAN} "Alchemy уже работает, выполнить установку невозможно.$\n$\nЗавершите текущую операцию и нажмите кнопку «OK», чтобы закрыть Alchemy и продолжить установку.$\nНажмите кнопку «ОТМЕНА» для отказа от установки."
+
+; closesecondlife function (uninstall)
+LangString CloseSecondLifeUnInstDP ${LANG_RUSSIAN} "Ожидаю завершения работы Alchemy..."
+LangString CloseSecondLifeUnInstMB ${LANG_RUSSIAN} "Alchemy уже работает, выполнить удаление невозможно.$\n$\nЗавершите текущую операцию и нажмите кнопку «OK», чтобы закрыть Alchemy и продолжить удаление.$\nНажмите кнопку «ОТМЕНА» для отказа от удаления."
+
+; CheckNetworkConnection
+LangString CheckNetworkConnectionDP ${LANG_RUSSIAN} "Проверка подключения к сети..."
+
+; removecachefiles
+LangString RemoveCacheFilesDP ${LANG_RUSSIAN} "Удаление файлов кэша из папки «Documents and Settings»"
+
+; delete program files
+LangString DeleteProgramFilesMB ${LANG_RUSSIAN} "В каталоге программы ${APPNAME} остались файлы.$\n$\nВероятно, это файлы, созданные или перемещенные вами в $\n$INSTDIR$\n$\nУдалить их?"
+
+; uninstall text
+LangString UninstallTextMsg ${LANG_RUSSIAN} "Программа ${APPNAME} ${VERSION_LONG} будет удалена из вашей системы."
diff --git a/indra/newview/installers/windows/lang_tr.nsi b/indra/newview/installers/windows/lang_tr.nsi
index 5d524929f2..6df21e89f4 100755
--- a/indra/newview/installers/windows/lang_tr.nsi
+++ b/indra/newview/installers/windows/lang_tr.nsi
@@ -1,56 +1,56 @@
-; First is default
-!insertmacro MUI_LANGUAGE "Turkish"
-
-; Language string
-LangString LanguageCode ${LANG_TURKISH}  "tr"
-
-; Language selection dialog
-LangString SelectInstallerLanguage  ${LANG_TURKISH} "Lütfen yükleyicinin dilini seçin"
-
-; installation directory text
-LangString DirectoryChooseTitle ${LANG_TURKISH} "Yükleme Dizini" 
-LangString DirectoryChooseUpdate ${LANG_TURKISH} "${VERSION_LONG}.(XXX) sürümüne güncelleştirme yapmak için ${APPNAME} dizinini seçin:"
-LangString DirectoryChooseSetup ${LANG_TURKISH} "${APPNAME}'ın yükleneceği dizini seçin:"
-
-; CheckStartupParams message box
-LangString CheckStartupParamsMB ${LANG_TURKISH} "'$INSTPROG' programı bulunamadı. Sessiz güncelleştirme başarılamadı."
-
-; check windows version
-LangString CheckWindowsVersionDP ${LANG_TURKISH} "Windows sürümü kontrol ediliyor..."
-LangString CheckWindowsVersionMB ${LANG_TURKISH} "${APPNAME} sadece Windows XP'i destekler.$\n$\nWindows $R0 üzerine yüklemeye çalışmak sistem çökmelerine ve veri kaybına neden olabilir.$\n$\n"
-LangString CheckWindowsServPackMB ${LANG_TURKISH} "It is recomended to run ${APPNAME} on the latest service pack for your operating system.$\nThis will help with performance and stability of the program."
-LangString UseLatestServPackDP ${LANG_TURKISH} "Please use Windows Update to install the latest Service Pack."
-
-; checkifadministrator function (install)
-LangString CheckAdministratorInstDP ${LANG_TURKISH} "Yükleme izni kontrol ediliyor..."
-LangString CheckAdministratorInstMB ${LANG_TURKISH} "'Sınırlı' bir hesap kullanıyor görünüyorsunuz.$\n${APPNAME}'ı yüklemek için bir 'yönetici' olmalısınız."
-
-; checkifadministrator function (uninstall)
-LangString CheckAdministratorUnInstDP ${LANG_TURKISH} "Kaldırma izni kontrol ediliyor..."
-LangString CheckAdministratorUnInstMB ${LANG_TURKISH} "'Sınırlı' bir hesap kullanıyor görünüyorsunuz.$\n${APPNAME}'ı kaldırmak için bir 'yönetici' olmalısınız."
-
-; checkifalreadycurrent
-LangString CheckIfCurrentMB ${LANG_TURKISH} "${APPNAME} ${VERSION_LONG} zaten yüklü.$\n$\nTekrar yüklemek ister misiniz?"
-
-; checkcpuflags
-LangString MissingSSE2 ${LANG_TURKISH} "Bu makinede SSE2 desteğine sahip bir CPU bulunmayabilir, ${APPNAME} ${VERSION_LONG} çalıştırmak için bu gereklidir. Devam etmek istiyor musunuz?"
-
-; closesecondlife function (install)
-LangString CloseSecondLifeInstDP ${LANG_TURKISH} "Alchemy'ın kapatılması bekleniyor..."
-LangString CloseSecondLifeInstMB ${LANG_TURKISH} "Alchemy zaten çalışırken kapatılamaz.$\n$\nYaptığınız işi bitirdikten sonra Alchemy'ı kapatmak ve devam etmek için Tamam seçimini yapın.$\nYüklemeyi iptal etmek için İPTAL seçimini yapın."
-
-; closesecondlife function (uninstall)
-LangString CloseSecondLifeUnInstDP ${LANG_TURKISH} "Alchemy'ın kapatılması bekleniyor..."
-LangString CloseSecondLifeUnInstMB ${LANG_TURKISH} "Alchemy zaten çalışırken kaldırılamaz.$\n$\nYaptığınız işi bitirdikten sonra Alchemy'ı kapatmak ve devam etmek için Tamam seçimini yapın.$\nİptal etmek için İPTAL seçimini yapın."
-
-; CheckNetworkConnection
-LangString CheckNetworkConnectionDP ${LANG_TURKISH} "Ağ bağlantısı kontrol ediliyor..."
-
-; removecachefiles
-LangString RemoveCacheFilesDP ${LANG_TURKISH} "Belgeler ve Ayarlar klasöründeki önbellek dosyaları siliniyor"
-
-; delete program files
-LangString DeleteProgramFilesMB ${LANG_TURKISH} "${APPNAME} program dizininizde hala dosyalar var.$\n$\nBunlar muhtemelen sizin oluşturduğunuz veya şuraya taşıdığınız dosyalar:$\n$INSTDIR$\n$\nBunları kaldırmak istiyor musunuz?"
-
-; uninstall text
-LangString UninstallTextMsg ${LANG_TURKISH} "Bu adımla ${APPNAME} ${VERSION_LONG} sisteminizden kaldırılacaktır."
+; First is default
+!insertmacro MUI_LANGUAGE "Turkish"
+
+; Language string
+LangString LanguageCode ${LANG_TURKISH}  "tr"
+
+; Language selection dialog
+LangString SelectInstallerLanguage  ${LANG_TURKISH} "Lütfen yükleyicinin dilini seçin"
+
+; installation directory text
+LangString DirectoryChooseTitle ${LANG_TURKISH} "Yükleme Dizini" 
+LangString DirectoryChooseUpdate ${LANG_TURKISH} "${VERSION_LONG}.(XXX) sürümüne güncelleştirme yapmak için ${APPNAME} dizinini seçin:"
+LangString DirectoryChooseSetup ${LANG_TURKISH} "${APPNAME}'ın yükleneceği dizini seçin:"
+
+; CheckStartupParams message box
+LangString CheckStartupParamsMB ${LANG_TURKISH} "'$INSTPROG' programı bulunamadı. Sessiz güncelleştirme başarılamadı."
+
+; check windows version
+LangString CheckWindowsVersionDP ${LANG_TURKISH} "Windows sürümü kontrol ediliyor..."
+LangString CheckWindowsVersionMB ${LANG_TURKISH} "${APPNAME} sadece Windows XP'i destekler.$\n$\nWindows $R0 üzerine yüklemeye çalışmak sistem çökmelerine ve veri kaybına neden olabilir.$\n$\n"
+LangString CheckWindowsServPackMB ${LANG_TURKISH} "It is recomended to run ${APPNAME} on the latest service pack for your operating system.$\nThis will help with performance and stability of the program."
+LangString UseLatestServPackDP ${LANG_TURKISH} "Please use Windows Update to install the latest Service Pack."
+
+; checkifadministrator function (install)
+LangString CheckAdministratorInstDP ${LANG_TURKISH} "Yükleme izni kontrol ediliyor..."
+LangString CheckAdministratorInstMB ${LANG_TURKISH} "'Sınırlı' bir hesap kullanıyor görünüyorsunuz.$\n${APPNAME}'ı yüklemek için bir 'yönetici' olmalısınız."
+
+; checkifadministrator function (uninstall)
+LangString CheckAdministratorUnInstDP ${LANG_TURKISH} "Kaldırma izni kontrol ediliyor..."
+LangString CheckAdministratorUnInstMB ${LANG_TURKISH} "'Sınırlı' bir hesap kullanıyor görünüyorsunuz.$\n${APPNAME}'ı kaldırmak için bir 'yönetici' olmalısınız."
+
+; checkifalreadycurrent
+LangString CheckIfCurrentMB ${LANG_TURKISH} "${APPNAME} ${VERSION_LONG} zaten yüklü.$\n$\nTekrar yüklemek ister misiniz?"
+
+; checkcpuflags
+LangString MissingSSE2 ${LANG_TURKISH} "Bu makinede SSE2 desteğine sahip bir CPU bulunmayabilir, ${APPNAME} ${VERSION_LONG} çalıştırmak için bu gereklidir. Devam etmek istiyor musunuz?"
+
+; closesecondlife function (install)
+LangString CloseSecondLifeInstDP ${LANG_TURKISH} "Alchemy'ın kapatılması bekleniyor..."
+LangString CloseSecondLifeInstMB ${LANG_TURKISH} "Alchemy zaten çalışırken kapatılamaz.$\n$\nYaptığınız işi bitirdikten sonra Alchemy'ı kapatmak ve devam etmek için Tamam seçimini yapın.$\nYüklemeyi iptal etmek için İPTAL seçimini yapın."
+
+; closesecondlife function (uninstall)
+LangString CloseSecondLifeUnInstDP ${LANG_TURKISH} "Alchemy'ın kapatılması bekleniyor..."
+LangString CloseSecondLifeUnInstMB ${LANG_TURKISH} "Alchemy zaten çalışırken kaldırılamaz.$\n$\nYaptığınız işi bitirdikten sonra Alchemy'ı kapatmak ve devam etmek için Tamam seçimini yapın.$\nİptal etmek için İPTAL seçimini yapın."
+
+; CheckNetworkConnection
+LangString CheckNetworkConnectionDP ${LANG_TURKISH} "Ağ bağlantısı kontrol ediliyor..."
+
+; removecachefiles
+LangString RemoveCacheFilesDP ${LANG_TURKISH} "Belgeler ve Ayarlar klasöründeki önbellek dosyaları siliniyor"
+
+; delete program files
+LangString DeleteProgramFilesMB ${LANG_TURKISH} "${APPNAME} program dizininizde hala dosyalar var.$\n$\nBunlar muhtemelen sizin oluşturduğunuz veya şuraya taşıdığınız dosyalar:$\n$INSTDIR$\n$\nBunları kaldırmak istiyor musunuz?"
+
+; uninstall text
+LangString UninstallTextMsg ${LANG_TURKISH} "Bu adımla ${APPNAME} ${VERSION_LONG} sisteminizden kaldırılacaktır."
diff --git a/indra/newview/installers/windows/lang_zh.nsi b/indra/newview/installers/windows/lang_zh.nsi
index 764ac0cfd2..3695b5e31c 100755
--- a/indra/newview/installers/windows/lang_zh.nsi
+++ b/indra/newview/installers/windows/lang_zh.nsi
@@ -1,56 +1,56 @@
-; First is default
-!insertmacro MUI_LANGUAGE "TradChinese"
-
-; Language string
-LangString LanguageCode ${LANG_TRADCHINESE}  "zh"
-
-; Language selection dialog
-LangString SelectInstallerLanguage ${LANG_TRADCHINESE} "請選擇安裝時使用的語言。"
-
-; installation directory text
-LangString DirectoryChooseTitle ${LANG_TRADCHINESE} "安裝目錄"
-LangString DirectoryChooseUpdate ${LANG_TRADCHINESE} "請選擇 ${APPNAME} 的安裝目錄,以便於將軟體更新成 ${VERSION_LONG} 版本(XXX):"
-LangString DirectoryChooseSetup ${LANG_TRADCHINESE} "請選擇安裝 ${APPNAME} 的目錄:"
-
-; CheckStartupParams message box
-LangString CheckStartupParamsMB ${LANG_TRADCHINESE} "找不到 '$INSTPROG' 程序。自動更新失敗。"
-
-; check windows version
-LangString CheckWindowsVersionDP ${LANG_TRADCHINESE} "檢查 Windows 版本…"
-LangString CheckWindowsVersionMB ${LANG_TRADCHINESE} "${APPNAME} 只支援 Windows XP。$\n$\n如果嘗試在 Windows $R0 上安裝,可能導致當機和資料遺失。$\n$\n"
-LangString CheckWindowsServPackMB ${LANG_TRADCHINESE} "It is recomended to run ${APPNAME} on the latest service pack for your operating system.$\nThis will help with performance and stability of the program."
-LangString UseLatestServPackDP ${LANG_TRADCHINESE} "Please use Windows Update to install the latest Service Pack."
-
-; checkifadministrator function (install)
-LangString CheckAdministratorInstDP ${LANG_TRADCHINESE} "檢查安裝所需的權限..."
-LangString CheckAdministratorInstMB ${LANG_TRADCHINESE} "您的帳戶似乎是「受限的帳戶」。$\n您必須有「管理員」權限才可以安裝 ${APPNAME}。"
-
-; checkifadministrator function (uninstall)
-LangString CheckAdministratorUnInstDP ${LANG_TRADCHINESE} "檢查卸載所需的權限..."
-LangString CheckAdministratorUnInstMB ${LANG_TRADCHINESE} "您的帳戶似乎是「受限的帳戶」。$\n您必須有「管理員」權限才可以卸載 ${APPNAME}。"
-
-; checkifalreadycurrent
-LangString CheckIfCurrentMB ${LANG_TRADCHINESE} "${APPNAME} ${VERSION_LONG} 版本似乎已經存在。$\n$\n您還想再安裝一次?"
-
-; checkcpuflags
-LangString MissingSSE2 ${LANG_TRADCHINESE} "This machine may not have a CPU with SSE2 support, which is required to run ${APPNAME} ${VERSION_LONG}. Do you want to continue?"
-
-; closesecondlife function (install)
-LangString CloseSecondLifeInstDP ${LANG_TRADCHINESE} "等待 Alchemy 停止運行…"
-LangString CloseSecondLifeInstMB ${LANG_TRADCHINESE} "如果 Alchemy 仍在運行,將無法進行安裝。$\n$\n請結束您在 Alchemy 內的活動,然後選擇確定,將 Alchemy 關閉,以繼續安裝。$\n選擇「取消」,取消安裝。"
-
-; closesecondlife function (uninstall)
-LangString CloseSecondLifeUnInstDP ${LANG_TRADCHINESE} "等待 Alchemy 停止運行…"
-LangString CloseSecondLifeUnInstMB ${LANG_TRADCHINESE} "如果 Alchemy 仍在運行,將無法進行卸載。$\n$\n請結束您在 Alchemy 內的活動,然後選擇確定,將 Alchemy 關閉,以繼續卸載。$\n選擇「取消」,取消卸載。"
-
-; CheckNetworkConnection
-LangString CheckNetworkConnectionDP ${LANG_TRADCHINESE} "正在檢查網路連接..."
-
-; removecachefiles
-LangString RemoveCacheFilesDP ${LANG_TRADCHINESE} "正在刪除 Documents and Settings 文件夾中的暫存文件。"
-
-; delete program files
-LangString DeleteProgramFilesMB ${LANG_TRADCHINESE} "在您的 ${APPNAME} 程式目錄裡仍存有一些文件。$\n$\n這些文件可能是您新建或移動到 $\n$INSTDIR 文件夾中的。$\n $\n您還想要加以刪除嗎?"
-
-; uninstall text
-LangString UninstallTextMsg ${LANG_TRADCHINESE} "將從您的系統中卸載 ${APPNAME} ${VERSION_LONG}。"
+; First is default
+!insertmacro MUI_LANGUAGE "TradChinese"
+
+; Language string
+LangString LanguageCode ${LANG_TRADCHINESE}  "zh"
+
+; Language selection dialog
+LangString SelectInstallerLanguage ${LANG_TRADCHINESE} "請選擇安裝時使用的語言。"
+
+; installation directory text
+LangString DirectoryChooseTitle ${LANG_TRADCHINESE} "安裝目錄"
+LangString DirectoryChooseUpdate ${LANG_TRADCHINESE} "請選擇 ${APPNAME} 的安裝目錄,以便於將軟體更新成 ${VERSION_LONG} 版本(XXX):"
+LangString DirectoryChooseSetup ${LANG_TRADCHINESE} "請選擇安裝 ${APPNAME} 的目錄:"
+
+; CheckStartupParams message box
+LangString CheckStartupParamsMB ${LANG_TRADCHINESE} "找不到 '$INSTPROG' 程序。自動更新失敗。"
+
+; check windows version
+LangString CheckWindowsVersionDP ${LANG_TRADCHINESE} "檢查 Windows 版本…"
+LangString CheckWindowsVersionMB ${LANG_TRADCHINESE} "${APPNAME} 只支援 Windows XP。$\n$\n如果嘗試在 Windows $R0 上安裝,可能導致當機和資料遺失。$\n$\n"
+LangString CheckWindowsServPackMB ${LANG_TRADCHINESE} "It is recomended to run ${APPNAME} on the latest service pack for your operating system.$\nThis will help with performance and stability of the program."
+LangString UseLatestServPackDP ${LANG_TRADCHINESE} "Please use Windows Update to install the latest Service Pack."
+
+; checkifadministrator function (install)
+LangString CheckAdministratorInstDP ${LANG_TRADCHINESE} "檢查安裝所需的權限..."
+LangString CheckAdministratorInstMB ${LANG_TRADCHINESE} "您的帳戶似乎是「受限的帳戶」。$\n您必須有「管理員」權限才可以安裝 ${APPNAME}。"
+
+; checkifadministrator function (uninstall)
+LangString CheckAdministratorUnInstDP ${LANG_TRADCHINESE} "檢查卸載所需的權限..."
+LangString CheckAdministratorUnInstMB ${LANG_TRADCHINESE} "您的帳戶似乎是「受限的帳戶」。$\n您必須有「管理員」權限才可以卸載 ${APPNAME}。"
+
+; checkifalreadycurrent
+LangString CheckIfCurrentMB ${LANG_TRADCHINESE} "${APPNAME} ${VERSION_LONG} 版本似乎已經存在。$\n$\n您還想再安裝一次?"
+
+; checkcpuflags
+LangString MissingSSE2 ${LANG_TRADCHINESE} "This machine may not have a CPU with SSE2 support, which is required to run ${APPNAME} ${VERSION_LONG}. Do you want to continue?"
+
+; closesecondlife function (install)
+LangString CloseSecondLifeInstDP ${LANG_TRADCHINESE} "等待 Alchemy 停止運行…"
+LangString CloseSecondLifeInstMB ${LANG_TRADCHINESE} "如果 Alchemy 仍在運行,將無法進行安裝。$\n$\n請結束您在 Alchemy 內的活動,然後選擇確定,將 Alchemy 關閉,以繼續安裝。$\n選擇「取消」,取消安裝。"
+
+; closesecondlife function (uninstall)
+LangString CloseSecondLifeUnInstDP ${LANG_TRADCHINESE} "等待 Alchemy 停止運行…"
+LangString CloseSecondLifeUnInstMB ${LANG_TRADCHINESE} "如果 Alchemy 仍在運行,將無法進行卸載。$\n$\n請結束您在 Alchemy 內的活動,然後選擇確定,將 Alchemy 關閉,以繼續卸載。$\n選擇「取消」,取消卸載。"
+
+; CheckNetworkConnection
+LangString CheckNetworkConnectionDP ${LANG_TRADCHINESE} "正在檢查網路連接..."
+
+; removecachefiles
+LangString RemoveCacheFilesDP ${LANG_TRADCHINESE} "正在刪除 Documents and Settings 文件夾中的暫存文件。"
+
+; delete program files
+LangString DeleteProgramFilesMB ${LANG_TRADCHINESE} "在您的 ${APPNAME} 程式目錄裡仍存有一些文件。$\n$\n這些文件可能是您新建或移動到 $\n$INSTDIR 文件夾中的。$\n $\n您還想要加以刪除嗎?"
+
+; uninstall text
+LangString UninstallTextMsg ${LANG_TRADCHINESE} "將從您的系統中卸載 ${APPNAME} ${VERSION_LONG}。"
diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp
index d6b3cd03af..398bb20b66 100644
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -1,2339 +1,2339 @@
-/** 
- * @file lldrawpoolavatar.cpp
- * @brief LLDrawPoolAvatar 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 "lldrawpoolavatar.h"
-#include "llskinningutil.h"
-#include "llrender.h"
-
-#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"
-#include "llviewercontrol.h" // for gSavedSettings
-#include "llviewertexturelist.h"
-
-#include <glm/mat3x3.hpp>
-#include <glm/mat4x4.hpp>
-#include <glm/gtc/matrix_inverse.hpp>
-#include <glm/gtc/type_ptr.hpp>
-
-static U32 sDataMask = LLDrawPoolAvatar::VERTEX_DATA_MASK;
-static U32 sBufferUsage = GL_STREAM_DRAW_ARB;
-static U32 sShaderLevel = 0;
-
-LLGLSLShader* LLDrawPoolAvatar::sVertexProgram = nullptr;
-BOOL	LLDrawPoolAvatar::sSkipOpaque = FALSE;
-BOOL	LLDrawPoolAvatar::sSkipTransparent = FALSE;
-S32     LLDrawPoolAvatar::sShadowPass = -1;
-S32 LLDrawPoolAvatar::sDiffuseChannel = 0;
-F32 LLDrawPoolAvatar::sMinimumAlpha = 0.2f;
-
-LLUUID gBlackSquareID;
-
-static bool is_deferred_render = false;
-static bool is_post_deferred_render = false;
-
-extern BOOL gUseGLPick;
-
-F32 CLOTHING_GRAVITY_EFFECT = 0.7f;
-F32 CLOTHING_ACCEL_FORCE_FACTOR = 0.2f;
-
-// Format for gAGPVertices
-// vertex format for bumpmapping:
-//  vertices   12
-//  pad		    4
-//  normals    12
-//  pad		    4
-//  texcoords0  8
-//  texcoords1  8
-// total       48
-//
-// for no bumpmapping
-//  vertices	   12
-//  texcoords	8
-//  normals	   12
-// total	   32
-//
-
-S32 AVATAR_OFFSET_POS = 0;
-S32 AVATAR_OFFSET_NORMAL = 16;
-S32 AVATAR_OFFSET_TEX0 = 32;
-S32 AVATAR_OFFSET_TEX1 = 40;
-S32 AVATAR_VERTEX_BYTES = 48;
-
-static BOOL sRenderingSkinned = FALSE;
-S32 normal_channel = -1;
-S32 specular_channel = -1;
-S32 cube_channel = -1;
-
-static LLTrace::BlockTimerStatHandle FTM_SHADOW_AVATAR("Avatar Shadow");
-
-LLDrawPoolAvatar::LLDrawPoolAvatar() : 
-	LLFacePool(POOL_AVATAR)	
-{
-}
-
-LLDrawPoolAvatar::~LLDrawPoolAvatar()
-{
-    if (!isDead())
-    {
-        LL_WARNS() << "Destroying avatar drawpool that still contains faces" << LL_ENDL;
-    }
-}
-
-// virtual
-BOOL LLDrawPoolAvatar::isDead()
-{
-    if (!LLFacePool::isDead())
-    {
-        return FALSE;
-    }
-    
-	for (auto& face : mRiggedFace)
-    {
-        if (!face.empty())
-        {
-            return FALSE;
-        }
-    }
-    return TRUE;
-}
- 
-//-----------------------------------------------------------------------------
-// instancePool()
-//-----------------------------------------------------------------------------
-LLDrawPool *LLDrawPoolAvatar::instancePool()
-{
-	return new LLDrawPoolAvatar();
-}
-
-
-S32 LLDrawPoolAvatar::getVertexShaderLevel() const
-{
-	return (S32) LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_AVATAR);
-}
-
-void LLDrawPoolAvatar::prerender()
-{
-	mVertexShaderLevel = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_AVATAR);
-	
-	sShaderLevel = mVertexShaderLevel;
-	
-	if (sShaderLevel > 0)
-	{
-		sBufferUsage = GL_DYNAMIC_DRAW_ARB;
-	}
-	else
-	{
-		sBufferUsage = GL_STREAM_DRAW_ARB;
-	}
-
-	if (!mDrawFace.empty())
-	{
-		const LLFace *facep = mDrawFace[0];
-		if (facep && facep->getDrawable())
-		{
-			LLVOAvatar* avatarp = (LLVOAvatar *)facep->getDrawable()->getVObj().get();
-			updateRiggedVertexBuffers(avatarp);
-		}
-	}
-}
-
-LLMatrix4& LLDrawPoolAvatar::getModelView()
-{
-	static LLMatrix4 ret;
-
-	ret.initRows(LLVector4(gGLModelView+0),
-				 LLVector4(gGLModelView+4),
-				 LLVector4(gGLModelView+8),
-				 LLVector4(gGLModelView+12));
-
-	return ret;
-}
-
-//-----------------------------------------------------------------------------
-// render()
-//-----------------------------------------------------------------------------
-
-
-
-void LLDrawPoolAvatar::beginDeferredPass(S32 pass)
-{
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_CHARACTERS);
-	
-	sSkipTransparent = TRUE;
-	is_deferred_render = true;
-	
-	if (LLPipeline::sImpostorRender)
-	{ //impostor pass does not have rigid or impostor rendering
-		pass += 2;
-	}
-
-	switch (pass)
-	{
-	case 0:
-		beginDeferredImpostor();
-		break;
-	case 1:
-		beginDeferredRigid();
-		break;
-	case 2:
-		beginDeferredSkinned();
-		break;
-	case 3:
-		beginDeferredRiggedSimple();
-		break;
-	case 4:
-		beginDeferredRiggedBump();
-		break;
-	default:
-		beginDeferredRiggedMaterial(pass-5);
-		break;
-	}
-}
-
-void LLDrawPoolAvatar::endDeferredPass(S32 pass)
-{
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_CHARACTERS);
-
-	sSkipTransparent = FALSE;
-	is_deferred_render = false;
-
-	if (LLPipeline::sImpostorRender)
-	{
-		pass += 2;
-	}
-
-	switch (pass)
-	{
-	case 0:
-		endDeferredImpostor();
-		break;
-	case 1:
-		endDeferredRigid();
-		break;
-	case 2:
-		endDeferredSkinned();
-		break;
-	case 3:
-		endDeferredRiggedSimple();
-		break;
-	case 4:
-		endDeferredRiggedBump();
-		break;
-	default:
-		endDeferredRiggedMaterial(pass-5);
-		break;
-	}
-}
-
-void LLDrawPoolAvatar::renderDeferred(S32 pass)
-{
-	render(pass);
-}
-
-S32 LLDrawPoolAvatar::getNumPostDeferredPasses()
-{
-	return 10;
-}
-
-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 9:
-		beginRiggedGlow();
-		break;
-	default:
-		beginDeferredRiggedMaterialAlpha(pass-5);
-		break;
-	}
-}
-
-void LLDrawPoolAvatar::beginPostDeferredAlpha()
-{
-	sSkipOpaque = TRUE;
-	sShaderLevel = mVertexShaderLevel;
-	sVertexProgram = &gDeferredAvatarAlphaProgram;
-	sRenderingSkinned = TRUE;
-
-	gPipeline.bindDeferredShader(*sVertexProgram);
-
-	sVertexProgram->setMinimumAlpha(LLDrawPoolAvatar::sMinimumAlpha);
-
-	sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-}
-
-void LLDrawPoolAvatar::beginDeferredRiggedAlpha()
-{
-	sVertexProgram = &gDeferredSkinnedAlphaProgram;
-	gPipeline.bindDeferredShader(*sVertexProgram);
-	sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-	gPipeline.enableLightsDynamic();
-}
-
-void LLDrawPoolAvatar::beginDeferredRiggedMaterialAlpha(S32 pass)
-{
-	switch (pass)
-	{
-	case 0: pass = 1; break;
-	case 1: pass = 5; break;
-	case 2: pass = 9; break;
-	default: pass = 13; break;
-	}
-
-	pass += LLMaterial::SHADER_COUNT;
-
-	sVertexProgram = &gDeferredMaterialProgram[pass];
-
-	if (LLPipeline::sUnderWaterRender)
-	{
-		sVertexProgram = &(gDeferredMaterialWaterProgram[pass]);
-	}
-
-	gPipeline.bindDeferredShader(*sVertexProgram);
-	sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-	normal_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::BUMP_MAP);
-	specular_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::SPECULAR_MAP);
-	gPipeline.enableLightsDynamic();
-}
-
-void LLDrawPoolAvatar::endDeferredRiggedAlpha()
-{
-	LLVertexBuffer::unbind();
-	gPipeline.unbindDeferredShader(*sVertexProgram);
-	sDiffuseChannel = 0;
-	normal_channel = -1;
-	specular_channel = -1;
-	sVertexProgram = nullptr;
-}
-
-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;
-	default:
-		endDeferredRiggedAlpha();
-		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;
-		
-	gPipeline.unbindDeferredShader(*sVertexProgram);
-	sDiffuseChannel = 0;
-	sShaderLevel = mVertexShaderLevel;
-}
-
-void LLDrawPoolAvatar::renderPostDeferred(S32 pass)
-{
-	static 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 material alpha 1
-		10,//rigged material alpha 2
-		11,//rigged material alpha 3
-		12,//rigged material alpha 4
-		13, //rigged glow
-	};
-
-	S32 p = actual_pass[pass];
-
-	if (LLPipeline::sImpostorRender)
-	{ //HACK for impostors so actual pass ends up being proper pass
-		p -= 2;
-	}
-
-	is_post_deferred_render = true;
-	render(p);
-	is_post_deferred_render = false;
-}
-
-
-S32 LLDrawPoolAvatar::getNumShadowPasses()
-{
-    // avatars opaque, avatar alpha, avatar alpha mask, alpha attachments, alpha mask attachments, opaque attachments...
-	return NUM_SHADOW_PASSES;
-}
-
-void LLDrawPoolAvatar::beginShadowPass(S32 pass)
-{
-	LL_RECORD_BLOCK_TIME(FTM_SHADOW_AVATAR);
-
-	if (pass == SHADOW_PASS_AVATAR_OPAQUE)
-	{
-		sVertexProgram = &gDeferredAvatarShadowProgram;
-		
-		if ((sShaderLevel > 0))  // for hardware blending
-		{
-			sRenderingSkinned = TRUE;
-			sVertexProgram->bind();
-		}
-
-		gGL.diffuseColor4f(1,1,1,1);
-	}
-    else if (pass == SHADOW_PASS_AVATAR_ALPHA_BLEND)
-	{
-		sVertexProgram = &gDeferredAvatarAlphaShadowProgram;
-
-        // bind diffuse tex so we can reference the alpha channel...
-        sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-		
-		if ((sShaderLevel > 0))  // for hardware blending
-		{
-			sRenderingSkinned = TRUE;
-			sVertexProgram->bind();
-		}
-
-		gGL.diffuseColor4f(1,1,1,1);
-	}
-    else if (pass == SHADOW_PASS_AVATAR_ALPHA_MASK)
-	{
-		sVertexProgram = &gDeferredAvatarAlphaMaskShadowProgram;
-
-        // bind diffuse tex so we can reference the alpha channel...
-        sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-		
-		if ((sShaderLevel > 0))  // for hardware blending
-		{
-			sRenderingSkinned = TRUE;
-			sVertexProgram->bind();
-		}
-
-		gGL.diffuseColor4f(1,1,1,1);
-	}
-    else if (pass == SHADOW_PASS_ATTACHMENT_ALPHA_BLEND)
-	{
-		sVertexProgram = &gDeferredAttachmentAlphaShadowProgram;
-
-        // bind diffuse tex so we can reference the alpha channel...
-        sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-		
-		if ((sShaderLevel > 0))  // for hardware blending
-		{
-			sRenderingSkinned = TRUE;
-			sVertexProgram->bind();
-		}
-
-		gGL.diffuseColor4f(1,1,1,1);
-	}
-    else if (pass == SHADOW_PASS_ATTACHMENT_ALPHA_MASK)
-	{
-		sVertexProgram = &gDeferredAttachmentAlphaMaskShadowProgram;
-
-        // bind diffuse tex so we can reference the alpha channel...
-		sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-
-		if ((sShaderLevel > 0))  // for hardware blending
-		{
-			sRenderingSkinned = TRUE;
-			sVertexProgram->bind();
-		}
-
-		gGL.diffuseColor4f(1,1,1,1);
-	}
-	else // SHADOW_PASS_ATTACHMENT_OPAQUE
-	{
-		sVertexProgram = &gDeferredAttachmentShadowProgram;
-		sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-		sVertexProgram->bind();
-	}
-}
-
-void LLDrawPoolAvatar::endShadowPass(S32 pass)
-{
-	LL_RECORD_BLOCK_TIME(FTM_SHADOW_AVATAR);
-
-	if (pass == SHADOW_PASS_ATTACHMENT_OPAQUE)
-	{
-		LLVertexBuffer::unbind();
-	}
-
-    if (sShaderLevel > 0)
-	{			
-		sVertexProgram->unbind();
-	}
-	sVertexProgram = nullptr;
-    sRenderingSkinned = FALSE;
-    LLDrawPoolAvatar::sShadowPass = -1;
-}
-
-void LLDrawPoolAvatar::renderShadow(S32 pass)
-{
-	LL_RECORD_BLOCK_TIME(FTM_SHADOW_AVATAR);
-
-	if (mDrawFace.empty())
-	{
-		return;
-	}
-
-	const LLFace *facep = mDrawFace[0];
-	if (!facep->getDrawable())
-	{
-		return;
-	}
-	LLVOAvatar *avatarp = (LLVOAvatar *)facep->getDrawable()->getVObj().get();
-
-	if (avatarp->isDead() || avatarp->isUIAvatar() || avatarp->mDrawable.isNull())
-	{
-		return;
-	}
-
-	BOOL impostor = avatarp->isImpostor();
-	if (impostor)
-	{
-		return;
-	}
-	
-    LLDrawPoolAvatar::sShadowPass = pass;
-
-	if (pass == SHADOW_PASS_AVATAR_OPAQUE)
-	{
-        LLDrawPoolAvatar::sSkipTransparent = true;
-		avatarp->renderSkinned();
-        LLDrawPoolAvatar::sSkipTransparent = false;
-	}
-    else if (pass == SHADOW_PASS_AVATAR_ALPHA_BLEND)
-	{
-        LLDrawPoolAvatar::sSkipOpaque = true;
-		avatarp->renderSkinned();
-        LLDrawPoolAvatar::sSkipOpaque = false;
-	}
-    else if (pass == SHADOW_PASS_AVATAR_ALPHA_MASK)
-	{
-        LLDrawPoolAvatar::sSkipOpaque = true;
-		avatarp->renderSkinned();
-        LLDrawPoolAvatar::sSkipOpaque = false;
-	}
-    else if (pass == SHADOW_PASS_ATTACHMENT_ALPHA_BLEND) // rigged alpha
-	{
-        LLDrawPoolAvatar::sSkipOpaque = true;
-        renderRigged(avatarp, RIGGED_MATERIAL_ALPHA);
-        renderRigged(avatarp, RIGGED_MATERIAL_ALPHA_EMISSIVE);
-        renderRigged(avatarp, RIGGED_ALPHA);
-        renderRigged(avatarp, RIGGED_FULLBRIGHT_ALPHA);
-        renderRigged(avatarp, RIGGED_GLOW);
-        renderRigged(avatarp, RIGGED_SPECMAP_BLEND);
-        renderRigged(avatarp, RIGGED_NORMMAP_BLEND);
-        renderRigged(avatarp, RIGGED_NORMSPEC_BLEND);
-        LLDrawPoolAvatar::sSkipOpaque = false;
-	}
-    else if (pass == SHADOW_PASS_ATTACHMENT_ALPHA_MASK) // rigged alpha mask
-	{
-        LLDrawPoolAvatar::sSkipOpaque = true;
-        renderRigged(avatarp, RIGGED_MATERIAL_ALPHA_MASK);
-        renderRigged(avatarp, RIGGED_NORMMAP_MASK);
-        renderRigged(avatarp, RIGGED_SPECMAP_MASK);
-		renderRigged(avatarp, RIGGED_NORMSPEC_MASK);    
-        renderRigged(avatarp, RIGGED_GLOW);
-        LLDrawPoolAvatar::sSkipOpaque = false;
-	}
-	else // rigged opaque (SHADOW_PASS_ATTACHMENT_OPAQUE
-	{
-        LLDrawPoolAvatar::sSkipTransparent = true;
-		renderRigged(avatarp, RIGGED_MATERIAL);
-        renderRigged(avatarp, RIGGED_SPECMAP);
-		renderRigged(avatarp, RIGGED_SPECMAP_EMISSIVE);
-		renderRigged(avatarp, RIGGED_NORMMAP);		
-		renderRigged(avatarp, RIGGED_NORMMAP_EMISSIVE);
-		renderRigged(avatarp, RIGGED_NORMSPEC);
-		renderRigged(avatarp, RIGGED_NORMSPEC_EMISSIVE);
-		renderRigged(avatarp, RIGGED_SIMPLE);
-		renderRigged(avatarp, RIGGED_FULLBRIGHT);
-		renderRigged(avatarp, RIGGED_SHINY);
-		renderRigged(avatarp, RIGGED_FULLBRIGHT_SHINY);
-		renderRigged(avatarp, RIGGED_GLOW);
-		renderRigged(avatarp, RIGGED_DEFERRED_BUMP);
-		renderRigged(avatarp, RIGGED_DEFERRED_SIMPLE);
-        LLDrawPoolAvatar::sSkipTransparent = false;
-	}
-}
-
-S32 LLDrawPoolAvatar::getNumPasses()
-{
-	if (LLPipeline::sImpostorRender)
-	{
-		return 8;
-	}
-	else 
-	{
-		return 10;
-	}
-}
-
-
-S32 LLDrawPoolAvatar::getNumDeferredPasses()
-{
-	if (LLPipeline::sImpostorRender)
-	{
-		return 19;
-	}
-	else
-	{
-		return 21;
-	}
-}
-
-
-void LLDrawPoolAvatar::render(S32 pass)
-{
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_CHARACTERS);
-	if (LLPipeline::sImpostorRender)
-	{
-		renderAvatars(nullptr, pass+2);
-		return;
-	}
-
-	renderAvatars(nullptr, pass); // render all avatars
-}
-
-void LLDrawPoolAvatar::beginRenderPass(S32 pass)
-{
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_CHARACTERS);
-	//reset vertex buffer mappings
-	LLVertexBuffer::unbind();
-
-	if (LLPipeline::sImpostorRender)
-	{ //impostor render does not have impostors or rigid rendering
-		pass += 2;
-	}
-
-	switch (pass)
-	{
-	case 0:
-		beginImpostor();
-		break;
-	case 1:
-		beginRigid();
-		break;
-	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;
-	}
-
-	if (pass == 0)
-	{ //make sure no stale colors are left over from a previous render
-		gGL.diffuseColor4f(1,1,1,1);
-	}
-}
-
-void LLDrawPoolAvatar::endRenderPass(S32 pass)
-{
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_CHARACTERS);
-
-	if (LLPipeline::sImpostorRender)
-	{
-		pass += 2;		
-	}
-
-	switch (pass)
-	{
-	case 0:
-		endImpostor();
-		break;
-	case 1:
-		endRigid();
-		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;
-	}
-}
-
-void LLDrawPoolAvatar::beginImpostor()
-{
-	if (!LLPipeline::sReflectionRender)
-	{
-		LLVOAvatar::sRenderDistance = llclamp(LLVOAvatar::sRenderDistance, 16.f, 256.f);
-		LLVOAvatar::sNumVisibleAvatars = 0;
-	}
-
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gImpostorProgram.bind();
-		gImpostorProgram.setMinimumAlpha(0.01f);
-	}
-
-	gPipeline.enableLightsFullbright(LLColor4(1,1,1,1));
-	sDiffuseChannel = 0;
-}
-
-void LLDrawPoolAvatar::endImpostor()
-{
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gImpostorProgram.unbind();
-	}
-	gPipeline.enableLightsDynamic();
-}
-
-void LLDrawPoolAvatar::beginRigid()
-{
-	if (gPipeline.canUseVertexShaders())
-	{
-		if (LLPipeline::sUnderWaterRender)
-		{
-			sVertexProgram = &gObjectAlphaMaskNoColorWaterProgram;
-		}
-		else
-		{
-			sVertexProgram = &gObjectAlphaMaskNoColorProgram;
-		}
-		
-		if (sVertexProgram != nullptr)
-		{	//eyeballs render with the specular shader
-			sVertexProgram->bind();
-			sVertexProgram->setMinimumAlpha(LLDrawPoolAvatar::sMinimumAlpha);
-		}
-	}
-	else
-	{
-		sVertexProgram = nullptr;
-	}
-}
-
-void LLDrawPoolAvatar::endRigid()
-{
-	sShaderLevel = mVertexShaderLevel;
-	if (sVertexProgram != nullptr)
-	{
-		sVertexProgram->unbind();
-	}
-}
-
-void LLDrawPoolAvatar::beginDeferredImpostor()
-{
-	if (!LLPipeline::sReflectionRender)
-	{
-		LLVOAvatar::sRenderDistance = llclamp(LLVOAvatar::sRenderDistance, 16.f, 256.f);
-		LLVOAvatar::sNumVisibleAvatars = 0;
-	}
-
-	sVertexProgram = &gDeferredImpostorProgram;
-	specular_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::SPECULAR_MAP);
-	normal_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::DEFERRED_NORMAL);
-	sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-	sVertexProgram->bind();
-	sVertexProgram->setMinimumAlpha(0.01f);
-}
-
-void LLDrawPoolAvatar::endDeferredImpostor()
-{
-	sShaderLevel = mVertexShaderLevel;
-	sVertexProgram->disableTexture(LLViewerShaderMgr::DEFERRED_NORMAL);
-	sVertexProgram->disableTexture(LLViewerShaderMgr::SPECULAR_MAP);
-	sVertexProgram->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-	gPipeline.unbindDeferredShader(*sVertexProgram);
-   sVertexProgram = nullptr;
-   sDiffuseChannel = 0;
-}
-
-void LLDrawPoolAvatar::beginDeferredRigid()
-{
-	sVertexProgram = &gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram;
-	sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-	sVertexProgram->bind();
-	sVertexProgram->setMinimumAlpha(LLDrawPoolAvatar::sMinimumAlpha);
-}
-
-void LLDrawPoolAvatar::endDeferredRigid()
-{
-	sShaderLevel = mVertexShaderLevel;
-	sVertexProgram->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-	sVertexProgram->unbind();
-	gGL.getTexUnit(0)->activate();
-}
-
-
-void LLDrawPoolAvatar::beginSkinned()
-{
-	if (sShaderLevel > 0)
-	{
-		if (LLPipeline::sUnderWaterRender)
-		{
-			sVertexProgram = &gAvatarWaterProgram;
-			sShaderLevel = llmin((U32) 1, sShaderLevel);
-		}
-		else
-		{
-			sVertexProgram = &gAvatarProgram;
-		}
-	}
-	else
-	{
-		if (LLPipeline::sUnderWaterRender)
-		{
-			sVertexProgram = &gObjectAlphaMaskNoColorWaterProgram;
-		}
-		else
-		{
-			sVertexProgram = &gObjectAlphaMaskNoColorProgram;
-		}
-	}
-	
-	if (sShaderLevel > 0)  // for hardware blending
-	{
-		sRenderingSkinned = TRUE;
-
-		sVertexProgram->bind();
-		sVertexProgram->enableTexture(LLViewerShaderMgr::BUMP_MAP);
-		gGL.getTexUnit(0)->activate();
-	}
-	else
-	{
-		if(gPipeline.canUseVertexShaders())
-		{
-			// software skinning, use a basic shader for windlight.
-			// TODO: find a better fallback method for software skinning.
-			sVertexProgram->bind();
-		}
-	}
-
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		sVertexProgram->setMinimumAlpha(LLDrawPoolAvatar::sMinimumAlpha);
-	}
-}
-
-void LLDrawPoolAvatar::endSkinned()
-{
-	// if we're in software-blending, remember to set the fence _after_ we draw so we wait till this rendering is done
-	if (sShaderLevel > 0)
-	{
-		sRenderingSkinned = FALSE;
-		sVertexProgram->disableTexture(LLViewerShaderMgr::BUMP_MAP);
-		gGL.getTexUnit(0)->activate();
-		sVertexProgram->unbind();
-		sShaderLevel = mVertexShaderLevel;
-	}
-	else
-	{
-		if(gPipeline.canUseVertexShaders())
-		{
-			// software skinning, use a basic shader for windlight.
-			// TODO: find a better fallback method for software skinning.
-			sVertexProgram->unbind();
-		}
-	}
-
-	gGL.getTexUnit(0)->activate();
-}
-
-void LLDrawPoolAvatar::beginRiggedSimple()
-{
-	if (sShaderLevel > 0)
-	{
-		if (LLPipeline::sUnderWaterRender)
-		{
-			sVertexProgram = &gSkinnedObjectSimpleWaterProgram;
-		}
-		else
-		{
-			sVertexProgram = &gSkinnedObjectSimpleProgram;
-		}
-	}
-	else
-	{
-		if (LLPipeline::sUnderWaterRender)
-		{
-			sVertexProgram = &gObjectSimpleNonIndexedWaterProgram;
-		}
-		else
-		{
-			sVertexProgram = &gObjectSimpleNonIndexedProgram;
-		}
-	}
-
-	if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
-	{
-		sDiffuseChannel = 0;
-		sVertexProgram->bind();
-	}
-}
-
-void LLDrawPoolAvatar::endRiggedSimple()
-{
-	LLVertexBuffer::unbind();
-	if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
-	{
-		sVertexProgram->unbind();
-		sVertexProgram = nullptr;
-	}
-}
-
-void LLDrawPoolAvatar::beginRiggedAlpha()
-{
-	beginRiggedSimple();
-}
-
-void LLDrawPoolAvatar::endRiggedAlpha()
-{
-	endRiggedSimple();
-}
-
-
-void LLDrawPoolAvatar::beginRiggedFullbrightAlpha()
-{
-	beginRiggedFullbright();
-}
-
-void LLDrawPoolAvatar::endRiggedFullbrightAlpha()
-{
-	endRiggedFullbright();
-}
-
-void LLDrawPoolAvatar::beginRiggedGlow()
-{
-	if (sShaderLevel > 0)
-	{
-		if (LLPipeline::sUnderWaterRender)
-		{
-			sVertexProgram = &gSkinnedObjectEmissiveWaterProgram;
-		}
-		else
-		{
-			sVertexProgram = &gSkinnedObjectEmissiveProgram;
-		}
-	}
-	else
-	{
-		if (LLPipeline::sUnderWaterRender)
-		{
-			sVertexProgram = &gObjectEmissiveNonIndexedWaterProgram;
-		}
-		else
-		{
-			sVertexProgram = &gObjectEmissiveNonIndexedProgram;
-		}
-	}
-
-	if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
-	{
-		sDiffuseChannel = 0;
-		sVertexProgram->bind();
-
-		sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, LLPipeline::sRenderDeferred ? 2.2f : 1.1f);
-	}
-}
-
-void LLDrawPoolAvatar::endRiggedGlow()
-{
-	endRiggedFullbright();
-}
-
-void LLDrawPoolAvatar::beginRiggedFullbright()
-{
-	if (sShaderLevel > 0)
-	{
-		if (LLPipeline::sUnderWaterRender)
-		{
-			sVertexProgram = &gSkinnedObjectFullbrightWaterProgram;
-		}
-		else
-		{
-			if (LLPipeline::sRenderDeferred)
-			{
-				sVertexProgram = &gDeferredSkinnedFullbrightProgram;
-			}
-			else
-			{
-				sVertexProgram = &gSkinnedObjectFullbrightProgram;
-			}
-		}
-	}
-	else
-	{
-		if (LLPipeline::sUnderWaterRender)
-		{
-			sVertexProgram = &gObjectFullbrightNonIndexedWaterProgram;
-		}
-		else
-		{
-			sVertexProgram = &gObjectFullbrightNonIndexedProgram;
-		}
-	}
-
-	if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
-	{
-		sDiffuseChannel = 0;
-		sVertexProgram->bind();
-
-		if (LLPipeline::sRenderingHUDs || !LLPipeline::sRenderDeferred)
-		{
-			sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f);
-		} 
-		else 
-		{
-			sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
-		}
-	}
-}
-
-void LLDrawPoolAvatar::endRiggedFullbright()
-{
-	LLVertexBuffer::unbind();
-	if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
-	{
-		sVertexProgram->unbind();
-		sVertexProgram = nullptr;
-	}
-}
-
-void LLDrawPoolAvatar::beginRiggedShinySimple()
-{
-	if (sShaderLevel > 0)
-	{
-		if (LLPipeline::sUnderWaterRender)
-		{
-			sVertexProgram = &gSkinnedObjectShinySimpleWaterProgram;
-		}
-		else
-		{
-			sVertexProgram = &gSkinnedObjectShinySimpleProgram;
-		}
-	}
-	else
-	{
-		if (LLPipeline::sUnderWaterRender)
-		{
-			sVertexProgram = &gObjectShinyNonIndexedWaterProgram;
-		}
-		else
-		{
-			sVertexProgram = &gObjectShinyNonIndexedProgram;
-		}
-	}
-
-	if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
-	{
-		sVertexProgram->bind();
-		LLDrawPoolBump::bindCubeMap(sVertexProgram, 2, sDiffuseChannel, cube_channel);
-	}
-}
-
-void LLDrawPoolAvatar::endRiggedShinySimple()
-{
-	LLVertexBuffer::unbind();
-	if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
-	{
-		LLDrawPoolBump::unbindCubeMap(sVertexProgram, 2, sDiffuseChannel, cube_channel);
-		sVertexProgram->unbind();
-		sVertexProgram = nullptr;
-	}
-}
-
-void LLDrawPoolAvatar::beginRiggedFullbrightShiny()
-{
-	if (sShaderLevel > 0)
-	{
-		if (LLPipeline::sUnderWaterRender)
-		{
-			sVertexProgram = &gSkinnedObjectFullbrightShinyWaterProgram;
-		}
-		else
-		{
-			if (LLPipeline::sRenderDeferred)
-			{
-				sVertexProgram = &gDeferredSkinnedFullbrightShinyProgram;
-			}
-			else
-			{
-				sVertexProgram = &gSkinnedObjectFullbrightShinyProgram;
-			}
-		}
-	}
-	else
-	{
-		if (LLPipeline::sUnderWaterRender)
-		{
-			sVertexProgram = &gObjectFullbrightShinyNonIndexedWaterProgram;
-		}
-		else
-		{
-			sVertexProgram = &gObjectFullbrightShinyNonIndexedProgram;
-		}
-	}
-
-	if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
-	{
-		sVertexProgram->bind();
-		LLDrawPoolBump::bindCubeMap(sVertexProgram, 2, sDiffuseChannel, cube_channel);
-
-		if (LLPipeline::sRenderingHUDs || !LLPipeline::sRenderDeferred)
-		{
-			sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f);
-		} 
-		else 
-		{
-			sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
-		}
-	}
-}
-
-void LLDrawPoolAvatar::endRiggedFullbrightShiny()
-{
-	LLVertexBuffer::unbind();
-	if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
-	{
-		LLDrawPoolBump::unbindCubeMap(sVertexProgram, 2, sDiffuseChannel, cube_channel);
-		sVertexProgram->unbind();
-		sVertexProgram = nullptr;
-	}
-}
-
-
-void LLDrawPoolAvatar::beginDeferredRiggedSimple()
-{
-	sVertexProgram = &gDeferredSkinnedDiffuseProgram;
-	sDiffuseChannel = 0;
-	sVertexProgram->bind();
-}
-
-void LLDrawPoolAvatar::endDeferredRiggedSimple()
-{
-	LLVertexBuffer::unbind();
-	sVertexProgram->unbind();
-	sVertexProgram = nullptr;
-}
-
-void LLDrawPoolAvatar::beginDeferredRiggedBump()
-{
-	sVertexProgram = &gDeferredSkinnedBumpProgram;
-	sVertexProgram->bind();
-	normal_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::BUMP_MAP);
-	sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-}
-
-void LLDrawPoolAvatar::endDeferredRiggedBump()
-{
-	LLVertexBuffer::unbind();
-	sVertexProgram->disableTexture(LLViewerShaderMgr::BUMP_MAP);
-	sVertexProgram->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-	sVertexProgram->unbind();
-	normal_channel = -1;
-	sDiffuseChannel = 0;
-	sVertexProgram = nullptr;
-}
-
-void LLDrawPoolAvatar::beginDeferredRiggedMaterial(S32 pass)
-{
-	if (pass == 1 ||
-		pass == 5 ||
-		pass == 9 ||
-		pass == 13)
-	{ //skip alpha passes
-		return;
-	}
-	sVertexProgram = &gDeferredMaterialProgram[pass+LLMaterial::SHADER_COUNT];
-
-	if (LLPipeline::sUnderWaterRender)
-	{
-		sVertexProgram = &(gDeferredMaterialWaterProgram[pass+LLMaterial::SHADER_COUNT]);
-	}
-
-	sVertexProgram->bind();
-	normal_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::BUMP_MAP);
-	specular_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::SPECULAR_MAP);
-	sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-}
-
-void LLDrawPoolAvatar::endDeferredRiggedMaterial(S32 pass)
-{
-	if (pass == 1 ||
-		pass == 5 ||
-		pass == 9 ||
-		pass == 13)
-	{
-		return;
-	}
-
-	LLVertexBuffer::unbind();
-	sVertexProgram->disableTexture(LLViewerShaderMgr::BUMP_MAP);
-	sVertexProgram->disableTexture(LLViewerShaderMgr::SPECULAR_MAP);
-	sVertexProgram->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-	sVertexProgram->unbind();
-	normal_channel = -1;
-	sDiffuseChannel = 0;
-	sVertexProgram = nullptr;
-}
-
-void LLDrawPoolAvatar::beginDeferredSkinned()
-{
-	sShaderLevel = mVertexShaderLevel;
-	sVertexProgram = &gDeferredAvatarProgram;
-	sRenderingSkinned = TRUE;
-
-	sVertexProgram->bind();
-	sVertexProgram->setMinimumAlpha(LLDrawPoolAvatar::sMinimumAlpha);
-	
-	sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-	gGL.getTexUnit(0)->activate();
-}
-
-void LLDrawPoolAvatar::endDeferredSkinned()
-{
-	// if we're in software-blending, remember to set the fence _after_ we draw so we wait till this rendering is done
-	sRenderingSkinned = FALSE;
-	sVertexProgram->unbind();
-
-	sVertexProgram->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-
-	sShaderLevel = mVertexShaderLevel;
-
-	gGL.getTexUnit(0)->activate();
-}
-
-static LLTrace::BlockTimerStatHandle FTM_RENDER_AVATARS("renderAvatars");
-
-
-void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass)
-{
-	LL_RECORD_BLOCK_TIME(FTM_RENDER_AVATARS);
-
-	if (pass == -1)
-	{
-		for (S32 i = 1; i < getNumPasses(); i++)
-		{ //skip foot shadows
-			prerender();
-			beginRenderPass(i);
-			renderAvatars(single_avatar, i);
-			endRenderPass(i);
-		}
-
-		return;
-	}
-
-	if (mDrawFace.empty() && !single_avatar)
-	{
-		return;
-	}
-
-	LLVOAvatar *avatarp;
-
-	if (single_avatar)
-	{
-		avatarp = single_avatar;
-	}
-	else
-	{
-		const LLFace *facep = mDrawFace[0];
-		if (!facep->getDrawable())
-		{
-			return;
-		}
-		avatarp = (LLVOAvatar *)facep->getDrawable()->getVObj().get();
-	}
-
-    if (avatarp->isDead() || avatarp->mDrawable.isNull())
-	{
-		return;
-	}
-
-	if (!single_avatar && !avatarp->isFullyLoaded() )
-	{
-		if (pass==0 && (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES) || LLViewerPartSim::getMaxPartCount() <= 0))
-		{
-			// debug code to draw a sphere in place of avatar
-			gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep);
-			gGL.setColorMask(true, true);
-			LLVector3 pos = avatarp->getPositionAgent();
-			gGL.color4f(1.0f, 1.0f, 1.0f, 0.7f);
-			
-			gGL.pushMatrix();	 
-			gGL.translatef((F32)(pos.mV[VX]),	 
-						   (F32)(pos.mV[VY]),	 
-							(F32)(pos.mV[VZ]));	 
-			 gGL.scalef(0.15f, 0.15f, 0.3f);
-
-			 gSphere.renderGGL();
-				 
-			 gGL.popMatrix();
-			 gGL.setColorMask(true, false);
-		}
-		// don't render please
-		return;
-	}
-
-	BOOL impostor = avatarp->isImpostor() && !single_avatar;
-
-	if (impostor && pass != 0)
-	{ //don't draw anything but the impostor for impostored avatars
-		return;
-	}
-	
-	if (pass == 0 && !impostor && LLPipeline::sUnderWaterRender)
-	{ //don't draw foot shadows under water
-		return;
-	}
-
-	if (pass == 0)
-	{
-		if (!LLPipeline::sReflectionRender)
-		{
-			LLVOAvatar::sNumVisibleAvatars++;
-		}
-
-		if (impostor)
-		{
-			if (LLPipeline::sRenderDeferred && !LLPipeline::sReflectionRender && avatarp->mImpostor.isComplete()) 
-			{
-				if (normal_channel > -1)
-				{
-					avatarp->mImpostor.bindTexture(2, normal_channel);
-				}
-				if (specular_channel > -1)
-				{
-					avatarp->mImpostor.bindTexture(1, specular_channel);
-				}
-			}
-			avatarp->renderImpostor(avatarp->getMutedAVColor(), sDiffuseChannel);
-		}
-		return;
-	}
-
-	if (pass == 1)
-	{
-		// render rigid meshes (eyeballs) first
-		avatarp->renderRigid();
-		return;
-	}
-
-	if (pass == 3)
-	{
-		if (is_deferred_render)
-		{
-			renderDeferredRiggedSimple(avatarp);
-		}
-		else
-		{
-			renderRiggedSimple(avatarp);
-
-			if (LLPipeline::sRenderDeferred)
-			{ //render "simple" materials
-				renderRigged(avatarp, RIGGED_MATERIAL);
-				renderRigged(avatarp, RIGGED_MATERIAL_ALPHA_MASK);
-				renderRigged(avatarp, RIGGED_MATERIAL_ALPHA_EMISSIVE);
-				renderRigged(avatarp, RIGGED_NORMMAP);
-				renderRigged(avatarp, RIGGED_NORMMAP_MASK);
-				renderRigged(avatarp, RIGGED_NORMMAP_EMISSIVE);	
-				renderRigged(avatarp, RIGGED_SPECMAP);
-				renderRigged(avatarp, RIGGED_SPECMAP_MASK);
-				renderRigged(avatarp, RIGGED_SPECMAP_EMISSIVE);
-				renderRigged(avatarp, RIGGED_NORMSPEC);
-				renderRigged(avatarp, RIGGED_NORMSPEC_MASK);
-				renderRigged(avatarp, RIGGED_NORMSPEC_EMISSIVE);
-			}
-		}
-		return;
-	}
-
-	if (pass == 4)
-	{
-		if (is_deferred_render)
-		{
-			renderDeferredRiggedBump(avatarp);
-		}
-		else
-		{
-			renderRiggedFullbright(avatarp);
-		}
-
-		return;
-	}
-
-	if (is_deferred_render && pass >= 5 && pass <= 21)
-	{
-		S32 p = pass-5;
-
-		if (p != 1 &&
-			p != 5 &&
-			p != 9 &&
-			p != 13)
-		{
-			renderDeferredRiggedMaterial(avatarp, p);
-		}
-		return;
-	}
-
-
-
-
-	if (pass == 5)
-	{
-		renderRiggedShinySimple(avatarp);
-				
-		return;
-	}
-
-	if (pass == 6)
-	{
-		renderRiggedFullbrightShiny(avatarp);
-		return;
-	}
-
-	if (pass >= 7 && pass < 13)
-	{
-		if (pass == 7)
-		{
-			renderRiggedAlpha(avatarp);
-
-			if (LLPipeline::sRenderDeferred && !is_post_deferred_render)
-			{ //render transparent materials under water
-				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);
-
-				renderRigged(avatarp, RIGGED_MATERIAL_ALPHA);
-				renderRigged(avatarp, RIGGED_SPECMAP_BLEND);
-				renderRigged(avatarp, RIGGED_NORMMAP_BLEND);
-				renderRigged(avatarp, RIGGED_NORMSPEC_BLEND);
-				gGL.setSceneBlendType(LLRender::BT_ALPHA); // <alchemy/>
-				gGL.setColorMask(true, false);
-			}
-			return;
-		}
-
-		if (pass == 8)
-		{
-			renderRiggedFullbrightAlpha(avatarp);
-			return;
-		}
-
-		if (LLPipeline::sRenderDeferred && is_post_deferred_render)
-		{
-			S32 p = 0;
-			switch (pass)
-			{
-			case 9: p = 1; break;
-			case 10: p = 5; break;
-			case 11: p = 9; break;
-			case 12: p = 13; break;
-			}
-
-			{
-				LLGLEnable blend(GL_BLEND);
-				renderDeferredRiggedMaterial(avatarp, p);
-			}
-			return;
-		}
-		else if (pass == 9)
-		{
-			renderRiggedGlow(avatarp);
-			return;
-		}
-	}
-
-	if (pass == 13)
-	{
-		renderRiggedGlow(avatarp);
-		
-		return;
-	}
-	
-	if ((sShaderLevel >= SHADER_LEVEL_CLOTH))
-	{
-		LLMatrix4 rot_mat;
-		LLViewerCamera::getInstance()->getMatrixToLocal(rot_mat);
-		static const LLMatrix4 cfr(OGL_TO_CFR_ROTATION);
-		rot_mat *= cfr;
-		
-		LLVector4 wind;
-		wind.setVec(avatarp->mWindVec);
-		wind.mV[VW] = 0;
-		wind = wind * rot_mat;
-		wind.mV[VW] = avatarp->mWindVec.mV[VW];
-
-		sVertexProgram->uniform4fv(LLViewerShaderMgr::AVATAR_WIND, 1, wind.mV);
-		F32 phase = -1.f * (avatarp->mRipplePhase);
-
-		F32 freq = 7.f + (noise1(avatarp->mRipplePhase) * 2.f);
-		LLVector4 sin_params(freq, freq, freq, phase);
-		sVertexProgram->uniform4fv(LLViewerShaderMgr::AVATAR_SINWAVE, 1, sin_params.mV);
-
-		LLVector4 gravity(0.f, 0.f, -CLOTHING_GRAVITY_EFFECT, 0.f);
-		gravity = gravity * rot_mat;
-		sVertexProgram->uniform4fv(LLViewerShaderMgr::AVATAR_GRAVITY, 1, gravity.mV);
-	}
-
-	if( !single_avatar || (avatarp == single_avatar) )
-	{
-		avatarp->renderSkinned();
-	}
-}
-
-void LLDrawPoolAvatar::getRiggedGeometry(
-    LLFace* face,
-    LLPointer<LLVertexBuffer>& buffer,
-    U32 data_mask,
-    const LLMeshSkinInfo* skin,
-    LLVolume* volume,
-    const LLVolumeFace& vol_face)
-{
-	face->setGeomIndex(0);
-	face->setIndicesIndex(0);
-		
-	//rigged faces do not batch textures
-	face->setTextureIndex(255);
-
-	if (buffer.isNull() || buffer->getTypeMask() != data_mask || !buffer->isWriteable())
-	{
-        // make a new buffer
-		if (sShaderLevel > 0)
-		{
-			buffer = new LLVertexBuffer(data_mask, GL_DYNAMIC_DRAW_ARB);
-		}
-		else
-		{
-			buffer = new LLVertexBuffer(data_mask, GL_STREAM_DRAW_ARB);
-		}
-
-		if (!buffer->allocateBuffer(vol_face.mNumVertices, vol_face.mNumIndices, true))
-		{
-			LL_WARNS("LLDrawPoolAvatar") << "Failed to allocate Vertex Buffer to "
-				<< vol_face.mNumVertices << " vertices and "
-				<< vol_face.mNumIndices << " indices" << LL_ENDL;
-			// allocate dummy triangle
-			buffer->allocateBuffer(1, 3, true);
-			memset((U8*)buffer->getMappedData(), 0, buffer->getSize());
-			memset((U8*)buffer->getMappedIndices(), 0, buffer->getIndicesSize());
-		}
-	}
-	else
-	{
-        //resize existing buffer
-		if(!buffer->resizeBuffer(vol_face.mNumVertices, vol_face.mNumIndices))
-		{
-			LL_WARNS("LLDrawPoolAvatar") << "Failed to resize Vertex Buffer to "
-				<< vol_face.mNumVertices << " vertices and "
-				<< vol_face.mNumIndices << " indices" << LL_ENDL;
-			// allocate dummy triangle
-			buffer->resizeBuffer(1, 3);
-			memset((U8*)buffer->getMappedData(), 0, buffer->getSize());
-			memset((U8*)buffer->getMappedIndices(), 0, buffer->getIndicesSize());
-		}
-	}
-
-	face->setSize(buffer->getNumVerts(), buffer->getNumIndices());
-	face->setVertexBuffer(buffer);
-
-	U16 offset = 0;
-		
-	LLMatrix4a mat_vert_inv = skin->mBindShapeMatrix;
-	mat_vert_inv.invert();
-	mat_vert_inv.transpose();
-
-	const F32* m = mat_vert_inv.getF32ptr();
-	F32 mat3[] = 
-        { m[0], m[1], m[2],
-          m[4], m[5], m[6],
-          m[8], m[9], m[10] };
-
-	LLMatrix3 mat_normal(mat3);				
-
-	//let getGeometryVolume know if alpha should override shiny
-	U32 type = gPipeline.getPoolTypeFromTE(face->getTextureEntry(), face->getTexture());
-
-	if (type == LLDrawPool::POOL_ALPHA)
-	{
-		face->setPoolType(LLDrawPool::POOL_ALPHA);
-	}
-	else
-	{
-		face->setPoolType(LLDrawPool::POOL_AVATAR);
-	}
-
-	//LL_INFOS() << "Rebuilt face " << face->getTEOffset() << " of " << face->getDrawable() << " at " << gFrameTimeSeconds << LL_ENDL;
-
-	// Let getGeometryVolume know if a texture matrix is in play
-	if (face->mTextureMatrix)
-	{
-		face->setState(LLFace::TEXTURE_ANIM);
-	}
-	else
-	{
-		face->clearState(LLFace::TEXTURE_ANIM);
-	}
-	LLMatrix4 mat_vert(skin->mBindShapeMatrix.getF32ptr());
-	face->getGeometryVolume(*volume, face->getTEOffset(), mat_vert, mat_normal, offset, true);
-
-	buffer->flush();
-}
-
-void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(
-    LLVOAvatar* avatar,
-    LLFace* face,
-    const LLMeshSkinInfo* skin,
-    LLVolume* volume,
-    const LLVolumeFace& vol_face)
-{
-	LLVector4a* weights = vol_face.mWeights;
-	if (!weights)
-	{
-		return;
-	}
-    // FIXME ugly const cast
-    LLSkinningUtil::scrubInvalidJoints(avatar, const_cast<LLMeshSkinInfo*>(skin));
-
-	LLPointer<LLVertexBuffer> buffer = face->getVertexBuffer();
-	LLDrawable* drawable = face->getDrawable();
-
-	if (drawable->getVOVolume() && drawable->getVOVolume()->isNoLOD())
-	{
-		return;
-	}
-
-	U32 data_mask = face->getRiggedVertexBufferDataMask();
-
-    if (!vol_face.mWeightsScrubbed)
-    {
-        LLSkinningUtil::scrubSkinWeights(weights, vol_face.mNumVertices, skin);
-        vol_face.mWeightsScrubbed = TRUE;
-    }
-	
-	if (buffer.isNull() || 
-		buffer->getTypeMask() != data_mask ||
-		buffer->getNumVerts() != vol_face.mNumVertices ||
-		buffer->getNumIndices() != vol_face.mNumIndices ||
-		(drawable && drawable->isState(LLDrawable::REBUILD_ALL)))
-	{
-		if (drawable && drawable->isState(LLDrawable::REBUILD_ALL))
-		{ //rebuild EVERY face in the drawable, not just this one, to avoid missing drawable wide rebuild issues
-			for (S32 i = 0; i < drawable->getNumFaces(); ++i)
-			{
-				LLFace* facep = drawable->getFace(i);
-				U32 face_data_mask = facep->getRiggedVertexBufferDataMask();
-				if (face_data_mask)
-				{
-					LLPointer<LLVertexBuffer> cur_buffer = facep->getVertexBuffer();
-					const LLVolumeFace& cur_vol_face = volume->getVolumeFace(i);
-					getRiggedGeometry(facep, cur_buffer, face_data_mask, skin, volume, cur_vol_face);
-				}
-			}
-			drawable->clearState(LLDrawable::REBUILD_ALL);
-
-			buffer = face->getVertexBuffer();
-		}
-		else
-		{ //just rebuild this face
-			getRiggedGeometry(face, buffer, data_mask, skin, volume, vol_face);
-		}
-	}
-
-	if (buffer.isNull() ||
-		buffer->getNumVerts() != vol_face.mNumVertices ||
-		buffer->getNumIndices() != vol_face.mNumIndices)
-	{
-		// Allocation failed
-		return;
-	}
-
-	if (!buffer.isNull() && 
-		sShaderLevel <= 0 && 
-		face->mLastSkinTime < avatar->getLastSkinTime())
-	{
-		//perform software vertex skinning for this face
-		LLStrider<LLVector3> position;
-		LLStrider<LLVector3> normal;
-
-		bool has_normal = buffer->hasDataType(LLVertexBuffer::TYPE_NORMAL);
-		buffer->getVertexStrider(position);
-
-		if (has_normal)
-		{
-			buffer->getNormalStrider(normal);
-		}
-
-		LLVector4a* pos = (LLVector4a*) position.get();
-
-		LLVector4a* norm = has_normal ? (LLVector4a*) normal.get() : NULL;
-		
-		//build matrix palette
-		LLMatrix4a mat[LL_MAX_JOINTS_PER_MESH_OBJECT];
-        U32 count = LLSkinningUtil::getMeshJointCount(skin);
-        LLSkinningUtil::initSkinningMatrixPalette(mat, count, skin, avatar);
-        LLSkinningUtil::checkSkinWeights(weights, buffer->getNumVerts(), skin);
-
-        const U32 max_joints = LLSkinningUtil::getMaxJointCount();
-		for (S32 j = 0; j < buffer->getNumVerts(); ++j)
-		{
-			LLMatrix4a final_mat;
-            LLSkinningUtil::getPerVertexSkinMatrix(weights[j], mat, false, final_mat, max_joints);
-			
-			const LLVector4a& v = vol_face.mPositions[j];
-
-			LLVector4a dst;
-			skin->mBindShapeMatrix.affineTransform(v, dst);
-			final_mat.affineTransform(dst, dst);
-			pos[j] = dst;
-
-			if (norm)
-			{
-				const LLVector4a& n = vol_face.mNormals[j];
-				skin->mBindShapeMatrix.rotate(n, dst);
-				final_mat.rotate(dst, dst);
-				dst.normalize3fast();
-				norm[j] = dst;
-			}
-		}
-	}
-}
-
-void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow)
-{
-	if (!avatar->shouldRenderRigged())
-	{
-		return;
-	}
-
-	stop_glerror();
-
-	for (LLFace* face : mRiggedFace[type])
-	{
-        S32 offset = face->getIndicesStart();
-		U32 count = face->getIndicesCount();
-
-        U16 start = face->getGeomStart();
-		U16 end = start + face->getGeomCount()-1;			
-
-		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 || !volume->isMeshAssetLoaded())
-		{
-			continue;
-		}
-
-		const LLMeshSkinInfo* skin = vobj->getSkinInfo();
-		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();
-
-        const LLTextureEntry* tex_entry = face->getTextureEntry();
-		LLMaterial* mat = tex_entry ? tex_entry->getMaterialParams().get() : nullptr;
-
-        if (LLDrawPoolAvatar::sShadowPass >= 0)
-        {
-            bool is_alpha_blend = false;
-            bool is_alpha_mask  = false;
-
-            LLViewerTexture* tex = face->getTexture(LLRender::DIFFUSE_MAP);
-            if (tex)
-            {
-                if (tex->getIsAlphaMask(-1.f, -1.f))
-                {
-                    is_alpha_mask = true;
-                }
-            }
-
-            if (tex)
-            {
-                LLGLenum image_format = tex->getPrimaryFormat();
-                if (!is_alpha_mask && (image_format == GL_RGBA || image_format == GL_ALPHA))
-                {
-                    is_alpha_blend = true;
-                }
-            }
-
-            if (tex_entry)
-            {
-                if (tex_entry->getAlpha() <= 0.99f)
-                {
-                    is_alpha_blend = true;
-                }
-            }
-
-            if (mat)
-            {                
-                switch (LLMaterial::eDiffuseAlphaMode(mat->getDiffuseAlphaMode()))
-                {
-                    case LLMaterial::DIFFUSE_ALPHA_MODE_MASK:
-                    {
-                        is_alpha_mask  = true;
-                        is_alpha_blend = false;
-                    }
-                    break;
-
-                    case LLMaterial::DIFFUSE_ALPHA_MODE_BLEND:
-                    {
-                        is_alpha_blend = true;
-                        is_alpha_mask  = false;
-                    }
-                    break;
-
-                    case LLMaterial::DIFFUSE_ALPHA_MODE_EMISSIVE:
-                    case LLMaterial::DIFFUSE_ALPHA_MODE_DEFAULT:
-                    case LLMaterial::DIFFUSE_ALPHA_MODE_NONE:
-                    default:
-                        is_alpha_blend = false;
-                        is_alpha_mask  = false;
-                        break;
-                }
-            }
-
-            // if this is alpha mask content and we're doing opaques or a non-alpha-mask shadow pass...
-            if (is_alpha_mask && (LLDrawPoolAvatar::sSkipTransparent || LLDrawPoolAvatar::sShadowPass != SHADOW_PASS_ATTACHMENT_ALPHA_MASK))
-            {
-                return;
-            }
-
-            // if this is alpha blend content and we're doing opaques or a non-alpha-blend shadow pass...
-            if (is_alpha_blend && (LLDrawPoolAvatar::sSkipTransparent || LLDrawPoolAvatar::sShadowPass != SHADOW_PASS_ATTACHMENT_ALPHA_BLEND))
-            {
-                return;
-            }
-
-            // if this is opaque content and we're skipping opaques...
-            if (!is_alpha_mask && !is_alpha_blend && LLDrawPoolAvatar::sSkipOpaque)
-            {
-                return;
-            }
-        }
-
-		if (buff)
-		{        
-			if (sShaderLevel > 0)
-			{
-				auto& mesh_cache = avatar->getRiggedMatrixCache();
-				const auto& mesh_id = skin->mMeshID;
-				const auto& rigged_matrix_data_iter = mesh_cache.find(mesh_id);
-				if (rigged_matrix_data_iter != mesh_cache.cend() && (!avatar->isSelf() || !avatar->isEditingAppearance()))
-				{
-					LLDrawPoolAvatar::sVertexProgram->uniformMatrix3x4fv(LLViewerShaderMgr::AVATAR_MATRIX,
-						rigged_matrix_data_iter->second.first,
-						FALSE,
-						(GLfloat*)rigged_matrix_data_iter->second.second.data());
-
-					stop_glerror();
-				}
-				else
-				{
-					// upload matrix palette to shader
-					LLMatrix4a mat[LL_MAX_JOINTS_PER_MESH_OBJECT];
-					U32 count = LLSkinningUtil::getMeshJointCount(skin);
-					LLSkinningUtil::initSkinningMatrixPalette(mat, count, skin, avatar);
-
-					stop_glerror();
-
-					std::vector<F32> mp;
-					mp.reserve(count * 12);
-
-					for (U32 i = 0; i < count; ++i)
-					{
-						F32* m = (F32*) mat[i].getF32ptr();
-
-						U32 idx = i * 12;
-
-						mp[idx + 0] = m[0];
-						mp[idx + 1] = m[1];
-						mp[idx + 2] = m[2];
-						mp[idx + 3] = m[12];
-
-						mp[idx + 4] = m[4];
-						mp[idx + 5] = m[5];
-						mp[idx + 6] = m[6];
-						mp[idx + 7] = m[13];
-
-						mp[idx + 8] = m[8];
-						mp[idx + 9] = m[9];
-						mp[idx + 10] = m[10];
-						mp[idx + 11] = m[14];
-					}
-					LLDrawPoolAvatar::sVertexProgram->uniformMatrix3x4fv(LLViewerShaderMgr::AVATAR_MATRIX,
-						count,
-						FALSE,
-						(GLfloat*) mp.data());
-					mesh_cache.emplace(mesh_id, std::make_pair(count, std::move(mp)));
-					stop_glerror();
-				}
-			}
-			else
-			{
-				data_mask &= ~LLVertexBuffer::MAP_WEIGHT4;
-			}
-
-			/*if (glow)
-			{
-				gGL.diffuseColor4f(0,0,0,face->getTextureEntry()->getGlow());
-			}*/
-
-			if (mat)
-			{
-				//order is important here LLRender::DIFFUSE_MAP should be last, because it changes 
-				//(gGL).mCurrTextureUnitIndex
-                LLViewerTexture* specular = nullptr;
-                if (LLPipeline::sImpostorRender && avatar->isVisuallyMuted())
-                {
-                    specular = LLViewerTextureManager::findFetchedTexture(gBlackSquareID, TEX_LIST_STANDARD);
-                }
-                else
-                {
-                    specular = face->getViewerObject()->getTESpecularMap(face->getTEOffset());
-                }
-                
-				gGL.getTexUnit(specular_channel)->bind(specular);
-				gGL.getTexUnit(normal_channel)->bind(face->getViewerObject()->getTENormalMap(face->getTEOffset()));
-				gGL.getTexUnit(sDiffuseChannel)->bind(face->getTexture(), false, true);
-
-				static const LLColor4 alpha[4] =
-				{
-					{0.00f,0.00f,0.00f,0.00f},
-					{0.25f,0.25f,0.25f,0.25f},
-					{0.50f,0.50f,0.50f,0.50f},
-					{0.75f,0.75f,0.75f,0.75f},
-				};
-
-				LLColor4 specColor = alpha[tex_entry->getShiny() & TEM_SHINY_MASK];
-				F32 env = specColor.mV[0];
-
-				if (!mat->getSpecularID().isNull())
-				{
-					const auto& spec_light_col = mat->getSpecularLightColor();
-					specColor.mV[0] = spec_light_col.mV[0];
-					specColor.mV[1] = spec_light_col.mV[1];
-					specColor.mV[2] = spec_light_col.mV[2];
-					specColor.mV[3] = mat->getSpecularLightExponent();
-					env = mat->getEnvironmentIntensity();
-				}
-
-				BOOL fullbright = tex_entry->getFullbright();
-
-				sVertexProgram->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, fullbright ? 1.f : 0.f);
-				sVertexProgram->uniform4fv(LLShaderMgr::SPECULAR_COLOR, 1, specColor.mV);
-				sVertexProgram->uniform1f(LLShaderMgr::ENVIRONMENT_INTENSITY, env);
-
-				if (mat->getDiffuseAlphaMode() == LLMaterial::DIFFUSE_ALPHA_MODE_MASK)
-				{
-					sVertexProgram->setMinimumAlpha(mat->getAlphaMaskCutoff());
-				}
-				else
-				{
-					sVertexProgram->setMinimumAlpha(0.f);
-				}
-
-				for (U32 i = 0; i < LLRender::NUM_TEXTURE_CHANNELS; ++i)
-				{
-					LLViewerTexture* tex = face->getTexture(i);
-					if (tex)
-					{
-						tex->addTextureStats(avatar->getPixelArea());
-					}
-				}
-			}
-			else
-			{
-				gGL.getTexUnit(sDiffuseChannel)->bind(face->getTexture());
-				sVertexProgram->setMinimumAlpha(0.f);
-				if (normal_channel > -1)
-				{
-					LLDrawPoolBump::bindBumpMap(face, normal_channel);
-				}
-			}
-
-			if (face->mTextureMatrix && vobj->mTexAnimMode)
-			{
-				gGL.matrixMode(LLRender::MM_TEXTURE);
-				gGL.loadMatrix((F32*) face->mTextureMatrix->mMatrix);
-				buff->setBuffer(data_mask);
-				buff->drawRange(LLRender::TRIANGLES, start, end, count, offset);
-				gGL.loadIdentity();
-				gGL.matrixMode(LLRender::MM_MODELVIEW);
-			}
-			else
-			{
-				buff->setBuffer(data_mask);
-				buff->drawRange(LLRender::TRIANGLES, start, end, count, offset);		
-			}
-
-			gPipeline.addTrianglesDrawn(count, LLRender::TRIANGLES);
-		}
-	}
-}
-
-void LLDrawPoolAvatar::renderDeferredRiggedSimple(LLVOAvatar* avatar)
-{
-	renderRigged(avatar, RIGGED_DEFERRED_SIMPLE);
-}
-
-void LLDrawPoolAvatar::renderDeferredRiggedBump(LLVOAvatar* avatar)
-{
-	renderRigged(avatar, RIGGED_DEFERRED_BUMP);
-}
-
-void LLDrawPoolAvatar::renderDeferredRiggedMaterial(LLVOAvatar* avatar, S32 pass)
-{
-	renderRigged(avatar, pass);
-}
-
-static LLTrace::BlockTimerStatHandle FTM_RIGGED_VBO("Rigged VBO");
-
-void LLDrawPoolAvatar::updateRiggedVertexBuffers(LLVOAvatar* avatar)
-{
-	LL_RECORD_BLOCK_TIME(FTM_RIGGED_VBO);
-
-	//update rigged vertex buffers
-	for (auto& type : mRiggedFace)
-    {
-		for (LLFace* face : type)
-		{
-			LLDrawable* drawable = face->getDrawable();
-			if (!drawable)
-			{
-				continue;
-			}
-
-			LLVOVolume* vobj = drawable->getVOVolume();
-
-			if (!vobj || vobj->isNoLOD())
-			{
-				continue;
-			}
-
-			LLVolume* volume = vobj->getVolume();
-			S32 te = face->getTEOffset();
-
-			if (!volume || volume->getNumVolumeFaces() <= te)
-			{
-				continue;
-			}
-
-			const LLMeshSkinInfo* skin = vobj->getSkinInfo();
-			if (!skin)
-			{
-				continue;
-			}
-
-			stop_glerror();
-
-			const LLVolumeFace& vol_face = volume->getVolumeFace(te);
-			updateRiggedFaceVertexBuffer(avatar, face, skin, volume, vol_face);
-		}
-	}
-}
-
-void LLDrawPoolAvatar::renderRiggedSimple(LLVOAvatar* avatar)
-{
-	renderRigged(avatar, RIGGED_SIMPLE);
-}
-
-void LLDrawPoolAvatar::renderRiggedFullbright(LLVOAvatar* avatar)
-{
-	renderRigged(avatar, RIGGED_FULLBRIGHT);
-}
-
-	
-void LLDrawPoolAvatar::renderRiggedShinySimple(LLVOAvatar* avatar)
-{
-	renderRigged(avatar, RIGGED_SHINY);
-}
-
-void LLDrawPoolAvatar::renderRiggedFullbrightShiny(LLVOAvatar* avatar)
-{
-	renderRigged(avatar, RIGGED_FULLBRIGHT_SHINY);
-}
-
-void LLDrawPoolAvatar::renderRiggedAlpha(LLVOAvatar* avatar)
-{
-	if (!mRiggedFace[RIGGED_ALPHA].empty())
-	{
-		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);
-
-		renderRigged(avatar, RIGGED_ALPHA);
-		gGL.setSceneBlendType(LLRender::BT_ALPHA); // <alchemy/>
-		gGL.setColorMask(true, false);
-	}
-}
-
-void LLDrawPoolAvatar::renderRiggedFullbrightAlpha(LLVOAvatar* avatar)
-{
-	if (!mRiggedFace[RIGGED_FULLBRIGHT_ALPHA].empty())
-	{
-		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);
-
-		renderRigged(avatar, RIGGED_FULLBRIGHT_ALPHA);
-		gGL.setSceneBlendType(LLRender::BT_ALPHA); // <alchemy/>
-		gGL.setColorMask(true, false);
-	}
-}
-
-void LLDrawPoolAvatar::renderRiggedGlow(LLVOAvatar* avatar)
-{
-	if (!mRiggedFace[RIGGED_GLOW].empty())
-	{
-		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);
-
-		renderRigged(avatar, RIGGED_GLOW, true);
-
-		gGL.setColorMask(true, false);
-		gGL.setSceneBlendType(LLRender::BT_ALPHA);
-	}
-}
-
-
-
-//-----------------------------------------------------------------------------
-// getDebugTexture()
-//-----------------------------------------------------------------------------
-LLViewerTexture *LLDrawPoolAvatar::getDebugTexture()
-{
-	if (mReferences.empty())
-	{
-		return nullptr;
-	}
-	LLFace *face = mReferences[0];
-	if (!face->getDrawable())
-	{
-		return nullptr;
-	}
-	const LLViewerObject *objectp = face->getDrawable()->getVObj();
-
-	// Avatar should always have at least 1 (maybe 3?) TE's.
-	return objectp->getTEImage(0);
-}
-
-
-LLColor3 LLDrawPoolAvatar::getDebugColor() const
-{
-	return LLColor3(0.f, 1.f, 0.f);
-}
-
-void LLDrawPoolAvatar::addRiggedFace(LLFace* facep, U32 type)
-{
-    llassert (facep->isState(LLFace::RIGGED));
-    llassert(getType() == LLDrawPool::POOL_AVATAR);
-    if (facep->getPool() && facep->getPool() != this)
-    {
-        LL_ERRS() << "adding rigged face that's already in another pool" << LL_ENDL;
-    }
-	if (type >= NUM_RIGGED_PASSES)
-	{
-		LL_ERRS() << "Invalid rigged face type." << LL_ENDL;
-	}
-	if (facep->getRiggedIndex(type) != -1)
-	{
-		LL_ERRS() << "Tried to add a rigged face that's referenced elsewhere." << LL_ENDL;
-	}	
-	
-	facep->setRiggedIndex(type, mRiggedFace[type].size());
-	facep->setPool(this);
-	mRiggedFace[type].push_back(facep);
-
-	facep->mShinyInAlpha = type == RIGGED_DEFERRED_SIMPLE || type == RIGGED_DEFERRED_BUMP || type == RIGGED_FULLBRIGHT_SHINY || type == RIGGED_SHINY;
-}
-
-void LLDrawPoolAvatar::removeRiggedFace(LLFace* facep)
-{
-    llassert (facep->isState(LLFace::RIGGED));
-    llassert(getType() == LLDrawPool::POOL_AVATAR);
-    if (facep->getPool() != this)
-    {
-        LL_ERRS() << "Tried to remove a rigged face from the wrong pool" << LL_ENDL;
-    }
-	facep->setPool(nullptr);
-
-	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
-			{
-				LL_ERRS() << "Face reference data corrupt for rigged type " << i
-					<< ((mRiggedFace[i].size() <= index) ? "; wrong index (out of bounds)" : (mRiggedFace[i][index] != facep) ? "; wrong face pointer" : "")
-					<< LL_ENDL;
-			}
-		}
-	}
-}
-
-LLVertexBufferAvatar::LLVertexBufferAvatar()
-: LLVertexBuffer(sDataMask, 
-	GL_STREAM_DRAW_ARB) //avatars are always stream draw due to morph targets
-{
-
-}
-
-
+/** 
+ * @file lldrawpoolavatar.cpp
+ * @brief LLDrawPoolAvatar 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 "lldrawpoolavatar.h"
+#include "llskinningutil.h"
+#include "llrender.h"
+
+#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"
+#include "llviewercontrol.h" // for gSavedSettings
+#include "llviewertexturelist.h"
+
+#include <glm/mat3x3.hpp>
+#include <glm/mat4x4.hpp>
+#include <glm/gtc/matrix_inverse.hpp>
+#include <glm/gtc/type_ptr.hpp>
+
+static U32 sDataMask = LLDrawPoolAvatar::VERTEX_DATA_MASK;
+static U32 sBufferUsage = GL_STREAM_DRAW_ARB;
+static U32 sShaderLevel = 0;
+
+LLGLSLShader* LLDrawPoolAvatar::sVertexProgram = nullptr;
+BOOL	LLDrawPoolAvatar::sSkipOpaque = FALSE;
+BOOL	LLDrawPoolAvatar::sSkipTransparent = FALSE;
+S32     LLDrawPoolAvatar::sShadowPass = -1;
+S32 LLDrawPoolAvatar::sDiffuseChannel = 0;
+F32 LLDrawPoolAvatar::sMinimumAlpha = 0.2f;
+
+LLUUID gBlackSquareID;
+
+static bool is_deferred_render = false;
+static bool is_post_deferred_render = false;
+
+extern BOOL gUseGLPick;
+
+F32 CLOTHING_GRAVITY_EFFECT = 0.7f;
+F32 CLOTHING_ACCEL_FORCE_FACTOR = 0.2f;
+
+// Format for gAGPVertices
+// vertex format for bumpmapping:
+//  vertices   12
+//  pad		    4
+//  normals    12
+//  pad		    4
+//  texcoords0  8
+//  texcoords1  8
+// total       48
+//
+// for no bumpmapping
+//  vertices	   12
+//  texcoords	8
+//  normals	   12
+// total	   32
+//
+
+S32 AVATAR_OFFSET_POS = 0;
+S32 AVATAR_OFFSET_NORMAL = 16;
+S32 AVATAR_OFFSET_TEX0 = 32;
+S32 AVATAR_OFFSET_TEX1 = 40;
+S32 AVATAR_VERTEX_BYTES = 48;
+
+static BOOL sRenderingSkinned = FALSE;
+S32 normal_channel = -1;
+S32 specular_channel = -1;
+S32 cube_channel = -1;
+
+static LLTrace::BlockTimerStatHandle FTM_SHADOW_AVATAR("Avatar Shadow");
+
+LLDrawPoolAvatar::LLDrawPoolAvatar() : 
+	LLFacePool(POOL_AVATAR)	
+{
+}
+
+LLDrawPoolAvatar::~LLDrawPoolAvatar()
+{
+    if (!isDead())
+    {
+        LL_WARNS() << "Destroying avatar drawpool that still contains faces" << LL_ENDL;
+    }
+}
+
+// virtual
+BOOL LLDrawPoolAvatar::isDead()
+{
+    if (!LLFacePool::isDead())
+    {
+        return FALSE;
+    }
+    
+	for (auto& face : mRiggedFace)
+    {
+        if (!face.empty())
+        {
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+ 
+//-----------------------------------------------------------------------------
+// instancePool()
+//-----------------------------------------------------------------------------
+LLDrawPool *LLDrawPoolAvatar::instancePool()
+{
+	return new LLDrawPoolAvatar();
+}
+
+
+S32 LLDrawPoolAvatar::getVertexShaderLevel() const
+{
+	return (S32) LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_AVATAR);
+}
+
+void LLDrawPoolAvatar::prerender()
+{
+	mVertexShaderLevel = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_AVATAR);
+	
+	sShaderLevel = mVertexShaderLevel;
+	
+	if (sShaderLevel > 0)
+	{
+		sBufferUsage = GL_DYNAMIC_DRAW_ARB;
+	}
+	else
+	{
+		sBufferUsage = GL_STREAM_DRAW_ARB;
+	}
+
+	if (!mDrawFace.empty())
+	{
+		const LLFace *facep = mDrawFace[0];
+		if (facep && facep->getDrawable())
+		{
+			LLVOAvatar* avatarp = (LLVOAvatar *)facep->getDrawable()->getVObj().get();
+			updateRiggedVertexBuffers(avatarp);
+		}
+	}
+}
+
+LLMatrix4& LLDrawPoolAvatar::getModelView()
+{
+	static LLMatrix4 ret;
+
+	ret.initRows(LLVector4(gGLModelView+0),
+				 LLVector4(gGLModelView+4),
+				 LLVector4(gGLModelView+8),
+				 LLVector4(gGLModelView+12));
+
+	return ret;
+}
+
+//-----------------------------------------------------------------------------
+// render()
+//-----------------------------------------------------------------------------
+
+
+
+void LLDrawPoolAvatar::beginDeferredPass(S32 pass)
+{
+	LL_RECORD_BLOCK_TIME(FTM_RENDER_CHARACTERS);
+	
+	sSkipTransparent = TRUE;
+	is_deferred_render = true;
+	
+	if (LLPipeline::sImpostorRender)
+	{ //impostor pass does not have rigid or impostor rendering
+		pass += 2;
+	}
+
+	switch (pass)
+	{
+	case 0:
+		beginDeferredImpostor();
+		break;
+	case 1:
+		beginDeferredRigid();
+		break;
+	case 2:
+		beginDeferredSkinned();
+		break;
+	case 3:
+		beginDeferredRiggedSimple();
+		break;
+	case 4:
+		beginDeferredRiggedBump();
+		break;
+	default:
+		beginDeferredRiggedMaterial(pass-5);
+		break;
+	}
+}
+
+void LLDrawPoolAvatar::endDeferredPass(S32 pass)
+{
+	LL_RECORD_BLOCK_TIME(FTM_RENDER_CHARACTERS);
+
+	sSkipTransparent = FALSE;
+	is_deferred_render = false;
+
+	if (LLPipeline::sImpostorRender)
+	{
+		pass += 2;
+	}
+
+	switch (pass)
+	{
+	case 0:
+		endDeferredImpostor();
+		break;
+	case 1:
+		endDeferredRigid();
+		break;
+	case 2:
+		endDeferredSkinned();
+		break;
+	case 3:
+		endDeferredRiggedSimple();
+		break;
+	case 4:
+		endDeferredRiggedBump();
+		break;
+	default:
+		endDeferredRiggedMaterial(pass-5);
+		break;
+	}
+}
+
+void LLDrawPoolAvatar::renderDeferred(S32 pass)
+{
+	render(pass);
+}
+
+S32 LLDrawPoolAvatar::getNumPostDeferredPasses()
+{
+	return 10;
+}
+
+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 9:
+		beginRiggedGlow();
+		break;
+	default:
+		beginDeferredRiggedMaterialAlpha(pass-5);
+		break;
+	}
+}
+
+void LLDrawPoolAvatar::beginPostDeferredAlpha()
+{
+	sSkipOpaque = TRUE;
+	sShaderLevel = mVertexShaderLevel;
+	sVertexProgram = &gDeferredAvatarAlphaProgram;
+	sRenderingSkinned = TRUE;
+
+	gPipeline.bindDeferredShader(*sVertexProgram);
+
+	sVertexProgram->setMinimumAlpha(LLDrawPoolAvatar::sMinimumAlpha);
+
+	sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+}
+
+void LLDrawPoolAvatar::beginDeferredRiggedAlpha()
+{
+	sVertexProgram = &gDeferredSkinnedAlphaProgram;
+	gPipeline.bindDeferredShader(*sVertexProgram);
+	sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+	gPipeline.enableLightsDynamic();
+}
+
+void LLDrawPoolAvatar::beginDeferredRiggedMaterialAlpha(S32 pass)
+{
+	switch (pass)
+	{
+	case 0: pass = 1; break;
+	case 1: pass = 5; break;
+	case 2: pass = 9; break;
+	default: pass = 13; break;
+	}
+
+	pass += LLMaterial::SHADER_COUNT;
+
+	sVertexProgram = &gDeferredMaterialProgram[pass];
+
+	if (LLPipeline::sUnderWaterRender)
+	{
+		sVertexProgram = &(gDeferredMaterialWaterProgram[pass]);
+	}
+
+	gPipeline.bindDeferredShader(*sVertexProgram);
+	sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+	normal_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::BUMP_MAP);
+	specular_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::SPECULAR_MAP);
+	gPipeline.enableLightsDynamic();
+}
+
+void LLDrawPoolAvatar::endDeferredRiggedAlpha()
+{
+	LLVertexBuffer::unbind();
+	gPipeline.unbindDeferredShader(*sVertexProgram);
+	sDiffuseChannel = 0;
+	normal_channel = -1;
+	specular_channel = -1;
+	sVertexProgram = nullptr;
+}
+
+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;
+	default:
+		endDeferredRiggedAlpha();
+		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;
+		
+	gPipeline.unbindDeferredShader(*sVertexProgram);
+	sDiffuseChannel = 0;
+	sShaderLevel = mVertexShaderLevel;
+}
+
+void LLDrawPoolAvatar::renderPostDeferred(S32 pass)
+{
+	static 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 material alpha 1
+		10,//rigged material alpha 2
+		11,//rigged material alpha 3
+		12,//rigged material alpha 4
+		13, //rigged glow
+	};
+
+	S32 p = actual_pass[pass];
+
+	if (LLPipeline::sImpostorRender)
+	{ //HACK for impostors so actual pass ends up being proper pass
+		p -= 2;
+	}
+
+	is_post_deferred_render = true;
+	render(p);
+	is_post_deferred_render = false;
+}
+
+
+S32 LLDrawPoolAvatar::getNumShadowPasses()
+{
+    // avatars opaque, avatar alpha, avatar alpha mask, alpha attachments, alpha mask attachments, opaque attachments...
+	return NUM_SHADOW_PASSES;
+}
+
+void LLDrawPoolAvatar::beginShadowPass(S32 pass)
+{
+	LL_RECORD_BLOCK_TIME(FTM_SHADOW_AVATAR);
+
+	if (pass == SHADOW_PASS_AVATAR_OPAQUE)
+	{
+		sVertexProgram = &gDeferredAvatarShadowProgram;
+		
+		if ((sShaderLevel > 0))  // for hardware blending
+		{
+			sRenderingSkinned = TRUE;
+			sVertexProgram->bind();
+		}
+
+		gGL.diffuseColor4f(1,1,1,1);
+	}
+    else if (pass == SHADOW_PASS_AVATAR_ALPHA_BLEND)
+	{
+		sVertexProgram = &gDeferredAvatarAlphaShadowProgram;
+
+        // bind diffuse tex so we can reference the alpha channel...
+        sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+		
+		if ((sShaderLevel > 0))  // for hardware blending
+		{
+			sRenderingSkinned = TRUE;
+			sVertexProgram->bind();
+		}
+
+		gGL.diffuseColor4f(1,1,1,1);
+	}
+    else if (pass == SHADOW_PASS_AVATAR_ALPHA_MASK)
+	{
+		sVertexProgram = &gDeferredAvatarAlphaMaskShadowProgram;
+
+        // bind diffuse tex so we can reference the alpha channel...
+        sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+		
+		if ((sShaderLevel > 0))  // for hardware blending
+		{
+			sRenderingSkinned = TRUE;
+			sVertexProgram->bind();
+		}
+
+		gGL.diffuseColor4f(1,1,1,1);
+	}
+    else if (pass == SHADOW_PASS_ATTACHMENT_ALPHA_BLEND)
+	{
+		sVertexProgram = &gDeferredAttachmentAlphaShadowProgram;
+
+        // bind diffuse tex so we can reference the alpha channel...
+        sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+		
+		if ((sShaderLevel > 0))  // for hardware blending
+		{
+			sRenderingSkinned = TRUE;
+			sVertexProgram->bind();
+		}
+
+		gGL.diffuseColor4f(1,1,1,1);
+	}
+    else if (pass == SHADOW_PASS_ATTACHMENT_ALPHA_MASK)
+	{
+		sVertexProgram = &gDeferredAttachmentAlphaMaskShadowProgram;
+
+        // bind diffuse tex so we can reference the alpha channel...
+		sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+
+		if ((sShaderLevel > 0))  // for hardware blending
+		{
+			sRenderingSkinned = TRUE;
+			sVertexProgram->bind();
+		}
+
+		gGL.diffuseColor4f(1,1,1,1);
+	}
+	else // SHADOW_PASS_ATTACHMENT_OPAQUE
+	{
+		sVertexProgram = &gDeferredAttachmentShadowProgram;
+		sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+		sVertexProgram->bind();
+	}
+}
+
+void LLDrawPoolAvatar::endShadowPass(S32 pass)
+{
+	LL_RECORD_BLOCK_TIME(FTM_SHADOW_AVATAR);
+
+	if (pass == SHADOW_PASS_ATTACHMENT_OPAQUE)
+	{
+		LLVertexBuffer::unbind();
+	}
+
+    if (sShaderLevel > 0)
+	{			
+		sVertexProgram->unbind();
+	}
+	sVertexProgram = nullptr;
+    sRenderingSkinned = FALSE;
+    LLDrawPoolAvatar::sShadowPass = -1;
+}
+
+void LLDrawPoolAvatar::renderShadow(S32 pass)
+{
+	LL_RECORD_BLOCK_TIME(FTM_SHADOW_AVATAR);
+
+	if (mDrawFace.empty())
+	{
+		return;
+	}
+
+	const LLFace *facep = mDrawFace[0];
+	if (!facep->getDrawable())
+	{
+		return;
+	}
+	LLVOAvatar *avatarp = (LLVOAvatar *)facep->getDrawable()->getVObj().get();
+
+	if (avatarp->isDead() || avatarp->isUIAvatar() || avatarp->mDrawable.isNull())
+	{
+		return;
+	}
+
+	BOOL impostor = avatarp->isImpostor();
+	if (impostor)
+	{
+		return;
+	}
+	
+    LLDrawPoolAvatar::sShadowPass = pass;
+
+	if (pass == SHADOW_PASS_AVATAR_OPAQUE)
+	{
+        LLDrawPoolAvatar::sSkipTransparent = true;
+		avatarp->renderSkinned();
+        LLDrawPoolAvatar::sSkipTransparent = false;
+	}
+    else if (pass == SHADOW_PASS_AVATAR_ALPHA_BLEND)
+	{
+        LLDrawPoolAvatar::sSkipOpaque = true;
+		avatarp->renderSkinned();
+        LLDrawPoolAvatar::sSkipOpaque = false;
+	}
+    else if (pass == SHADOW_PASS_AVATAR_ALPHA_MASK)
+	{
+        LLDrawPoolAvatar::sSkipOpaque = true;
+		avatarp->renderSkinned();
+        LLDrawPoolAvatar::sSkipOpaque = false;
+	}
+    else if (pass == SHADOW_PASS_ATTACHMENT_ALPHA_BLEND) // rigged alpha
+	{
+        LLDrawPoolAvatar::sSkipOpaque = true;
+        renderRigged(avatarp, RIGGED_MATERIAL_ALPHA);
+        renderRigged(avatarp, RIGGED_MATERIAL_ALPHA_EMISSIVE);
+        renderRigged(avatarp, RIGGED_ALPHA);
+        renderRigged(avatarp, RIGGED_FULLBRIGHT_ALPHA);
+        renderRigged(avatarp, RIGGED_GLOW);
+        renderRigged(avatarp, RIGGED_SPECMAP_BLEND);
+        renderRigged(avatarp, RIGGED_NORMMAP_BLEND);
+        renderRigged(avatarp, RIGGED_NORMSPEC_BLEND);
+        LLDrawPoolAvatar::sSkipOpaque = false;
+	}
+    else if (pass == SHADOW_PASS_ATTACHMENT_ALPHA_MASK) // rigged alpha mask
+	{
+        LLDrawPoolAvatar::sSkipOpaque = true;
+        renderRigged(avatarp, RIGGED_MATERIAL_ALPHA_MASK);
+        renderRigged(avatarp, RIGGED_NORMMAP_MASK);
+        renderRigged(avatarp, RIGGED_SPECMAP_MASK);
+		renderRigged(avatarp, RIGGED_NORMSPEC_MASK);    
+        renderRigged(avatarp, RIGGED_GLOW);
+        LLDrawPoolAvatar::sSkipOpaque = false;
+	}
+	else // rigged opaque (SHADOW_PASS_ATTACHMENT_OPAQUE
+	{
+        LLDrawPoolAvatar::sSkipTransparent = true;
+		renderRigged(avatarp, RIGGED_MATERIAL);
+        renderRigged(avatarp, RIGGED_SPECMAP);
+		renderRigged(avatarp, RIGGED_SPECMAP_EMISSIVE);
+		renderRigged(avatarp, RIGGED_NORMMAP);		
+		renderRigged(avatarp, RIGGED_NORMMAP_EMISSIVE);
+		renderRigged(avatarp, RIGGED_NORMSPEC);
+		renderRigged(avatarp, RIGGED_NORMSPEC_EMISSIVE);
+		renderRigged(avatarp, RIGGED_SIMPLE);
+		renderRigged(avatarp, RIGGED_FULLBRIGHT);
+		renderRigged(avatarp, RIGGED_SHINY);
+		renderRigged(avatarp, RIGGED_FULLBRIGHT_SHINY);
+		renderRigged(avatarp, RIGGED_GLOW);
+		renderRigged(avatarp, RIGGED_DEFERRED_BUMP);
+		renderRigged(avatarp, RIGGED_DEFERRED_SIMPLE);
+        LLDrawPoolAvatar::sSkipTransparent = false;
+	}
+}
+
+S32 LLDrawPoolAvatar::getNumPasses()
+{
+	if (LLPipeline::sImpostorRender)
+	{
+		return 8;
+	}
+	else 
+	{
+		return 10;
+	}
+}
+
+
+S32 LLDrawPoolAvatar::getNumDeferredPasses()
+{
+	if (LLPipeline::sImpostorRender)
+	{
+		return 19;
+	}
+	else
+	{
+		return 21;
+	}
+}
+
+
+void LLDrawPoolAvatar::render(S32 pass)
+{
+	LL_RECORD_BLOCK_TIME(FTM_RENDER_CHARACTERS);
+	if (LLPipeline::sImpostorRender)
+	{
+		renderAvatars(nullptr, pass+2);
+		return;
+	}
+
+	renderAvatars(nullptr, pass); // render all avatars
+}
+
+void LLDrawPoolAvatar::beginRenderPass(S32 pass)
+{
+	LL_RECORD_BLOCK_TIME(FTM_RENDER_CHARACTERS);
+	//reset vertex buffer mappings
+	LLVertexBuffer::unbind();
+
+	if (LLPipeline::sImpostorRender)
+	{ //impostor render does not have impostors or rigid rendering
+		pass += 2;
+	}
+
+	switch (pass)
+	{
+	case 0:
+		beginImpostor();
+		break;
+	case 1:
+		beginRigid();
+		break;
+	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;
+	}
+
+	if (pass == 0)
+	{ //make sure no stale colors are left over from a previous render
+		gGL.diffuseColor4f(1,1,1,1);
+	}
+}
+
+void LLDrawPoolAvatar::endRenderPass(S32 pass)
+{
+	LL_RECORD_BLOCK_TIME(FTM_RENDER_CHARACTERS);
+
+	if (LLPipeline::sImpostorRender)
+	{
+		pass += 2;		
+	}
+
+	switch (pass)
+	{
+	case 0:
+		endImpostor();
+		break;
+	case 1:
+		endRigid();
+		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;
+	}
+}
+
+void LLDrawPoolAvatar::beginImpostor()
+{
+	if (!LLPipeline::sReflectionRender)
+	{
+		LLVOAvatar::sRenderDistance = llclamp(LLVOAvatar::sRenderDistance, 16.f, 256.f);
+		LLVOAvatar::sNumVisibleAvatars = 0;
+	}
+
+	if (LLGLSLShader::sNoFixedFunction)
+	{
+		gImpostorProgram.bind();
+		gImpostorProgram.setMinimumAlpha(0.01f);
+	}
+
+	gPipeline.enableLightsFullbright(LLColor4(1,1,1,1));
+	sDiffuseChannel = 0;
+}
+
+void LLDrawPoolAvatar::endImpostor()
+{
+	if (LLGLSLShader::sNoFixedFunction)
+	{
+		gImpostorProgram.unbind();
+	}
+	gPipeline.enableLightsDynamic();
+}
+
+void LLDrawPoolAvatar::beginRigid()
+{
+	if (gPipeline.canUseVertexShaders())
+	{
+		if (LLPipeline::sUnderWaterRender)
+		{
+			sVertexProgram = &gObjectAlphaMaskNoColorWaterProgram;
+		}
+		else
+		{
+			sVertexProgram = &gObjectAlphaMaskNoColorProgram;
+		}
+		
+		if (sVertexProgram != nullptr)
+		{	//eyeballs render with the specular shader
+			sVertexProgram->bind();
+			sVertexProgram->setMinimumAlpha(LLDrawPoolAvatar::sMinimumAlpha);
+		}
+	}
+	else
+	{
+		sVertexProgram = nullptr;
+	}
+}
+
+void LLDrawPoolAvatar::endRigid()
+{
+	sShaderLevel = mVertexShaderLevel;
+	if (sVertexProgram != nullptr)
+	{
+		sVertexProgram->unbind();
+	}
+}
+
+void LLDrawPoolAvatar::beginDeferredImpostor()
+{
+	if (!LLPipeline::sReflectionRender)
+	{
+		LLVOAvatar::sRenderDistance = llclamp(LLVOAvatar::sRenderDistance, 16.f, 256.f);
+		LLVOAvatar::sNumVisibleAvatars = 0;
+	}
+
+	sVertexProgram = &gDeferredImpostorProgram;
+	specular_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::SPECULAR_MAP);
+	normal_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::DEFERRED_NORMAL);
+	sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+	sVertexProgram->bind();
+	sVertexProgram->setMinimumAlpha(0.01f);
+}
+
+void LLDrawPoolAvatar::endDeferredImpostor()
+{
+	sShaderLevel = mVertexShaderLevel;
+	sVertexProgram->disableTexture(LLViewerShaderMgr::DEFERRED_NORMAL);
+	sVertexProgram->disableTexture(LLViewerShaderMgr::SPECULAR_MAP);
+	sVertexProgram->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+	gPipeline.unbindDeferredShader(*sVertexProgram);
+   sVertexProgram = nullptr;
+   sDiffuseChannel = 0;
+}
+
+void LLDrawPoolAvatar::beginDeferredRigid()
+{
+	sVertexProgram = &gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram;
+	sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+	sVertexProgram->bind();
+	sVertexProgram->setMinimumAlpha(LLDrawPoolAvatar::sMinimumAlpha);
+}
+
+void LLDrawPoolAvatar::endDeferredRigid()
+{
+	sShaderLevel = mVertexShaderLevel;
+	sVertexProgram->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+	sVertexProgram->unbind();
+	gGL.getTexUnit(0)->activate();
+}
+
+
+void LLDrawPoolAvatar::beginSkinned()
+{
+	if (sShaderLevel > 0)
+	{
+		if (LLPipeline::sUnderWaterRender)
+		{
+			sVertexProgram = &gAvatarWaterProgram;
+			sShaderLevel = llmin((U32) 1, sShaderLevel);
+		}
+		else
+		{
+			sVertexProgram = &gAvatarProgram;
+		}
+	}
+	else
+	{
+		if (LLPipeline::sUnderWaterRender)
+		{
+			sVertexProgram = &gObjectAlphaMaskNoColorWaterProgram;
+		}
+		else
+		{
+			sVertexProgram = &gObjectAlphaMaskNoColorProgram;
+		}
+	}
+	
+	if (sShaderLevel > 0)  // for hardware blending
+	{
+		sRenderingSkinned = TRUE;
+
+		sVertexProgram->bind();
+		sVertexProgram->enableTexture(LLViewerShaderMgr::BUMP_MAP);
+		gGL.getTexUnit(0)->activate();
+	}
+	else
+	{
+		if(gPipeline.canUseVertexShaders())
+		{
+			// software skinning, use a basic shader for windlight.
+			// TODO: find a better fallback method for software skinning.
+			sVertexProgram->bind();
+		}
+	}
+
+	if (LLGLSLShader::sNoFixedFunction)
+	{
+		sVertexProgram->setMinimumAlpha(LLDrawPoolAvatar::sMinimumAlpha);
+	}
+}
+
+void LLDrawPoolAvatar::endSkinned()
+{
+	// if we're in software-blending, remember to set the fence _after_ we draw so we wait till this rendering is done
+	if (sShaderLevel > 0)
+	{
+		sRenderingSkinned = FALSE;
+		sVertexProgram->disableTexture(LLViewerShaderMgr::BUMP_MAP);
+		gGL.getTexUnit(0)->activate();
+		sVertexProgram->unbind();
+		sShaderLevel = mVertexShaderLevel;
+	}
+	else
+	{
+		if(gPipeline.canUseVertexShaders())
+		{
+			// software skinning, use a basic shader for windlight.
+			// TODO: find a better fallback method for software skinning.
+			sVertexProgram->unbind();
+		}
+	}
+
+	gGL.getTexUnit(0)->activate();
+}
+
+void LLDrawPoolAvatar::beginRiggedSimple()
+{
+	if (sShaderLevel > 0)
+	{
+		if (LLPipeline::sUnderWaterRender)
+		{
+			sVertexProgram = &gSkinnedObjectSimpleWaterProgram;
+		}
+		else
+		{
+			sVertexProgram = &gSkinnedObjectSimpleProgram;
+		}
+	}
+	else
+	{
+		if (LLPipeline::sUnderWaterRender)
+		{
+			sVertexProgram = &gObjectSimpleNonIndexedWaterProgram;
+		}
+		else
+		{
+			sVertexProgram = &gObjectSimpleNonIndexedProgram;
+		}
+	}
+
+	if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
+	{
+		sDiffuseChannel = 0;
+		sVertexProgram->bind();
+	}
+}
+
+void LLDrawPoolAvatar::endRiggedSimple()
+{
+	LLVertexBuffer::unbind();
+	if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
+	{
+		sVertexProgram->unbind();
+		sVertexProgram = nullptr;
+	}
+}
+
+void LLDrawPoolAvatar::beginRiggedAlpha()
+{
+	beginRiggedSimple();
+}
+
+void LLDrawPoolAvatar::endRiggedAlpha()
+{
+	endRiggedSimple();
+}
+
+
+void LLDrawPoolAvatar::beginRiggedFullbrightAlpha()
+{
+	beginRiggedFullbright();
+}
+
+void LLDrawPoolAvatar::endRiggedFullbrightAlpha()
+{
+	endRiggedFullbright();
+}
+
+void LLDrawPoolAvatar::beginRiggedGlow()
+{
+	if (sShaderLevel > 0)
+	{
+		if (LLPipeline::sUnderWaterRender)
+		{
+			sVertexProgram = &gSkinnedObjectEmissiveWaterProgram;
+		}
+		else
+		{
+			sVertexProgram = &gSkinnedObjectEmissiveProgram;
+		}
+	}
+	else
+	{
+		if (LLPipeline::sUnderWaterRender)
+		{
+			sVertexProgram = &gObjectEmissiveNonIndexedWaterProgram;
+		}
+		else
+		{
+			sVertexProgram = &gObjectEmissiveNonIndexedProgram;
+		}
+	}
+
+	if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
+	{
+		sDiffuseChannel = 0;
+		sVertexProgram->bind();
+
+		sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, LLPipeline::sRenderDeferred ? 2.2f : 1.1f);
+	}
+}
+
+void LLDrawPoolAvatar::endRiggedGlow()
+{
+	endRiggedFullbright();
+}
+
+void LLDrawPoolAvatar::beginRiggedFullbright()
+{
+	if (sShaderLevel > 0)
+	{
+		if (LLPipeline::sUnderWaterRender)
+		{
+			sVertexProgram = &gSkinnedObjectFullbrightWaterProgram;
+		}
+		else
+		{
+			if (LLPipeline::sRenderDeferred)
+			{
+				sVertexProgram = &gDeferredSkinnedFullbrightProgram;
+			}
+			else
+			{
+				sVertexProgram = &gSkinnedObjectFullbrightProgram;
+			}
+		}
+	}
+	else
+	{
+		if (LLPipeline::sUnderWaterRender)
+		{
+			sVertexProgram = &gObjectFullbrightNonIndexedWaterProgram;
+		}
+		else
+		{
+			sVertexProgram = &gObjectFullbrightNonIndexedProgram;
+		}
+	}
+
+	if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
+	{
+		sDiffuseChannel = 0;
+		sVertexProgram->bind();
+
+		if (LLPipeline::sRenderingHUDs || !LLPipeline::sRenderDeferred)
+		{
+			sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f);
+		} 
+		else 
+		{
+			sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
+		}
+	}
+}
+
+void LLDrawPoolAvatar::endRiggedFullbright()
+{
+	LLVertexBuffer::unbind();
+	if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
+	{
+		sVertexProgram->unbind();
+		sVertexProgram = nullptr;
+	}
+}
+
+void LLDrawPoolAvatar::beginRiggedShinySimple()
+{
+	if (sShaderLevel > 0)
+	{
+		if (LLPipeline::sUnderWaterRender)
+		{
+			sVertexProgram = &gSkinnedObjectShinySimpleWaterProgram;
+		}
+		else
+		{
+			sVertexProgram = &gSkinnedObjectShinySimpleProgram;
+		}
+	}
+	else
+	{
+		if (LLPipeline::sUnderWaterRender)
+		{
+			sVertexProgram = &gObjectShinyNonIndexedWaterProgram;
+		}
+		else
+		{
+			sVertexProgram = &gObjectShinyNonIndexedProgram;
+		}
+	}
+
+	if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
+	{
+		sVertexProgram->bind();
+		LLDrawPoolBump::bindCubeMap(sVertexProgram, 2, sDiffuseChannel, cube_channel);
+	}
+}
+
+void LLDrawPoolAvatar::endRiggedShinySimple()
+{
+	LLVertexBuffer::unbind();
+	if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
+	{
+		LLDrawPoolBump::unbindCubeMap(sVertexProgram, 2, sDiffuseChannel, cube_channel);
+		sVertexProgram->unbind();
+		sVertexProgram = nullptr;
+	}
+}
+
+void LLDrawPoolAvatar::beginRiggedFullbrightShiny()
+{
+	if (sShaderLevel > 0)
+	{
+		if (LLPipeline::sUnderWaterRender)
+		{
+			sVertexProgram = &gSkinnedObjectFullbrightShinyWaterProgram;
+		}
+		else
+		{
+			if (LLPipeline::sRenderDeferred)
+			{
+				sVertexProgram = &gDeferredSkinnedFullbrightShinyProgram;
+			}
+			else
+			{
+				sVertexProgram = &gSkinnedObjectFullbrightShinyProgram;
+			}
+		}
+	}
+	else
+	{
+		if (LLPipeline::sUnderWaterRender)
+		{
+			sVertexProgram = &gObjectFullbrightShinyNonIndexedWaterProgram;
+		}
+		else
+		{
+			sVertexProgram = &gObjectFullbrightShinyNonIndexedProgram;
+		}
+	}
+
+	if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
+	{
+		sVertexProgram->bind();
+		LLDrawPoolBump::bindCubeMap(sVertexProgram, 2, sDiffuseChannel, cube_channel);
+
+		if (LLPipeline::sRenderingHUDs || !LLPipeline::sRenderDeferred)
+		{
+			sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f);
+		} 
+		else 
+		{
+			sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
+		}
+	}
+}
+
+void LLDrawPoolAvatar::endRiggedFullbrightShiny()
+{
+	LLVertexBuffer::unbind();
+	if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
+	{
+		LLDrawPoolBump::unbindCubeMap(sVertexProgram, 2, sDiffuseChannel, cube_channel);
+		sVertexProgram->unbind();
+		sVertexProgram = nullptr;
+	}
+}
+
+
+void LLDrawPoolAvatar::beginDeferredRiggedSimple()
+{
+	sVertexProgram = &gDeferredSkinnedDiffuseProgram;
+	sDiffuseChannel = 0;
+	sVertexProgram->bind();
+}
+
+void LLDrawPoolAvatar::endDeferredRiggedSimple()
+{
+	LLVertexBuffer::unbind();
+	sVertexProgram->unbind();
+	sVertexProgram = nullptr;
+}
+
+void LLDrawPoolAvatar::beginDeferredRiggedBump()
+{
+	sVertexProgram = &gDeferredSkinnedBumpProgram;
+	sVertexProgram->bind();
+	normal_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::BUMP_MAP);
+	sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+}
+
+void LLDrawPoolAvatar::endDeferredRiggedBump()
+{
+	LLVertexBuffer::unbind();
+	sVertexProgram->disableTexture(LLViewerShaderMgr::BUMP_MAP);
+	sVertexProgram->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+	sVertexProgram->unbind();
+	normal_channel = -1;
+	sDiffuseChannel = 0;
+	sVertexProgram = nullptr;
+}
+
+void LLDrawPoolAvatar::beginDeferredRiggedMaterial(S32 pass)
+{
+	if (pass == 1 ||
+		pass == 5 ||
+		pass == 9 ||
+		pass == 13)
+	{ //skip alpha passes
+		return;
+	}
+	sVertexProgram = &gDeferredMaterialProgram[pass+LLMaterial::SHADER_COUNT];
+
+	if (LLPipeline::sUnderWaterRender)
+	{
+		sVertexProgram = &(gDeferredMaterialWaterProgram[pass+LLMaterial::SHADER_COUNT]);
+	}
+
+	sVertexProgram->bind();
+	normal_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::BUMP_MAP);
+	specular_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::SPECULAR_MAP);
+	sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+}
+
+void LLDrawPoolAvatar::endDeferredRiggedMaterial(S32 pass)
+{
+	if (pass == 1 ||
+		pass == 5 ||
+		pass == 9 ||
+		pass == 13)
+	{
+		return;
+	}
+
+	LLVertexBuffer::unbind();
+	sVertexProgram->disableTexture(LLViewerShaderMgr::BUMP_MAP);
+	sVertexProgram->disableTexture(LLViewerShaderMgr::SPECULAR_MAP);
+	sVertexProgram->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+	sVertexProgram->unbind();
+	normal_channel = -1;
+	sDiffuseChannel = 0;
+	sVertexProgram = nullptr;
+}
+
+void LLDrawPoolAvatar::beginDeferredSkinned()
+{
+	sShaderLevel = mVertexShaderLevel;
+	sVertexProgram = &gDeferredAvatarProgram;
+	sRenderingSkinned = TRUE;
+
+	sVertexProgram->bind();
+	sVertexProgram->setMinimumAlpha(LLDrawPoolAvatar::sMinimumAlpha);
+	
+	sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+	gGL.getTexUnit(0)->activate();
+}
+
+void LLDrawPoolAvatar::endDeferredSkinned()
+{
+	// if we're in software-blending, remember to set the fence _after_ we draw so we wait till this rendering is done
+	sRenderingSkinned = FALSE;
+	sVertexProgram->unbind();
+
+	sVertexProgram->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+
+	sShaderLevel = mVertexShaderLevel;
+
+	gGL.getTexUnit(0)->activate();
+}
+
+static LLTrace::BlockTimerStatHandle FTM_RENDER_AVATARS("renderAvatars");
+
+
+void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass)
+{
+	LL_RECORD_BLOCK_TIME(FTM_RENDER_AVATARS);
+
+	if (pass == -1)
+	{
+		for (S32 i = 1; i < getNumPasses(); i++)
+		{ //skip foot shadows
+			prerender();
+			beginRenderPass(i);
+			renderAvatars(single_avatar, i);
+			endRenderPass(i);
+		}
+
+		return;
+	}
+
+	if (mDrawFace.empty() && !single_avatar)
+	{
+		return;
+	}
+
+	LLVOAvatar *avatarp;
+
+	if (single_avatar)
+	{
+		avatarp = single_avatar;
+	}
+	else
+	{
+		const LLFace *facep = mDrawFace[0];
+		if (!facep->getDrawable())
+		{
+			return;
+		}
+		avatarp = (LLVOAvatar *)facep->getDrawable()->getVObj().get();
+	}
+
+    if (avatarp->isDead() || avatarp->mDrawable.isNull())
+	{
+		return;
+	}
+
+	if (!single_avatar && !avatarp->isFullyLoaded() )
+	{
+		if (pass==0 && (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES) || LLViewerPartSim::getMaxPartCount() <= 0))
+		{
+			// debug code to draw a sphere in place of avatar
+			gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep);
+			gGL.setColorMask(true, true);
+			LLVector3 pos = avatarp->getPositionAgent();
+			gGL.color4f(1.0f, 1.0f, 1.0f, 0.7f);
+			
+			gGL.pushMatrix();	 
+			gGL.translatef((F32)(pos.mV[VX]),	 
+						   (F32)(pos.mV[VY]),	 
+							(F32)(pos.mV[VZ]));	 
+			 gGL.scalef(0.15f, 0.15f, 0.3f);
+
+			 gSphere.renderGGL();
+				 
+			 gGL.popMatrix();
+			 gGL.setColorMask(true, false);
+		}
+		// don't render please
+		return;
+	}
+
+	BOOL impostor = avatarp->isImpostor() && !single_avatar;
+
+	if (impostor && pass != 0)
+	{ //don't draw anything but the impostor for impostored avatars
+		return;
+	}
+	
+	if (pass == 0 && !impostor && LLPipeline::sUnderWaterRender)
+	{ //don't draw foot shadows under water
+		return;
+	}
+
+	if (pass == 0)
+	{
+		if (!LLPipeline::sReflectionRender)
+		{
+			LLVOAvatar::sNumVisibleAvatars++;
+		}
+
+		if (impostor)
+		{
+			if (LLPipeline::sRenderDeferred && !LLPipeline::sReflectionRender && avatarp->mImpostor.isComplete()) 
+			{
+				if (normal_channel > -1)
+				{
+					avatarp->mImpostor.bindTexture(2, normal_channel);
+				}
+				if (specular_channel > -1)
+				{
+					avatarp->mImpostor.bindTexture(1, specular_channel);
+				}
+			}
+			avatarp->renderImpostor(avatarp->getMutedAVColor(), sDiffuseChannel);
+		}
+		return;
+	}
+
+	if (pass == 1)
+	{
+		// render rigid meshes (eyeballs) first
+		avatarp->renderRigid();
+		return;
+	}
+
+	if (pass == 3)
+	{
+		if (is_deferred_render)
+		{
+			renderDeferredRiggedSimple(avatarp);
+		}
+		else
+		{
+			renderRiggedSimple(avatarp);
+
+			if (LLPipeline::sRenderDeferred)
+			{ //render "simple" materials
+				renderRigged(avatarp, RIGGED_MATERIAL);
+				renderRigged(avatarp, RIGGED_MATERIAL_ALPHA_MASK);
+				renderRigged(avatarp, RIGGED_MATERIAL_ALPHA_EMISSIVE);
+				renderRigged(avatarp, RIGGED_NORMMAP);
+				renderRigged(avatarp, RIGGED_NORMMAP_MASK);
+				renderRigged(avatarp, RIGGED_NORMMAP_EMISSIVE);	
+				renderRigged(avatarp, RIGGED_SPECMAP);
+				renderRigged(avatarp, RIGGED_SPECMAP_MASK);
+				renderRigged(avatarp, RIGGED_SPECMAP_EMISSIVE);
+				renderRigged(avatarp, RIGGED_NORMSPEC);
+				renderRigged(avatarp, RIGGED_NORMSPEC_MASK);
+				renderRigged(avatarp, RIGGED_NORMSPEC_EMISSIVE);
+			}
+		}
+		return;
+	}
+
+	if (pass == 4)
+	{
+		if (is_deferred_render)
+		{
+			renderDeferredRiggedBump(avatarp);
+		}
+		else
+		{
+			renderRiggedFullbright(avatarp);
+		}
+
+		return;
+	}
+
+	if (is_deferred_render && pass >= 5 && pass <= 21)
+	{
+		S32 p = pass-5;
+
+		if (p != 1 &&
+			p != 5 &&
+			p != 9 &&
+			p != 13)
+		{
+			renderDeferredRiggedMaterial(avatarp, p);
+		}
+		return;
+	}
+
+
+
+
+	if (pass == 5)
+	{
+		renderRiggedShinySimple(avatarp);
+				
+		return;
+	}
+
+	if (pass == 6)
+	{
+		renderRiggedFullbrightShiny(avatarp);
+		return;
+	}
+
+	if (pass >= 7 && pass < 13)
+	{
+		if (pass == 7)
+		{
+			renderRiggedAlpha(avatarp);
+
+			if (LLPipeline::sRenderDeferred && !is_post_deferred_render)
+			{ //render transparent materials under water
+				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);
+
+				renderRigged(avatarp, RIGGED_MATERIAL_ALPHA);
+				renderRigged(avatarp, RIGGED_SPECMAP_BLEND);
+				renderRigged(avatarp, RIGGED_NORMMAP_BLEND);
+				renderRigged(avatarp, RIGGED_NORMSPEC_BLEND);
+				gGL.setSceneBlendType(LLRender::BT_ALPHA); // <alchemy/>
+				gGL.setColorMask(true, false);
+			}
+			return;
+		}
+
+		if (pass == 8)
+		{
+			renderRiggedFullbrightAlpha(avatarp);
+			return;
+		}
+
+		if (LLPipeline::sRenderDeferred && is_post_deferred_render)
+		{
+			S32 p = 0;
+			switch (pass)
+			{
+			case 9: p = 1; break;
+			case 10: p = 5; break;
+			case 11: p = 9; break;
+			case 12: p = 13; break;
+			}
+
+			{
+				LLGLEnable blend(GL_BLEND);
+				renderDeferredRiggedMaterial(avatarp, p);
+			}
+			return;
+		}
+		else if (pass == 9)
+		{
+			renderRiggedGlow(avatarp);
+			return;
+		}
+	}
+
+	if (pass == 13)
+	{
+		renderRiggedGlow(avatarp);
+		
+		return;
+	}
+	
+	if ((sShaderLevel >= SHADER_LEVEL_CLOTH))
+	{
+		LLMatrix4 rot_mat;
+		LLViewerCamera::getInstance()->getMatrixToLocal(rot_mat);
+		static const LLMatrix4 cfr(OGL_TO_CFR_ROTATION);
+		rot_mat *= cfr;
+		
+		LLVector4 wind;
+		wind.setVec(avatarp->mWindVec);
+		wind.mV[VW] = 0;
+		wind = wind * rot_mat;
+		wind.mV[VW] = avatarp->mWindVec.mV[VW];
+
+		sVertexProgram->uniform4fv(LLViewerShaderMgr::AVATAR_WIND, 1, wind.mV);
+		F32 phase = -1.f * (avatarp->mRipplePhase);
+
+		F32 freq = 7.f + (noise1(avatarp->mRipplePhase) * 2.f);
+		LLVector4 sin_params(freq, freq, freq, phase);
+		sVertexProgram->uniform4fv(LLViewerShaderMgr::AVATAR_SINWAVE, 1, sin_params.mV);
+
+		LLVector4 gravity(0.f, 0.f, -CLOTHING_GRAVITY_EFFECT, 0.f);
+		gravity = gravity * rot_mat;
+		sVertexProgram->uniform4fv(LLViewerShaderMgr::AVATAR_GRAVITY, 1, gravity.mV);
+	}
+
+	if( !single_avatar || (avatarp == single_avatar) )
+	{
+		avatarp->renderSkinned();
+	}
+}
+
+void LLDrawPoolAvatar::getRiggedGeometry(
+    LLFace* face,
+    LLPointer<LLVertexBuffer>& buffer,
+    U32 data_mask,
+    const LLMeshSkinInfo* skin,
+    LLVolume* volume,
+    const LLVolumeFace& vol_face)
+{
+	face->setGeomIndex(0);
+	face->setIndicesIndex(0);
+		
+	//rigged faces do not batch textures
+	face->setTextureIndex(255);
+
+	if (buffer.isNull() || buffer->getTypeMask() != data_mask || !buffer->isWriteable())
+	{
+        // make a new buffer
+		if (sShaderLevel > 0)
+		{
+			buffer = new LLVertexBuffer(data_mask, GL_DYNAMIC_DRAW_ARB);
+		}
+		else
+		{
+			buffer = new LLVertexBuffer(data_mask, GL_STREAM_DRAW_ARB);
+		}
+
+		if (!buffer->allocateBuffer(vol_face.mNumVertices, vol_face.mNumIndices, true))
+		{
+			LL_WARNS("LLDrawPoolAvatar") << "Failed to allocate Vertex Buffer to "
+				<< vol_face.mNumVertices << " vertices and "
+				<< vol_face.mNumIndices << " indices" << LL_ENDL;
+			// allocate dummy triangle
+			buffer->allocateBuffer(1, 3, true);
+			memset((U8*)buffer->getMappedData(), 0, buffer->getSize());
+			memset((U8*)buffer->getMappedIndices(), 0, buffer->getIndicesSize());
+		}
+	}
+	else
+	{
+        //resize existing buffer
+		if(!buffer->resizeBuffer(vol_face.mNumVertices, vol_face.mNumIndices))
+		{
+			LL_WARNS("LLDrawPoolAvatar") << "Failed to resize Vertex Buffer to "
+				<< vol_face.mNumVertices << " vertices and "
+				<< vol_face.mNumIndices << " indices" << LL_ENDL;
+			// allocate dummy triangle
+			buffer->resizeBuffer(1, 3);
+			memset((U8*)buffer->getMappedData(), 0, buffer->getSize());
+			memset((U8*)buffer->getMappedIndices(), 0, buffer->getIndicesSize());
+		}
+	}
+
+	face->setSize(buffer->getNumVerts(), buffer->getNumIndices());
+	face->setVertexBuffer(buffer);
+
+	U16 offset = 0;
+		
+	LLMatrix4a mat_vert_inv = skin->mBindShapeMatrix;
+	mat_vert_inv.invert();
+	mat_vert_inv.transpose();
+
+	const F32* m = mat_vert_inv.getF32ptr();
+	F32 mat3[] = 
+        { m[0], m[1], m[2],
+          m[4], m[5], m[6],
+          m[8], m[9], m[10] };
+
+	LLMatrix3 mat_normal(mat3);				
+
+	//let getGeometryVolume know if alpha should override shiny
+	U32 type = gPipeline.getPoolTypeFromTE(face->getTextureEntry(), face->getTexture());
+
+	if (type == LLDrawPool::POOL_ALPHA)
+	{
+		face->setPoolType(LLDrawPool::POOL_ALPHA);
+	}
+	else
+	{
+		face->setPoolType(LLDrawPool::POOL_AVATAR);
+	}
+
+	//LL_INFOS() << "Rebuilt face " << face->getTEOffset() << " of " << face->getDrawable() << " at " << gFrameTimeSeconds << LL_ENDL;
+
+	// Let getGeometryVolume know if a texture matrix is in play
+	if (face->mTextureMatrix)
+	{
+		face->setState(LLFace::TEXTURE_ANIM);
+	}
+	else
+	{
+		face->clearState(LLFace::TEXTURE_ANIM);
+	}
+	LLMatrix4 mat_vert(skin->mBindShapeMatrix.getF32ptr());
+	face->getGeometryVolume(*volume, face->getTEOffset(), mat_vert, mat_normal, offset, true);
+
+	buffer->flush();
+}
+
+void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(
+    LLVOAvatar* avatar,
+    LLFace* face,
+    const LLMeshSkinInfo* skin,
+    LLVolume* volume,
+    const LLVolumeFace& vol_face)
+{
+	LLVector4a* weights = vol_face.mWeights;
+	if (!weights)
+	{
+		return;
+	}
+    // FIXME ugly const cast
+    LLSkinningUtil::scrubInvalidJoints(avatar, const_cast<LLMeshSkinInfo*>(skin));
+
+	LLPointer<LLVertexBuffer> buffer = face->getVertexBuffer();
+	LLDrawable* drawable = face->getDrawable();
+
+	if (drawable->getVOVolume() && drawable->getVOVolume()->isNoLOD())
+	{
+		return;
+	}
+
+	U32 data_mask = face->getRiggedVertexBufferDataMask();
+
+    if (!vol_face.mWeightsScrubbed)
+    {
+        LLSkinningUtil::scrubSkinWeights(weights, vol_face.mNumVertices, skin);
+        vol_face.mWeightsScrubbed = TRUE;
+    }
+	
+	if (buffer.isNull() || 
+		buffer->getTypeMask() != data_mask ||
+		buffer->getNumVerts() != vol_face.mNumVertices ||
+		buffer->getNumIndices() != vol_face.mNumIndices ||
+		(drawable && drawable->isState(LLDrawable::REBUILD_ALL)))
+	{
+		if (drawable && drawable->isState(LLDrawable::REBUILD_ALL))
+		{ //rebuild EVERY face in the drawable, not just this one, to avoid missing drawable wide rebuild issues
+			for (S32 i = 0; i < drawable->getNumFaces(); ++i)
+			{
+				LLFace* facep = drawable->getFace(i);
+				U32 face_data_mask = facep->getRiggedVertexBufferDataMask();
+				if (face_data_mask)
+				{
+					LLPointer<LLVertexBuffer> cur_buffer = facep->getVertexBuffer();
+					const LLVolumeFace& cur_vol_face = volume->getVolumeFace(i);
+					getRiggedGeometry(facep, cur_buffer, face_data_mask, skin, volume, cur_vol_face);
+				}
+			}
+			drawable->clearState(LLDrawable::REBUILD_ALL);
+
+			buffer = face->getVertexBuffer();
+		}
+		else
+		{ //just rebuild this face
+			getRiggedGeometry(face, buffer, data_mask, skin, volume, vol_face);
+		}
+	}
+
+	if (buffer.isNull() ||
+		buffer->getNumVerts() != vol_face.mNumVertices ||
+		buffer->getNumIndices() != vol_face.mNumIndices)
+	{
+		// Allocation failed
+		return;
+	}
+
+	if (!buffer.isNull() && 
+		sShaderLevel <= 0 && 
+		face->mLastSkinTime < avatar->getLastSkinTime())
+	{
+		//perform software vertex skinning for this face
+		LLStrider<LLVector3> position;
+		LLStrider<LLVector3> normal;
+
+		bool has_normal = buffer->hasDataType(LLVertexBuffer::TYPE_NORMAL);
+		buffer->getVertexStrider(position);
+
+		if (has_normal)
+		{
+			buffer->getNormalStrider(normal);
+		}
+
+		LLVector4a* pos = (LLVector4a*) position.get();
+
+		LLVector4a* norm = has_normal ? (LLVector4a*) normal.get() : NULL;
+		
+		//build matrix palette
+		LLMatrix4a mat[LL_MAX_JOINTS_PER_MESH_OBJECT];
+        U32 count = LLSkinningUtil::getMeshJointCount(skin);
+        LLSkinningUtil::initSkinningMatrixPalette(mat, count, skin, avatar);
+        LLSkinningUtil::checkSkinWeights(weights, buffer->getNumVerts(), skin);
+
+        const U32 max_joints = LLSkinningUtil::getMaxJointCount();
+		for (S32 j = 0; j < buffer->getNumVerts(); ++j)
+		{
+			LLMatrix4a final_mat;
+            LLSkinningUtil::getPerVertexSkinMatrix(weights[j], mat, false, final_mat, max_joints);
+			
+			const LLVector4a& v = vol_face.mPositions[j];
+
+			LLVector4a dst;
+			skin->mBindShapeMatrix.affineTransform(v, dst);
+			final_mat.affineTransform(dst, dst);
+			pos[j] = dst;
+
+			if (norm)
+			{
+				const LLVector4a& n = vol_face.mNormals[j];
+				skin->mBindShapeMatrix.rotate(n, dst);
+				final_mat.rotate(dst, dst);
+				dst.normalize3fast();
+				norm[j] = dst;
+			}
+		}
+	}
+}
+
+void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow)
+{
+	if (!avatar->shouldRenderRigged())
+	{
+		return;
+	}
+
+	stop_glerror();
+
+	for (LLFace* face : mRiggedFace[type])
+	{
+        S32 offset = face->getIndicesStart();
+		U32 count = face->getIndicesCount();
+
+        U16 start = face->getGeomStart();
+		U16 end = start + face->getGeomCount()-1;			
+
+		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 || !volume->isMeshAssetLoaded())
+		{
+			continue;
+		}
+
+		const LLMeshSkinInfo* skin = vobj->getSkinInfo();
+		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();
+
+        const LLTextureEntry* tex_entry = face->getTextureEntry();
+		LLMaterial* mat = tex_entry ? tex_entry->getMaterialParams().get() : nullptr;
+
+        if (LLDrawPoolAvatar::sShadowPass >= 0)
+        {
+            bool is_alpha_blend = false;
+            bool is_alpha_mask  = false;
+
+            LLViewerTexture* tex = face->getTexture(LLRender::DIFFUSE_MAP);
+            if (tex)
+            {
+                if (tex->getIsAlphaMask(-1.f, -1.f))
+                {
+                    is_alpha_mask = true;
+                }
+            }
+
+            if (tex)
+            {
+                LLGLenum image_format = tex->getPrimaryFormat();
+                if (!is_alpha_mask && (image_format == GL_RGBA || image_format == GL_ALPHA))
+                {
+                    is_alpha_blend = true;
+                }
+            }
+
+            if (tex_entry)
+            {
+                if (tex_entry->getAlpha() <= 0.99f)
+                {
+                    is_alpha_blend = true;
+                }
+            }
+
+            if (mat)
+            {                
+                switch (LLMaterial::eDiffuseAlphaMode(mat->getDiffuseAlphaMode()))
+                {
+                    case LLMaterial::DIFFUSE_ALPHA_MODE_MASK:
+                    {
+                        is_alpha_mask  = true;
+                        is_alpha_blend = false;
+                    }
+                    break;
+
+                    case LLMaterial::DIFFUSE_ALPHA_MODE_BLEND:
+                    {
+                        is_alpha_blend = true;
+                        is_alpha_mask  = false;
+                    }
+                    break;
+
+                    case LLMaterial::DIFFUSE_ALPHA_MODE_EMISSIVE:
+                    case LLMaterial::DIFFUSE_ALPHA_MODE_DEFAULT:
+                    case LLMaterial::DIFFUSE_ALPHA_MODE_NONE:
+                    default:
+                        is_alpha_blend = false;
+                        is_alpha_mask  = false;
+                        break;
+                }
+            }
+
+            // if this is alpha mask content and we're doing opaques or a non-alpha-mask shadow pass...
+            if (is_alpha_mask && (LLDrawPoolAvatar::sSkipTransparent || LLDrawPoolAvatar::sShadowPass != SHADOW_PASS_ATTACHMENT_ALPHA_MASK))
+            {
+                return;
+            }
+
+            // if this is alpha blend content and we're doing opaques or a non-alpha-blend shadow pass...
+            if (is_alpha_blend && (LLDrawPoolAvatar::sSkipTransparent || LLDrawPoolAvatar::sShadowPass != SHADOW_PASS_ATTACHMENT_ALPHA_BLEND))
+            {
+                return;
+            }
+
+            // if this is opaque content and we're skipping opaques...
+            if (!is_alpha_mask && !is_alpha_blend && LLDrawPoolAvatar::sSkipOpaque)
+            {
+                return;
+            }
+        }
+
+		if (buff)
+		{        
+			if (sShaderLevel > 0)
+			{
+				auto& mesh_cache = avatar->getRiggedMatrixCache();
+				const auto& mesh_id = skin->mMeshID;
+				const auto& rigged_matrix_data_iter = mesh_cache.find(mesh_id);
+				if (rigged_matrix_data_iter != mesh_cache.cend() && (!avatar->isSelf() || !avatar->isEditingAppearance()))
+				{
+					LLDrawPoolAvatar::sVertexProgram->uniformMatrix3x4fv(LLViewerShaderMgr::AVATAR_MATRIX,
+						rigged_matrix_data_iter->second.first,
+						FALSE,
+						(GLfloat*)rigged_matrix_data_iter->second.second.data());
+
+					stop_glerror();
+				}
+				else
+				{
+					// upload matrix palette to shader
+					LLMatrix4a mat[LL_MAX_JOINTS_PER_MESH_OBJECT];
+					U32 count = LLSkinningUtil::getMeshJointCount(skin);
+					LLSkinningUtil::initSkinningMatrixPalette(mat, count, skin, avatar);
+
+					stop_glerror();
+
+					std::vector<F32> mp;
+					mp.reserve(count * 12);
+
+					for (U32 i = 0; i < count; ++i)
+					{
+						F32* m = (F32*) mat[i].getF32ptr();
+
+						U32 idx = i * 12;
+
+						mp[idx + 0] = m[0];
+						mp[idx + 1] = m[1];
+						mp[idx + 2] = m[2];
+						mp[idx + 3] = m[12];
+
+						mp[idx + 4] = m[4];
+						mp[idx + 5] = m[5];
+						mp[idx + 6] = m[6];
+						mp[idx + 7] = m[13];
+
+						mp[idx + 8] = m[8];
+						mp[idx + 9] = m[9];
+						mp[idx + 10] = m[10];
+						mp[idx + 11] = m[14];
+					}
+					LLDrawPoolAvatar::sVertexProgram->uniformMatrix3x4fv(LLViewerShaderMgr::AVATAR_MATRIX,
+						count,
+						FALSE,
+						(GLfloat*) mp.data());
+					mesh_cache.emplace(mesh_id, std::make_pair(count, std::move(mp)));
+					stop_glerror();
+				}
+			}
+			else
+			{
+				data_mask &= ~LLVertexBuffer::MAP_WEIGHT4;
+			}
+
+			/*if (glow)
+			{
+				gGL.diffuseColor4f(0,0,0,face->getTextureEntry()->getGlow());
+			}*/
+
+			if (mat)
+			{
+				//order is important here LLRender::DIFFUSE_MAP should be last, because it changes 
+				//(gGL).mCurrTextureUnitIndex
+                LLViewerTexture* specular = nullptr;
+                if (LLPipeline::sImpostorRender && avatar->isVisuallyMuted())
+                {
+                    specular = LLViewerTextureManager::findFetchedTexture(gBlackSquareID, TEX_LIST_STANDARD);
+                }
+                else
+                {
+                    specular = face->getViewerObject()->getTESpecularMap(face->getTEOffset());
+                }
+                
+				gGL.getTexUnit(specular_channel)->bind(specular);
+				gGL.getTexUnit(normal_channel)->bind(face->getViewerObject()->getTENormalMap(face->getTEOffset()));
+				gGL.getTexUnit(sDiffuseChannel)->bind(face->getTexture(), false, true);
+
+				static const LLColor4 alpha[4] =
+				{
+					{0.00f,0.00f,0.00f,0.00f},
+					{0.25f,0.25f,0.25f,0.25f},
+					{0.50f,0.50f,0.50f,0.50f},
+					{0.75f,0.75f,0.75f,0.75f},
+				};
+
+				LLColor4 specColor = alpha[tex_entry->getShiny() & TEM_SHINY_MASK];
+				F32 env = specColor.mV[0];
+
+				if (!mat->getSpecularID().isNull())
+				{
+					const auto& spec_light_col = mat->getSpecularLightColor();
+					specColor.mV[0] = spec_light_col.mV[0];
+					specColor.mV[1] = spec_light_col.mV[1];
+					specColor.mV[2] = spec_light_col.mV[2];
+					specColor.mV[3] = mat->getSpecularLightExponent();
+					env = mat->getEnvironmentIntensity();
+				}
+
+				BOOL fullbright = tex_entry->getFullbright();
+
+				sVertexProgram->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, fullbright ? 1.f : 0.f);
+				sVertexProgram->uniform4fv(LLShaderMgr::SPECULAR_COLOR, 1, specColor.mV);
+				sVertexProgram->uniform1f(LLShaderMgr::ENVIRONMENT_INTENSITY, env);
+
+				if (mat->getDiffuseAlphaMode() == LLMaterial::DIFFUSE_ALPHA_MODE_MASK)
+				{
+					sVertexProgram->setMinimumAlpha(mat->getAlphaMaskCutoff());
+				}
+				else
+				{
+					sVertexProgram->setMinimumAlpha(0.f);
+				}
+
+				for (U32 i = 0; i < LLRender::NUM_TEXTURE_CHANNELS; ++i)
+				{
+					LLViewerTexture* tex = face->getTexture(i);
+					if (tex)
+					{
+						tex->addTextureStats(avatar->getPixelArea());
+					}
+				}
+			}
+			else
+			{
+				gGL.getTexUnit(sDiffuseChannel)->bind(face->getTexture());
+				sVertexProgram->setMinimumAlpha(0.f);
+				if (normal_channel > -1)
+				{
+					LLDrawPoolBump::bindBumpMap(face, normal_channel);
+				}
+			}
+
+			if (face->mTextureMatrix && vobj->mTexAnimMode)
+			{
+				gGL.matrixMode(LLRender::MM_TEXTURE);
+				gGL.loadMatrix((F32*) face->mTextureMatrix->mMatrix);
+				buff->setBuffer(data_mask);
+				buff->drawRange(LLRender::TRIANGLES, start, end, count, offset);
+				gGL.loadIdentity();
+				gGL.matrixMode(LLRender::MM_MODELVIEW);
+			}
+			else
+			{
+				buff->setBuffer(data_mask);
+				buff->drawRange(LLRender::TRIANGLES, start, end, count, offset);		
+			}
+
+			gPipeline.addTrianglesDrawn(count, LLRender::TRIANGLES);
+		}
+	}
+}
+
+void LLDrawPoolAvatar::renderDeferredRiggedSimple(LLVOAvatar* avatar)
+{
+	renderRigged(avatar, RIGGED_DEFERRED_SIMPLE);
+}
+
+void LLDrawPoolAvatar::renderDeferredRiggedBump(LLVOAvatar* avatar)
+{
+	renderRigged(avatar, RIGGED_DEFERRED_BUMP);
+}
+
+void LLDrawPoolAvatar::renderDeferredRiggedMaterial(LLVOAvatar* avatar, S32 pass)
+{
+	renderRigged(avatar, pass);
+}
+
+static LLTrace::BlockTimerStatHandle FTM_RIGGED_VBO("Rigged VBO");
+
+void LLDrawPoolAvatar::updateRiggedVertexBuffers(LLVOAvatar* avatar)
+{
+	LL_RECORD_BLOCK_TIME(FTM_RIGGED_VBO);
+
+	//update rigged vertex buffers
+	for (auto& type : mRiggedFace)
+    {
+		for (LLFace* face : type)
+		{
+			LLDrawable* drawable = face->getDrawable();
+			if (!drawable)
+			{
+				continue;
+			}
+
+			LLVOVolume* vobj = drawable->getVOVolume();
+
+			if (!vobj || vobj->isNoLOD())
+			{
+				continue;
+			}
+
+			LLVolume* volume = vobj->getVolume();
+			S32 te = face->getTEOffset();
+
+			if (!volume || volume->getNumVolumeFaces() <= te)
+			{
+				continue;
+			}
+
+			const LLMeshSkinInfo* skin = vobj->getSkinInfo();
+			if (!skin)
+			{
+				continue;
+			}
+
+			stop_glerror();
+
+			const LLVolumeFace& vol_face = volume->getVolumeFace(te);
+			updateRiggedFaceVertexBuffer(avatar, face, skin, volume, vol_face);
+		}
+	}
+}
+
+void LLDrawPoolAvatar::renderRiggedSimple(LLVOAvatar* avatar)
+{
+	renderRigged(avatar, RIGGED_SIMPLE);
+}
+
+void LLDrawPoolAvatar::renderRiggedFullbright(LLVOAvatar* avatar)
+{
+	renderRigged(avatar, RIGGED_FULLBRIGHT);
+}
+
+	
+void LLDrawPoolAvatar::renderRiggedShinySimple(LLVOAvatar* avatar)
+{
+	renderRigged(avatar, RIGGED_SHINY);
+}
+
+void LLDrawPoolAvatar::renderRiggedFullbrightShiny(LLVOAvatar* avatar)
+{
+	renderRigged(avatar, RIGGED_FULLBRIGHT_SHINY);
+}
+
+void LLDrawPoolAvatar::renderRiggedAlpha(LLVOAvatar* avatar)
+{
+	if (!mRiggedFace[RIGGED_ALPHA].empty())
+	{
+		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);
+
+		renderRigged(avatar, RIGGED_ALPHA);
+		gGL.setSceneBlendType(LLRender::BT_ALPHA); // <alchemy/>
+		gGL.setColorMask(true, false);
+	}
+}
+
+void LLDrawPoolAvatar::renderRiggedFullbrightAlpha(LLVOAvatar* avatar)
+{
+	if (!mRiggedFace[RIGGED_FULLBRIGHT_ALPHA].empty())
+	{
+		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);
+
+		renderRigged(avatar, RIGGED_FULLBRIGHT_ALPHA);
+		gGL.setSceneBlendType(LLRender::BT_ALPHA); // <alchemy/>
+		gGL.setColorMask(true, false);
+	}
+}
+
+void LLDrawPoolAvatar::renderRiggedGlow(LLVOAvatar* avatar)
+{
+	if (!mRiggedFace[RIGGED_GLOW].empty())
+	{
+		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);
+
+		renderRigged(avatar, RIGGED_GLOW, true);
+
+		gGL.setColorMask(true, false);
+		gGL.setSceneBlendType(LLRender::BT_ALPHA);
+	}
+}
+
+
+
+//-----------------------------------------------------------------------------
+// getDebugTexture()
+//-----------------------------------------------------------------------------
+LLViewerTexture *LLDrawPoolAvatar::getDebugTexture()
+{
+	if (mReferences.empty())
+	{
+		return nullptr;
+	}
+	LLFace *face = mReferences[0];
+	if (!face->getDrawable())
+	{
+		return nullptr;
+	}
+	const LLViewerObject *objectp = face->getDrawable()->getVObj();
+
+	// Avatar should always have at least 1 (maybe 3?) TE's.
+	return objectp->getTEImage(0);
+}
+
+
+LLColor3 LLDrawPoolAvatar::getDebugColor() const
+{
+	return LLColor3(0.f, 1.f, 0.f);
+}
+
+void LLDrawPoolAvatar::addRiggedFace(LLFace* facep, U32 type)
+{
+    llassert (facep->isState(LLFace::RIGGED));
+    llassert(getType() == LLDrawPool::POOL_AVATAR);
+    if (facep->getPool() && facep->getPool() != this)
+    {
+        LL_ERRS() << "adding rigged face that's already in another pool" << LL_ENDL;
+    }
+	if (type >= NUM_RIGGED_PASSES)
+	{
+		LL_ERRS() << "Invalid rigged face type." << LL_ENDL;
+	}
+	if (facep->getRiggedIndex(type) != -1)
+	{
+		LL_ERRS() << "Tried to add a rigged face that's referenced elsewhere." << LL_ENDL;
+	}	
+	
+	facep->setRiggedIndex(type, mRiggedFace[type].size());
+	facep->setPool(this);
+	mRiggedFace[type].push_back(facep);
+
+	facep->mShinyInAlpha = type == RIGGED_DEFERRED_SIMPLE || type == RIGGED_DEFERRED_BUMP || type == RIGGED_FULLBRIGHT_SHINY || type == RIGGED_SHINY;
+}
+
+void LLDrawPoolAvatar::removeRiggedFace(LLFace* facep)
+{
+    llassert (facep->isState(LLFace::RIGGED));
+    llassert(getType() == LLDrawPool::POOL_AVATAR);
+    if (facep->getPool() != this)
+    {
+        LL_ERRS() << "Tried to remove a rigged face from the wrong pool" << LL_ENDL;
+    }
+	facep->setPool(nullptr);
+
+	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
+			{
+				LL_ERRS() << "Face reference data corrupt for rigged type " << i
+					<< ((mRiggedFace[i].size() <= index) ? "; wrong index (out of bounds)" : (mRiggedFace[i][index] != facep) ? "; wrong face pointer" : "")
+					<< LL_ENDL;
+			}
+		}
+	}
+}
+
+LLVertexBufferAvatar::LLVertexBufferAvatar()
+: LLVertexBuffer(sDataMask, 
+	GL_STREAM_DRAW_ARB) //avatars are always stream draw due to morph targets
+{
+
+}
+
+
diff --git a/indra/newview/llmaterialmgr.h b/indra/newview/llmaterialmgr.h
index eb72b5fcac..8aa41dece8 100644
--- a/indra/newview/llmaterialmgr.h
+++ b/indra/newview/llmaterialmgr.h
@@ -91,9 +91,9 @@ private:
 		U32 te;
 		LLMaterialID materialID;
 
-		template <typename H>
-		friend H AbslHashValue(H h, const TEMaterialPair& m) {
-			return H::combine(std::move(h), m.materialID, m.te);
+		template <typename H>
+		friend H AbslHashValue(H h, const TEMaterialPair& m) {
+			return H::combine(std::move(h), m.materialID, m.te);
 		}
 
 		bool operator==(const TEMaterialPair& b) const { return (materialID == b.materialID) && (te == b.te); }
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index 755093a40c..ec639333ec 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -1,4163 +1,4163 @@
-/** 
- * @file llspatialpartition.cpp
- * @brief LLSpatialGroup class implementation and supporting functions
- *
- * $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$
- */
-
-#include "llviewerprecompiledheaders.h"
-
-#include "llspatialpartition.h"
-
-#include "llappviewer.h"
-#include "llcallstack.h"
-#include "lltexturecache.h"
-#include "lltexturefetch.h"
-#include "llimageworker.h"
-#include "llviewerwindow.h"
-#include "llviewerobjectlist.h"
-#include "llvovolume.h"
-#include "llvolume.h"
-#include "llvolumeoctree.h"
-#include "llviewercamera.h"
-#include "llface.h"
-#include "llfloatertools.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 "llviewershadermgr.h"
-#include "llcontrolavatar.h"
-#include "llfloaterreg.h" // <alchemy/>
-
-//#pragma optimize("", off)
-
-static LLTrace::BlockTimerStatHandle FTM_FRUSTUM_CULL("Frustum Culling");
-static LLTrace::BlockTimerStatHandle FTM_CULL_REBOUND("Cull Rebound Partition");
-
-extern bool gShiftFrame;
-
-static U32 sZombieGroups = 0;
-U32 LLSpatialGroup::sNodeCount = 0;
-
-BOOL LLSpatialGroup::sNoDelete = FALSE;
-
-static F32 sLastMaxTexPriority = 1.f;
-static F32 sCurMaxTexPriority = 1.f;
-
-BOOL LLSpatialPartition::sTeleportRequested = FALSE;
-
-//static counter for frame to switch LOD on
-
-void sg_assert(BOOL expr)
-{
-#if LL_OCTREE_PARANOIA_CHECK
-	if (!expr)
-	{
-		LL_ERRS() << "Octree invalid!" << LL_ENDL;
-	}
-#endif
-}
-
-//returns:
-//	0 if sphere and AABB are not intersecting 
-//	1 if they are
-//	2 if AABB is entirely inside sphere
-
-S32 LLSphereAABB(const LLVector3& center, const LLVector3& size, const LLVector3& pos, const F32 &rad)
-{
-	S32 ret = 2;
-
-	LLVector3 min = center - size;
-	LLVector3 max = center + size;
-	for (U32 i = 0; i < 3; i++)
-	{
-		if (min.mV[i] > pos.mV[i] + rad ||
-			max.mV[i] < pos.mV[i] - rad)
-		{	//totally outside
-			return 0;
-		}
-		
-		if (min.mV[i] < pos.mV[i] - rad ||
-			max.mV[i] > pos.mV[i] + rad)
-		{	//intersecting
-			ret = 1;
-		}
-	}
-
-	return ret;
-}
-
-LLSpatialGroup::~LLSpatialGroup()
-{
-	/*if (sNoDelete)
-	{
-		LL_ERRS() << "Illegal deletion of LLSpatialGroup!" << LL_ENDL;
-	}*/
-
-	if (gDebugGL)
-	{
-		gPipeline.checkReferences(this);
-	}
-
-	if (hasState(DEAD))
-	{
-		sZombieGroups--;
-	}
-	
-	sNodeCount--;
-
-	clearDrawMap();
-}
-
-void LLSpatialGroup::clearDrawMap()
-{
-	mDrawMap.clear();
-}
-
-BOOL LLSpatialGroup::isHUDGroup() 
-{
-	return getSpatialPartition() && getSpatialPartition()->isHUDPartition() ; 
-}
-
-void LLSpatialGroup::validate()
-{
-	ll_assert_aligned(this,64);
-#if LL_OCTREE_PARANOIA_CHECK
-
-	sg_assert(!isState(DIRTY));
-	sg_assert(!isDead());
-
-	LLVector4a myMin;
-	myMin.setSub(mBounds[0], mBounds[1]);
-	LLVector4a myMax;
-	myMax.setAdd(mBounds[0], mBounds[1]);
-
-	validateDrawMap();
-
-	for (element_iter i = getDataBegin(); i != getDataEnd(); ++i)
-	{
-		LLDrawable* drawable = *i;
-		sg_assert(drawable->getSpatialGroup() == this);
-		if (drawable->getSpatialBridge())
-		{
-			sg_assert(drawable->getSpatialBridge() == getSpatialPartition()->asBridge());
-		}
-
-		/*if (drawable->isSpatialBridge())
-		{
-			LLSpatialPartition* part = drawable->asPartition();
-			if (!part)
-			{
-				LL_ERRS() << "Drawable reports it is a spatial bridge but not a partition." << LL_ENDL;
-			}
-			LLSpatialGroup* group = (LLSpatialGroup*) part->mOctree->getListener(0);
-			group->validate();
-		}*/
-	}
-
-	for (U32 i = 0; i < mOctreeNode->getChildCount(); ++i)
-	{
-		LLSpatialGroup* group = (LLSpatialGroup*) mOctreeNode->getChild(i)->getListener(0);
-
-		group->validate();
-		
-		//ensure all children are enclosed in this node
-		LLVector4a center = group->mBounds[0];
-		LLVector4a size = group->mBounds[1];
-		
-		LLVector4a min;
-		min.setSub(center, size);
-		LLVector4a max;
-		max.setAdd(center, size);
-		
-		for (U32 j = 0; j < 3; j++)
-		{
-			sg_assert(min[j] >= myMin[j]-0.02f);
-			sg_assert(max[j] <= myMax[j]+0.02f);
-		}
-	}
-
-#endif
-}
-
-void LLSpatialGroup::validateDrawMap()
-{
-#if LL_OCTREE_PARANOIA_CHECK
-	for (draw_map_t::iterator i = mDrawMap.begin(); i != mDrawMap.end(); ++i)
-	{
-		LLSpatialGroup::drawmap_elem_t& draw_vec = i->second;
-		for (drawmap_elem_t::iterator j = draw_vec.begin(); j != draw_vec.end(); ++j)
-		{
-			LLDrawInfo& params = **j;
-		
-			params.validate();
-		}
-	}
-#endif
-}
-
-BOOL LLSpatialGroup::updateInGroup(LLDrawable *drawablep, BOOL immediate)
-{
-	drawablep->updateSpatialExtents();
-
-	OctreeNode* parent = mOctreeNode->getOctParent();
-	
-	if (mOctreeNode->isInside(drawablep->getPositionGroup()) && 
-		(mOctreeNode->contains(drawablep->getEntry()) ||
-		 (drawablep->getBinRadius() > mOctreeNode->getSize()[0] &&
-				parent && parent->getElementCount() >= gOctreeMaxCapacity)))
-	{
-		unbound();
-		setState(OBJECT_DIRTY);
-		//setState(GEOM_DIRTY);
-		return TRUE;
-	}
-		
-	return FALSE;
-}
-
-
-BOOL LLSpatialGroup::addObject(LLDrawable *drawablep)
-{
-	if(!drawablep)
-	{
-		return FALSE;
-	}
-	{
-		drawablep->setGroup(this);
-		setState(OBJECT_DIRTY | GEOM_DIRTY);
-		setOcclusionState(LLSpatialGroup::DISCARD_QUERY, LLSpatialGroup::STATE_MODE_ALL_CAMERAS);
-		gPipeline.markRebuild(this, TRUE);
-		if (drawablep->isSpatialBridge())
-		{
-			mBridgeList.push_back((LLSpatialBridge*) drawablep);
-		}
-		if (drawablep->getRadius() > 1.f)
-		{
-			setState(IMAGE_DIRTY);
-		}
-	}
-
-	return TRUE;
-}
-
-void LLSpatialGroup::rebuildGeom()
-{
-	if (!isDead())
-	{
-		getSpatialPartition()->rebuildGeom(this);
-
-		if (hasState(LLSpatialGroup::MESH_DIRTY))
-		{
-			gPipeline.markMeshDirty(this);
-		}
-	}
-}
-
-void LLSpatialGroup::rebuildMesh()
-{
-	if (!isDead())
-	{
-		getSpatialPartition()->rebuildMesh(this);
-	}
-}
-
-static LLTrace::BlockTimerStatHandle FTM_REBUILD_VBO("VBO Rebuilt");
-static LLTrace::BlockTimerStatHandle FTM_ADD_GEOMETRY_COUNT("Add Geometry");
-static LLTrace::BlockTimerStatHandle FTM_CREATE_VB("Create VB");
-static LLTrace::BlockTimerStatHandle FTM_GET_GEOMETRY("Get Geometry");
-
-void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group)
-{
-	if (group->isDead() || !group->hasState(LLSpatialGroup::GEOM_DIRTY))
-	{
-		return;
-	}
-
-	if (group->changeLOD())
-	{
-		group->mLastUpdateDistance = group->mDistance;
-		group->mLastUpdateViewAngle = group->mViewAngle;
-	}
-	
-	LL_RECORD_BLOCK_TIME(FTM_REBUILD_VBO);	
-
-	group->clearDrawMap();
-	
-	//get geometry count
-	U32 index_count = 0;
-	U32 vertex_count = 0;
-
-	{
-		LL_RECORD_BLOCK_TIME(FTM_ADD_GEOMETRY_COUNT);
-		addGeometryCount(group, vertex_count, index_count);
-	}
-
-	if (vertex_count > 0 && index_count > 0)
-	{ //create vertex buffer containing volume geometry for this node
-		{
-			LL_RECORD_BLOCK_TIME(FTM_CREATE_VB);
-			group->mBuilt = 1.f;
-			if (group->mVertexBuffer.isNull() ||
-				!group->mVertexBuffer->isWriteable() ||
-				(group->mBufferUsage != (U32)group->mVertexBuffer->getUsage() && LLVertexBuffer::sEnableVBOs))
-			{
-				group->mVertexBuffer = createVertexBuffer(mVertexDataMask, group->mBufferUsage);
-				if (!group->mVertexBuffer->allocateBuffer(vertex_count, index_count, true))
-				{
-					LL_WARNS() << "Failed to allocate Vertex Buffer on rebuild to "
-						<< vertex_count << " vertices and "
-						<< index_count << " indices" << LL_ENDL;
-					group->mVertexBuffer = NULL;
-					group->mBufferMap.clear();
-				}
-				stop_glerror();
-			}
-			else
-			{
-				if (!group->mVertexBuffer->resizeBuffer(vertex_count, index_count))
-				{
-					// Is likely to cause a crash. If this gets triggered find a way to avoid it (don't forget to reset face)
-					LL_WARNS() << "Failed to resize Vertex Buffer on rebuild to "
-						<< vertex_count << " vertices and "
-						<< index_count << " indices" << LL_ENDL;
-					group->mVertexBuffer = NULL;
-					group->mBufferMap.clear();
-				}
-				stop_glerror();
-			}
-		}
-
-		if (group->mVertexBuffer)
-		{
-			LL_RECORD_BLOCK_TIME(FTM_GET_GEOMETRY);
-			getGeometry(group);
-		}
-	}
-	else
-	{
-		group->mVertexBuffer = NULL;
-		group->mBufferMap.clear();
-	}
-
-	group->mLastUpdateTime = gFrameTimeSeconds;
-	group->clearState(LLSpatialGroup::GEOM_DIRTY);
-}
-
-
-void LLSpatialPartition::rebuildMesh(LLSpatialGroup* group)
-{
-
-}
-
-LLSpatialGroup* LLSpatialGroup::getParent()
-{
-	return (LLSpatialGroup*)LLViewerOctreeGroup::getParent();
-	}
-
-BOOL LLSpatialGroup::removeObject(LLDrawable *drawablep, BOOL from_octree)
-	{
-	if(!drawablep)
-	{
-		return FALSE;
-	}
-
-	unbound();
-	if (mOctreeNode && !from_octree)
-	{
-		drawablep->setGroup(NULL);
-	}
-	else
-	{
-		drawablep->setGroup(NULL);
-		setState(GEOM_DIRTY);
-		gPipeline.markRebuild(this, TRUE);
-
-		if (drawablep->isSpatialBridge())
-		{
-			for (bridge_list_t::iterator i = mBridgeList.begin(); i != mBridgeList.end(); ++i)
-			{
-				if (*i == drawablep)
-				{
-					mBridgeList.erase(i);
-					break;
-				}
-			}
-		}
-
-		if (getElementCount() == 0)
-		{ //delete draw map on last element removal since a rebuild might never happen
-			clearDrawMap();
-		}
-	}
-	return TRUE;
-}
-
-void LLSpatialGroup::shift(const LLVector4a &offset)
-{
-	LLVector4a t = mOctreeNode->getCenter();
-	t.add(offset);	
-	mOctreeNode->setCenter(t);
-	mOctreeNode->updateMinMax();
-	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 (!getSpatialPartition()->mRenderByGroup && 
-		getSpatialPartition()->mPartitionType != LLViewerRegion::PARTITION_TREE &&
-		getSpatialPartition()->mPartitionType != LLViewerRegion::PARTITION_TERRAIN &&
-		getSpatialPartition()->mPartitionType != LLViewerRegion::PARTITION_BRIDGE)
-	{
-		setState(GEOM_DIRTY);
-		gPipeline.markRebuild(this, TRUE);
-	}
-}
-
-class LLSpatialSetState : public OctreeTraveler
-{
-public:
-	U32 mState;
-	LLSpatialSetState(U32 state) : mState(state) { }
-    void visit(const OctreeNode* branch) final override { ((LLSpatialGroup*) branch->getListener(0))->setState(mState); }	
-};
-
-class LLSpatialSetStateDiff final : public LLSpatialSetState
-{
-public:
-	LLSpatialSetStateDiff(U32 state) : LLSpatialSetState(state) { }
-
-    void traverse(const OctreeNode* n) override
-	{
-		LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
-		
-		if (!group->hasState(mState))
-		{
-			OctreeTraveler::traverse(n);
-		}
-	}
-};
-
-void LLSpatialGroup::setState(U32 state, S32 mode) 
-{
-	llassert(state <= LLSpatialGroup::STATE_MASK);
-	
-	if (mode > STATE_MODE_SINGLE)
-	{
-		if (mode == STATE_MODE_DIFF)
-		{
-			LLSpatialSetStateDiff setter(state);
-			setter.traverse(mOctreeNode);
-		}
-		else
-		{
-			LLSpatialSetState setter(state);
-			setter.traverse(mOctreeNode);
-		}
-	}
-	else
-	{
-		mState |= state;
-	}
-}
-
-class LLSpatialClearState : public OctreeTraveler
-{
-public:
-	U32 mState;
-	LLSpatialClearState(U32 state) : mState(state) { }
-    void visit(const OctreeNode* branch) final override { ((LLSpatialGroup*) branch->getListener(0))->clearState(mState); }
-};
-
-class LLSpatialClearStateDiff final : public LLSpatialClearState
-{
-public:
-	LLSpatialClearStateDiff(U32 state) : LLSpatialClearState(state) { }
-
-    void traverse(const OctreeNode* n) override
-	{
-		LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
-		
-		if (group->hasState(mState))
-		{
-			OctreeTraveler::traverse(n);
-		}
-	}
-};
-
-void LLSpatialGroup::clearState(U32 state, S32 mode)
-{
-	llassert(state <= LLSpatialGroup::STATE_MASK);
-
-	if (mode > STATE_MODE_SINGLE)
-	{
-		if (mode == STATE_MODE_DIFF)
-		{
-			LLSpatialClearStateDiff clearer(state);
-			clearer.traverse(mOctreeNode);
-		}
-		else
-		{
-			LLSpatialClearState clearer(state);
-			clearer.traverse(mOctreeNode);
-		}
-	}
-	else
-	{
-		mState &= ~state;
-	}
-}
-
-//======================================
-//		Octree Listener Implementation
-//======================================
-
-LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) : LLOcclusionCullingGroup(node, part),
-	mObjectBoxSize(1.f),
-	mGeometryBytes(0),
-	mSurfaceArea(0.f),
-	mBuilt(0.f),
-	mVertexBuffer(NULL), 
-	mBufferUsage(part->mBufferUsage),
-	mDistance(0.f),
-	mDepth(0.f),
-	mLastUpdateDistance(-1.f), 
-	mLastUpdateTime(gFrameTimeSeconds)
-{
-	ll_assert_aligned(this,16);
-	
-	sNodeCount++;
-
-	mViewAngle.splat(0.f);
-	mLastUpdateViewAngle.splat(-1.f);
-
-	sg_assert(mOctreeNode->getListenerCount() == 0);
-	setState(SG_INITIAL_STATE_MASK);
-	gPipeline.markRebuild(this, TRUE);
-
-	mRadius = 1;
-	mPixelArea = 1024.f;
-}
-
-void LLSpatialGroup::updateDistance(LLCamera &camera)
-{
-	if (LLViewerCamera::sCurCameraID != LLViewerCamera::CAMERA_WORLD)
-	{
-		LL_WARNS() << "Attempted to update distance for camera other than world camera!" << LL_ENDL;
-		return;
-	}
-
-	if (gShiftFrame)
-	{
-		return;
-	}
-
-#if !LL_RELEASE_FOR_DOWNLOAD
-	if (hasState(LLSpatialGroup::OBJECT_DIRTY))
-	{
-		LL_ERRS() << "Spatial group dirty on distance update." << LL_ENDL;
-	}
-#endif
-	if (!isEmpty())
-	{
-		mRadius = getSpatialPartition()->mRenderByGroup ? mObjectBounds[1].getLength3().getF32() :
-						(F32) mOctreeNode->getSize().getLength3().getF32();
-		mDistance = getSpatialPartition()->calcDistance(this, camera);
-		mPixelArea = getSpatialPartition()->calcPixelArea(this, camera);
-	}
-}
-
-F32 LLSpatialPartition::calcDistance(LLSpatialGroup* group, LLCamera& camera)
-{
-	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())
-	{
-		LLVector4a v = eye;
-
-		dist = eye.getLength3().getF32();
-		eye.normalize3fast();
-
-		if (!group->hasState(LLSpatialGroup::ALPHA_DIRTY))
-		{
-			if (!group->getSpatialPartition()->isBridge())
-			{
-				LLVector4a view_angle = eye;
-
-				LLVector4a diff;
-				diff.setSub(view_angle, group->mLastUpdateViewAngle);
-
-				if (diff.getLength3().getF32() > 0.64f)
-				{
-					group->mViewAngle = view_angle;
-					group->mLastUpdateViewAngle = view_angle;
-					//for occasional alpha sorting within the group
-					//NOTE: If there is a trivial way to detect that alpha sorting here would not change the render order,
-					//not setting this node to dirty would be a very good thing
-					group->setState(LLSpatialGroup::ALPHA_DIRTY);
-					gPipeline.markRebuild(group, FALSE);
-				}
-			}
-		}
-
-		//calculate depth of node for alpha sorting
-
-		LLVector3 at = camera.getAtAxis();
-
-		LLVector4a ata;
-		ata.load3(at.mV);
-
-		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.getLength3().getF32();
-	}
-
-    LL_DEBUGS("RiggedBox") << "calcDistance, group " << group << " camera " << origin << " obj bounds " 
-                           << group->mObjectBounds[0] << ", " << group->mObjectBounds[1] 
-                           << " dist " << dist << " radius " << group->mRadius << LL_ENDL;
-
-	if (dist < 16.f)
-	{
-		dist /= 16.f;
-		dist *= dist;
-		dist *= 16.f;
-	}
-
-	return dist;
-}
-
-F32 LLSpatialPartition::calcPixelArea(LLSpatialGroup* group, LLCamera& camera)
-{
-	return LLPipeline::calcPixelArea(group->mObjectBounds[0], group->mObjectBounds[1], camera);
-}
-
-F32 LLSpatialGroup::getUpdateUrgency() const
-{
-	if (!isVisible())
-	{
-		return 0.f;
-	}
-	else
-	{
-		F32 time = gFrameTimeSeconds-mLastUpdateTime+4.f;
-		return time + (mObjectBounds[1].dot3(mObjectBounds[1]).getF32()+1.f)/mDistance;
-	}
-}
-
-BOOL LLSpatialGroup::changeLOD()
-{
-	if (hasState(ALPHA_DIRTY | OBJECT_DIRTY))
-	{
-		//a rebuild is going to happen, update distance and LoD
-		return TRUE;
-	}
-
-	if (getSpatialPartition()->mSlopRatio > 0.f)
-	{
-		F32 ratio = (mDistance - mLastUpdateDistance)/(llmax(mLastUpdateDistance, mRadius));
-
-        // MAINT-8264 - this check is not robust if it needs to work
-        // for bounding boxes much larger than the actual enclosed
-        // objects, and using distance to box center is also
-        // problematic. Consider the case that you have a large box
-        // where the enclosed object is in one corner. As you zoom in
-        // on the corner, the object gets much closer to the camera,
-        // but the distance to the box center changes very little, and
-        // an LOD change will not trigger, so object LOD gets "stuck"
-        // at a too-low value. In the case of the above JIRA, the box
-        // was large only due to another error, so this logic did not
-        // need to be changed.
-
-		if (fabsf(ratio) >= getSpatialPartition()->mSlopRatio)
-		{
-            LL_DEBUGS("RiggedBox") << "changeLOD true because of ratio compare "
-                                   << fabsf(ratio) << " " << getSpatialPartition()->mSlopRatio << LL_ENDL;
-            LL_DEBUGS("RiggedBox") << "sg " << this << "\nmDistance " << mDistance
-                                   << " mLastUpdateDistance " << mLastUpdateDistance
-                                   << " mRadius " << mRadius
-                                   << " fab ratio " << fabsf(ratio) 
-                                   << " slop " << getSpatialPartition()->mSlopRatio << LL_ENDL;
-       
-			return TRUE;
-		}
-
-		if (mDistance > mRadius*2.f)
-		{
-			return FALSE;
-		}
-	}
-	
-	if (needsUpdate())
-	{
-		return TRUE;
-	}
-	
-	return FALSE;
-}
-
-void LLSpatialGroup::handleInsertion(const TreeNode* node, LLViewerOctreeEntry* entry)
-{
-	addObject((LLDrawable*)entry->getDrawable());
-	unbound();
-	setState(OBJECT_DIRTY);
-}
-
-void LLSpatialGroup::handleRemoval(const TreeNode* node, LLViewerOctreeEntry* entry)
-{
-	removeObject((LLDrawable*)entry->getDrawable(), TRUE);
-	LLViewerOctreeGroup::handleRemoval(node, entry);
-}
-
-void LLSpatialGroup::handleDestruction(const TreeNode* node)
-{
-	if(isDead())
-	{
-		return;
-	}
-	setState(DEAD);	
-
-	for (element_iter i = getDataBegin(), i_end = getDataEnd(); i != i_end; ++i)
-	{
-		LLViewerOctreeEntry* entry = *i;
-
-		if (entry->getGroup() == this)
-		{
-			if(entry->hasDrawable())
-			{
-				((LLDrawable*)entry->getDrawable())->setGroup(NULL);
-			}
-		}
-	}
-	
-	clearDrawMap();
-	mVertexBuffer = NULL;
-	mBufferMap.clear();
-	sZombieGroups++;
-	mOctreeNode = NULL;
-}
-
-void LLSpatialGroup::handleChildAddition(const OctreeNode* parent, OctreeNode* child) 
-{
-	if (child->getListenerCount() == 0)
-	{
-		new LLSpatialGroup(child, getSpatialPartition());
-	}
-	else
-	{
-		OCT_ERRS << "LLSpatialGroup redundancy detected." << LL_ENDL;
-	}
-
-	unbound();
-
-	assert_states_valid(this);
-}
-
-void LLSpatialGroup::destroyGL(bool keep_occlusion) 
-{
-	setState(LLSpatialGroup::GEOM_DIRTY | LLSpatialGroup::IMAGE_DIRTY);
-
-	if (!keep_occlusion)
-	{ //going to need a rebuild
-		gPipeline.markRebuild(this, TRUE);
-	}
-
-	mLastUpdateTime = gFrameTimeSeconds;
-	mVertexBuffer = NULL;
-	mBufferMap.clear();
-
-	clearDrawMap();
-
-	if (!keep_occlusion)
-	{
-		releaseOcclusionQueryObjectNames();
-	}
-
-
-	for (LLSpatialGroup::element_iter i = getDataBegin(), i_end = getDataEnd(); i != i_end; ++i)
-	{
-		LLDrawable* drawable = (LLDrawable*)(*i)->getDrawable();
-		if(!drawable)
-		{
-			continue;
-		}
-		for (S32 j = 0; j < drawable->getNumFaces(); j++)
-		{
-			LLFace* facep = drawable->getFace(j);
-			if (facep)
-			{
-				facep->clearVertexBuffer();
-			}
-		}
-	}
-}
-
-//==============================================
-
-LLSpatialPartition::LLSpatialPartition(U32 data_mask, BOOL render_by_group, U32 buffer_usage, LLViewerRegion* regionp)
-: mBridge(NULL), mRenderByGroup(render_by_group)
-{
-	mRegionp = regionp;		
-	mPartitionType = LLViewerRegion::PARTITION_NONE;
-	mVertexDataMask = data_mask;
-	mBufferUsage = buffer_usage;
-	mDepthMask = FALSE;
-	mSlopRatio = 0.25f;
-	mInfiniteFarClip = FALSE;
-
-	new LLSpatialGroup(mOctree, this);
-}
-
-LLSpatialGroup *LLSpatialPartition::put(LLDrawable *drawablep, BOOL was_visible)
-{
-	drawablep->updateSpatialExtents();
-
-	//keep drawable from being garbage collected
-	LLPointer<LLDrawable> ptr = drawablep;
-		
-	if(!drawablep->getGroup())
-	{
-	assert_octree_valid(mOctree);
-		mOctree->insert(drawablep->getEntry());
-	assert_octree_valid(mOctree);
-	}	
-	
-	LLSpatialGroup* group = drawablep->getSpatialGroup();
-	llassert(group != NULL);
-
-	if (group && was_visible && group->isOcclusionState(LLSpatialGroup::QUERY_PENDING))
-	{
-		group->setOcclusionState(LLSpatialGroup::DISCARD_QUERY, LLSpatialGroup::STATE_MODE_ALL_CAMERAS);
-	}
-
-	return group;
-}
-
-BOOL LLSpatialPartition::remove(LLDrawable *drawablep, LLSpatialGroup *curp)
-{
-	if (!curp->removeObject(drawablep))
-	{
-		OCT_ERRS << "Failed to remove drawable from octree!" << LL_ENDL;
-	}
-	else
-	{
-		drawablep->setGroup(NULL);
-	}
-
-	assert_octree_valid(mOctree);
-	
-	return TRUE;
-}
-
-void LLSpatialPartition::move(LLDrawable *drawablep, LLSpatialGroup *curp, BOOL immediate)
-{
-	// sanity check submitted by open source user bushing Spatula
-	// who was seeing crashing here. (See VWR-424 reported by Bunny Mayne)
-	if (!drawablep)
-	{
-		OCT_ERRS << "LLSpatialPartition::move was passed a bad drawable." << LL_ENDL;
-		return;
-	}
-		
-	BOOL was_visible = curp ? curp->isVisible() : FALSE;
-
-	if (curp && curp->getSpatialPartition() != this)
-	{
-		//keep drawable from being garbage collected
-		LLPointer<LLDrawable> ptr = drawablep;
-		if (curp->getSpatialPartition()->remove(drawablep, curp))
-		{
-			put(drawablep, was_visible);
-			return;
-		}
-		else
-		{
-			OCT_ERRS << "Drawable lost between spatial partitions on outbound transition." << LL_ENDL;
-		}
-	}
-		
-	if (curp && curp->updateInGroup(drawablep, immediate))
-	{
-		// Already updated, don't need to do anything
-		assert_octree_valid(mOctree);
-		return;
-	}
-
-	//keep drawable from being garbage collected
-	LLPointer<LLDrawable> ptr = drawablep;
-	if (curp && !remove(drawablep, curp))
-	{
-		OCT_ERRS << "Move couldn't find existing spatial group!" << LL_ENDL;
-	}
-
-	put(drawablep, was_visible);
-}
-
-class LLSpatialShift final : public OctreeTraveler
-{
-public:
-	const LLVector4a& mOffset;
-
-	LLSpatialShift(const LLVector4a& offset) : mOffset(offset) { }
-
-    void visit(const OctreeNode* branch) override
-	{ 
-		((LLSpatialGroup*) branch->getListener(0))->shift(mOffset); 
-	}
-};
-
-void LLSpatialPartition::shift(const LLVector4a &offset)
-{ //shift octree node bounding boxes by offset
-	LLSpatialShift shifter(offset);
-	shifter.traverse(mOctree);
-}
-
-class LLOctreeCull : public LLViewerOctreeCull
-{
-public:
-	LLOctreeCull(LLCamera* camera) : LLViewerOctreeCull(camera) {}
-
-    bool earlyFail(LLViewerOctreeGroup* base_group) override
-	{
-		LLSpatialGroup* group = (LLSpatialGroup*)base_group;
-		group->checkOcclusion();
-
-		if (group->getOctreeNode()->getParent() &&	//never occlusion cull the root node
-		  	LLPipeline::sUseOcclusion &&			//ignore occlusion if disabled
-			group->isOcclusionState(LLSpatialGroup::OCCLUDED))
-		{
-			gPipeline.markOccluder(group);
-			return true;
-		}
-		
-		return false;
-	}
-
-    S32 frustumCheck(const LLViewerOctreeGroup* group) override
-	{
-		S32 res = AABBInFrustumNoFarClipGroupBounds(group);
-		if (res != 0)
-		{
-			res = llmin(res, AABBSphereIntersectGroupExtents(group));
-		}
-		return res;
-	}
-
-    S32 frustumCheckObjects(const LLViewerOctreeGroup* group) override
-	{
-		S32 res = AABBInFrustumNoFarClipObjectBounds(group);
-		if (res != 0)
-		{
-			res = llmin(res, AABBSphereIntersectObjectExtents(group));
-		}
-		return res;
-	}
-
-    void processGroup(LLViewerOctreeGroup* base_group) override
-	{
-		LLSpatialGroup* group = (LLSpatialGroup*)base_group;
-		if (group->needsUpdate() ||
-			group->getVisible(LLViewerCamera::sCurCameraID) < LLDrawable::getCurrentFrame() - 1)
-		{
-			group->doOcclusion(mCamera);
-		}
-		gPipeline.markNotCulled(group, *mCamera);
-	}
-};
-
-class LLOctreeCullNoFarClip final : public LLOctreeCull
-{
-public: 
-	LLOctreeCullNoFarClip(LLCamera* camera) 
-		: LLOctreeCull(camera) { }
-
-    S32 frustumCheck(const LLViewerOctreeGroup* group) override
-	{
-		return AABBInFrustumNoFarClipGroupBounds(group);
-	}
-
-    S32 frustumCheckObjects(const LLViewerOctreeGroup* group) override
-	{
-		S32 res = AABBInFrustumNoFarClipObjectBounds(group);
-		return res;
-	}
-};
-
-class LLOctreeCullShadow : public LLOctreeCull
-{
-public:
-	LLOctreeCullShadow(LLCamera* camera)
-		: LLOctreeCull(camera) { }
-
-    S32 frustumCheck(const LLViewerOctreeGroup* group) final override
-	{
-		return AABBInFrustumGroupBounds(group);
-	}
-
-    S32 frustumCheckObjects(const LLViewerOctreeGroup* group) final override
-	{
-		return AABBInFrustumObjectBounds(group);
-	}
-};
-
-class LLOctreeCullVisExtents final: public LLOctreeCullShadow
-{
-public:
-	LLOctreeCullVisExtents(LLCamera* camera, LLVector4a& min, LLVector4a& max)
-		: LLOctreeCullShadow(camera), mEmpty(TRUE), mMin(min), mMax(max) { }
-
-    bool earlyFail(LLViewerOctreeGroup* base_group) override
-	{
-		LLSpatialGroup* group = (LLSpatialGroup*)base_group;
-
-		if (group->getOctreeNode()->getParent() &&	//never occlusion cull the root node
-			LLPipeline::sUseOcclusion &&			//ignore occlusion if disabled
-			group->isOcclusionState(LLSpatialGroup::OCCLUDED))
-		{
-			return true;
-		}
-		
-		return false;
-	}
-
-    void traverse(const OctreeNode* n) override
-	{
-		LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
-
-		if (earlyFail(group))
-		{
-			return;
-		}
-		
-		if ((mRes && group->hasState(LLSpatialGroup::SKIP_FRUSTUM_CHECK)) ||
-			mRes == 2)
-		{	//don't need to do frustum check
-			OctreeTraveler::traverse(n);
-		}
-		else
-		{  
-			mRes = frustumCheck(group);
-				
-			if (mRes)
-			{ //at least partially in, run on down
-				OctreeTraveler::traverse(n);
-			}
-
-			mRes = 0;
-		}
-	}
-
-    void processGroup(LLViewerOctreeGroup* base_group) override
-	{
-		LLSpatialGroup* group = (LLSpatialGroup*)base_group;
-		
-		llassert(!group->hasState(LLSpatialGroup::DIRTY) && !group->isEmpty());
-		
-		if (mRes < 2)
-		{
-			if (AABBInFrustumObjectBounds(group) > 0)
-			{
-				mEmpty = FALSE;
-				const LLVector4a* exts = group->getObjectExtents();
-				update_min_max(mMin, mMax, exts[0]);
-				update_min_max(mMin, mMax, exts[1]);
-			}
-		}
-		else
-		{
-			mEmpty = FALSE;
-			const LLVector4a* exts = group->getExtents();
-			update_min_max(mMin, mMax, exts[0]);
-			update_min_max(mMin, mMax, exts[1]);
-		}
-	}
-
-	BOOL mEmpty;
-	LLVector4a& mMin;
-	LLVector4a& mMax;
-};
-
-class LLOctreeCullDetectVisible final: public LLOctreeCullShadow
-{
-public:
-	LLOctreeCullDetectVisible(LLCamera* camera)
-		: LLOctreeCullShadow(camera), mResult(FALSE) { }
-
-    bool earlyFail(LLViewerOctreeGroup* base_group) override
-	{
-		LLSpatialGroup* group = (LLSpatialGroup*)base_group;
-
-		if (mResult || //already found a node, don't check any more
-			(group->getOctreeNode()->getParent() &&	//never occlusion cull the root node
-			 LLPipeline::sUseOcclusion &&			//ignore occlusion if disabled
-			 group->isOcclusionState(LLSpatialGroup::OCCLUDED)))
-		{
-			return true;
-		}
-		
-		return false;
-	}
-
-    void processGroup(LLViewerOctreeGroup* base_group) override
-	{
-		if (base_group->isVisible())
-		{
-			mResult = TRUE;
-		}
-	}
-
-	BOOL mResult;
-};
-
-class LLOctreeSelect final : public LLOctreeCull
-{
-public:
-	LLOctreeSelect(LLCamera* camera, std::vector<LLDrawable*>* results)
-		: LLOctreeCull(camera), mResults(results) { }
-
-    bool earlyFail(LLViewerOctreeGroup* group) override { return false; }
-    void preprocess(LLViewerOctreeGroup* group) override { }
-
-    void processGroup(LLViewerOctreeGroup* base_group) override
-	{
-		LLSpatialGroup* group = (LLSpatialGroup*)base_group;
-		OctreeNode* branch = group->getOctreeNode();
-
-		for (OctreeNode::const_element_iter i = branch->getDataBegin(), i_end = branch->getDataEnd(); i != i_end; ++i)
-		{
-			LLDrawable* drawable = (LLDrawable*)(*i)->getDrawable();
-			if(!drawable)
-		{
-				continue;
-			}
-			if (!drawable->isDead())
-			{
-				if (drawable->isSpatialBridge())
-				{
-					drawable->setVisible(*mCamera, mResults, TRUE);
-				}
-				else
-				{
-					mResults->push_back(drawable);
-				}
-			}		
-		}
-	}
-	
-	std::vector<LLDrawable*>* mResults;
-};
-
-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);
-	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,1))).mV);
-	//right front
-	gGL.vertex3fv((c+r.scaledVec(LLVector3(1,1,-1))).mV);
-	gGL.vertex3fv((c+r.scaledVec(LLVector3(1,1,1))).mV);
-	//right back
- 	gGL.vertex3fv((c+r.scaledVec(LLVector3(1,-1,-1))).mV);
-	gGL.vertex3fv((c+r.scaledVec(LLVector3(1,-1,1))).mV);
-	//left back
-	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,-1,-1))).mV);
-	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,-1,1))).mV);
-	//left front
-	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,-1))).mV);
-	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,1))).mV);
-	gGL.end();
-	
-	//bottom
-	gGL.begin(LLRender::TRIANGLE_STRIP);
-	gGL.vertex3fv((c+r.scaledVec(LLVector3(1,1,-1))).mV);
-	gGL.vertex3fv((c+r.scaledVec(LLVector3(1,-1,-1))).mV);
-	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,-1))).mV);
-	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,-1,-1))).mV);
-	gGL.end();
-
-	//top
-	gGL.begin(LLRender::TRIANGLE_STRIP);
-	gGL.vertex3fv((c+r.scaledVec(LLVector3(1,1,1))).mV);
-	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,1))).mV);
-	gGL.vertex3fv((c+r.scaledVec(LLVector3(1,-1,1))).mV);
-	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,-1,1))).mV);
-	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)
-{
-
-	llassert(pos.isFinite());
-	llassert(size.isFinite());
-
-	llassert(!llisnan(pos.mV[0]));
-	llassert(!llisnan(pos.mV[1]));
-	llassert(!llisnan(pos.mV[2]));
-
-	llassert(!llisnan(size.mV[0]));
-	llassert(!llisnan(size.mV[1]));
-	llassert(!llisnan(size.mV[2]));
-
-	LLVector3 v1 = size.scaledVec(LLVector3( 1, 1,1));
-	LLVector3 v2 = size.scaledVec(LLVector3(-1, 1,1));
-	LLVector3 v3 = size.scaledVec(LLVector3(-1,-1,1));
-	LLVector3 v4 = size.scaledVec(LLVector3( 1,-1,1));
-
-	gGL.begin(LLRender::LINES); 
-	
-	//top
-	gGL.vertex3fv((pos+v1).mV);
-	gGL.vertex3fv((pos+v2).mV);
-	gGL.vertex3fv((pos+v2).mV);
-	gGL.vertex3fv((pos+v3).mV);
-	gGL.vertex3fv((pos+v3).mV);
-	gGL.vertex3fv((pos+v4).mV);
-	gGL.vertex3fv((pos+v4).mV);
-	gGL.vertex3fv((pos+v1).mV);
-	
-	//bottom
-	gGL.vertex3fv((pos-v1).mV);
-	gGL.vertex3fv((pos-v2).mV);
-	gGL.vertex3fv((pos-v2).mV);
-	gGL.vertex3fv((pos-v3).mV);
-	gGL.vertex3fv((pos-v3).mV);
-	gGL.vertex3fv((pos-v4).mV);
-	gGL.vertex3fv((pos-v4).mV);
-	gGL.vertex3fv((pos-v1).mV);
-	
-	//right
-	gGL.vertex3fv((pos+v1).mV);
-	gGL.vertex3fv((pos-v3).mV);
-			
-	gGL.vertex3fv((pos+v4).mV);
-	gGL.vertex3fv((pos-v2).mV);
-
-	//left
-	gGL.vertex3fv((pos+v2).mV);
-	gGL.vertex3fv((pos-v4).mV);
-
-	gGL.vertex3fv((pos+v3).mV);
-	gGL.vertex3fv((pos-v1).mV);
-
-	gGL.end();
-}
-
-void drawBoxOutline(const LLVector4a& pos, const LLVector4a& size)
-{
-	drawBoxOutline(reinterpret_cast<const LLVector3&>(pos), reinterpret_cast<const LLVector3&>(size));
-}
-
-class LLOctreeDirty final : public OctreeTraveler
-{
-public:
-	LLOctreeDirty(bool no_rebuild) : mNoRebuild(no_rebuild){}
-
-    void visit(const OctreeNode* state) override
-	{
-		LLSpatialGroup* group = (LLSpatialGroup*) state->getListener(0);
-		group->destroyGL();
-
-		for (LLSpatialGroup::element_iter i = group->getDataBegin(), i_end = group->getDataEnd(); i != i_end; ++i)
-		{
-			LLDrawable* drawable = (LLDrawable*)(*i)->getDrawable();
-			if(!drawable)
-			{
-				continue;
-			}
-			if (drawable->getVObj().notNull())
-			{
-				drawable->getVObj()->resetVertexBuffers();
-			}
-			if (!mNoRebuild && drawable->getVObj().notNull() && !group->getSpatialPartition()->mRenderByGroup)
-			{
-				gPipeline.markRebuild(drawable, LLDrawable::REBUILD_ALL, TRUE);
-			}
-		}
-
-		for (LLSpatialBridge* bridge : group->mBridgeList)
-		{
-			traverse(bridge->mOctree);
-		}
-	}
-
-private:
-	BOOL mNoRebuild;
-};
-
-void LLSpatialPartition::restoreGL()
-{
-}
-
-void LLSpatialPartition::resetVertexBuffers()
-{
-	LLOctreeDirty dirty(sTeleportRequested);
-	dirty.traverse(mOctree);
-}
-
-BOOL LLSpatialPartition::getVisibleExtents(LLCamera& camera, LLVector3& visMin, LLVector3& visMax)
-{
-	LLVector4a visMina, visMaxa;
-	visMina.load3(visMin.mV);
-	visMaxa.load3(visMax.mV);
-
-	{
-		LL_RECORD_BLOCK_TIME(FTM_CULL_REBOUND);		
-		LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0);
-		group->rebound();
-	}
-
-	LLOctreeCullVisExtents vis(&camera, visMina, visMaxa);
-	vis.traverse(mOctree);
-
-	visMin.set(visMina.getF32ptr());
-	visMax.set(visMaxa.getF32ptr());
-	return vis.mEmpty;
-}
-
-BOOL LLSpatialPartition::visibleObjectsInFrustum(LLCamera& camera)
-{
-	LLOctreeCullDetectVisible vis(&camera);
-	vis.traverse(mOctree);
-	return vis.mResult;
-}
-
-S32 LLSpatialPartition::cull(LLCamera &camera, std::vector<LLDrawable *>* results, BOOL for_select)
-{
-#if LL_OCTREE_PARANOIA_CHECK
-	((LLSpatialGroup*)mOctree->getListener(0))->checkStates();
-#endif
-	{
-		LL_RECORD_BLOCK_TIME(FTM_CULL_REBOUND);		
-		LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0);
-		group->rebound();
-	}
-
-#if LL_OCTREE_PARANOIA_CHECK
-	((LLSpatialGroup*)mOctree->getListener(0))->validate();
-#endif
-
-		LLOctreeSelect selecter(&camera, results);
-		selecter.traverse(mOctree);
-	
-	return 0;
-	}
-	
-S32 LLSpatialPartition::cull(LLCamera &camera, bool do_occlusion)
-{
-#if LL_OCTREE_PARANOIA_CHECK
-	((LLSpatialGroup*)mOctree->getListener(0))->checkStates();
-#endif
-	{
-		LL_RECORD_BLOCK_TIME(FTM_CULL_REBOUND);		
-		LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0);
-		group->rebound();
-	}
-
-#if LL_OCTREE_PARANOIA_CHECK
-	((LLSpatialGroup*)mOctree->getListener(0))->validate();
-#endif
-
-	if (LLPipeline::sShadowRender)
-	{
-		LL_RECORD_BLOCK_TIME(FTM_FRUSTUM_CULL);
-		LLOctreeCullShadow culler(&camera);
-		culler.traverse(mOctree);
-	}
-	else if (mInfiniteFarClip || !LLPipeline::sUseFarClip)
-	{
-		LL_RECORD_BLOCK_TIME(FTM_FRUSTUM_CULL);		
-		LLOctreeCullNoFarClip culler(&camera);
-		culler.traverse(mOctree);
-	}
-	else
-	{
-		LL_RECORD_BLOCK_TIME(FTM_FRUSTUM_CULL);		
-		LLOctreeCull culler(&camera);
-		culler.traverse(mOctree);
-	}
-	
-	return 0;
-}
-
-void pushVerts(LLDrawInfo* params, U32 mask)
-{
-	LLRenderPass::applyModelMatrix(*params);
-	params->mVertexBuffer->setBuffer(mask);
-	params->mVertexBuffer->drawRange(params->mParticle ? LLRender::POINTS : LLRender::TRIANGLES,
-								params->mStart, params->mEnd, params->mCount, params->mOffset);
-}
-
-void pushVerts(LLSpatialGroup* group, U32 mask)
-{
-	for (auto& pair : group->mDrawMap)
-	{
-		for (LLDrawInfo* params : pair.second)
-		{
-			pushVerts(params, mask);
-		}
-	}
-}
-
-void pushVerts(LLFace* face, U32 mask)
-{
-	if (face)
-	{
-		llassert(face->verify());
-
-		LLVertexBuffer* buffer = face->getVertexBuffer();
-
-		if (buffer && (face->getGeomCount() >= 3))
-		{
-			buffer->setBuffer(mask);
-			U16 start = face->getGeomStart();
-			U16 end = start + face->getGeomCount()-1;
-			U32 count = face->getIndicesCount();
-			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);
-		LLVertexBuffer::drawElements(LLRender::TRIANGLES, face.mNumVertices, face.mPositions, NULL, face.mNumIndices, face.mIndices);
-	}
-}
-
-void pushBufferVerts(LLVertexBuffer* buffer, U32 mask)
-{
-	if (buffer)
-	{
-		buffer->setBuffer(mask);
-		buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
-	}
-}
-
-void pushBufferVerts(LLSpatialGroup* group, U32 mask, bool push_alpha = true)
-{
-	if (group->getSpatialPartition()->mRenderByGroup)
-	{
-		if (!group->mDrawMap.empty())
-		{
-			LLDrawInfo* params = *(group->mDrawMap.begin()->second.begin());
-			LLRenderPass::applyModelMatrix(*params);
-		
-			if (push_alpha)
-			{
-				pushBufferVerts(group->mVertexBuffer, mask);
-			}
-
-			for (auto& buff_pair : group->mBufferMap)
-			{
-				for (auto& buff_tex_pair : buff_pair.second)
-				{
-					for (LLVertexBuffer* buff : buff_tex_pair.second)
-					{
-						pushBufferVerts(buff, mask);
-					}
-				}
-			}
-		}
-	}
-	/*else
-	{
-		//const LLVector4a* bounds = group->getBounds();
-		//drawBox(bounds[0], bounds[1]);
-	}*/
-}
-
-void pushVertsColorCoded(LLSpatialGroup* group, U32 mask)
-{
-	LLDrawInfo* params = NULL;
-
-	static const std::array<LLColor4, 7> colors {{
-		LLColor4::green,
-		LLColor4::green1,
-		LLColor4::green2,
-		LLColor4::green3,
-		LLColor4::green4,
-		LLColor4::green5,
-		LLColor4::green6
-	}};
-
-	U32 col = 0;
-
-	for (auto& i : group->mDrawMap)
-    {
-		for (auto& j : i.second)
-        {
-			params = j;
-			LLRenderPass::applyModelMatrix(*params);
-			gGL.diffuseColor4f(colors[col].mV[0], colors[col].mV[1], colors[col].mV[2], 0.5f);
-			params->mVertexBuffer->setBuffer(mask);
-			params->mVertexBuffer->drawRange(params->mParticle ? LLRender::POINTS : LLRender::TRIANGLES,
-				params->mStart, params->mEnd, params->mCount, params->mOffset);
-			col = (col+1)%colors.size();
-		}
-	}
-}
-
-void renderOctree(LLSpatialGroup* group)
-{
-	//render solid object bounding box, color
-	//coded by buffer usage and activity
-	gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA);
-	LLVector4 col;
-	if (group->mBuilt > 0.f)
-	{
-		group->mBuilt -= 2.f * gFrameIntervalSeconds.value();
-		if (group->mBufferUsage == GL_STATIC_DRAW_ARB)
-		{
-			col.setVec(1.0f, 0, 0, group->mBuilt*0.5f);
-		}
-		else 
-		{
-			col.setVec(0.1f,0.1f,1,0.1f);
-			//col.setVec(1.0f, 1.0f, 0, sinf(group->mBuilt*3.14159f)*0.5f);
-		}
-
-		if (group->mBufferUsage != GL_STATIC_DRAW_ARB)
-		{
-			LLGLDepthTest gl_depth(FALSE, FALSE);
-			glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
-
-			gGL.diffuseColor4f(1,0,0,group->mBuilt);
-			gGL.flush();
-			gGL.setLineWidth(5.f);
-
-			const LLVector4a* bounds = group->getObjectBounds();
-			drawBoxOutline(bounds[0], bounds[1]);
-			gGL.flush();
-			gGL.setLineWidth(1.f);
-			gGL.flush();
-			for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i)
-			{
-				LLDrawable* drawable = (LLDrawable*)(*i)->getDrawable();
-				if(!drawable)
-				{
-					continue;
-				}
-				if (!group->getSpatialPartition()->isBridge())
-				{
-					gGL.pushMatrix();
-					LLVector3 trans = drawable->getRegion()->getOriginAgent();
-					gGL.translatef(trans.mV[0], trans.mV[1], trans.mV[2]);
-				}
-				
-				for (S32 j = 0; j < drawable->getNumFaces(); j++)
-				{
-					LLFace* face = drawable->getFace(j);
-					if (face && face->getVertexBuffer())
-					{
-						if (gFrameTimeSeconds - face->mLastUpdateTime < 0.5f)
-						{
-							gGL.diffuseColor4f(0, 1, 0, group->mBuilt);
-						}
-						else if (gFrameTimeSeconds - face->mLastMoveTime < 0.5f)
-						{
-							gGL.diffuseColor4f(1, 0, 0, group->mBuilt);
-						}
-						else
-						{
-							continue;
-						}
-
-						face->getVertexBuffer()->setBuffer(LLVertexBuffer::MAP_VERTEX);
-						//drawBox((face->mExtents[0] + face->mExtents[1])*0.5f,
-						//		(face->mExtents[1]-face->mExtents[0])*0.5f);
-						face->getVertexBuffer()->draw(LLRender::TRIANGLES, face->getIndicesCount(), face->getIndicesStart());
-					}
-				}
-
-				if (!group->getSpatialPartition()->isBridge())
-				{
-					gGL.popMatrix();
-				}
-			}
-			glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
-			gGL.diffuseColor4f(1,1,1,1);
-		}
-	}
-	else
-	{
-		if (group->mBufferUsage == GL_STATIC_DRAW_ARB && !group->isEmpty() 
-			&& group->getSpatialPartition()->mRenderByGroup)
-		{
-			col.setVec(0.8f, 0.4f, 0.1f, 0.1f);
-		}
-		else
-		{
-			col.setVec(0.1f, 0.1f, 1.f, 0.1f);
-		}
-	}
-
-	gGL.diffuseColor4fv(col.mV);
-	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);
-
-	//if (group->mBuilt <= 0.f)
-	{
-		//draw opaque outline
-		//gGL.diffuseColor4f(col.mV[0], col.mV[1], col.mV[2], 1.f);
-		//drawBoxOutline(group->mObjectBounds[0], group->mObjectBounds[1]);
-
-		gGL.diffuseColor4f(0,1,1,1);
-
-		const LLVector4a* bounds = group->getBounds();
-		drawBoxOutline(bounds[0], bounds[1]);
-		
-		//draw bounding box for draw info
-		/*if (group->getSpatialPartition()->mRenderByGroup)
-		{
-			gGL.diffuseColor4f(1.0f, 0.75f, 0.25f, 0.6f);
-			for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i)
-			{
-				for (LLSpatialGroup::drawmap_elem_t::iterator j = i->second.begin(); j != i->second.end(); ++j)
-				{
-					LLDrawInfo* draw_info = *j;
-					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);
-				}
-			}
-		}*/
-	}
-	
-//	LLSpatialGroup::OctreeNode* node = group->mOctreeNode;
-//	gGL.diffuseColor4f(0,1,0,1);
-//	drawBoxOutline(LLVector3(node->getCenter()), LLVector3(node->getSize()));
-}
-
-std::set<LLSpatialGroup*> visible_selected_groups;
-
-void renderVisibility(LLSpatialGroup* group, LLCamera* camera)
-{
-	/*LLGLEnable blend(GL_BLEND);
-	gGL.setSceneBlendType(LLRender::BT_ALPHA);
-	LLGLEnable cull(GL_CULL_FACE);
-	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);*/
-
-	/*BOOL render_objects = (!LLPipeline::sUseOcclusion || !group->isOcclusionState(LLSpatialGroup::OCCLUDED)) && group->isVisible() &&
-							!group->isEmpty();
-
-
-	if (render_objects)
-	{
-		LLGLDepthTest depth(GL_TRUE, GL_FALSE);
-
-		LLGLDisable blend(GL_BLEND);
-		gGL.diffuseColor4f(0.f, 0.75f, 0.f,0.5f);
-		pushBufferVerts(group, LLVertexBuffer::MAP_VERTEX, false);
-		
-		glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
-		gGL.setLineWidth(4.f);
-		gGL.diffuseColor4f(0.f, 0.5f, 0.f, 1.f);
-		pushBufferVerts(group, LLVertexBuffer::MAP_VERTEX, false);
-		gGL.setLineWidth(1.f);
-		glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
-
-		bool selected = false;
-		
-		for (LLSpatialGroup::element_iter iter = group->getDataBegin(); iter != group->getDataEnd(); ++iter)
-		{
-			LLDrawable* drawable = *iter;
-			if (drawable->getVObj().notNull() && drawable->getVObj()->isSelected())
-			{
-				selected = true;
-				break;
-			}
-		}
-		
-		if (selected)
-		{ //store for rendering occlusion volume as overlay
-			visible_selected_groups.insert(group);
-		}
-	}*/		
-
-	/*if (render_objects)
-	{
-		LLGLDepthTest depth_under(GL_TRUE, GL_FALSE, GL_GREATER);
-		gGL.diffuseColor4f(0, 0.5f, 0, 0.5f);
-		pushBufferVerts(group, LLVertexBuffer::MAP_VERTEX);
-	}
-
-	{
-		LLGLDepthTest depth_over(GL_TRUE, GL_FALSE, GL_LEQUAL);
-
-		if (render_objects)
-		{
-			gGL.diffuseColor4f(0.f, 0.5f, 0.f,1.f);
-			pushBufferVerts(group, LLVertexBuffer::MAP_VERTEX);
-		}
-
-		glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
-
-		if (render_objects)
-		{
-			gGL.diffuseColor4f(0.f, 0.75f, 0.f,0.5f);
-			pushBufferVerts(group, LLVertexBuffer::MAP_VERTEX);
-		
-			bool selected = false;
-		
-			for (LLSpatialGroup::element_iter iter = group->getDataBegin(); iter != group->getDataEnd(); ++iter)
-			{
-				LLDrawable* drawable = *iter;
-				if (drawable->getVObj().notNull() && drawable->getVObj()->isSelected())
-				{
-					selected = true;
-					break;
-				}
-			}
-		
-			if (selected)
-			{ //store for rendering occlusion volume as overlay
-				visible_selected_groups.insert(group);
-			}
-		}		
-	}*/
-}
-
-void renderXRay(LLSpatialGroup* group, LLCamera* camera)
-{
-	BOOL render_objects = (!LLPipeline::sUseOcclusion || !group->isOcclusionState(LLSpatialGroup::OCCLUDED)) && group->isVisible() &&
-							!group->isEmpty();
-	
-	if (render_objects)
-	{
-		pushBufferVerts(group, LLVertexBuffer::MAP_VERTEX, false);
-
-		bool selected = false;
-
-		for (LLSpatialGroup::element_iter iter = group->getDataBegin(); iter != group->getDataEnd(); ++iter)
-		{
-			LLDrawable* drawable = (LLDrawable*)(*iter)->getDrawable();
-			if (drawable->getVObj().notNull() && drawable->getVObj()->isSelected())
-			{
-				selected = true;
-				break;
-			}
-		}
-
-		if (selected)
-		{ //store for rendering occlusion volume as overlay
-
-			if (!group->getSpatialPartition()->isBridge())
-			{
-				visible_selected_groups.insert(group);
-			}
-			else
-			{
-				visible_selected_groups.insert(group->getSpatialPartition()->asBridge()->getSpatialGroup());
-			}
-		}
-	}
-}
-
-void renderCrossHairs(LLVector3 position, F32 size, LLColor4 color)
-{
-	gGL.color4fv(color.mV);
-	gGL.begin(LLRender::LINES);
-	{
-		gGL.vertex3fv((position - LLVector3(size, 0.f, 0.f)).mV);
-		gGL.vertex3fv((position + LLVector3(size, 0.f, 0.f)).mV);
-		gGL.vertex3fv((position - LLVector3(0.f, size, 0.f)).mV);
-		gGL.vertex3fv((position + LLVector3(0.f, size, 0.f)).mV);
-		gGL.vertex3fv((position - LLVector3(0.f, 0.f, size)).mV);
-		gGL.vertex3fv((position + LLVector3(0.f, 0.f, size)).mV);
-	}
-	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:
-		gGL.diffuseColor4f(0,1,0,0.5f);
-		break;
-	case OUT_TERSE_IMPROVED:
-		gGL.diffuseColor4f(0,1,1,0.5f);
-		break;
-	case OUT_FULL_COMPRESSED:
-		if (vobj->getLastUpdateCached())
-		{
-			gGL.diffuseColor4f(1,0,0,0.5f);
-		}
-		else
-		{
-			gGL.diffuseColor4f(1,1,0,0.5f);
-		}
-		break;
-	case OUT_FULL_CACHED:
-		gGL.diffuseColor4f(0,0,1,0.5f);
-		break;
-	default:
-		LL_WARNS() << "Unknown update_type " << vobj->getLastUpdateType() << LL_ENDL;
-		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 renderComplexityDisplay(LLDrawable* drawablep)
-{
-	LLViewerObject* vobj = drawablep->getVObj();
-	if (!vobj)
-	{
-		return;
-	}
-
-	LLVOVolume *voVol = vobj->asVolume();;
-
-	if (!voVol)
-	{
-		return;
-	}
-
-	if (!voVol->isRoot())
-	{
-		return;
-	}
-
-	LLVOVolume::texture_cost_t textures;
-	F32 cost = (F32) voVol->getRenderCost(textures);
-
-	// add any child volumes
-	LLViewerObject::const_child_list_t children = voVol->getChildren();
-	for (const auto& iter : children)
-    {
-		const LLViewerObject *child = iter;
-		const LLVOVolume *child_volume = dynamic_cast<const LLVOVolume*>(child);
-		if (child_volume)
-		{
-			cost += child_volume->getRenderCost(textures);
-		}
-	}
-
-	// add texture cost
-	for (auto& texture : textures)
-    {
-		// add the cost of each individual texture in the linkset
-		cost += texture.second;
-	}
-
-	F32 cost_max = (F32) LLVOVolume::getRenderComplexityMax();
-
-
-
-	// allow user to set a static color scale
-	if (gSavedSettings.getS32("RenderComplexityStaticMax") > 0)
-	{
-		cost_max = gSavedSettings.getS32("RenderComplexityStaticMax");
-	}
-
-	F32 cost_ratio = cost / cost_max;
-	
-	// cap cost ratio at 1.0f in case cost_max is at a low threshold
-	cost_ratio = cost_ratio > 1.0f ? 1.0f : cost_ratio;
-	
-	LLGLEnable blend(GL_BLEND);
-
-	LLColor4 color;
-	const LLColor4 color_min = gSavedSettings.getColor4("RenderComplexityColorMin");
-	const LLColor4 color_mid = gSavedSettings.getColor4("RenderComplexityColorMid");
-	const LLColor4 color_max = gSavedSettings.getColor4("RenderComplexityColorMax");
-
-	if (cost_ratio < 0.5f)
-	{
-		color = color_min * (1 - cost_ratio * 2) + color_mid * (cost_ratio * 2);
-	}
-	else
-	{
-		color = color_mid * (1 - (cost_ratio - 0.5) * 2) + color_max * ((cost_ratio - 0.5) * 2);
-	}
-
-	LLSD color_val = color.getValue();
-
-	// don't highlight objects below the threshold
-	if (cost > gSavedSettings.getS32("RenderComplexityThreshold"))
-	{
-		gGL.diffuseColor4f(color[0],color[1],color[2],0.5f);
-
-
-		S32 num_faces = drawablep->getNumFaces();
-		if (num_faces)
-		{
-			for (S32 i = 0; i < num_faces; ++i)
-			{
-				pushVerts(drawablep->getFace(i), LLVertexBuffer::MAP_VERTEX);
-			}
-		}
-		LLViewerObject::const_child_list_t children = voVol->getChildren();
-		for (const auto& iter : children)
-        {
-			const LLViewerObject *child = iter;
-			if (child)
-			{
-				num_faces = child->getNumFaces();
-				if (num_faces)
-				{
-					for (S32 i = 0; i < num_faces; ++i)
-					{
-						pushVerts(child->mDrawable->getFace(i), LLVertexBuffer::MAP_VERTEX);
-					}
-				}
-			}
-		}
-	}
-	
-	voVol->setDebugText(llformat("%4.0f", cost));	
-}
-
-void renderBoundingBox(LLDrawable* drawable, BOOL set_color = TRUE)
-{
-	if (set_color)
-	{
-		if (drawable->isSpatialBridge())
-		{
-			gGL.diffuseColor4f(1,0.5f,0,1); // orange
-		}
-		else if (drawable->getVOVolume())
-		{ 
-            if (drawable->isRoot())
-			{
-				gGL.diffuseColor4f(1,1,0,1); // yellow
-			}
-			else
-			{
-				gGL.diffuseColor4f(0,1,0,1); // green
-			}
-		}
-		else if (drawable->getVObj())
-		{
-			switch (drawable->getVObj()->getPCode())
-			{
-				case LLViewerObject::LL_VO_SURFACE_PATCH:
-                    	gGL.diffuseColor4f(0,1,1,1); // cyan
-						break;
-				case LLViewerObject::LL_VO_CLOUDS:
-						// no longer used
-						break;
-				case LLViewerObject::LL_VO_PART_GROUP:
-				case LLViewerObject::LL_VO_HUD_PART_GROUP:
-                    	gGL.diffuseColor4f(0,0,1,1); // blue
-						break;
-				case LLViewerObject::LL_VO_VOID_WATER:
-				case LLViewerObject::LL_VO_WATER:
-                    	gGL.diffuseColor4f(0,0.5f,1,1); // medium blue
-						break;
-				case LL_PCODE_LEGACY_TREE:
-                    	gGL.diffuseColor4f(0,0.5f,0,1); // dark green
-						break;
-				default:
-						auto avatar = drawable->getVObj()->asAvatar();
-						if (avatar->isControlAvatar())
-						{
-							LLControlAvatar* cav = static_cast<LLControlAvatar*>(avatar);
-							bool has_pos_constraint = (cav->mPositionConstraintFixup != LLVector3());
-							bool has_scale_constraint = (cav->mScaleConstraintFixup != 1.0f);
-							if (has_pos_constraint || has_scale_constraint)
-							{
-								gGL.diffuseColor4f(1,0,0,1); 
-							}
-							else
-							{
-								gGL.diffuseColor4f(0,1,0.5,1); 
-							}
-						}
-						else
-						{
-							gGL.diffuseColor4f(1,0,1,1); // magenta
-						}
-						break;
-			}
-		}
-		else 
-		{
-			gGL.diffuseColor4f(1,0,0,1);
-		}
-	}
-
-	const LLVector4a* ext;
-	LLVector4a pos, size;
-
-	if (drawable->getVOVolume())
-	{
-		//render face bounding boxes
-		for (S32 i = 0; i < drawable->getNumFaces(); i++)
-		{
-			LLFace* facep = drawable->getFace(i);
-			if (facep)
-			{
-				ext = facep->mExtents;
-
-				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.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())
-	{
-		gGL.flush();
-		gGL.setLineWidth(llmax(4.f*sinf(gFrameTimeSeconds*2.f)+1.f, 1.f));
-		//gGL.setLineWidth(4.f*(sinf(gFrameTimeSeconds*2.f)*0.25f+0.75f));
-		stop_glerror();
-		drawBoxOutline(pos,size);
-		gGL.flush();
-		gGL.setLineWidth(1.f);
-	}
-	else
-	{
-		drawBoxOutline(pos,size);
-	}
-}
-
-void renderNormals(LLDrawable* drawablep)
-{
-	LLVertexBuffer::unbind();
-
-	LLVOVolume* vol = drawablep->getVOVolume();
-	if (vol)
-	{
-		LLVolume* volume = vol->getVolume();
-		gGL.pushMatrix();
-		gGL.multMatrix((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);
-
-			for (S32 j = 0; j < face.mNumVertices; ++j)
-			{
-				gGL.begin(LLRender::LINES);
-				LLVector4a n,p;
-				
-				n.setMul(face.mNormals[j], scale);
-				p.setAdd(face.mPositions[j], n);
-				
-				gGL.diffuseColor4f(1,1,1,1);
-				gGL.vertex3fv(face.mPositions[j].getF32ptr());
-				gGL.vertex3fv(p.getF32ptr());
-				
-				if (face.mTangents)
-				{
-					n.setMul(face.mTangents[j], scale);
-					p.setAdd(face.mPositions[j], n);
-				
-					gGL.diffuseColor4f(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())
-		{
-			gGL.diffuseColor4fv(color.mV);
-			LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mBaseHullMesh.mPositions, decomp->mBaseHullMesh.mNormals);
-		}
-		else
-		{
-			gMeshRepo.buildPhysicsMesh(*decomp);
-			gGL.diffuseColor4f(0,1,1,1);
-			drawBoxOutline(center, size);
-		}
-
-	}
-	else
-	{
-		gGL.diffuseColor3f(1,0,1);
-		drawBoxOutline(center, size);
-	}
-}
-
-void render_hull(LLModel::PhysicsMesh& mesh, const LLColor4& color, const LLColor4& line_color)
-{
-	gGL.diffuseColor4fv(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);
-	gGL.setLineWidth(3.f);
-	gGL.diffuseColor4fv(line_color.mV);
-	LLVertexBuffer::drawArrays(LLRender::TRIANGLES, mesh.mPositions, mesh.mNormals);
-	gGL.setLineWidth(1.f);
-	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
-}
-
-void renderPhysicsShape(LLDrawable* drawable, LLVOVolume* volume)
-{
-	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();
-	gGL.multMatrix((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 (auto& i : decomp->mMesh)
-                {		
-					render_hull(i, color, line_color);
-				}
-			}
-			else if (!decomp->mPhysicsShapeMesh.empty())
-			{ 
-				//decomp has physics mesh, render that mesh
-				gGL.diffuseColor4fv(color.mV);
-				LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mPhysicsShapeMesh.mPositions, decomp->mPhysicsShapeMesh.mNormals);
-								
-				glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
-				gGL.diffuseColor4fv(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.diffuseColor3f(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);
-		}
-		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.emplace_back(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 && phys_volume->mHullIndices && phys_volume->mNumHullPoints > 0 && phys_volume->mNumHullIndices > 0)
-			{
-				//render hull
-			
-				glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
-				
-				gGL.diffuseColor4fv(line_color.mV);
-				LLVertexBuffer::unbind();
-
-				llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShader != 0);
-							
-				LLVertexBuffer::drawElements(LLRender::TRIANGLES, phys_volume->mNumHullPoints, phys_volume->mHullPoints, NULL, phys_volume->mNumHullIndices, phys_volume->mHullIndices);
-				
-				gGL.diffuseColor4fv(color.mV);
-				glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
-				LLVertexBuffer::drawElements(LLRender::TRIANGLES, phys_volume->mNumHullPoints, phys_volume->mHullPoints, NULL, phys_volume->mNumHullIndices, phys_volume->mHullIndices);
-				
-			}
-			else
-			{
-				gGL.diffuseColor4f(1,0,1,1);
-				drawBoxOutline(center, size);
-			}
-
-			LLPrimitive::sVolumeManager->unrefVolume(phys_volume);
-		}
-	}
-	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.diffuseColor4fv(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);
-		
-		gGL.diffuseColor4fv(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);
-		
-		gGL.diffuseColor4fv(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);
-		
-		gGL.diffuseColor4fv(line_color.mV);
-		pushVerts(phys_volume);
-		
-		gGL.diffuseColor4fv(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)
-		{
-			gGL.diffuseColor4fv(line_color.mV);
-			glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
-			LLVertexBuffer::drawElements(LLRender::TRIANGLES, phys_volume->mNumHullPoints, phys_volume->mHullPoints, NULL, phys_volume->mNumHullIndices, phys_volume->mHullIndices);
-
-			gGL.diffuseColor4fv(color.mV);
-			glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
-			LLVertexBuffer::drawElements(LLRender::TRIANGLES, phys_volume->mNumHullPoints, phys_volume->mHullPoints, NULL, phys_volume->mNumHullIndices, phys_volume->mHullIndices);
-		}
-		else
-		{
-			gGL.diffuseColor3f(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 
-	{
-		LL_ERRS() << "Unhandled type" << LL_ENDL;
-	}
-
-	gGL.popMatrix();
-}
-
-void renderPhysicsShapes(LLSpatialGroup* group)
-{
-	for (OctreeNode::const_element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i)
-	{
-		LLDrawable* drawable = (LLDrawable*)(*i)->getDrawable();
-		if(!drawable)
-	{
-			continue;
-		}
-
-		if (drawable->isSpatialBridge())
-		{
-			LLSpatialBridge* bridge = drawable->asPartition()->asBridge();
-
-			if (bridge)
-			{
-				gGL.pushMatrix();
-				gGL.multMatrix((F32*)bridge->mDrawable->getRenderMatrix().mMatrix);
-				bridge->renderPhysicsShapes();
-				gGL.popMatrix();
-			}
-		}
-		else
-		{
-			LLVOVolume* volume = drawable->getVOVolume();
-			if (volume && !volume->isAttachment() && volume->getPhysicsShapeType() != LLViewerObject::PHYSICS_SHAPE_NONE )
-			{
-				if (!group->getSpatialPartition()->isBridge())
-				{
-					gGL.pushMatrix();
-					LLVector3 trans = drawable->getRegion()->getOriginAgent();
-					gGL.translatef(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)
-				{
-					gGL.pushMatrix();
-					gGL.multMatrix((F32*) object->getRegion()->mRenderMatrix.mMatrix);
-					//push face vertices for terrain
-					for (S32 i = 0; i < drawable->getNumFaces(); ++i)
-					{
-						LLFace* face = drawable->getFace(i);
-						if (face)
-						{
-							LLVertexBuffer* buff = face->getVertexBuffer();
-							if (buff)
-							{
-								glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
-
-								buff->setBuffer(LLVertexBuffer::MAP_VERTEX);
-								gGL.diffuseColor3f(0.2f, 0.5f, 0.3f);
-								buff->draw(LLRender::TRIANGLES, buff->getNumIndices(), 0);
-									
-								gGL.diffuseColor3f(0.2f, 1.f, 0.3f);
-								glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
-								buff->draw(LLRender::TRIANGLES, buff->getNumIndices(), 0);
-							}
-						}
-					}
-					gGL.popMatrix();
-				}
-			}
-		}
-	}
-}
-
-void renderTexturePriority(LLDrawable* drawable)
-{
-	for (int face=0; face<drawable->getNumFaces(); ++face)
-	{
-		LLFace *facep = drawable->getFace(face);
-		
-		LLVector4 cold(0,0,0.25f);
-		LLVector4 hot(1,0.25f,0.25f);
-	
-		LLVector4 boost_cold(0,0,0,0);
-		LLVector4 boost_hot(0,1,0,1);
-		
-		LLGLDisable blend(GL_BLEND);
-		
-		//LLViewerTexture* imagep = facep->getTexture();
-		//if (imagep)
-		if (facep)
-		{
-				
-			//F32 vsize = imagep->mMaxVirtualSize;
-			F32 vsize = facep->getPixelArea();
-
-			if (vsize > sCurMaxTexPriority)
-			{
-				sCurMaxTexPriority = vsize;
-			}
-			
-			F32 t = vsize/sLastMaxTexPriority;
-			
-			LLVector4 col = lerp(cold, hot, t);
-			gGL.diffuseColor4fv(col.mV);
-		}
-		//else
-		//{
-		//	gGL.diffuseColor4f(1,0,1,1);
-		//}
-		
-		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();
-		if (boost>LLGLTexture::BOOST_NONE)
-		{
-			F32 t = (F32) boost / (F32) (LLGLTexture::BOOST_MAX_LEVEL-1);
-			LLVector4 col = lerp(boost_cold, boost_hot, t);
-			LLGLEnable blend_on(GL_BLEND);
-			gGL.blendFunc(GL_SRC_ALPHA, GL_ONE);
-			gGL.diffuseColor4fv(col.mV);
-			drawBox(center, size);
-			gGL.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-		}*/
-	}
-}
-
-void renderPoints(LLDrawable* drawablep)
-{
-	LLGLDepthTest depth(GL_FALSE, GL_FALSE);
-	if (drawablep->getNumFaces())
-	{
-		gGL.begin(LLRender::POINTS);
-		gGL.diffuseColor3f(1,1,1);
-		for (S32 i = 0; i < drawablep->getNumFaces(); i++)
-		{
-			LLFace * face = drawablep->getFace(i);
-			if (face)
-			{
-				gGL.vertex3fv(face->mCenterLocal.mV);
-			}
-		}
-		gGL.end();
-	}
-}
-
-void renderTextureAnim(LLDrawInfo* params)
-{
-	if (!params->mTextureMatrix)
-	{
-		return;
-	}
-	
-	LLGLEnable blend(GL_BLEND);
-	gGL.diffuseColor4f(1,1,0,0.5f);
-	pushVerts(params, LLVertexBuffer::MAP_VERTEX);
-}
-
-void renderBatchSize(LLDrawInfo* params)
-{
-	LLGLEnable offset(GL_POLYGON_OFFSET_FILL);
-	glPolygonOffset(-1.f, 1.f);
-	if (params->mDebugColor == LLColor4U::black)
-	{
-		params->mDebugColor = LLColor4U(ll_rand(255), ll_rand(255), ll_rand(255), 255U);
-	}
-	gGL.diffuseColor4ubv((U8*)params->mDebugColor.mV);
-	pushVerts(params, LLVertexBuffer::MAP_VERTEX);
-}
-
-void renderShadowFrusta(LLDrawInfo* params)
-{
-	LLGLEnable blend(GL_BLEND);
-	gGL.setSceneBlendType(LLRender::BT_ADD);
-
-	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))
-	{
-		gGL.diffuseColor3f(1,0,0);
-		pushVerts(params, LLVertexBuffer::MAP_VERTEX);
-	}
-	if (gPipeline.mShadowCamera[5].AABBInFrustum(center, size))
-	{
-		gGL.diffuseColor3f(0,1,0);
-		pushVerts(params, LLVertexBuffer::MAP_VERTEX);
-	}
-	if (gPipeline.mShadowCamera[6].AABBInFrustum(center, size))
-	{
-		gGL.diffuseColor3f(0,0,1);
-		pushVerts(params, LLVertexBuffer::MAP_VERTEX);
-	}
-	if (gPipeline.mShadowCamera[7].AABBInFrustum(center, size))
-	{
-		gGL.diffuseColor3f(1,0,1);
-		pushVerts(params, LLVertexBuffer::MAP_VERTEX);
-	}
-
-	gGL.setSceneBlendType(LLRender::BT_ALPHA);
-}
-
-void renderTexelDensity(LLDrawable* drawable)
-{
-	if (LLViewerTexture::sDebugTexelsMode == LLViewerTexture::DEBUG_TEXELS_OFF
-		|| LLViewerTexture::sCheckerBoardImagep.isNull())
-	{
-		return;
-	}
-
-	LLGLEnable _(GL_BLEND);
-	//gObjectFullbrightProgram.bind();
-
-	LLMatrix4 checkerboard_matrix;
-	S32 discard_level = -1;
-
-	for (S32 f = 0; f < drawable->getNumFaces(); f++)
-	{
-		LLFace* facep = drawable->getFace(f);
-		LLVertexBuffer* buffer = facep->getVertexBuffer();
-		LLViewerTexture* texturep = facep->getTexture();
-
-		if (texturep == NULL) continue;
-
-		switch(LLViewerTexture::sDebugTexelsMode)
-		{
-		case LLViewerTexture::DEBUG_TEXELS_CURRENT:
-			discard_level = -1;
-			break;
-		case LLViewerTexture::DEBUG_TEXELS_DESIRED:
-			{
-				LLViewerFetchedTexture* fetched_texturep = dynamic_cast<LLViewerFetchedTexture*>(texturep);
-				discard_level = fetched_texturep ? fetched_texturep->getDesiredDiscardLevel() : -1;
-				break;
-			}
-		default:
-		case LLViewerTexture::DEBUG_TEXELS_FULL:
-			discard_level = 0;
-			break;
-		}
-
-		checkerboard_matrix.initScale(LLVector3(texturep->getWidth(discard_level) / 8, texturep->getHeight(discard_level) / 8, 1.f));
-
-		gGL.getTexUnit(0)->bind(LLViewerTexture::sCheckerBoardImagep, TRUE);
-		gGL.matrixMode(LLRender::MM_TEXTURE);
-		gGL.loadMatrix((GLfloat*)&checkerboard_matrix.mMatrix);
-
-		if (buffer && (facep->getGeomCount() >= 3))
-		{
-			buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0);
-			U16 start = facep->getGeomStart();
-			U16 end = start + facep->getGeomCount()-1;
-			U32 count = facep->getIndicesCount();
-			U16 offset = facep->getIndicesStart();
-			buffer->drawRange(LLRender::TRIANGLES, start, end, count, offset);
-		}
-
-		gGL.loadIdentity();
-		gGL.matrixMode(LLRender::MM_MODELVIEW);
-	}
-
-	//S32 num_textures = llmax(1, (S32)params->mTextureList.size());
-
-	//for (S32 i = 0; i < num_textures; i++)
-	//{
-	//	LLViewerTexture* texturep = params->mTextureList.empty() ? params->mTexture.get() : params->mTextureList[i].get();
-	//	if (texturep == NULL) continue;
-
-	//	LLMatrix4 checkboard_matrix;
-	//	S32 discard_level = -1;
-	//	switch(LLViewerTexture::sDebugTexelsMode)
-	//	{
-	//	case LLViewerTexture::DEBUG_TEXELS_CURRENT:
-	//		discard_level = -1;
-	//		break;
-	//	case LLViewerTexture::DEBUG_TEXELS_DESIRED:
-	//		{
-	//			LLViewerFetchedTexture* fetched_texturep = dynamic_cast<LLViewerFetchedTexture*>(texturep);
-	//			discard_level = fetched_texturep ? fetched_texturep->getDesiredDiscardLevel() : -1;
-	//			break;
-	//		}
-	//	default:
-	//	case LLViewerTexture::DEBUG_TEXELS_FULL:
-	//		discard_level = 0;
-	//		break;
-	//	}
-
-	//	checkboard_matrix.initScale(LLVector3(texturep->getWidth(discard_level) / 8, texturep->getHeight(discard_level) / 8, 1.f));
-	//	gGL.getTexUnit(i)->activate();
-
-	//	glMatrixMode(GL_TEXTURE);
-	//	glPushMatrix();
-	//	glLoadIdentity();
-	//	//gGL.matrixMode(LLRender::MM_TEXTURE);
-	//	glLoadMatrixf((GLfloat*) checkboard_matrix.mMatrix);
-
-	//	gGL.getTexUnit(i)->bind(LLViewerTexture::sCheckerBoardImagep, TRUE);
-
-	//	pushVerts(params, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_NORMAL );
-
-	//	glPopMatrix();
-	//	glMatrixMode(GL_MODELVIEW);
-	//	//gGL.matrixMode(LLRender::MM_MODELVIEW);
-	//}
-}
-
-
-void renderLights(LLDrawable* drawablep)
-{
-	if (!drawablep->isLight())
-	{
-		return;
-	}
-
-	if (drawablep->getNumFaces())
-	{
-		LLGLEnable blend(GL_BLEND);
-		gGL.diffuseColor4f(0,1,1,0.5f);
-
-		for (S32 i = 0; i < drawablep->getNumFaces(); i++)
-		{
-			LLFace * face = drawablep->getFace(i);
-			if (face)
-			{
-				pushVerts(face, LLVertexBuffer::MAP_VERTEX);
-			}
-		}
-
-		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.diffuseColor4f(1,1,1,1);
-			drawBoxOutline(pos, size);
-		}
-
-		gGL.diffuseColor4f(1,1,0,1);
-		F32 rad = drawablep->getVOVolume()->getLightRadius();
-		drawBoxOutline(pos, LLVector4a(rad));
-	}
-}
-
-class LLRenderOctreeRaycast final : public LLOctreeTriangleRayIntersect
-{
-public:
-	
-	
-	LLRenderOctreeRaycast(const LLVector4a& start, const LLVector4a& dir, F32* closest_t)
-		: LLOctreeTriangleRayIntersect(start, dir, NULL, closest_t, NULL, NULL, NULL, NULL)
-	{
-
-	}
-
-	void visit(const LLOctreeNode<LLVolumeTriangle>* branch) override
-	{
-		LLVolumeOctreeListener* vl = (LLVolumeOctreeListener*) branch->getListener(0);
-
-		LLVector3 center, size;
-		
-		if (branch->isEmpty())
-		{
-			gGL.diffuseColor3f(1.f,0.2f,0.f);
-			center.set(branch->getCenter().getF32ptr());
-			size.set(branch->getSize().getF32ptr());
-		}
-		else
-		{
-			gGL.diffuseColor3f(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.diffuseColor4f(0,1,1,0.5f);
-			}
-			else
-			{
-				gGL.diffuseColor4f(0,0.5f,0.5f, 0.25f);
-				drawBoxOutline(center, size);
-			}
-			
-			if (i == 1)
-			{
-				gGL.flush();
-				gGL.setLineWidth(3.f);
-			}
-
-			gGL.begin(LLRender::TRIANGLES);
-			for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter = branch->getDataBegin();
-					iter != branch->getDataEnd();
-					++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();
-				gGL.setLineWidth(1.f);
-			}
-		}
-	}
-};
-
-void renderRaycast(LLDrawable* drawablep)
-{
-	if (drawablep->getNumFaces())
-	{
-		LLGLEnable blend(GL_BLEND);
-		gGL.diffuseColor4f(0,1,1,0.5f);
-
-		if (drawablep->getVOVolume())
-		{
-			//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);
-					
-					gGL.pushMatrix();
-					gGL.translatef(trans.mV[0], trans.mV[1], trans.mV[2]);					
-					gGL.multMatrix((F32*) vobj->getRelativeXform().mMatrix);
-
-					LLVector4a start, end;
-					if (transform)
-					{
-						LLVector3 v_start(gDebugRaycastStart.getF32ptr());
-						LLVector3 v_end(gDebugRaycastEnd.getF32ptr());
-
-						v_start = vobj->agentPositionToVolume(v_start);
-						v_end = vobj->agentPositionToVolume(v_end);
-
-						start.load3(v_start.mV);
-						end.load3(v_end.mV);
-					}
-					else
-					{
-						start = gDebugRaycastStart;
-						end = gDebugRaycastEnd;
-					}
-
-					LLVector4a dir;
-					dir.setSub(end, start);
-
-					gGL.flush();
-					glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);				
-
-					{
-						//render face positions
-						gGL.diffuseColor4f(0.f, 1.f, 1.f, 0.5f);
-						LLVertexBuffer::drawElements(LLRender::TRIANGLES, face.mNumVertices, face.mPositions, NULL, face.mNumIndices, face.mIndices);
-					}
-					
-					if (!volume->isUnique())
-					{
-						F32 t = 1.f;
-
-						if (!face.mOctree)
-						{
-							((LLVolumeFace*) &face)->createOctree(); 
-						}
-
-						LLRenderOctreeRaycast render(start, dir, &t);
-					
-						render.traverse(face.mOctree);
-					}
-
-					gGL.popMatrix();		
-					glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
-				}
-			}
-		}
-		else if (drawablep->isAvatar())
-		{
-			if (drawablep->getVObj() == gDebugRaycastObject)
-			{
-				LLGLDepthTest depth(GL_FALSE);
-				LLVOAvatar* av = (LLVOAvatar*) drawablep->getVObj().get();
-				av->renderCollisionVolumes();
-			}
-		}
-
-		if (drawablep->getVObj() == gDebugRaycastObject)
-		{
-			// draw intersection point
-			gGL.pushMatrix();
-			gGL.loadMatrix(gGLModelView);
-			LLVector3 translate(gDebugRaycastIntersection.getF32ptr());
-			gGL.translatef(translate.mV[0], translate.mV[1], translate.mV[2]);
-			LLCoordFrame orient;
-			LLVector4a debug_binormal;
-			
-			debug_binormal.setCross3(gDebugRaycastNormal, gDebugRaycastTangent);
-			debug_binormal.mul(gDebugRaycastTangent.getF32ptr()[3]);
-
-			LLVector3 normal(gDebugRaycastNormal.getF32ptr());
-			LLVector3 binormal(debug_binormal.getF32ptr());
-						
-			orient.lookDir(normal, binormal);
-			LLMatrix4 rotation;
-			orient.getRotMatrixToParent(rotation);
-			gGL.multMatrix((float*)rotation.mMatrix);
-			
-			gGL.diffuseColor4f(1,0,0,0.5f);
-			drawBox(LLVector3(0, 0, 0), LLVector3(0.1f, 0.022f, 0.022f));
-			gGL.diffuseColor4f(0,1,0,0.5f);
-			drawBox(LLVector3(0, 0, 0), LLVector3(0.021f, 0.1f, 0.021f));
-			gGL.diffuseColor4f(0,0,1,0.5f);
-			drawBox(LLVector3(0, 0, 0), LLVector3(0.02f, 0.02f, 0.1f));
-			gGL.popMatrix();
-
-			// 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.diffuseColor4f(0,0.5f,0.5f,1);
-			drawBoxOutline(pos, size);		
-		}
-	}
-}
-
-
-void renderAvatarCollisionVolumes(LLVOAvatar* avatar)
-{
-	avatar->renderCollisionVolumes();
-}
-
-void renderAvatarBones(LLVOAvatar* avatar)
-{
-	avatar->renderBones();
-}
-
-void renderAgentTarget(LLVOAvatar* avatar)
-{
-	// render these for self only (why, i don't know)
-	if (avatar->isSelf())
-	{
-		renderCrossHairs(avatar->getPositionAgent(), 0.2f, LLColor4(1, 0, 0, 0.8f));
-		renderCrossHairs(avatar->mDrawable->getPositionAgent(), 0.2f, LLColor4(0, 1, 0, 0.8f));
-		renderCrossHairs(avatar->mRoot->getWorldPosition(), 0.2f, LLColor4(1, 1, 1, 0.8f));
-		renderCrossHairs(avatar->mPelvisp->getWorldPosition(), 0.2f, LLColor4(0, 0, 1, 0.8f));
-	}
-}
-
-class LLOctreeRenderNonOccluded final : public OctreeTraveler
-{
-public:
-	LLCamera* mCamera;
-	LLOctreeRenderNonOccluded(LLCamera* camera): mCamera(camera) {}
-
-    void traverse(const OctreeNode* node) override
-	{
-		LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
-		
-		const LLVector4a* bounds = group->getBounds();
-		if (!mCamera || mCamera->AABBInFrustumNoFarClip(bounds[0], bounds[1]))
-		{
-			node->accept(this);
-			stop_glerror();
-
-			for (U32 i = 0; i < node->getChildCount(); i++)
-			{
-				traverse(node->getChild(i));
-				stop_glerror();
-			}
-			
-			//draw tight fit bounding boxes for spatial group
-			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCTREE))
-			{	
-				group->rebuildGeom();
-				group->rebuildMesh();
-
-				renderOctree(group);
-				stop_glerror();
-			}
-
-			//render visibility wireframe
-			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION))
-			{
-				group->rebuildGeom();
-				group->rebuildMesh();
-
-				gGL.flush();
-				gGL.pushMatrix();
-				gGLLastMatrix = NULL;
-				gGL.loadMatrix(gGLModelView);
-				renderVisibility(group, mCamera);
-				stop_glerror();
-				gGLLastMatrix = NULL;
-				gGL.popMatrix();
-				gGL.diffuseColor4f(1,1,1,1);
-			}
-		}
-	}
-
-    void visit(const OctreeNode* branch) override
-	{
-		LLSpatialGroup* group = (LLSpatialGroup*) branch->getListener(0);
-		const LLVector4a* bounds = group->getBounds();
-		if (group->hasState(LLSpatialGroup::GEOM_DIRTY) || (mCamera && !mCamera->AABBInFrustumNoFarClip(bounds[0], bounds[1])))
-		{
-			return;
-		}
-
-		LLGLDisable stencil(GL_STENCIL_TEST);
-
-		group->rebuildGeom();
-		group->rebuildMesh();
-
-		if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BBOXES))
-		{
-			if (!group->isEmpty())
-			{
-				gGL.diffuseColor3f(0,0,1);
-				const LLVector4a* obj_bounds = group->getObjectBounds();
-				drawBoxOutline(obj_bounds[0], obj_bounds[1]);
-			}
-		}
-
-		for (OctreeNode::const_element_iter i = branch->getDataBegin(); i != branch->getDataEnd(); ++i)
-		{
-			LLDrawable* drawable = (LLDrawable*)(*i)->getDrawable();
-			if(!drawable)
-		{
-				continue;
-			}
-					
-			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BBOXES))
-			{
-				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.diffuseColor4f(0.6f, 0.6f, 0.1f, 1.f);
-					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);
-				}
-			}	
-
-			if (drawable->getVOVolume() && gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY))
-			{
-				renderTexturePriority(drawable);
-			}
-
-			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_POINTS))
-			{
-				renderPoints(drawable);
-			}
-
-			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_LIGHTS))
-			{
-				renderLights(drawable);
-			}
-
-			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RAYCAST))
-			{
-				renderRaycast(drawable);
-			}
-			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_UPDATE_TYPE))
-			{
-				renderUpdateType(drawable);
-			}
-			if(gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RENDER_COMPLEXITY))
-			{
-				renderComplexityDisplay(drawable);
-			}
-			if(gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY))
-			{
-				renderTexelDensity(drawable);
-			}
-
-			LLVOAvatar* avatar = drawable->getVObj()->asAvatar();
-			
-			if (avatar && gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_AVATAR_VOLUME))
-			{
-				renderAvatarCollisionVolumes(avatar);
-			}
-
-			if (avatar && gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_AVATAR_JOINTS))
-			{
-				renderAvatarBones(avatar);
-			}
-
-			if (avatar && gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_AGENT_TARGET))
-			{
-				renderAgentTarget(avatar);
-			}
-			
-			if (gDebugGL)
-			{
-				for (S32 i = 0; i < drawable->getNumFaces(); ++i)
-				{
-					LLFace* facep = drawable->getFace(i);
-					if (facep)
-					{
-						U8 index = facep->getTextureIndex();
-						if (facep->mDrawInfo)
-						{
-							if (index < 255)
-							{
-								if (facep->mDrawInfo->mTextureList.size() <= index)
-								{
-									LL_ERRS() << "Face texture index out of bounds." << LL_ENDL;
-								}
-								else if (facep->mDrawInfo->mTextureList[index] != facep->getTexture())
-								{
-									LL_ERRS() << "Face texture index incorrect." << LL_ENDL;
-								}
-							}
-						}
-					}
-				}
-			}
-		}
-		
-		for (auto& i : group->mDrawMap)
-        {
-			LLSpatialGroup::drawmap_elem_t& draw_vec = i.second;	
-			for (auto& j : draw_vec)
-            {
-				LLDrawInfo* draw_info = j;
-				if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_ANIM))
-				{
-					renderTextureAnim(draw_info);
-				}
-				if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BATCH_SIZE))
-				{
-					renderBatchSize(draw_info);
-				}
-				if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
-				{
-					renderShadowFrusta(draw_info);
-				}
-			}
-		}
-	}
-};
-
-class LLOctreeRenderXRay final : public OctreeTraveler
-{
-public:
-	LLCamera* mCamera;
-	LLOctreeRenderXRay(LLCamera* camera): mCamera(camera) {}
-
-    void traverse(const OctreeNode* node) override
-	{
-		LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
-		
-		const LLVector4a* bounds = group->getBounds();
-		if (!mCamera || mCamera->AABBInFrustumNoFarClip(bounds[0], bounds[1]))
-		{
-			node->accept(this);
-			stop_glerror();
-
-			for (U32 i = 0; i < node->getChildCount(); i++)
-			{
-				traverse(node->getChild(i));
-				stop_glerror();
-			}
-			
-			//render visibility wireframe
-			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION))
-			{
-				group->rebuildGeom();
-				group->rebuildMesh();
-
-				gGL.flush();
-				gGL.pushMatrix();
-				gGLLastMatrix = NULL;
-				gGL.loadMatrix(gGLModelView);
-				renderXRay(group, mCamera);
-				stop_glerror();
-				gGLLastMatrix = NULL;
-				gGL.popMatrix();
-			}
-		}
-	}
-
-    void visit(const OctreeNode* node) override {}
-
-};
-
-class LLOctreeRenderPhysicsShapes final : public OctreeTraveler
-{
-public:
-	LLCamera* mCamera;
-	LLOctreeRenderPhysicsShapes(LLCamera* camera): mCamera(camera) {}
-
-    void traverse(const OctreeNode* node) override
-	{
-		LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
-		
-		const LLVector4a* bounds = group->getBounds();
-		if (!mCamera || mCamera->AABBInFrustumNoFarClip(bounds[0], bounds[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);
-		}
-	}
-
-    void visit(const OctreeNode* branch) override
-	{
-		
-	}
-};
-
-class LLOctreePushBBoxVerts final : public OctreeTraveler
-{
-public:
-	LLCamera* mCamera;
-	LLOctreePushBBoxVerts(LLCamera* camera): mCamera(camera) {}
-
-    void traverse(const OctreeNode* node) override
-	{
-		LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
-		
-		const LLVector4a* bounds = group->getBounds();
-		if (!mCamera || mCamera->AABBInFrustum(bounds[0], bounds[1]))
-		{
-			node->accept(this);
-
-			for (U32 i = 0; i < node->getChildCount(); i++)
-			{
-				traverse(node->getChild(i));
-			}
-		}
-	}
-
-    void visit(const OctreeNode* branch) override
-	{
-		LLSpatialGroup* group = (LLSpatialGroup*) branch->getListener(0);
-
-		const LLVector4a* bounds = group->getBounds();
-		if (group->hasState(LLSpatialGroup::GEOM_DIRTY) || (mCamera && !mCamera->AABBInFrustumNoFarClip(bounds[0], bounds[1])))
-		{
-			return;
-		}
-
-		for (OctreeNode::const_element_iter i = branch->getDataBegin(); i != branch->getDataEnd(); ++i)
-		{
-			LLDrawable* drawable = (LLDrawable*)(*i)->getDrawable();
-			if(!drawable)
-		{
-				continue;
-			}
-			renderBoundingBox(drawable, FALSE);			
-		}
-	}
-};
-
-void LLSpatialPartition::renderIntersectingBBoxes(LLCamera* camera)
-{
-	LLOctreePushBBoxVerts pusher(camera);
-	pusher.traverse(mOctree);
-}
-
-class LLOctreeStateCheck final : public OctreeTraveler
-{
-public:
-	U32 mInheritedMask[LLViewerCamera::NUM_CAMERAS];
-
-	LLOctreeStateCheck()
-	{ 
-		for (unsigned int& i : mInheritedMask)
-        {
-            i = 0;
-		}
-	}
-
-    void traverse(const OctreeNode* node) override
-	{
-		LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
-		
-		node->accept(this);
-
-
-		U32 temp[LLViewerCamera::NUM_CAMERAS];
-
-		for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
-		{
-			temp[i] = mInheritedMask[i];
-			mInheritedMask[i] |= group->mOcclusionState[i] & LLSpatialGroup::OCCLUDED; 
-		}
-
-		for (U32 i = 0; i < node->getChildCount(); i++)
-		{
-			traverse(node->getChild(i));
-		}
-
-		for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
-		{
-			mInheritedMask[i] = temp[i];
-		}
-	}
-
-
-    void visit(const OctreeNode* state) override
-	{
-		LLSpatialGroup* group = (LLSpatialGroup*) state->getListener(0);
-
-		for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
-		{
-			if (mInheritedMask[i] && !(group->mOcclusionState[i] & mInheritedMask[i]))
-			{
-				LL_ERRS() << "Spatial group failed inherited mask test." << LL_ENDL;
-			}
-		}
-
-		if (group->hasState(LLSpatialGroup::DIRTY))
-		{
-			assert_parent_state(group, LLSpatialGroup::DIRTY);
-		}
-	}
-
-	void assert_parent_state(LLSpatialGroup* group, U32 state)
-	{
-		LLSpatialGroup* parent = group->getParent();
-		while (parent)
-		{
-			if (!parent->hasState(state))
-			{
-				LL_ERRS() << "Spatial group failed parent state check." << LL_ENDL;
-			}
-			parent = parent->getParent();
-		}
-	}	
-};
-
-
-void LLSpatialPartition::renderPhysicsShapes()
-{
-	LLSpatialBridge* bridge = asBridge();
-	LLCamera* camera = LLViewerCamera::getInstance();
-	
-	if (bridge)
-	{
-		camera = NULL;
-	}
-
-	gGL.flush();
-	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-	gGL.setLineWidth(3.f);
-	LLOctreeRenderPhysicsShapes render_physics(camera);
-	render_physics.traverse(mOctree);
-	gGL.flush();
-	gGL.setLineWidth(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_AVATAR_JOINTS |
-									  LLPipeline::RENDER_DEBUG_AGENT_TARGET |
-									  //LLPipeline::RENDER_DEBUG_BUILD_QUEUE |
-									  LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA |
-									  LLPipeline::RENDER_DEBUG_RENDER_COMPLEXITY |
-									  LLPipeline::RENDER_DEBUG_TEXEL_DENSITY)) 
-	{
-		return;
-	}
-	
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gDebugProgram.bind();
-	}
-
-	if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY))
-	{
-		//sLastMaxTexPriority = lerp(sLastMaxTexPriority, sCurMaxTexPriority, gFrameIntervalSeconds);
-		sLastMaxTexPriority = (F32) LLViewerCamera::getInstance()->getScreenPixelArea();
-		sCurMaxTexPriority = 0.f;
-	}
-
-	LLGLDisable cullface(GL_CULL_FACE);
-	LLGLEnable blend(GL_BLEND);
-	gGL.setSceneBlendType(LLRender::BT_ALPHA);
-	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-	gPipeline.disableLights();
-
-	LLSpatialBridge* bridge = asBridge();
-	LLCamera* camera = LLViewerCamera::getInstance();
-	
-	if (bridge)
-	{
-		camera = NULL;
-	}
-
-	LLOctreeStateCheck checker;
-	checker.traverse(mOctree);
-
-	LLOctreeRenderNonOccluded render_debug(camera);
-	render_debug.traverse(mOctree);
-
-
-	if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION))
-	{
-		{
-			LLGLEnable cull(GL_CULL_FACE);
-			
-			LLGLEnable blend(GL_BLEND);
-			LLGLDepthTest depth_under(GL_TRUE, GL_FALSE, GL_GREATER);
-			glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
-			gGL.diffuseColor4f(0.5f, 0.0f, 0, 0.25f);
-
-			LLGLEnable offset(GL_POLYGON_OFFSET_LINE);
-			glPolygonOffset(-1.f, -1.f);
-
-			LLOctreeRenderXRay xray(camera);
-			xray.traverse(mOctree);
-
-			glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
-		}
-	}
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		gDebugProgram.unbind();
-	}
-}
-
-void LLSpatialGroup::drawObjectBox(LLColor4 col)
-{
-	gGL.diffuseColor4fv(col.mV);
-	LLVector4a size;
-	size = mObjectBounds[1];
-	size.mul(1.01f);
-	size.add(LLVector4a(0.001f));
-	drawBox(mObjectBounds[0], size);
-}
-
-bool LLSpatialPartition::isHUDPartition() 
-{ 
-	return mPartitionType == LLViewerRegion::PARTITION_HUD ;
-} 
-
-BOOL LLSpatialPartition::isVisible(const LLVector3& v)
-{
-	if (!LLViewerCamera::getInstance()->sphereInFrustum(v, 4.0f))
-	{
-		return FALSE;
-	}
-
-	return TRUE;
-}
-
-LL_ALIGN_PREFIX(16)
-class LLOctreeIntersect : public LLOctreeTraveler<LLViewerOctreeEntry>
-{
-public:
-	LL_ALIGN_16(LLVector4a mStart);
-	LL_ALIGN_16(LLVector4a mEnd);
-
-	S32       *mFaceHit;
-	LLVector4a *mIntersection;
-	LLVector2 *mTexCoord;
-	LLVector4a *mNormal;
-	LLVector4a *mTangent;
-	LLDrawable* mHit;
-	BOOL mPickTransparent;
-	BOOL mPickRigged;
-
-	LLOctreeIntersect(const LLVector4a& start, const LLVector4a& end, BOOL pick_transparent, BOOL pick_rigged,
-					  S32* face_hit, LLVector4a* intersection, LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent)
-		: mStart(start),
-		  mEnd(end),
-		  mFaceHit(face_hit),
-		  mIntersection(intersection),
-		  mTexCoord(tex_coord),
-		  mNormal(normal),
-		  mTangent(tangent),
-		  mHit(NULL),
-		  mPickTransparent(pick_transparent),
-		  mPickRigged(pick_rigged)
-	{
-	}
-
-    void visit(const OctreeNode* branch) override
-	{	
-		for (OctreeNode::const_element_iter i = branch->getDataBegin(); i != branch->getDataEnd(); ++i)
-		{
-			check(*i);
-		}
-	}
-
-	virtual LLDrawable* check(const OctreeNode* node)
-	{
-		node->accept(this);
-	
-		for (U32 i = 0; i < node->getChildCount(); i++)
-		{
-			const OctreeNode* child = node->getChild(i);
-			LLVector3 res;
-
-			LLSpatialGroup* group = (LLSpatialGroup*) child->getListener(0);
-			
-			LLVector4a size;
-			LLVector4a center;
-			
-			const LLVector4a* bounds = group->getBounds();
-			size = bounds[1];
-			center = bounds[0];
-			
-			LLVector4a local_start = mStart;
-			LLVector4a local_end   = mEnd;
-
-			if (group->getSpatialPartition()->isBridge())
-			{
-				LLMatrix4a local_matrix4a(group->getSpatialPartition()->asBridge()->mDrawable->getRenderMatrix());
-				local_matrix4a.invert();
-
-				local_matrix4a.affineTransform(mStart, local_start);
-				local_matrix4a.affineTransform(mEnd, local_end);
-			}
-
-			if (LLLineSegmentBoxIntersect(local_start, local_end, center, size))
-			{
-				check(child);
-			}
-		}	
-
-		return mHit;
-	}
-
-	virtual bool check(LLViewerOctreeEntry* entry)
-	{	
-		LLDrawable* drawable = (LLDrawable*)entry->getDrawable();
-	
-		if (!drawable || !gPipeline.hasRenderType(drawable->getRenderType()) || !drawable->isVisible())
-		{
-			return false;
-		}
-
-		if (drawable->isSpatialBridge())
-		{
-			LLSpatialPartition *part = drawable->asPartition();
-			LLSpatialBridge* bridge = part->asBridge();
-			if (bridge && gPipeline.hasRenderType(bridge->mDrawableType))
-			{
-				check(part->mOctree);
-			}
-		}
-		else
-		{
-			LLViewerObject* vobj = drawable->getVObj();
-
-			if (vobj)
-			{
-				LLVector4a intersection;
-				bool skip_check = false;
-				if (vobj->isAvatar())
-				{
-					LLVOAvatar* avatar = (LLVOAvatar*) vobj;
-					if ((mPickRigged) || ((avatar->isSelf()) && (LLFloater::isVisible(gFloaterTools))))
-					{
-						LLViewerObject* hit = avatar->lineSegmentIntersectRiggedAttachments(mStart, mEnd, -1, mPickTransparent, mPickRigged, mFaceHit, &intersection, mTexCoord, mNormal, mTangent);
-						if (hit)
-						{
-							mEnd = intersection;
-							if (mIntersection)
-							{
-								*mIntersection = intersection;
-							}
-							
-							mHit = hit->mDrawable;
-							skip_check = true;
-						}
-
-					}
-				}
-
-				if (!skip_check && vobj->lineSegmentIntersect(mStart, mEnd, -1, mPickTransparent, mPickRigged, mFaceHit, &intersection, mTexCoord, mNormal, mTangent))
-				{
-					mEnd = intersection;  // shorten ray so we only find CLOSER hits
-					if (mIntersection)
-					{
-						*mIntersection = intersection;
-					}
-					
-					mHit = vobj->mDrawable;
-				}
-			}
-		}
-				
-		return false;
-	}
-} LL_ALIGN_POSTFIX(16);
-
-LLDrawable* LLSpatialPartition::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end,
-													 BOOL pick_transparent,
-													 BOOL pick_rigged,
-													 S32* face_hit,                   // return the face hit
-													 LLVector4a* intersection,         // return the intersection point
-													 LLVector2* tex_coord,            // return the texture coordinates of the intersection point
-													 LLVector4a* normal,               // return the surface normal at the intersection point
-													 LLVector4a* tangent			// return the surface tangent at the intersection point
-	)
-
-{
-	LLOctreeIntersect intersect(start, end, pick_transparent, pick_rigged, face_hit, intersection, tex_coord, normal, tangent);
-	LLDrawable* drawable = intersect.check(mOctree);
-
-	return drawable;
-}
-
-LLDrawInfo::LLDrawInfo(U16 start, U16 end, U32 count, U32 offset, 
-					   LLViewerTexture* texture, LLVertexBuffer* buffer,
-					   bool selected,
-					   BOOL fullbright, U8 bump, BOOL particle, F32 part_size)
-:	LLTrace::MemTrackable<LLDrawInfo, 16>("LLDrawInfo"),
-	mVertexBuffer(buffer),
-	mTexture(texture),
-	mTextureMatrix(NULL),
-	mModelMatrix(NULL),
-	mStart(start),
-	mEnd(end),
-	mCount(count),
-	mOffset(offset), 
-	mFullbright(fullbright),
-	mBump(bump),
-	mShiny(0),
-	mParticle(particle),
-	mPartSize(part_size),
-	mVSize(0.f),
-	mGroup(NULL),
-	mFace(NULL),
-	mDistance(0.f),
-	mDrawMode(LLRender::TRIANGLES),
-	mMaterial(NULL),
-	mShaderMask(0),
-	mBlendFuncSrc(LLRender::BF_SOURCE_ALPHA),
-	mBlendFuncDst(LLRender::BF_ONE_MINUS_SOURCE_ALPHA),
-	mHasGlow(FALSE),
-	mSpecColor(1.0f, 1.0f, 1.0f, 0.5f),
-	mEnvIntensity(0.0f),
-	mAlphaMaskCutoff(0.5f),
-	mDiffuseAlphaMode(0),
-	mSelected(selected)
-{
-	mVertexBuffer->validateRange(mStart, mEnd, mCount, mOffset);
-}
-
-LLDrawInfo::~LLDrawInfo()	
-{
-	/*if (LLSpatialGroup::sNoDelete)
-	{
-		LL_ERRS() << "LLDrawInfo deleted illegally!" << LL_ENDL;
-	}*/
-
-	if (mFace)
-	{
-		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)
-{
-	return new LLVertexBuffer(type_mask, usage);
-}
-
-LLCullResult::LLCullResult() 
-{
-	mVisibleGroupsAllocated = 0;
-	mAlphaGroupsAllocated = 0;
-	mOcclusionGroupsAllocated = 0;
-	mDrawableGroupsAllocated = 0;
-	mVisibleListAllocated = 0;
-	mVisibleBridgeAllocated = 0;
-
-	mVisibleGroups.clear();
-	mVisibleGroups.push_back(NULL);
-	mVisibleGroupsEnd = &mVisibleGroups[0];
-	mAlphaGroups.clear();
-	mAlphaGroups.push_back(NULL);
-	mAlphaGroupsEnd = &mAlphaGroups[0];
-	mOcclusionGroups.clear();
-	mOcclusionGroups.push_back(NULL);
-	mOcclusionGroupsEnd = &mOcclusionGroups[0];
-	mDrawableGroups.clear();
-	mDrawableGroups.push_back(NULL);
-	mDrawableGroupsEnd = &mDrawableGroups[0];
-	mVisibleList.clear();
-	mVisibleList.push_back(NULL);
-	mVisibleListEnd = &mVisibleList[0];
-	mVisibleBridge.clear();
-	mVisibleBridge.push_back(NULL);
-	mVisibleBridgeEnd = &mVisibleBridge[0];
-
-	for (U32 i = 0; i < LLRenderPass::NUM_RENDER_TYPES; i++)
-	{
-		mRenderMap[i].clear();
-		mRenderMap[i].push_back(NULL);
-		mRenderMapEnd[i] = &mRenderMap[i][0];
-		mRenderMapAllocated[i] = 0;
-		mRenderMapSize[i] = 0;
-	}
-
-	clear();
-}
-
-template <class T, class V> 
-void LLCullResult::pushBack(T& head, U32& count, V* val)
-{
-	head[count] = val;
-	head.push_back(NULL);
-	count++;
-}
-
-void LLCullResult::clear()
-{
-	mVisibleGroupsSize = 0;
-	mVisibleGroupsEnd = &mVisibleGroups[0];
-
-	mAlphaGroupsSize = 0;
-	mAlphaGroupsEnd = &mAlphaGroups[0];
-
-	mOcclusionGroupsSize = 0;
-	mOcclusionGroupsEnd = &mOcclusionGroups[0];
-
-	mDrawableGroupsSize = 0;
-	mDrawableGroupsEnd = &mDrawableGroups[0];
-
-	mVisibleListSize = 0;
-	mVisibleListEnd = &mVisibleList[0];
-
-	mVisibleBridgeSize = 0;
-	mVisibleBridgeEnd = &mVisibleBridge[0];
-
-
-	for (U32 i = 0; i < LLRenderPass::NUM_RENDER_TYPES; i++)
-	{
-		for (U32 j = 0; j < mRenderMapSize[i]; j++)
-		{
-			mRenderMap[i][j] = 0;
-		}
-		mRenderMapSize[i] = 0;
-		mRenderMapEnd[i] = &(mRenderMap[i][0]);
-	}
-}
-
-LLCullResult::sg_iterator LLCullResult::beginVisibleGroups()
-{
-	return &mVisibleGroups[0];
-}
-
-LLCullResult::sg_iterator LLCullResult::endVisibleGroups()
-{
-	return mVisibleGroupsEnd;
-}
-
-LLCullResult::sg_iterator LLCullResult::beginAlphaGroups()
-{
-	return &mAlphaGroups[0];
-}
-
-LLCullResult::sg_iterator LLCullResult::endAlphaGroups()
-{
-	return mAlphaGroupsEnd;
-}
-
-LLCullResult::sg_iterator LLCullResult::beginOcclusionGroups()
-{
-	return &mOcclusionGroups[0];
-}
-
-LLCullResult::sg_iterator LLCullResult::endOcclusionGroups()
-{
-	return mOcclusionGroupsEnd;
-}
-
-LLCullResult::sg_iterator LLCullResult::beginDrawableGroups()
-{
-	return &mDrawableGroups[0];
-}
-
-LLCullResult::sg_iterator LLCullResult::endDrawableGroups()
-{
-	return mDrawableGroupsEnd;
-}
-
-LLCullResult::drawable_iterator LLCullResult::beginVisibleList()
-{
-	return &mVisibleList[0];
-}
-
-LLCullResult::drawable_iterator LLCullResult::endVisibleList()
-{
-	return mVisibleListEnd;
-}
-
-LLCullResult::bridge_iterator LLCullResult::beginVisibleBridge()
-{
-	return &mVisibleBridge[0];
-}
-
-LLCullResult::bridge_iterator LLCullResult::endVisibleBridge()
-{
-	return mVisibleBridgeEnd;
-}
-
-LLCullResult::drawinfo_iterator LLCullResult::beginRenderMap(U32 type)
-{
-	return &mRenderMap[type][0];
-}
-
-LLCullResult::drawinfo_iterator LLCullResult::endRenderMap(U32 type)
-{
-	return mRenderMapEnd[type];
-}
-
-void LLCullResult::pushVisibleGroup(LLSpatialGroup* group)
-{
-	if (mVisibleGroupsSize < mVisibleGroupsAllocated)
-	{
-		mVisibleGroups[mVisibleGroupsSize] = group;
-	}
-	else
-	{
-		pushBack(mVisibleGroups, mVisibleGroupsAllocated, group);
-	}
-	++mVisibleGroupsSize;
-	mVisibleGroupsEnd = &mVisibleGroups[mVisibleGroupsSize];
-}
-
-void LLCullResult::pushAlphaGroup(LLSpatialGroup* group)
-{
-	if (mAlphaGroupsSize < mAlphaGroupsAllocated)
-	{
-		mAlphaGroups[mAlphaGroupsSize] = group;
-	}
-	else
-	{
-		pushBack(mAlphaGroups, mAlphaGroupsAllocated, group);
-	}
-	++mAlphaGroupsSize;
-	mAlphaGroupsEnd = &mAlphaGroups[mAlphaGroupsSize];
-}
-
-void LLCullResult::pushOcclusionGroup(LLSpatialGroup* group)
-{
-	if (mOcclusionGroupsSize < mOcclusionGroupsAllocated)
-	{
-		mOcclusionGroups[mOcclusionGroupsSize] = group;
-	}
-	else
-	{
-		pushBack(mOcclusionGroups, mOcclusionGroupsAllocated, group);
-	}
-	++mOcclusionGroupsSize;
-	mOcclusionGroupsEnd = &mOcclusionGroups[mOcclusionGroupsSize];
-}
-
-void LLCullResult::pushDrawableGroup(LLSpatialGroup* group)
-{
-	if (mDrawableGroupsSize < mDrawableGroupsAllocated)
-	{
-		mDrawableGroups[mDrawableGroupsSize] = group;
-	}
-	else
-	{
-		pushBack(mDrawableGroups, mDrawableGroupsAllocated, group);
-	}
-	++mDrawableGroupsSize;
-	mDrawableGroupsEnd = &mDrawableGroups[mDrawableGroupsSize];
-}
-
-void LLCullResult::pushDrawable(LLDrawable* drawable)
-{
-	if (mVisibleListSize < mVisibleListAllocated)
-	{
-		mVisibleList[mVisibleListSize] = drawable;
-	}
-	else
-	{
-		pushBack(mVisibleList, mVisibleListAllocated, drawable);
-	}
-	++mVisibleListSize;
-	mVisibleListEnd = &mVisibleList[mVisibleListSize];
-}
-
-void LLCullResult::pushBridge(LLSpatialBridge* bridge)
-{
-	if (mVisibleBridgeSize < mVisibleBridgeAllocated)
-	{
-		mVisibleBridge[mVisibleBridgeSize] = bridge;
-	}
-	else
-	{
-		pushBack(mVisibleBridge, mVisibleBridgeAllocated, bridge);
-	}
-	++mVisibleBridgeSize;
-	mVisibleBridgeEnd = &mVisibleBridge[mVisibleBridgeSize];
-}
-
-void LLCullResult::pushDrawInfo(U32 type, LLDrawInfo* draw_info)
-{
-	if (mRenderMapSize[type] < mRenderMapAllocated[type])
-	{
-		mRenderMap[type][mRenderMapSize[type]] = draw_info;
-	}
-	else
-	{
-		pushBack(mRenderMap[type], mRenderMapAllocated[type], draw_info);
-	}
-	++mRenderMapSize[type];
-	mRenderMapEnd[type] = &(mRenderMap[type][mRenderMapSize[type]]);
-}
-
-
-void LLCullResult::assertDrawMapsEmpty()
-{
-	for (unsigned int i : mRenderMapSize)
-    {
-		if (i != 0)
-		{
-			LL_ERRS() << "Stale LLDrawInfo's in LLCullResult!" << LL_ENDL;
-		}
-	}
-}
-
+/** 
+ * @file llspatialpartition.cpp
+ * @brief LLSpatialGroup class implementation and supporting functions
+ *
+ * $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$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llspatialpartition.h"
+
+#include "llappviewer.h"
+#include "llcallstack.h"
+#include "lltexturecache.h"
+#include "lltexturefetch.h"
+#include "llimageworker.h"
+#include "llviewerwindow.h"
+#include "llviewerobjectlist.h"
+#include "llvovolume.h"
+#include "llvolume.h"
+#include "llvolumeoctree.h"
+#include "llviewercamera.h"
+#include "llface.h"
+#include "llfloatertools.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 "llviewershadermgr.h"
+#include "llcontrolavatar.h"
+#include "llfloaterreg.h" // <alchemy/>
+
+//#pragma optimize("", off)
+
+static LLTrace::BlockTimerStatHandle FTM_FRUSTUM_CULL("Frustum Culling");
+static LLTrace::BlockTimerStatHandle FTM_CULL_REBOUND("Cull Rebound Partition");
+
+extern bool gShiftFrame;
+
+static U32 sZombieGroups = 0;
+U32 LLSpatialGroup::sNodeCount = 0;
+
+BOOL LLSpatialGroup::sNoDelete = FALSE;
+
+static F32 sLastMaxTexPriority = 1.f;
+static F32 sCurMaxTexPriority = 1.f;
+
+BOOL LLSpatialPartition::sTeleportRequested = FALSE;
+
+//static counter for frame to switch LOD on
+
+void sg_assert(BOOL expr)
+{
+#if LL_OCTREE_PARANOIA_CHECK
+	if (!expr)
+	{
+		LL_ERRS() << "Octree invalid!" << LL_ENDL;
+	}
+#endif
+}
+
+//returns:
+//	0 if sphere and AABB are not intersecting 
+//	1 if they are
+//	2 if AABB is entirely inside sphere
+
+S32 LLSphereAABB(const LLVector3& center, const LLVector3& size, const LLVector3& pos, const F32 &rad)
+{
+	S32 ret = 2;
+
+	LLVector3 min = center - size;
+	LLVector3 max = center + size;
+	for (U32 i = 0; i < 3; i++)
+	{
+		if (min.mV[i] > pos.mV[i] + rad ||
+			max.mV[i] < pos.mV[i] - rad)
+		{	//totally outside
+			return 0;
+		}
+		
+		if (min.mV[i] < pos.mV[i] - rad ||
+			max.mV[i] > pos.mV[i] + rad)
+		{	//intersecting
+			ret = 1;
+		}
+	}
+
+	return ret;
+}
+
+LLSpatialGroup::~LLSpatialGroup()
+{
+	/*if (sNoDelete)
+	{
+		LL_ERRS() << "Illegal deletion of LLSpatialGroup!" << LL_ENDL;
+	}*/
+
+	if (gDebugGL)
+	{
+		gPipeline.checkReferences(this);
+	}
+
+	if (hasState(DEAD))
+	{
+		sZombieGroups--;
+	}
+	
+	sNodeCount--;
+
+	clearDrawMap();
+}
+
+void LLSpatialGroup::clearDrawMap()
+{
+	mDrawMap.clear();
+}
+
+BOOL LLSpatialGroup::isHUDGroup() 
+{
+	return getSpatialPartition() && getSpatialPartition()->isHUDPartition() ; 
+}
+
+void LLSpatialGroup::validate()
+{
+	ll_assert_aligned(this,64);
+#if LL_OCTREE_PARANOIA_CHECK
+
+	sg_assert(!isState(DIRTY));
+	sg_assert(!isDead());
+
+	LLVector4a myMin;
+	myMin.setSub(mBounds[0], mBounds[1]);
+	LLVector4a myMax;
+	myMax.setAdd(mBounds[0], mBounds[1]);
+
+	validateDrawMap();
+
+	for (element_iter i = getDataBegin(); i != getDataEnd(); ++i)
+	{
+		LLDrawable* drawable = *i;
+		sg_assert(drawable->getSpatialGroup() == this);
+		if (drawable->getSpatialBridge())
+		{
+			sg_assert(drawable->getSpatialBridge() == getSpatialPartition()->asBridge());
+		}
+
+		/*if (drawable->isSpatialBridge())
+		{
+			LLSpatialPartition* part = drawable->asPartition();
+			if (!part)
+			{
+				LL_ERRS() << "Drawable reports it is a spatial bridge but not a partition." << LL_ENDL;
+			}
+			LLSpatialGroup* group = (LLSpatialGroup*) part->mOctree->getListener(0);
+			group->validate();
+		}*/
+	}
+
+	for (U32 i = 0; i < mOctreeNode->getChildCount(); ++i)
+	{
+		LLSpatialGroup* group = (LLSpatialGroup*) mOctreeNode->getChild(i)->getListener(0);
+
+		group->validate();
+		
+		//ensure all children are enclosed in this node
+		LLVector4a center = group->mBounds[0];
+		LLVector4a size = group->mBounds[1];
+		
+		LLVector4a min;
+		min.setSub(center, size);
+		LLVector4a max;
+		max.setAdd(center, size);
+		
+		for (U32 j = 0; j < 3; j++)
+		{
+			sg_assert(min[j] >= myMin[j]-0.02f);
+			sg_assert(max[j] <= myMax[j]+0.02f);
+		}
+	}
+
+#endif
+}
+
+void LLSpatialGroup::validateDrawMap()
+{
+#if LL_OCTREE_PARANOIA_CHECK
+	for (draw_map_t::iterator i = mDrawMap.begin(); i != mDrawMap.end(); ++i)
+	{
+		LLSpatialGroup::drawmap_elem_t& draw_vec = i->second;
+		for (drawmap_elem_t::iterator j = draw_vec.begin(); j != draw_vec.end(); ++j)
+		{
+			LLDrawInfo& params = **j;
+		
+			params.validate();
+		}
+	}
+#endif
+}
+
+BOOL LLSpatialGroup::updateInGroup(LLDrawable *drawablep, BOOL immediate)
+{
+	drawablep->updateSpatialExtents();
+
+	OctreeNode* parent = mOctreeNode->getOctParent();
+	
+	if (mOctreeNode->isInside(drawablep->getPositionGroup()) && 
+		(mOctreeNode->contains(drawablep->getEntry()) ||
+		 (drawablep->getBinRadius() > mOctreeNode->getSize()[0] &&
+				parent && parent->getElementCount() >= gOctreeMaxCapacity)))
+	{
+		unbound();
+		setState(OBJECT_DIRTY);
+		//setState(GEOM_DIRTY);
+		return TRUE;
+	}
+		
+	return FALSE;
+}
+
+
+BOOL LLSpatialGroup::addObject(LLDrawable *drawablep)
+{
+	if(!drawablep)
+	{
+		return FALSE;
+	}
+	{
+		drawablep->setGroup(this);
+		setState(OBJECT_DIRTY | GEOM_DIRTY);
+		setOcclusionState(LLSpatialGroup::DISCARD_QUERY, LLSpatialGroup::STATE_MODE_ALL_CAMERAS);
+		gPipeline.markRebuild(this, TRUE);
+		if (drawablep->isSpatialBridge())
+		{
+			mBridgeList.push_back((LLSpatialBridge*) drawablep);
+		}
+		if (drawablep->getRadius() > 1.f)
+		{
+			setState(IMAGE_DIRTY);
+		}
+	}
+
+	return TRUE;
+}
+
+void LLSpatialGroup::rebuildGeom()
+{
+	if (!isDead())
+	{
+		getSpatialPartition()->rebuildGeom(this);
+
+		if (hasState(LLSpatialGroup::MESH_DIRTY))
+		{
+			gPipeline.markMeshDirty(this);
+		}
+	}
+}
+
+void LLSpatialGroup::rebuildMesh()
+{
+	if (!isDead())
+	{
+		getSpatialPartition()->rebuildMesh(this);
+	}
+}
+
+static LLTrace::BlockTimerStatHandle FTM_REBUILD_VBO("VBO Rebuilt");
+static LLTrace::BlockTimerStatHandle FTM_ADD_GEOMETRY_COUNT("Add Geometry");
+static LLTrace::BlockTimerStatHandle FTM_CREATE_VB("Create VB");
+static LLTrace::BlockTimerStatHandle FTM_GET_GEOMETRY("Get Geometry");
+
+void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group)
+{
+	if (group->isDead() || !group->hasState(LLSpatialGroup::GEOM_DIRTY))
+	{
+		return;
+	}
+
+	if (group->changeLOD())
+	{
+		group->mLastUpdateDistance = group->mDistance;
+		group->mLastUpdateViewAngle = group->mViewAngle;
+	}
+	
+	LL_RECORD_BLOCK_TIME(FTM_REBUILD_VBO);	
+
+	group->clearDrawMap();
+	
+	//get geometry count
+	U32 index_count = 0;
+	U32 vertex_count = 0;
+
+	{
+		LL_RECORD_BLOCK_TIME(FTM_ADD_GEOMETRY_COUNT);
+		addGeometryCount(group, vertex_count, index_count);
+	}
+
+	if (vertex_count > 0 && index_count > 0)
+	{ //create vertex buffer containing volume geometry for this node
+		{
+			LL_RECORD_BLOCK_TIME(FTM_CREATE_VB);
+			group->mBuilt = 1.f;
+			if (group->mVertexBuffer.isNull() ||
+				!group->mVertexBuffer->isWriteable() ||
+				(group->mBufferUsage != (U32)group->mVertexBuffer->getUsage() && LLVertexBuffer::sEnableVBOs))
+			{
+				group->mVertexBuffer = createVertexBuffer(mVertexDataMask, group->mBufferUsage);
+				if (!group->mVertexBuffer->allocateBuffer(vertex_count, index_count, true))
+				{
+					LL_WARNS() << "Failed to allocate Vertex Buffer on rebuild to "
+						<< vertex_count << " vertices and "
+						<< index_count << " indices" << LL_ENDL;
+					group->mVertexBuffer = NULL;
+					group->mBufferMap.clear();
+				}
+				stop_glerror();
+			}
+			else
+			{
+				if (!group->mVertexBuffer->resizeBuffer(vertex_count, index_count))
+				{
+					// Is likely to cause a crash. If this gets triggered find a way to avoid it (don't forget to reset face)
+					LL_WARNS() << "Failed to resize Vertex Buffer on rebuild to "
+						<< vertex_count << " vertices and "
+						<< index_count << " indices" << LL_ENDL;
+					group->mVertexBuffer = NULL;
+					group->mBufferMap.clear();
+				}
+				stop_glerror();
+			}
+		}
+
+		if (group->mVertexBuffer)
+		{
+			LL_RECORD_BLOCK_TIME(FTM_GET_GEOMETRY);
+			getGeometry(group);
+		}
+	}
+	else
+	{
+		group->mVertexBuffer = NULL;
+		group->mBufferMap.clear();
+	}
+
+	group->mLastUpdateTime = gFrameTimeSeconds;
+	group->clearState(LLSpatialGroup::GEOM_DIRTY);
+}
+
+
+void LLSpatialPartition::rebuildMesh(LLSpatialGroup* group)
+{
+
+}
+
+LLSpatialGroup* LLSpatialGroup::getParent()
+{
+	return (LLSpatialGroup*)LLViewerOctreeGroup::getParent();
+	}
+
+BOOL LLSpatialGroup::removeObject(LLDrawable *drawablep, BOOL from_octree)
+	{
+	if(!drawablep)
+	{
+		return FALSE;
+	}
+
+	unbound();
+	if (mOctreeNode && !from_octree)
+	{
+		drawablep->setGroup(NULL);
+	}
+	else
+	{
+		drawablep->setGroup(NULL);
+		setState(GEOM_DIRTY);
+		gPipeline.markRebuild(this, TRUE);
+
+		if (drawablep->isSpatialBridge())
+		{
+			for (bridge_list_t::iterator i = mBridgeList.begin(); i != mBridgeList.end(); ++i)
+			{
+				if (*i == drawablep)
+				{
+					mBridgeList.erase(i);
+					break;
+				}
+			}
+		}
+
+		if (getElementCount() == 0)
+		{ //delete draw map on last element removal since a rebuild might never happen
+			clearDrawMap();
+		}
+	}
+	return TRUE;
+}
+
+void LLSpatialGroup::shift(const LLVector4a &offset)
+{
+	LLVector4a t = mOctreeNode->getCenter();
+	t.add(offset);	
+	mOctreeNode->setCenter(t);
+	mOctreeNode->updateMinMax();
+	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 (!getSpatialPartition()->mRenderByGroup && 
+		getSpatialPartition()->mPartitionType != LLViewerRegion::PARTITION_TREE &&
+		getSpatialPartition()->mPartitionType != LLViewerRegion::PARTITION_TERRAIN &&
+		getSpatialPartition()->mPartitionType != LLViewerRegion::PARTITION_BRIDGE)
+	{
+		setState(GEOM_DIRTY);
+		gPipeline.markRebuild(this, TRUE);
+	}
+}
+
+class LLSpatialSetState : public OctreeTraveler
+{
+public:
+	U32 mState;
+	LLSpatialSetState(U32 state) : mState(state) { }
+    void visit(const OctreeNode* branch) final override { ((LLSpatialGroup*) branch->getListener(0))->setState(mState); }	
+};
+
+class LLSpatialSetStateDiff final : public LLSpatialSetState
+{
+public:
+	LLSpatialSetStateDiff(U32 state) : LLSpatialSetState(state) { }
+
+    void traverse(const OctreeNode* n) override
+	{
+		LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
+		
+		if (!group->hasState(mState))
+		{
+			OctreeTraveler::traverse(n);
+		}
+	}
+};
+
+void LLSpatialGroup::setState(U32 state, S32 mode) 
+{
+	llassert(state <= LLSpatialGroup::STATE_MASK);
+	
+	if (mode > STATE_MODE_SINGLE)
+	{
+		if (mode == STATE_MODE_DIFF)
+		{
+			LLSpatialSetStateDiff setter(state);
+			setter.traverse(mOctreeNode);
+		}
+		else
+		{
+			LLSpatialSetState setter(state);
+			setter.traverse(mOctreeNode);
+		}
+	}
+	else
+	{
+		mState |= state;
+	}
+}
+
+class LLSpatialClearState : public OctreeTraveler
+{
+public:
+	U32 mState;
+	LLSpatialClearState(U32 state) : mState(state) { }
+    void visit(const OctreeNode* branch) final override { ((LLSpatialGroup*) branch->getListener(0))->clearState(mState); }
+};
+
+class LLSpatialClearStateDiff final : public LLSpatialClearState
+{
+public:
+	LLSpatialClearStateDiff(U32 state) : LLSpatialClearState(state) { }
+
+    void traverse(const OctreeNode* n) override
+	{
+		LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
+		
+		if (group->hasState(mState))
+		{
+			OctreeTraveler::traverse(n);
+		}
+	}
+};
+
+void LLSpatialGroup::clearState(U32 state, S32 mode)
+{
+	llassert(state <= LLSpatialGroup::STATE_MASK);
+
+	if (mode > STATE_MODE_SINGLE)
+	{
+		if (mode == STATE_MODE_DIFF)
+		{
+			LLSpatialClearStateDiff clearer(state);
+			clearer.traverse(mOctreeNode);
+		}
+		else
+		{
+			LLSpatialClearState clearer(state);
+			clearer.traverse(mOctreeNode);
+		}
+	}
+	else
+	{
+		mState &= ~state;
+	}
+}
+
+//======================================
+//		Octree Listener Implementation
+//======================================
+
+LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) : LLOcclusionCullingGroup(node, part),
+	mObjectBoxSize(1.f),
+	mGeometryBytes(0),
+	mSurfaceArea(0.f),
+	mBuilt(0.f),
+	mVertexBuffer(NULL), 
+	mBufferUsage(part->mBufferUsage),
+	mDistance(0.f),
+	mDepth(0.f),
+	mLastUpdateDistance(-1.f), 
+	mLastUpdateTime(gFrameTimeSeconds)
+{
+	ll_assert_aligned(this,16);
+	
+	sNodeCount++;
+
+	mViewAngle.splat(0.f);
+	mLastUpdateViewAngle.splat(-1.f);
+
+	sg_assert(mOctreeNode->getListenerCount() == 0);
+	setState(SG_INITIAL_STATE_MASK);
+	gPipeline.markRebuild(this, TRUE);
+
+	mRadius = 1;
+	mPixelArea = 1024.f;
+}
+
+void LLSpatialGroup::updateDistance(LLCamera &camera)
+{
+	if (LLViewerCamera::sCurCameraID != LLViewerCamera::CAMERA_WORLD)
+	{
+		LL_WARNS() << "Attempted to update distance for camera other than world camera!" << LL_ENDL;
+		return;
+	}
+
+	if (gShiftFrame)
+	{
+		return;
+	}
+
+#if !LL_RELEASE_FOR_DOWNLOAD
+	if (hasState(LLSpatialGroup::OBJECT_DIRTY))
+	{
+		LL_ERRS() << "Spatial group dirty on distance update." << LL_ENDL;
+	}
+#endif
+	if (!isEmpty())
+	{
+		mRadius = getSpatialPartition()->mRenderByGroup ? mObjectBounds[1].getLength3().getF32() :
+						(F32) mOctreeNode->getSize().getLength3().getF32();
+		mDistance = getSpatialPartition()->calcDistance(this, camera);
+		mPixelArea = getSpatialPartition()->calcPixelArea(this, camera);
+	}
+}
+
+F32 LLSpatialPartition::calcDistance(LLSpatialGroup* group, LLCamera& camera)
+{
+	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())
+	{
+		LLVector4a v = eye;
+
+		dist = eye.getLength3().getF32();
+		eye.normalize3fast();
+
+		if (!group->hasState(LLSpatialGroup::ALPHA_DIRTY))
+		{
+			if (!group->getSpatialPartition()->isBridge())
+			{
+				LLVector4a view_angle = eye;
+
+				LLVector4a diff;
+				diff.setSub(view_angle, group->mLastUpdateViewAngle);
+
+				if (diff.getLength3().getF32() > 0.64f)
+				{
+					group->mViewAngle = view_angle;
+					group->mLastUpdateViewAngle = view_angle;
+					//for occasional alpha sorting within the group
+					//NOTE: If there is a trivial way to detect that alpha sorting here would not change the render order,
+					//not setting this node to dirty would be a very good thing
+					group->setState(LLSpatialGroup::ALPHA_DIRTY);
+					gPipeline.markRebuild(group, FALSE);
+				}
+			}
+		}
+
+		//calculate depth of node for alpha sorting
+
+		LLVector3 at = camera.getAtAxis();
+
+		LLVector4a ata;
+		ata.load3(at.mV);
+
+		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.getLength3().getF32();
+	}
+
+    LL_DEBUGS("RiggedBox") << "calcDistance, group " << group << " camera " << origin << " obj bounds " 
+                           << group->mObjectBounds[0] << ", " << group->mObjectBounds[1] 
+                           << " dist " << dist << " radius " << group->mRadius << LL_ENDL;
+
+	if (dist < 16.f)
+	{
+		dist /= 16.f;
+		dist *= dist;
+		dist *= 16.f;
+	}
+
+	return dist;
+}
+
+F32 LLSpatialPartition::calcPixelArea(LLSpatialGroup* group, LLCamera& camera)
+{
+	return LLPipeline::calcPixelArea(group->mObjectBounds[0], group->mObjectBounds[1], camera);
+}
+
+F32 LLSpatialGroup::getUpdateUrgency() const
+{
+	if (!isVisible())
+	{
+		return 0.f;
+	}
+	else
+	{
+		F32 time = gFrameTimeSeconds-mLastUpdateTime+4.f;
+		return time + (mObjectBounds[1].dot3(mObjectBounds[1]).getF32()+1.f)/mDistance;
+	}
+}
+
+BOOL LLSpatialGroup::changeLOD()
+{
+	if (hasState(ALPHA_DIRTY | OBJECT_DIRTY))
+	{
+		//a rebuild is going to happen, update distance and LoD
+		return TRUE;
+	}
+
+	if (getSpatialPartition()->mSlopRatio > 0.f)
+	{
+		F32 ratio = (mDistance - mLastUpdateDistance)/(llmax(mLastUpdateDistance, mRadius));
+
+        // MAINT-8264 - this check is not robust if it needs to work
+        // for bounding boxes much larger than the actual enclosed
+        // objects, and using distance to box center is also
+        // problematic. Consider the case that you have a large box
+        // where the enclosed object is in one corner. As you zoom in
+        // on the corner, the object gets much closer to the camera,
+        // but the distance to the box center changes very little, and
+        // an LOD change will not trigger, so object LOD gets "stuck"
+        // at a too-low value. In the case of the above JIRA, the box
+        // was large only due to another error, so this logic did not
+        // need to be changed.
+
+		if (fabsf(ratio) >= getSpatialPartition()->mSlopRatio)
+		{
+            LL_DEBUGS("RiggedBox") << "changeLOD true because of ratio compare "
+                                   << fabsf(ratio) << " " << getSpatialPartition()->mSlopRatio << LL_ENDL;
+            LL_DEBUGS("RiggedBox") << "sg " << this << "\nmDistance " << mDistance
+                                   << " mLastUpdateDistance " << mLastUpdateDistance
+                                   << " mRadius " << mRadius
+                                   << " fab ratio " << fabsf(ratio) 
+                                   << " slop " << getSpatialPartition()->mSlopRatio << LL_ENDL;
+       
+			return TRUE;
+		}
+
+		if (mDistance > mRadius*2.f)
+		{
+			return FALSE;
+		}
+	}
+	
+	if (needsUpdate())
+	{
+		return TRUE;
+	}
+	
+	return FALSE;
+}
+
+void LLSpatialGroup::handleInsertion(const TreeNode* node, LLViewerOctreeEntry* entry)
+{
+	addObject((LLDrawable*)entry->getDrawable());
+	unbound();
+	setState(OBJECT_DIRTY);
+}
+
+void LLSpatialGroup::handleRemoval(const TreeNode* node, LLViewerOctreeEntry* entry)
+{
+	removeObject((LLDrawable*)entry->getDrawable(), TRUE);
+	LLViewerOctreeGroup::handleRemoval(node, entry);
+}
+
+void LLSpatialGroup::handleDestruction(const TreeNode* node)
+{
+	if(isDead())
+	{
+		return;
+	}
+	setState(DEAD);	
+
+	for (element_iter i = getDataBegin(), i_end = getDataEnd(); i != i_end; ++i)
+	{
+		LLViewerOctreeEntry* entry = *i;
+
+		if (entry->getGroup() == this)
+		{
+			if(entry->hasDrawable())
+			{
+				((LLDrawable*)entry->getDrawable())->setGroup(NULL);
+			}
+		}
+	}
+	
+	clearDrawMap();
+	mVertexBuffer = NULL;
+	mBufferMap.clear();
+	sZombieGroups++;
+	mOctreeNode = NULL;
+}
+
+void LLSpatialGroup::handleChildAddition(const OctreeNode* parent, OctreeNode* child) 
+{
+	if (child->getListenerCount() == 0)
+	{
+		new LLSpatialGroup(child, getSpatialPartition());
+	}
+	else
+	{
+		OCT_ERRS << "LLSpatialGroup redundancy detected." << LL_ENDL;
+	}
+
+	unbound();
+
+	assert_states_valid(this);
+}
+
+void LLSpatialGroup::destroyGL(bool keep_occlusion) 
+{
+	setState(LLSpatialGroup::GEOM_DIRTY | LLSpatialGroup::IMAGE_DIRTY);
+
+	if (!keep_occlusion)
+	{ //going to need a rebuild
+		gPipeline.markRebuild(this, TRUE);
+	}
+
+	mLastUpdateTime = gFrameTimeSeconds;
+	mVertexBuffer = NULL;
+	mBufferMap.clear();
+
+	clearDrawMap();
+
+	if (!keep_occlusion)
+	{
+		releaseOcclusionQueryObjectNames();
+	}
+
+
+	for (LLSpatialGroup::element_iter i = getDataBegin(), i_end = getDataEnd(); i != i_end; ++i)
+	{
+		LLDrawable* drawable = (LLDrawable*)(*i)->getDrawable();
+		if(!drawable)
+		{
+			continue;
+		}
+		for (S32 j = 0; j < drawable->getNumFaces(); j++)
+		{
+			LLFace* facep = drawable->getFace(j);
+			if (facep)
+			{
+				facep->clearVertexBuffer();
+			}
+		}
+	}
+}
+
+//==============================================
+
+LLSpatialPartition::LLSpatialPartition(U32 data_mask, BOOL render_by_group, U32 buffer_usage, LLViewerRegion* regionp)
+: mBridge(NULL), mRenderByGroup(render_by_group)
+{
+	mRegionp = regionp;		
+	mPartitionType = LLViewerRegion::PARTITION_NONE;
+	mVertexDataMask = data_mask;
+	mBufferUsage = buffer_usage;
+	mDepthMask = FALSE;
+	mSlopRatio = 0.25f;
+	mInfiniteFarClip = FALSE;
+
+	new LLSpatialGroup(mOctree, this);
+}
+
+LLSpatialGroup *LLSpatialPartition::put(LLDrawable *drawablep, BOOL was_visible)
+{
+	drawablep->updateSpatialExtents();
+
+	//keep drawable from being garbage collected
+	LLPointer<LLDrawable> ptr = drawablep;
+		
+	if(!drawablep->getGroup())
+	{
+	assert_octree_valid(mOctree);
+		mOctree->insert(drawablep->getEntry());
+	assert_octree_valid(mOctree);
+	}	
+	
+	LLSpatialGroup* group = drawablep->getSpatialGroup();
+	llassert(group != NULL);
+
+	if (group && was_visible && group->isOcclusionState(LLSpatialGroup::QUERY_PENDING))
+	{
+		group->setOcclusionState(LLSpatialGroup::DISCARD_QUERY, LLSpatialGroup::STATE_MODE_ALL_CAMERAS);
+	}
+
+	return group;
+}
+
+BOOL LLSpatialPartition::remove(LLDrawable *drawablep, LLSpatialGroup *curp)
+{
+	if (!curp->removeObject(drawablep))
+	{
+		OCT_ERRS << "Failed to remove drawable from octree!" << LL_ENDL;
+	}
+	else
+	{
+		drawablep->setGroup(NULL);
+	}
+
+	assert_octree_valid(mOctree);
+	
+	return TRUE;
+}
+
+void LLSpatialPartition::move(LLDrawable *drawablep, LLSpatialGroup *curp, BOOL immediate)
+{
+	// sanity check submitted by open source user bushing Spatula
+	// who was seeing crashing here. (See VWR-424 reported by Bunny Mayne)
+	if (!drawablep)
+	{
+		OCT_ERRS << "LLSpatialPartition::move was passed a bad drawable." << LL_ENDL;
+		return;
+	}
+		
+	BOOL was_visible = curp ? curp->isVisible() : FALSE;
+
+	if (curp && curp->getSpatialPartition() != this)
+	{
+		//keep drawable from being garbage collected
+		LLPointer<LLDrawable> ptr = drawablep;
+		if (curp->getSpatialPartition()->remove(drawablep, curp))
+		{
+			put(drawablep, was_visible);
+			return;
+		}
+		else
+		{
+			OCT_ERRS << "Drawable lost between spatial partitions on outbound transition." << LL_ENDL;
+		}
+	}
+		
+	if (curp && curp->updateInGroup(drawablep, immediate))
+	{
+		// Already updated, don't need to do anything
+		assert_octree_valid(mOctree);
+		return;
+	}
+
+	//keep drawable from being garbage collected
+	LLPointer<LLDrawable> ptr = drawablep;
+	if (curp && !remove(drawablep, curp))
+	{
+		OCT_ERRS << "Move couldn't find existing spatial group!" << LL_ENDL;
+	}
+
+	put(drawablep, was_visible);
+}
+
+class LLSpatialShift final : public OctreeTraveler
+{
+public:
+	const LLVector4a& mOffset;
+
+	LLSpatialShift(const LLVector4a& offset) : mOffset(offset) { }
+
+    void visit(const OctreeNode* branch) override
+	{ 
+		((LLSpatialGroup*) branch->getListener(0))->shift(mOffset); 
+	}
+};
+
+void LLSpatialPartition::shift(const LLVector4a &offset)
+{ //shift octree node bounding boxes by offset
+	LLSpatialShift shifter(offset);
+	shifter.traverse(mOctree);
+}
+
+class LLOctreeCull : public LLViewerOctreeCull
+{
+public:
+	LLOctreeCull(LLCamera* camera) : LLViewerOctreeCull(camera) {}
+
+    bool earlyFail(LLViewerOctreeGroup* base_group) override
+	{
+		LLSpatialGroup* group = (LLSpatialGroup*)base_group;
+		group->checkOcclusion();
+
+		if (group->getOctreeNode()->getParent() &&	//never occlusion cull the root node
+		  	LLPipeline::sUseOcclusion &&			//ignore occlusion if disabled
+			group->isOcclusionState(LLSpatialGroup::OCCLUDED))
+		{
+			gPipeline.markOccluder(group);
+			return true;
+		}
+		
+		return false;
+	}
+
+    S32 frustumCheck(const LLViewerOctreeGroup* group) override
+	{
+		S32 res = AABBInFrustumNoFarClipGroupBounds(group);
+		if (res != 0)
+		{
+			res = llmin(res, AABBSphereIntersectGroupExtents(group));
+		}
+		return res;
+	}
+
+    S32 frustumCheckObjects(const LLViewerOctreeGroup* group) override
+	{
+		S32 res = AABBInFrustumNoFarClipObjectBounds(group);
+		if (res != 0)
+		{
+			res = llmin(res, AABBSphereIntersectObjectExtents(group));
+		}
+		return res;
+	}
+
+    void processGroup(LLViewerOctreeGroup* base_group) override
+	{
+		LLSpatialGroup* group = (LLSpatialGroup*)base_group;
+		if (group->needsUpdate() ||
+			group->getVisible(LLViewerCamera::sCurCameraID) < LLDrawable::getCurrentFrame() - 1)
+		{
+			group->doOcclusion(mCamera);
+		}
+		gPipeline.markNotCulled(group, *mCamera);
+	}
+};
+
+class LLOctreeCullNoFarClip final : public LLOctreeCull
+{
+public: 
+	LLOctreeCullNoFarClip(LLCamera* camera) 
+		: LLOctreeCull(camera) { }
+
+    S32 frustumCheck(const LLViewerOctreeGroup* group) override
+	{
+		return AABBInFrustumNoFarClipGroupBounds(group);
+	}
+
+    S32 frustumCheckObjects(const LLViewerOctreeGroup* group) override
+	{
+		S32 res = AABBInFrustumNoFarClipObjectBounds(group);
+		return res;
+	}
+};
+
+class LLOctreeCullShadow : public LLOctreeCull
+{
+public:
+	LLOctreeCullShadow(LLCamera* camera)
+		: LLOctreeCull(camera) { }
+
+    S32 frustumCheck(const LLViewerOctreeGroup* group) final override
+	{
+		return AABBInFrustumGroupBounds(group);
+	}
+
+    S32 frustumCheckObjects(const LLViewerOctreeGroup* group) final override
+	{
+		return AABBInFrustumObjectBounds(group);
+	}
+};
+
+class LLOctreeCullVisExtents final: public LLOctreeCullShadow
+{
+public:
+	LLOctreeCullVisExtents(LLCamera* camera, LLVector4a& min, LLVector4a& max)
+		: LLOctreeCullShadow(camera), mEmpty(TRUE), mMin(min), mMax(max) { }
+
+    bool earlyFail(LLViewerOctreeGroup* base_group) override
+	{
+		LLSpatialGroup* group = (LLSpatialGroup*)base_group;
+
+		if (group->getOctreeNode()->getParent() &&	//never occlusion cull the root node
+			LLPipeline::sUseOcclusion &&			//ignore occlusion if disabled
+			group->isOcclusionState(LLSpatialGroup::OCCLUDED))
+		{
+			return true;
+		}
+		
+		return false;
+	}
+
+    void traverse(const OctreeNode* n) override
+	{
+		LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
+
+		if (earlyFail(group))
+		{
+			return;
+		}
+		
+		if ((mRes && group->hasState(LLSpatialGroup::SKIP_FRUSTUM_CHECK)) ||
+			mRes == 2)
+		{	//don't need to do frustum check
+			OctreeTraveler::traverse(n);
+		}
+		else
+		{  
+			mRes = frustumCheck(group);
+				
+			if (mRes)
+			{ //at least partially in, run on down
+				OctreeTraveler::traverse(n);
+			}
+
+			mRes = 0;
+		}
+	}
+
+    void processGroup(LLViewerOctreeGroup* base_group) override
+	{
+		LLSpatialGroup* group = (LLSpatialGroup*)base_group;
+		
+		llassert(!group->hasState(LLSpatialGroup::DIRTY) && !group->isEmpty());
+		
+		if (mRes < 2)
+		{
+			if (AABBInFrustumObjectBounds(group) > 0)
+			{
+				mEmpty = FALSE;
+				const LLVector4a* exts = group->getObjectExtents();
+				update_min_max(mMin, mMax, exts[0]);
+				update_min_max(mMin, mMax, exts[1]);
+			}
+		}
+		else
+		{
+			mEmpty = FALSE;
+			const LLVector4a* exts = group->getExtents();
+			update_min_max(mMin, mMax, exts[0]);
+			update_min_max(mMin, mMax, exts[1]);
+		}
+	}
+
+	BOOL mEmpty;
+	LLVector4a& mMin;
+	LLVector4a& mMax;
+};
+
+class LLOctreeCullDetectVisible final: public LLOctreeCullShadow
+{
+public:
+	LLOctreeCullDetectVisible(LLCamera* camera)
+		: LLOctreeCullShadow(camera), mResult(FALSE) { }
+
+    bool earlyFail(LLViewerOctreeGroup* base_group) override
+	{
+		LLSpatialGroup* group = (LLSpatialGroup*)base_group;
+
+		if (mResult || //already found a node, don't check any more
+			(group->getOctreeNode()->getParent() &&	//never occlusion cull the root node
+			 LLPipeline::sUseOcclusion &&			//ignore occlusion if disabled
+			 group->isOcclusionState(LLSpatialGroup::OCCLUDED)))
+		{
+			return true;
+		}
+		
+		return false;
+	}
+
+    void processGroup(LLViewerOctreeGroup* base_group) override
+	{
+		if (base_group->isVisible())
+		{
+			mResult = TRUE;
+		}
+	}
+
+	BOOL mResult;
+};
+
+class LLOctreeSelect final : public LLOctreeCull
+{
+public:
+	LLOctreeSelect(LLCamera* camera, std::vector<LLDrawable*>* results)
+		: LLOctreeCull(camera), mResults(results) { }
+
+    bool earlyFail(LLViewerOctreeGroup* group) override { return false; }
+    void preprocess(LLViewerOctreeGroup* group) override { }
+
+    void processGroup(LLViewerOctreeGroup* base_group) override
+	{
+		LLSpatialGroup* group = (LLSpatialGroup*)base_group;
+		OctreeNode* branch = group->getOctreeNode();
+
+		for (OctreeNode::const_element_iter i = branch->getDataBegin(), i_end = branch->getDataEnd(); i != i_end; ++i)
+		{
+			LLDrawable* drawable = (LLDrawable*)(*i)->getDrawable();
+			if(!drawable)
+		{
+				continue;
+			}
+			if (!drawable->isDead())
+			{
+				if (drawable->isSpatialBridge())
+				{
+					drawable->setVisible(*mCamera, mResults, TRUE);
+				}
+				else
+				{
+					mResults->push_back(drawable);
+				}
+			}		
+		}
+	}
+	
+	std::vector<LLDrawable*>* mResults;
+};
+
+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);
+	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,1))).mV);
+	//right front
+	gGL.vertex3fv((c+r.scaledVec(LLVector3(1,1,-1))).mV);
+	gGL.vertex3fv((c+r.scaledVec(LLVector3(1,1,1))).mV);
+	//right back
+ 	gGL.vertex3fv((c+r.scaledVec(LLVector3(1,-1,-1))).mV);
+	gGL.vertex3fv((c+r.scaledVec(LLVector3(1,-1,1))).mV);
+	//left back
+	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,-1,-1))).mV);
+	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,-1,1))).mV);
+	//left front
+	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,-1))).mV);
+	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,1))).mV);
+	gGL.end();
+	
+	//bottom
+	gGL.begin(LLRender::TRIANGLE_STRIP);
+	gGL.vertex3fv((c+r.scaledVec(LLVector3(1,1,-1))).mV);
+	gGL.vertex3fv((c+r.scaledVec(LLVector3(1,-1,-1))).mV);
+	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,-1))).mV);
+	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,-1,-1))).mV);
+	gGL.end();
+
+	//top
+	gGL.begin(LLRender::TRIANGLE_STRIP);
+	gGL.vertex3fv((c+r.scaledVec(LLVector3(1,1,1))).mV);
+	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,1))).mV);
+	gGL.vertex3fv((c+r.scaledVec(LLVector3(1,-1,1))).mV);
+	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,-1,1))).mV);
+	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)
+{
+
+	llassert(pos.isFinite());
+	llassert(size.isFinite());
+
+	llassert(!llisnan(pos.mV[0]));
+	llassert(!llisnan(pos.mV[1]));
+	llassert(!llisnan(pos.mV[2]));
+
+	llassert(!llisnan(size.mV[0]));
+	llassert(!llisnan(size.mV[1]));
+	llassert(!llisnan(size.mV[2]));
+
+	LLVector3 v1 = size.scaledVec(LLVector3( 1, 1,1));
+	LLVector3 v2 = size.scaledVec(LLVector3(-1, 1,1));
+	LLVector3 v3 = size.scaledVec(LLVector3(-1,-1,1));
+	LLVector3 v4 = size.scaledVec(LLVector3( 1,-1,1));
+
+	gGL.begin(LLRender::LINES); 
+	
+	//top
+	gGL.vertex3fv((pos+v1).mV);
+	gGL.vertex3fv((pos+v2).mV);
+	gGL.vertex3fv((pos+v2).mV);
+	gGL.vertex3fv((pos+v3).mV);
+	gGL.vertex3fv((pos+v3).mV);
+	gGL.vertex3fv((pos+v4).mV);
+	gGL.vertex3fv((pos+v4).mV);
+	gGL.vertex3fv((pos+v1).mV);
+	
+	//bottom
+	gGL.vertex3fv((pos-v1).mV);
+	gGL.vertex3fv((pos-v2).mV);
+	gGL.vertex3fv((pos-v2).mV);
+	gGL.vertex3fv((pos-v3).mV);
+	gGL.vertex3fv((pos-v3).mV);
+	gGL.vertex3fv((pos-v4).mV);
+	gGL.vertex3fv((pos-v4).mV);
+	gGL.vertex3fv((pos-v1).mV);
+	
+	//right
+	gGL.vertex3fv((pos+v1).mV);
+	gGL.vertex3fv((pos-v3).mV);
+			
+	gGL.vertex3fv((pos+v4).mV);
+	gGL.vertex3fv((pos-v2).mV);
+
+	//left
+	gGL.vertex3fv((pos+v2).mV);
+	gGL.vertex3fv((pos-v4).mV);
+
+	gGL.vertex3fv((pos+v3).mV);
+	gGL.vertex3fv((pos-v1).mV);
+
+	gGL.end();
+}
+
+void drawBoxOutline(const LLVector4a& pos, const LLVector4a& size)
+{
+	drawBoxOutline(reinterpret_cast<const LLVector3&>(pos), reinterpret_cast<const LLVector3&>(size));
+}
+
+class LLOctreeDirty final : public OctreeTraveler
+{
+public:
+	LLOctreeDirty(bool no_rebuild) : mNoRebuild(no_rebuild){}
+
+    void visit(const OctreeNode* state) override
+	{
+		LLSpatialGroup* group = (LLSpatialGroup*) state->getListener(0);
+		group->destroyGL();
+
+		for (LLSpatialGroup::element_iter i = group->getDataBegin(), i_end = group->getDataEnd(); i != i_end; ++i)
+		{
+			LLDrawable* drawable = (LLDrawable*)(*i)->getDrawable();
+			if(!drawable)
+			{
+				continue;
+			}
+			if (drawable->getVObj().notNull())
+			{
+				drawable->getVObj()->resetVertexBuffers();
+			}
+			if (!mNoRebuild && drawable->getVObj().notNull() && !group->getSpatialPartition()->mRenderByGroup)
+			{
+				gPipeline.markRebuild(drawable, LLDrawable::REBUILD_ALL, TRUE);
+			}
+		}
+
+		for (LLSpatialBridge* bridge : group->mBridgeList)
+		{
+			traverse(bridge->mOctree);
+		}
+	}
+
+private:
+	BOOL mNoRebuild;
+};
+
+void LLSpatialPartition::restoreGL()
+{
+}
+
+void LLSpatialPartition::resetVertexBuffers()
+{
+	LLOctreeDirty dirty(sTeleportRequested);
+	dirty.traverse(mOctree);
+}
+
+BOOL LLSpatialPartition::getVisibleExtents(LLCamera& camera, LLVector3& visMin, LLVector3& visMax)
+{
+	LLVector4a visMina, visMaxa;
+	visMina.load3(visMin.mV);
+	visMaxa.load3(visMax.mV);
+
+	{
+		LL_RECORD_BLOCK_TIME(FTM_CULL_REBOUND);		
+		LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0);
+		group->rebound();
+	}
+
+	LLOctreeCullVisExtents vis(&camera, visMina, visMaxa);
+	vis.traverse(mOctree);
+
+	visMin.set(visMina.getF32ptr());
+	visMax.set(visMaxa.getF32ptr());
+	return vis.mEmpty;
+}
+
+BOOL LLSpatialPartition::visibleObjectsInFrustum(LLCamera& camera)
+{
+	LLOctreeCullDetectVisible vis(&camera);
+	vis.traverse(mOctree);
+	return vis.mResult;
+}
+
+S32 LLSpatialPartition::cull(LLCamera &camera, std::vector<LLDrawable *>* results, BOOL for_select)
+{
+#if LL_OCTREE_PARANOIA_CHECK
+	((LLSpatialGroup*)mOctree->getListener(0))->checkStates();
+#endif
+	{
+		LL_RECORD_BLOCK_TIME(FTM_CULL_REBOUND);		
+		LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0);
+		group->rebound();
+	}
+
+#if LL_OCTREE_PARANOIA_CHECK
+	((LLSpatialGroup*)mOctree->getListener(0))->validate();
+#endif
+
+		LLOctreeSelect selecter(&camera, results);
+		selecter.traverse(mOctree);
+	
+	return 0;
+	}
+	
+S32 LLSpatialPartition::cull(LLCamera &camera, bool do_occlusion)
+{
+#if LL_OCTREE_PARANOIA_CHECK
+	((LLSpatialGroup*)mOctree->getListener(0))->checkStates();
+#endif
+	{
+		LL_RECORD_BLOCK_TIME(FTM_CULL_REBOUND);		
+		LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0);
+		group->rebound();
+	}
+
+#if LL_OCTREE_PARANOIA_CHECK
+	((LLSpatialGroup*)mOctree->getListener(0))->validate();
+#endif
+
+	if (LLPipeline::sShadowRender)
+	{
+		LL_RECORD_BLOCK_TIME(FTM_FRUSTUM_CULL);
+		LLOctreeCullShadow culler(&camera);
+		culler.traverse(mOctree);
+	}
+	else if (mInfiniteFarClip || !LLPipeline::sUseFarClip)
+	{
+		LL_RECORD_BLOCK_TIME(FTM_FRUSTUM_CULL);		
+		LLOctreeCullNoFarClip culler(&camera);
+		culler.traverse(mOctree);
+	}
+	else
+	{
+		LL_RECORD_BLOCK_TIME(FTM_FRUSTUM_CULL);		
+		LLOctreeCull culler(&camera);
+		culler.traverse(mOctree);
+	}
+	
+	return 0;
+}
+
+void pushVerts(LLDrawInfo* params, U32 mask)
+{
+	LLRenderPass::applyModelMatrix(*params);
+	params->mVertexBuffer->setBuffer(mask);
+	params->mVertexBuffer->drawRange(params->mParticle ? LLRender::POINTS : LLRender::TRIANGLES,
+								params->mStart, params->mEnd, params->mCount, params->mOffset);
+}
+
+void pushVerts(LLSpatialGroup* group, U32 mask)
+{
+	for (auto& pair : group->mDrawMap)
+	{
+		for (LLDrawInfo* params : pair.second)
+		{
+			pushVerts(params, mask);
+		}
+	}
+}
+
+void pushVerts(LLFace* face, U32 mask)
+{
+	if (face)
+	{
+		llassert(face->verify());
+
+		LLVertexBuffer* buffer = face->getVertexBuffer();
+
+		if (buffer && (face->getGeomCount() >= 3))
+		{
+			buffer->setBuffer(mask);
+			U16 start = face->getGeomStart();
+			U16 end = start + face->getGeomCount()-1;
+			U32 count = face->getIndicesCount();
+			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);
+		LLVertexBuffer::drawElements(LLRender::TRIANGLES, face.mNumVertices, face.mPositions, NULL, face.mNumIndices, face.mIndices);
+	}
+}
+
+void pushBufferVerts(LLVertexBuffer* buffer, U32 mask)
+{
+	if (buffer)
+	{
+		buffer->setBuffer(mask);
+		buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
+	}
+}
+
+void pushBufferVerts(LLSpatialGroup* group, U32 mask, bool push_alpha = true)
+{
+	if (group->getSpatialPartition()->mRenderByGroup)
+	{
+		if (!group->mDrawMap.empty())
+		{
+			LLDrawInfo* params = *(group->mDrawMap.begin()->second.begin());
+			LLRenderPass::applyModelMatrix(*params);
+		
+			if (push_alpha)
+			{
+				pushBufferVerts(group->mVertexBuffer, mask);
+			}
+
+			for (auto& buff_pair : group->mBufferMap)
+			{
+				for (auto& buff_tex_pair : buff_pair.second)
+				{
+					for (LLVertexBuffer* buff : buff_tex_pair.second)
+					{
+						pushBufferVerts(buff, mask);
+					}
+				}
+			}
+		}
+	}
+	/*else
+	{
+		//const LLVector4a* bounds = group->getBounds();
+		//drawBox(bounds[0], bounds[1]);
+	}*/
+}
+
+void pushVertsColorCoded(LLSpatialGroup* group, U32 mask)
+{
+	LLDrawInfo* params = NULL;
+
+	static const std::array<LLColor4, 7> colors {{
+		LLColor4::green,
+		LLColor4::green1,
+		LLColor4::green2,
+		LLColor4::green3,
+		LLColor4::green4,
+		LLColor4::green5,
+		LLColor4::green6
+	}};
+
+	U32 col = 0;
+
+	for (auto& i : group->mDrawMap)
+    {
+		for (auto& j : i.second)
+        {
+			params = j;
+			LLRenderPass::applyModelMatrix(*params);
+			gGL.diffuseColor4f(colors[col].mV[0], colors[col].mV[1], colors[col].mV[2], 0.5f);
+			params->mVertexBuffer->setBuffer(mask);
+			params->mVertexBuffer->drawRange(params->mParticle ? LLRender::POINTS : LLRender::TRIANGLES,
+				params->mStart, params->mEnd, params->mCount, params->mOffset);
+			col = (col+1)%colors.size();
+		}
+	}
+}
+
+void renderOctree(LLSpatialGroup* group)
+{
+	//render solid object bounding box, color
+	//coded by buffer usage and activity
+	gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA);
+	LLVector4 col;
+	if (group->mBuilt > 0.f)
+	{
+		group->mBuilt -= 2.f * gFrameIntervalSeconds.value();
+		if (group->mBufferUsage == GL_STATIC_DRAW_ARB)
+		{
+			col.setVec(1.0f, 0, 0, group->mBuilt*0.5f);
+		}
+		else 
+		{
+			col.setVec(0.1f,0.1f,1,0.1f);
+			//col.setVec(1.0f, 1.0f, 0, sinf(group->mBuilt*3.14159f)*0.5f);
+		}
+
+		if (group->mBufferUsage != GL_STATIC_DRAW_ARB)
+		{
+			LLGLDepthTest gl_depth(FALSE, FALSE);
+			glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+
+			gGL.diffuseColor4f(1,0,0,group->mBuilt);
+			gGL.flush();
+			gGL.setLineWidth(5.f);
+
+			const LLVector4a* bounds = group->getObjectBounds();
+			drawBoxOutline(bounds[0], bounds[1]);
+			gGL.flush();
+			gGL.setLineWidth(1.f);
+			gGL.flush();
+			for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i)
+			{
+				LLDrawable* drawable = (LLDrawable*)(*i)->getDrawable();
+				if(!drawable)
+				{
+					continue;
+				}
+				if (!group->getSpatialPartition()->isBridge())
+				{
+					gGL.pushMatrix();
+					LLVector3 trans = drawable->getRegion()->getOriginAgent();
+					gGL.translatef(trans.mV[0], trans.mV[1], trans.mV[2]);
+				}
+				
+				for (S32 j = 0; j < drawable->getNumFaces(); j++)
+				{
+					LLFace* face = drawable->getFace(j);
+					if (face && face->getVertexBuffer())
+					{
+						if (gFrameTimeSeconds - face->mLastUpdateTime < 0.5f)
+						{
+							gGL.diffuseColor4f(0, 1, 0, group->mBuilt);
+						}
+						else if (gFrameTimeSeconds - face->mLastMoveTime < 0.5f)
+						{
+							gGL.diffuseColor4f(1, 0, 0, group->mBuilt);
+						}
+						else
+						{
+							continue;
+						}
+
+						face->getVertexBuffer()->setBuffer(LLVertexBuffer::MAP_VERTEX);
+						//drawBox((face->mExtents[0] + face->mExtents[1])*0.5f,
+						//		(face->mExtents[1]-face->mExtents[0])*0.5f);
+						face->getVertexBuffer()->draw(LLRender::TRIANGLES, face->getIndicesCount(), face->getIndicesStart());
+					}
+				}
+
+				if (!group->getSpatialPartition()->isBridge())
+				{
+					gGL.popMatrix();
+				}
+			}
+			glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+			gGL.diffuseColor4f(1,1,1,1);
+		}
+	}
+	else
+	{
+		if (group->mBufferUsage == GL_STATIC_DRAW_ARB && !group->isEmpty() 
+			&& group->getSpatialPartition()->mRenderByGroup)
+		{
+			col.setVec(0.8f, 0.4f, 0.1f, 0.1f);
+		}
+		else
+		{
+			col.setVec(0.1f, 0.1f, 1.f, 0.1f);
+		}
+	}
+
+	gGL.diffuseColor4fv(col.mV);
+	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);
+
+	//if (group->mBuilt <= 0.f)
+	{
+		//draw opaque outline
+		//gGL.diffuseColor4f(col.mV[0], col.mV[1], col.mV[2], 1.f);
+		//drawBoxOutline(group->mObjectBounds[0], group->mObjectBounds[1]);
+
+		gGL.diffuseColor4f(0,1,1,1);
+
+		const LLVector4a* bounds = group->getBounds();
+		drawBoxOutline(bounds[0], bounds[1]);
+		
+		//draw bounding box for draw info
+		/*if (group->getSpatialPartition()->mRenderByGroup)
+		{
+			gGL.diffuseColor4f(1.0f, 0.75f, 0.25f, 0.6f);
+			for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i)
+			{
+				for (LLSpatialGroup::drawmap_elem_t::iterator j = i->second.begin(); j != i->second.end(); ++j)
+				{
+					LLDrawInfo* draw_info = *j;
+					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);
+				}
+			}
+		}*/
+	}
+	
+//	LLSpatialGroup::OctreeNode* node = group->mOctreeNode;
+//	gGL.diffuseColor4f(0,1,0,1);
+//	drawBoxOutline(LLVector3(node->getCenter()), LLVector3(node->getSize()));
+}
+
+std::set<LLSpatialGroup*> visible_selected_groups;
+
+void renderVisibility(LLSpatialGroup* group, LLCamera* camera)
+{
+	/*LLGLEnable blend(GL_BLEND);
+	gGL.setSceneBlendType(LLRender::BT_ALPHA);
+	LLGLEnable cull(GL_CULL_FACE);
+	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);*/
+
+	/*BOOL render_objects = (!LLPipeline::sUseOcclusion || !group->isOcclusionState(LLSpatialGroup::OCCLUDED)) && group->isVisible() &&
+							!group->isEmpty();
+
+
+	if (render_objects)
+	{
+		LLGLDepthTest depth(GL_TRUE, GL_FALSE);
+
+		LLGLDisable blend(GL_BLEND);
+		gGL.diffuseColor4f(0.f, 0.75f, 0.f,0.5f);
+		pushBufferVerts(group, LLVertexBuffer::MAP_VERTEX, false);
+		
+		glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+		gGL.setLineWidth(4.f);
+		gGL.diffuseColor4f(0.f, 0.5f, 0.f, 1.f);
+		pushBufferVerts(group, LLVertexBuffer::MAP_VERTEX, false);
+		gGL.setLineWidth(1.f);
+		glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+
+		bool selected = false;
+		
+		for (LLSpatialGroup::element_iter iter = group->getDataBegin(); iter != group->getDataEnd(); ++iter)
+		{
+			LLDrawable* drawable = *iter;
+			if (drawable->getVObj().notNull() && drawable->getVObj()->isSelected())
+			{
+				selected = true;
+				break;
+			}
+		}
+		
+		if (selected)
+		{ //store for rendering occlusion volume as overlay
+			visible_selected_groups.insert(group);
+		}
+	}*/		
+
+	/*if (render_objects)
+	{
+		LLGLDepthTest depth_under(GL_TRUE, GL_FALSE, GL_GREATER);
+		gGL.diffuseColor4f(0, 0.5f, 0, 0.5f);
+		pushBufferVerts(group, LLVertexBuffer::MAP_VERTEX);
+	}
+
+	{
+		LLGLDepthTest depth_over(GL_TRUE, GL_FALSE, GL_LEQUAL);
+
+		if (render_objects)
+		{
+			gGL.diffuseColor4f(0.f, 0.5f, 0.f,1.f);
+			pushBufferVerts(group, LLVertexBuffer::MAP_VERTEX);
+		}
+
+		glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+
+		if (render_objects)
+		{
+			gGL.diffuseColor4f(0.f, 0.75f, 0.f,0.5f);
+			pushBufferVerts(group, LLVertexBuffer::MAP_VERTEX);
+		
+			bool selected = false;
+		
+			for (LLSpatialGroup::element_iter iter = group->getDataBegin(); iter != group->getDataEnd(); ++iter)
+			{
+				LLDrawable* drawable = *iter;
+				if (drawable->getVObj().notNull() && drawable->getVObj()->isSelected())
+				{
+					selected = true;
+					break;
+				}
+			}
+		
+			if (selected)
+			{ //store for rendering occlusion volume as overlay
+				visible_selected_groups.insert(group);
+			}
+		}		
+	}*/
+}
+
+void renderXRay(LLSpatialGroup* group, LLCamera* camera)
+{
+	BOOL render_objects = (!LLPipeline::sUseOcclusion || !group->isOcclusionState(LLSpatialGroup::OCCLUDED)) && group->isVisible() &&
+							!group->isEmpty();
+	
+	if (render_objects)
+	{
+		pushBufferVerts(group, LLVertexBuffer::MAP_VERTEX, false);
+
+		bool selected = false;
+
+		for (LLSpatialGroup::element_iter iter = group->getDataBegin(); iter != group->getDataEnd(); ++iter)
+		{
+			LLDrawable* drawable = (LLDrawable*)(*iter)->getDrawable();
+			if (drawable->getVObj().notNull() && drawable->getVObj()->isSelected())
+			{
+				selected = true;
+				break;
+			}
+		}
+
+		if (selected)
+		{ //store for rendering occlusion volume as overlay
+
+			if (!group->getSpatialPartition()->isBridge())
+			{
+				visible_selected_groups.insert(group);
+			}
+			else
+			{
+				visible_selected_groups.insert(group->getSpatialPartition()->asBridge()->getSpatialGroup());
+			}
+		}
+	}
+}
+
+void renderCrossHairs(LLVector3 position, F32 size, LLColor4 color)
+{
+	gGL.color4fv(color.mV);
+	gGL.begin(LLRender::LINES);
+	{
+		gGL.vertex3fv((position - LLVector3(size, 0.f, 0.f)).mV);
+		gGL.vertex3fv((position + LLVector3(size, 0.f, 0.f)).mV);
+		gGL.vertex3fv((position - LLVector3(0.f, size, 0.f)).mV);
+		gGL.vertex3fv((position + LLVector3(0.f, size, 0.f)).mV);
+		gGL.vertex3fv((position - LLVector3(0.f, 0.f, size)).mV);
+		gGL.vertex3fv((position + LLVector3(0.f, 0.f, size)).mV);
+	}
+	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:
+		gGL.diffuseColor4f(0,1,0,0.5f);
+		break;
+	case OUT_TERSE_IMPROVED:
+		gGL.diffuseColor4f(0,1,1,0.5f);
+		break;
+	case OUT_FULL_COMPRESSED:
+		if (vobj->getLastUpdateCached())
+		{
+			gGL.diffuseColor4f(1,0,0,0.5f);
+		}
+		else
+		{
+			gGL.diffuseColor4f(1,1,0,0.5f);
+		}
+		break;
+	case OUT_FULL_CACHED:
+		gGL.diffuseColor4f(0,0,1,0.5f);
+		break;
+	default:
+		LL_WARNS() << "Unknown update_type " << vobj->getLastUpdateType() << LL_ENDL;
+		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 renderComplexityDisplay(LLDrawable* drawablep)
+{
+	LLViewerObject* vobj = drawablep->getVObj();
+	if (!vobj)
+	{
+		return;
+	}
+
+	LLVOVolume *voVol = vobj->asVolume();;
+
+	if (!voVol)
+	{
+		return;
+	}
+
+	if (!voVol->isRoot())
+	{
+		return;
+	}
+
+	LLVOVolume::texture_cost_t textures;
+	F32 cost = (F32) voVol->getRenderCost(textures);
+
+	// add any child volumes
+	LLViewerObject::const_child_list_t children = voVol->getChildren();
+	for (const auto& iter : children)
+    {
+		const LLViewerObject *child = iter;
+		const LLVOVolume *child_volume = dynamic_cast<const LLVOVolume*>(child);
+		if (child_volume)
+		{
+			cost += child_volume->getRenderCost(textures);
+		}
+	}
+
+	// add texture cost
+	for (auto& texture : textures)
+    {
+		// add the cost of each individual texture in the linkset
+		cost += texture.second;
+	}
+
+	F32 cost_max = (F32) LLVOVolume::getRenderComplexityMax();
+
+
+
+	// allow user to set a static color scale
+	if (gSavedSettings.getS32("RenderComplexityStaticMax") > 0)
+	{
+		cost_max = gSavedSettings.getS32("RenderComplexityStaticMax");
+	}
+
+	F32 cost_ratio = cost / cost_max;
+	
+	// cap cost ratio at 1.0f in case cost_max is at a low threshold
+	cost_ratio = cost_ratio > 1.0f ? 1.0f : cost_ratio;
+	
+	LLGLEnable blend(GL_BLEND);
+
+	LLColor4 color;
+	const LLColor4 color_min = gSavedSettings.getColor4("RenderComplexityColorMin");
+	const LLColor4 color_mid = gSavedSettings.getColor4("RenderComplexityColorMid");
+	const LLColor4 color_max = gSavedSettings.getColor4("RenderComplexityColorMax");
+
+	if (cost_ratio < 0.5f)
+	{
+		color = color_min * (1 - cost_ratio * 2) + color_mid * (cost_ratio * 2);
+	}
+	else
+	{
+		color = color_mid * (1 - (cost_ratio - 0.5) * 2) + color_max * ((cost_ratio - 0.5) * 2);
+	}
+
+	LLSD color_val = color.getValue();
+
+	// don't highlight objects below the threshold
+	if (cost > gSavedSettings.getS32("RenderComplexityThreshold"))
+	{
+		gGL.diffuseColor4f(color[0],color[1],color[2],0.5f);
+
+
+		S32 num_faces = drawablep->getNumFaces();
+		if (num_faces)
+		{
+			for (S32 i = 0; i < num_faces; ++i)
+			{
+				pushVerts(drawablep->getFace(i), LLVertexBuffer::MAP_VERTEX);
+			}
+		}
+		LLViewerObject::const_child_list_t children = voVol->getChildren();
+		for (const auto& iter : children)
+        {
+			const LLViewerObject *child = iter;
+			if (child)
+			{
+				num_faces = child->getNumFaces();
+				if (num_faces)
+				{
+					for (S32 i = 0; i < num_faces; ++i)
+					{
+						pushVerts(child->mDrawable->getFace(i), LLVertexBuffer::MAP_VERTEX);
+					}
+				}
+			}
+		}
+	}
+	
+	voVol->setDebugText(llformat("%4.0f", cost));	
+}
+
+void renderBoundingBox(LLDrawable* drawable, BOOL set_color = TRUE)
+{
+	if (set_color)
+	{
+		if (drawable->isSpatialBridge())
+		{
+			gGL.diffuseColor4f(1,0.5f,0,1); // orange
+		}
+		else if (drawable->getVOVolume())
+		{ 
+            if (drawable->isRoot())
+			{
+				gGL.diffuseColor4f(1,1,0,1); // yellow
+			}
+			else
+			{
+				gGL.diffuseColor4f(0,1,0,1); // green
+			}
+		}
+		else if (drawable->getVObj())
+		{
+			switch (drawable->getVObj()->getPCode())
+			{
+				case LLViewerObject::LL_VO_SURFACE_PATCH:
+                    	gGL.diffuseColor4f(0,1,1,1); // cyan
+						break;
+				case LLViewerObject::LL_VO_CLOUDS:
+						// no longer used
+						break;
+				case LLViewerObject::LL_VO_PART_GROUP:
+				case LLViewerObject::LL_VO_HUD_PART_GROUP:
+                    	gGL.diffuseColor4f(0,0,1,1); // blue
+						break;
+				case LLViewerObject::LL_VO_VOID_WATER:
+				case LLViewerObject::LL_VO_WATER:
+                    	gGL.diffuseColor4f(0,0.5f,1,1); // medium blue
+						break;
+				case LL_PCODE_LEGACY_TREE:
+                    	gGL.diffuseColor4f(0,0.5f,0,1); // dark green
+						break;
+				default:
+						auto avatar = drawable->getVObj()->asAvatar();
+						if (avatar->isControlAvatar())
+						{
+							LLControlAvatar* cav = static_cast<LLControlAvatar*>(avatar);
+							bool has_pos_constraint = (cav->mPositionConstraintFixup != LLVector3());
+							bool has_scale_constraint = (cav->mScaleConstraintFixup != 1.0f);
+							if (has_pos_constraint || has_scale_constraint)
+							{
+								gGL.diffuseColor4f(1,0,0,1); 
+							}
+							else
+							{
+								gGL.diffuseColor4f(0,1,0.5,1); 
+							}
+						}
+						else
+						{
+							gGL.diffuseColor4f(1,0,1,1); // magenta
+						}
+						break;
+			}
+		}
+		else 
+		{
+			gGL.diffuseColor4f(1,0,0,1);
+		}
+	}
+
+	const LLVector4a* ext;
+	LLVector4a pos, size;
+
+	if (drawable->getVOVolume())
+	{
+		//render face bounding boxes
+		for (S32 i = 0; i < drawable->getNumFaces(); i++)
+		{
+			LLFace* facep = drawable->getFace(i);
+			if (facep)
+			{
+				ext = facep->mExtents;
+
+				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.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())
+	{
+		gGL.flush();
+		gGL.setLineWidth(llmax(4.f*sinf(gFrameTimeSeconds*2.f)+1.f, 1.f));
+		//gGL.setLineWidth(4.f*(sinf(gFrameTimeSeconds*2.f)*0.25f+0.75f));
+		stop_glerror();
+		drawBoxOutline(pos,size);
+		gGL.flush();
+		gGL.setLineWidth(1.f);
+	}
+	else
+	{
+		drawBoxOutline(pos,size);
+	}
+}
+
+void renderNormals(LLDrawable* drawablep)
+{
+	LLVertexBuffer::unbind();
+
+	LLVOVolume* vol = drawablep->getVOVolume();
+	if (vol)
+	{
+		LLVolume* volume = vol->getVolume();
+		gGL.pushMatrix();
+		gGL.multMatrix((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);
+
+			for (S32 j = 0; j < face.mNumVertices; ++j)
+			{
+				gGL.begin(LLRender::LINES);
+				LLVector4a n,p;
+				
+				n.setMul(face.mNormals[j], scale);
+				p.setAdd(face.mPositions[j], n);
+				
+				gGL.diffuseColor4f(1,1,1,1);
+				gGL.vertex3fv(face.mPositions[j].getF32ptr());
+				gGL.vertex3fv(p.getF32ptr());
+				
+				if (face.mTangents)
+				{
+					n.setMul(face.mTangents[j], scale);
+					p.setAdd(face.mPositions[j], n);
+				
+					gGL.diffuseColor4f(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())
+		{
+			gGL.diffuseColor4fv(color.mV);
+			LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mBaseHullMesh.mPositions, decomp->mBaseHullMesh.mNormals);
+		}
+		else
+		{
+			gMeshRepo.buildPhysicsMesh(*decomp);
+			gGL.diffuseColor4f(0,1,1,1);
+			drawBoxOutline(center, size);
+		}
+
+	}
+	else
+	{
+		gGL.diffuseColor3f(1,0,1);
+		drawBoxOutline(center, size);
+	}
+}
+
+void render_hull(LLModel::PhysicsMesh& mesh, const LLColor4& color, const LLColor4& line_color)
+{
+	gGL.diffuseColor4fv(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);
+	gGL.setLineWidth(3.f);
+	gGL.diffuseColor4fv(line_color.mV);
+	LLVertexBuffer::drawArrays(LLRender::TRIANGLES, mesh.mPositions, mesh.mNormals);
+	gGL.setLineWidth(1.f);
+	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+}
+
+void renderPhysicsShape(LLDrawable* drawable, LLVOVolume* volume)
+{
+	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();
+	gGL.multMatrix((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 (auto& i : decomp->mMesh)
+                {		
+					render_hull(i, color, line_color);
+				}
+			}
+			else if (!decomp->mPhysicsShapeMesh.empty())
+			{ 
+				//decomp has physics mesh, render that mesh
+				gGL.diffuseColor4fv(color.mV);
+				LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mPhysicsShapeMesh.mPositions, decomp->mPhysicsShapeMesh.mNormals);
+								
+				glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+				gGL.diffuseColor4fv(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.diffuseColor3f(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);
+		}
+		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.emplace_back(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 && phys_volume->mHullIndices && phys_volume->mNumHullPoints > 0 && phys_volume->mNumHullIndices > 0)
+			{
+				//render hull
+			
+				glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+				
+				gGL.diffuseColor4fv(line_color.mV);
+				LLVertexBuffer::unbind();
+
+				llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShader != 0);
+							
+				LLVertexBuffer::drawElements(LLRender::TRIANGLES, phys_volume->mNumHullPoints, phys_volume->mHullPoints, NULL, phys_volume->mNumHullIndices, phys_volume->mHullIndices);
+				
+				gGL.diffuseColor4fv(color.mV);
+				glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+				LLVertexBuffer::drawElements(LLRender::TRIANGLES, phys_volume->mNumHullPoints, phys_volume->mHullPoints, NULL, phys_volume->mNumHullIndices, phys_volume->mHullIndices);
+				
+			}
+			else
+			{
+				gGL.diffuseColor4f(1,0,1,1);
+				drawBoxOutline(center, size);
+			}
+
+			LLPrimitive::sVolumeManager->unrefVolume(phys_volume);
+		}
+	}
+	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.diffuseColor4fv(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);
+		
+		gGL.diffuseColor4fv(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);
+		
+		gGL.diffuseColor4fv(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);
+		
+		gGL.diffuseColor4fv(line_color.mV);
+		pushVerts(phys_volume);
+		
+		gGL.diffuseColor4fv(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)
+		{
+			gGL.diffuseColor4fv(line_color.mV);
+			glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+			LLVertexBuffer::drawElements(LLRender::TRIANGLES, phys_volume->mNumHullPoints, phys_volume->mHullPoints, NULL, phys_volume->mNumHullIndices, phys_volume->mHullIndices);
+
+			gGL.diffuseColor4fv(color.mV);
+			glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+			LLVertexBuffer::drawElements(LLRender::TRIANGLES, phys_volume->mNumHullPoints, phys_volume->mHullPoints, NULL, phys_volume->mNumHullIndices, phys_volume->mHullIndices);
+		}
+		else
+		{
+			gGL.diffuseColor3f(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 
+	{
+		LL_ERRS() << "Unhandled type" << LL_ENDL;
+	}
+
+	gGL.popMatrix();
+}
+
+void renderPhysicsShapes(LLSpatialGroup* group)
+{
+	for (OctreeNode::const_element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i)
+	{
+		LLDrawable* drawable = (LLDrawable*)(*i)->getDrawable();
+		if(!drawable)
+	{
+			continue;
+		}
+
+		if (drawable->isSpatialBridge())
+		{
+			LLSpatialBridge* bridge = drawable->asPartition()->asBridge();
+
+			if (bridge)
+			{
+				gGL.pushMatrix();
+				gGL.multMatrix((F32*)bridge->mDrawable->getRenderMatrix().mMatrix);
+				bridge->renderPhysicsShapes();
+				gGL.popMatrix();
+			}
+		}
+		else
+		{
+			LLVOVolume* volume = drawable->getVOVolume();
+			if (volume && !volume->isAttachment() && volume->getPhysicsShapeType() != LLViewerObject::PHYSICS_SHAPE_NONE )
+			{
+				if (!group->getSpatialPartition()->isBridge())
+				{
+					gGL.pushMatrix();
+					LLVector3 trans = drawable->getRegion()->getOriginAgent();
+					gGL.translatef(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)
+				{
+					gGL.pushMatrix();
+					gGL.multMatrix((F32*) object->getRegion()->mRenderMatrix.mMatrix);
+					//push face vertices for terrain
+					for (S32 i = 0; i < drawable->getNumFaces(); ++i)
+					{
+						LLFace* face = drawable->getFace(i);
+						if (face)
+						{
+							LLVertexBuffer* buff = face->getVertexBuffer();
+							if (buff)
+							{
+								glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+
+								buff->setBuffer(LLVertexBuffer::MAP_VERTEX);
+								gGL.diffuseColor3f(0.2f, 0.5f, 0.3f);
+								buff->draw(LLRender::TRIANGLES, buff->getNumIndices(), 0);
+									
+								gGL.diffuseColor3f(0.2f, 1.f, 0.3f);
+								glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+								buff->draw(LLRender::TRIANGLES, buff->getNumIndices(), 0);
+							}
+						}
+					}
+					gGL.popMatrix();
+				}
+			}
+		}
+	}
+}
+
+void renderTexturePriority(LLDrawable* drawable)
+{
+	for (int face=0; face<drawable->getNumFaces(); ++face)
+	{
+		LLFace *facep = drawable->getFace(face);
+		
+		LLVector4 cold(0,0,0.25f);
+		LLVector4 hot(1,0.25f,0.25f);
+	
+		LLVector4 boost_cold(0,0,0,0);
+		LLVector4 boost_hot(0,1,0,1);
+		
+		LLGLDisable blend(GL_BLEND);
+		
+		//LLViewerTexture* imagep = facep->getTexture();
+		//if (imagep)
+		if (facep)
+		{
+				
+			//F32 vsize = imagep->mMaxVirtualSize;
+			F32 vsize = facep->getPixelArea();
+
+			if (vsize > sCurMaxTexPriority)
+			{
+				sCurMaxTexPriority = vsize;
+			}
+			
+			F32 t = vsize/sLastMaxTexPriority;
+			
+			LLVector4 col = lerp(cold, hot, t);
+			gGL.diffuseColor4fv(col.mV);
+		}
+		//else
+		//{
+		//	gGL.diffuseColor4f(1,0,1,1);
+		//}
+		
+		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();
+		if (boost>LLGLTexture::BOOST_NONE)
+		{
+			F32 t = (F32) boost / (F32) (LLGLTexture::BOOST_MAX_LEVEL-1);
+			LLVector4 col = lerp(boost_cold, boost_hot, t);
+			LLGLEnable blend_on(GL_BLEND);
+			gGL.blendFunc(GL_SRC_ALPHA, GL_ONE);
+			gGL.diffuseColor4fv(col.mV);
+			drawBox(center, size);
+			gGL.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+		}*/
+	}
+}
+
+void renderPoints(LLDrawable* drawablep)
+{
+	LLGLDepthTest depth(GL_FALSE, GL_FALSE);
+	if (drawablep->getNumFaces())
+	{
+		gGL.begin(LLRender::POINTS);
+		gGL.diffuseColor3f(1,1,1);
+		for (S32 i = 0; i < drawablep->getNumFaces(); i++)
+		{
+			LLFace * face = drawablep->getFace(i);
+			if (face)
+			{
+				gGL.vertex3fv(face->mCenterLocal.mV);
+			}
+		}
+		gGL.end();
+	}
+}
+
+void renderTextureAnim(LLDrawInfo* params)
+{
+	if (!params->mTextureMatrix)
+	{
+		return;
+	}
+	
+	LLGLEnable blend(GL_BLEND);
+	gGL.diffuseColor4f(1,1,0,0.5f);
+	pushVerts(params, LLVertexBuffer::MAP_VERTEX);
+}
+
+void renderBatchSize(LLDrawInfo* params)
+{
+	LLGLEnable offset(GL_POLYGON_OFFSET_FILL);
+	glPolygonOffset(-1.f, 1.f);
+	if (params->mDebugColor == LLColor4U::black)
+	{
+		params->mDebugColor = LLColor4U(ll_rand(255), ll_rand(255), ll_rand(255), 255U);
+	}
+	gGL.diffuseColor4ubv((U8*)params->mDebugColor.mV);
+	pushVerts(params, LLVertexBuffer::MAP_VERTEX);
+}
+
+void renderShadowFrusta(LLDrawInfo* params)
+{
+	LLGLEnable blend(GL_BLEND);
+	gGL.setSceneBlendType(LLRender::BT_ADD);
+
+	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))
+	{
+		gGL.diffuseColor3f(1,0,0);
+		pushVerts(params, LLVertexBuffer::MAP_VERTEX);
+	}
+	if (gPipeline.mShadowCamera[5].AABBInFrustum(center, size))
+	{
+		gGL.diffuseColor3f(0,1,0);
+		pushVerts(params, LLVertexBuffer::MAP_VERTEX);
+	}
+	if (gPipeline.mShadowCamera[6].AABBInFrustum(center, size))
+	{
+		gGL.diffuseColor3f(0,0,1);
+		pushVerts(params, LLVertexBuffer::MAP_VERTEX);
+	}
+	if (gPipeline.mShadowCamera[7].AABBInFrustum(center, size))
+	{
+		gGL.diffuseColor3f(1,0,1);
+		pushVerts(params, LLVertexBuffer::MAP_VERTEX);
+	}
+
+	gGL.setSceneBlendType(LLRender::BT_ALPHA);
+}
+
+void renderTexelDensity(LLDrawable* drawable)
+{
+	if (LLViewerTexture::sDebugTexelsMode == LLViewerTexture::DEBUG_TEXELS_OFF
+		|| LLViewerTexture::sCheckerBoardImagep.isNull())
+	{
+		return;
+	}
+
+	LLGLEnable _(GL_BLEND);
+	//gObjectFullbrightProgram.bind();
+
+	LLMatrix4 checkerboard_matrix;
+	S32 discard_level = -1;
+
+	for (S32 f = 0; f < drawable->getNumFaces(); f++)
+	{
+		LLFace* facep = drawable->getFace(f);
+		LLVertexBuffer* buffer = facep->getVertexBuffer();
+		LLViewerTexture* texturep = facep->getTexture();
+
+		if (texturep == NULL) continue;
+
+		switch(LLViewerTexture::sDebugTexelsMode)
+		{
+		case LLViewerTexture::DEBUG_TEXELS_CURRENT:
+			discard_level = -1;
+			break;
+		case LLViewerTexture::DEBUG_TEXELS_DESIRED:
+			{
+				LLViewerFetchedTexture* fetched_texturep = dynamic_cast<LLViewerFetchedTexture*>(texturep);
+				discard_level = fetched_texturep ? fetched_texturep->getDesiredDiscardLevel() : -1;
+				break;
+			}
+		default:
+		case LLViewerTexture::DEBUG_TEXELS_FULL:
+			discard_level = 0;
+			break;
+		}
+
+		checkerboard_matrix.initScale(LLVector3(texturep->getWidth(discard_level) / 8, texturep->getHeight(discard_level) / 8, 1.f));
+
+		gGL.getTexUnit(0)->bind(LLViewerTexture::sCheckerBoardImagep, TRUE);
+		gGL.matrixMode(LLRender::MM_TEXTURE);
+		gGL.loadMatrix((GLfloat*)&checkerboard_matrix.mMatrix);
+
+		if (buffer && (facep->getGeomCount() >= 3))
+		{
+			buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0);
+			U16 start = facep->getGeomStart();
+			U16 end = start + facep->getGeomCount()-1;
+			U32 count = facep->getIndicesCount();
+			U16 offset = facep->getIndicesStart();
+			buffer->drawRange(LLRender::TRIANGLES, start, end, count, offset);
+		}
+
+		gGL.loadIdentity();
+		gGL.matrixMode(LLRender::MM_MODELVIEW);
+	}
+
+	//S32 num_textures = llmax(1, (S32)params->mTextureList.size());
+
+	//for (S32 i = 0; i < num_textures; i++)
+	//{
+	//	LLViewerTexture* texturep = params->mTextureList.empty() ? params->mTexture.get() : params->mTextureList[i].get();
+	//	if (texturep == NULL) continue;
+
+	//	LLMatrix4 checkboard_matrix;
+	//	S32 discard_level = -1;
+	//	switch(LLViewerTexture::sDebugTexelsMode)
+	//	{
+	//	case LLViewerTexture::DEBUG_TEXELS_CURRENT:
+	//		discard_level = -1;
+	//		break;
+	//	case LLViewerTexture::DEBUG_TEXELS_DESIRED:
+	//		{
+	//			LLViewerFetchedTexture* fetched_texturep = dynamic_cast<LLViewerFetchedTexture*>(texturep);
+	//			discard_level = fetched_texturep ? fetched_texturep->getDesiredDiscardLevel() : -1;
+	//			break;
+	//		}
+	//	default:
+	//	case LLViewerTexture::DEBUG_TEXELS_FULL:
+	//		discard_level = 0;
+	//		break;
+	//	}
+
+	//	checkboard_matrix.initScale(LLVector3(texturep->getWidth(discard_level) / 8, texturep->getHeight(discard_level) / 8, 1.f));
+	//	gGL.getTexUnit(i)->activate();
+
+	//	glMatrixMode(GL_TEXTURE);
+	//	glPushMatrix();
+	//	glLoadIdentity();
+	//	//gGL.matrixMode(LLRender::MM_TEXTURE);
+	//	glLoadMatrixf((GLfloat*) checkboard_matrix.mMatrix);
+
+	//	gGL.getTexUnit(i)->bind(LLViewerTexture::sCheckerBoardImagep, TRUE);
+
+	//	pushVerts(params, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_NORMAL );
+
+	//	glPopMatrix();
+	//	glMatrixMode(GL_MODELVIEW);
+	//	//gGL.matrixMode(LLRender::MM_MODELVIEW);
+	//}
+}
+
+
+void renderLights(LLDrawable* drawablep)
+{
+	if (!drawablep->isLight())
+	{
+		return;
+	}
+
+	if (drawablep->getNumFaces())
+	{
+		LLGLEnable blend(GL_BLEND);
+		gGL.diffuseColor4f(0,1,1,0.5f);
+
+		for (S32 i = 0; i < drawablep->getNumFaces(); i++)
+		{
+			LLFace * face = drawablep->getFace(i);
+			if (face)
+			{
+				pushVerts(face, LLVertexBuffer::MAP_VERTEX);
+			}
+		}
+
+		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.diffuseColor4f(1,1,1,1);
+			drawBoxOutline(pos, size);
+		}
+
+		gGL.diffuseColor4f(1,1,0,1);
+		F32 rad = drawablep->getVOVolume()->getLightRadius();
+		drawBoxOutline(pos, LLVector4a(rad));
+	}
+}
+
+class LLRenderOctreeRaycast final : public LLOctreeTriangleRayIntersect
+{
+public:
+	
+	
+	LLRenderOctreeRaycast(const LLVector4a& start, const LLVector4a& dir, F32* closest_t)
+		: LLOctreeTriangleRayIntersect(start, dir, NULL, closest_t, NULL, NULL, NULL, NULL)
+	{
+
+	}
+
+	void visit(const LLOctreeNode<LLVolumeTriangle>* branch) override
+	{
+		LLVolumeOctreeListener* vl = (LLVolumeOctreeListener*) branch->getListener(0);
+
+		LLVector3 center, size;
+		
+		if (branch->isEmpty())
+		{
+			gGL.diffuseColor3f(1.f,0.2f,0.f);
+			center.set(branch->getCenter().getF32ptr());
+			size.set(branch->getSize().getF32ptr());
+		}
+		else
+		{
+			gGL.diffuseColor3f(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.diffuseColor4f(0,1,1,0.5f);
+			}
+			else
+			{
+				gGL.diffuseColor4f(0,0.5f,0.5f, 0.25f);
+				drawBoxOutline(center, size);
+			}
+			
+			if (i == 1)
+			{
+				gGL.flush();
+				gGL.setLineWidth(3.f);
+			}
+
+			gGL.begin(LLRender::TRIANGLES);
+			for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter = branch->getDataBegin();
+					iter != branch->getDataEnd();
+					++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();
+				gGL.setLineWidth(1.f);
+			}
+		}
+	}
+};
+
+void renderRaycast(LLDrawable* drawablep)
+{
+	if (drawablep->getNumFaces())
+	{
+		LLGLEnable blend(GL_BLEND);
+		gGL.diffuseColor4f(0,1,1,0.5f);
+
+		if (drawablep->getVOVolume())
+		{
+			//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);
+					
+					gGL.pushMatrix();
+					gGL.translatef(trans.mV[0], trans.mV[1], trans.mV[2]);					
+					gGL.multMatrix((F32*) vobj->getRelativeXform().mMatrix);
+
+					LLVector4a start, end;
+					if (transform)
+					{
+						LLVector3 v_start(gDebugRaycastStart.getF32ptr());
+						LLVector3 v_end(gDebugRaycastEnd.getF32ptr());
+
+						v_start = vobj->agentPositionToVolume(v_start);
+						v_end = vobj->agentPositionToVolume(v_end);
+
+						start.load3(v_start.mV);
+						end.load3(v_end.mV);
+					}
+					else
+					{
+						start = gDebugRaycastStart;
+						end = gDebugRaycastEnd;
+					}
+
+					LLVector4a dir;
+					dir.setSub(end, start);
+
+					gGL.flush();
+					glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);				
+
+					{
+						//render face positions
+						gGL.diffuseColor4f(0.f, 1.f, 1.f, 0.5f);
+						LLVertexBuffer::drawElements(LLRender::TRIANGLES, face.mNumVertices, face.mPositions, NULL, face.mNumIndices, face.mIndices);
+					}
+					
+					if (!volume->isUnique())
+					{
+						F32 t = 1.f;
+
+						if (!face.mOctree)
+						{
+							((LLVolumeFace*) &face)->createOctree(); 
+						}
+
+						LLRenderOctreeRaycast render(start, dir, &t);
+					
+						render.traverse(face.mOctree);
+					}
+
+					gGL.popMatrix();		
+					glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+				}
+			}
+		}
+		else if (drawablep->isAvatar())
+		{
+			if (drawablep->getVObj() == gDebugRaycastObject)
+			{
+				LLGLDepthTest depth(GL_FALSE);
+				LLVOAvatar* av = (LLVOAvatar*) drawablep->getVObj().get();
+				av->renderCollisionVolumes();
+			}
+		}
+
+		if (drawablep->getVObj() == gDebugRaycastObject)
+		{
+			// draw intersection point
+			gGL.pushMatrix();
+			gGL.loadMatrix(gGLModelView);
+			LLVector3 translate(gDebugRaycastIntersection.getF32ptr());
+			gGL.translatef(translate.mV[0], translate.mV[1], translate.mV[2]);
+			LLCoordFrame orient;
+			LLVector4a debug_binormal;
+			
+			debug_binormal.setCross3(gDebugRaycastNormal, gDebugRaycastTangent);
+			debug_binormal.mul(gDebugRaycastTangent.getF32ptr()[3]);
+
+			LLVector3 normal(gDebugRaycastNormal.getF32ptr());
+			LLVector3 binormal(debug_binormal.getF32ptr());
+						
+			orient.lookDir(normal, binormal);
+			LLMatrix4 rotation;
+			orient.getRotMatrixToParent(rotation);
+			gGL.multMatrix((float*)rotation.mMatrix);
+			
+			gGL.diffuseColor4f(1,0,0,0.5f);
+			drawBox(LLVector3(0, 0, 0), LLVector3(0.1f, 0.022f, 0.022f));
+			gGL.diffuseColor4f(0,1,0,0.5f);
+			drawBox(LLVector3(0, 0, 0), LLVector3(0.021f, 0.1f, 0.021f));
+			gGL.diffuseColor4f(0,0,1,0.5f);
+			drawBox(LLVector3(0, 0, 0), LLVector3(0.02f, 0.02f, 0.1f));
+			gGL.popMatrix();
+
+			// 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.diffuseColor4f(0,0.5f,0.5f,1);
+			drawBoxOutline(pos, size);		
+		}
+	}
+}
+
+
+void renderAvatarCollisionVolumes(LLVOAvatar* avatar)
+{
+	avatar->renderCollisionVolumes();
+}
+
+void renderAvatarBones(LLVOAvatar* avatar)
+{
+	avatar->renderBones();
+}
+
+void renderAgentTarget(LLVOAvatar* avatar)
+{
+	// render these for self only (why, i don't know)
+	if (avatar->isSelf())
+	{
+		renderCrossHairs(avatar->getPositionAgent(), 0.2f, LLColor4(1, 0, 0, 0.8f));
+		renderCrossHairs(avatar->mDrawable->getPositionAgent(), 0.2f, LLColor4(0, 1, 0, 0.8f));
+		renderCrossHairs(avatar->mRoot->getWorldPosition(), 0.2f, LLColor4(1, 1, 1, 0.8f));
+		renderCrossHairs(avatar->mPelvisp->getWorldPosition(), 0.2f, LLColor4(0, 0, 1, 0.8f));
+	}
+}
+
+class LLOctreeRenderNonOccluded final : public OctreeTraveler
+{
+public:
+	LLCamera* mCamera;
+	LLOctreeRenderNonOccluded(LLCamera* camera): mCamera(camera) {}
+
+    void traverse(const OctreeNode* node) override
+	{
+		LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
+		
+		const LLVector4a* bounds = group->getBounds();
+		if (!mCamera || mCamera->AABBInFrustumNoFarClip(bounds[0], bounds[1]))
+		{
+			node->accept(this);
+			stop_glerror();
+
+			for (U32 i = 0; i < node->getChildCount(); i++)
+			{
+				traverse(node->getChild(i));
+				stop_glerror();
+			}
+			
+			//draw tight fit bounding boxes for spatial group
+			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCTREE))
+			{	
+				group->rebuildGeom();
+				group->rebuildMesh();
+
+				renderOctree(group);
+				stop_glerror();
+			}
+
+			//render visibility wireframe
+			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION))
+			{
+				group->rebuildGeom();
+				group->rebuildMesh();
+
+				gGL.flush();
+				gGL.pushMatrix();
+				gGLLastMatrix = NULL;
+				gGL.loadMatrix(gGLModelView);
+				renderVisibility(group, mCamera);
+				stop_glerror();
+				gGLLastMatrix = NULL;
+				gGL.popMatrix();
+				gGL.diffuseColor4f(1,1,1,1);
+			}
+		}
+	}
+
+    void visit(const OctreeNode* branch) override
+	{
+		LLSpatialGroup* group = (LLSpatialGroup*) branch->getListener(0);
+		const LLVector4a* bounds = group->getBounds();
+		if (group->hasState(LLSpatialGroup::GEOM_DIRTY) || (mCamera && !mCamera->AABBInFrustumNoFarClip(bounds[0], bounds[1])))
+		{
+			return;
+		}
+
+		LLGLDisable stencil(GL_STENCIL_TEST);
+
+		group->rebuildGeom();
+		group->rebuildMesh();
+
+		if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BBOXES))
+		{
+			if (!group->isEmpty())
+			{
+				gGL.diffuseColor3f(0,0,1);
+				const LLVector4a* obj_bounds = group->getObjectBounds();
+				drawBoxOutline(obj_bounds[0], obj_bounds[1]);
+			}
+		}
+
+		for (OctreeNode::const_element_iter i = branch->getDataBegin(); i != branch->getDataEnd(); ++i)
+		{
+			LLDrawable* drawable = (LLDrawable*)(*i)->getDrawable();
+			if(!drawable)
+		{
+				continue;
+			}
+					
+			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BBOXES))
+			{
+				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.diffuseColor4f(0.6f, 0.6f, 0.1f, 1.f);
+					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);
+				}
+			}	
+
+			if (drawable->getVOVolume() && gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY))
+			{
+				renderTexturePriority(drawable);
+			}
+
+			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_POINTS))
+			{
+				renderPoints(drawable);
+			}
+
+			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_LIGHTS))
+			{
+				renderLights(drawable);
+			}
+
+			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RAYCAST))
+			{
+				renderRaycast(drawable);
+			}
+			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_UPDATE_TYPE))
+			{
+				renderUpdateType(drawable);
+			}
+			if(gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RENDER_COMPLEXITY))
+			{
+				renderComplexityDisplay(drawable);
+			}
+			if(gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY))
+			{
+				renderTexelDensity(drawable);
+			}
+
+			LLVOAvatar* avatar = drawable->getVObj()->asAvatar();
+			
+			if (avatar && gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_AVATAR_VOLUME))
+			{
+				renderAvatarCollisionVolumes(avatar);
+			}
+
+			if (avatar && gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_AVATAR_JOINTS))
+			{
+				renderAvatarBones(avatar);
+			}
+
+			if (avatar && gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_AGENT_TARGET))
+			{
+				renderAgentTarget(avatar);
+			}
+			
+			if (gDebugGL)
+			{
+				for (S32 i = 0; i < drawable->getNumFaces(); ++i)
+				{
+					LLFace* facep = drawable->getFace(i);
+					if (facep)
+					{
+						U8 index = facep->getTextureIndex();
+						if (facep->mDrawInfo)
+						{
+							if (index < 255)
+							{
+								if (facep->mDrawInfo->mTextureList.size() <= index)
+								{
+									LL_ERRS() << "Face texture index out of bounds." << LL_ENDL;
+								}
+								else if (facep->mDrawInfo->mTextureList[index] != facep->getTexture())
+								{
+									LL_ERRS() << "Face texture index incorrect." << LL_ENDL;
+								}
+							}
+						}
+					}
+				}
+			}
+		}
+		
+		for (auto& i : group->mDrawMap)
+        {
+			LLSpatialGroup::drawmap_elem_t& draw_vec = i.second;	
+			for (auto& j : draw_vec)
+            {
+				LLDrawInfo* draw_info = j;
+				if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_ANIM))
+				{
+					renderTextureAnim(draw_info);
+				}
+				if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BATCH_SIZE))
+				{
+					renderBatchSize(draw_info);
+				}
+				if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
+				{
+					renderShadowFrusta(draw_info);
+				}
+			}
+		}
+	}
+};
+
+class LLOctreeRenderXRay final : public OctreeTraveler
+{
+public:
+	LLCamera* mCamera;
+	LLOctreeRenderXRay(LLCamera* camera): mCamera(camera) {}
+
+    void traverse(const OctreeNode* node) override
+	{
+		LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
+		
+		const LLVector4a* bounds = group->getBounds();
+		if (!mCamera || mCamera->AABBInFrustumNoFarClip(bounds[0], bounds[1]))
+		{
+			node->accept(this);
+			stop_glerror();
+
+			for (U32 i = 0; i < node->getChildCount(); i++)
+			{
+				traverse(node->getChild(i));
+				stop_glerror();
+			}
+			
+			//render visibility wireframe
+			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION))
+			{
+				group->rebuildGeom();
+				group->rebuildMesh();
+
+				gGL.flush();
+				gGL.pushMatrix();
+				gGLLastMatrix = NULL;
+				gGL.loadMatrix(gGLModelView);
+				renderXRay(group, mCamera);
+				stop_glerror();
+				gGLLastMatrix = NULL;
+				gGL.popMatrix();
+			}
+		}
+	}
+
+    void visit(const OctreeNode* node) override {}
+
+};
+
+class LLOctreeRenderPhysicsShapes final : public OctreeTraveler
+{
+public:
+	LLCamera* mCamera;
+	LLOctreeRenderPhysicsShapes(LLCamera* camera): mCamera(camera) {}
+
+    void traverse(const OctreeNode* node) override
+	{
+		LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
+		
+		const LLVector4a* bounds = group->getBounds();
+		if (!mCamera || mCamera->AABBInFrustumNoFarClip(bounds[0], bounds[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);
+		}
+	}
+
+    void visit(const OctreeNode* branch) override
+	{
+		
+	}
+};
+
+class LLOctreePushBBoxVerts final : public OctreeTraveler
+{
+public:
+	LLCamera* mCamera;
+	LLOctreePushBBoxVerts(LLCamera* camera): mCamera(camera) {}
+
+    void traverse(const OctreeNode* node) override
+	{
+		LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
+		
+		const LLVector4a* bounds = group->getBounds();
+		if (!mCamera || mCamera->AABBInFrustum(bounds[0], bounds[1]))
+		{
+			node->accept(this);
+
+			for (U32 i = 0; i < node->getChildCount(); i++)
+			{
+				traverse(node->getChild(i));
+			}
+		}
+	}
+
+    void visit(const OctreeNode* branch) override
+	{
+		LLSpatialGroup* group = (LLSpatialGroup*) branch->getListener(0);
+
+		const LLVector4a* bounds = group->getBounds();
+		if (group->hasState(LLSpatialGroup::GEOM_DIRTY) || (mCamera && !mCamera->AABBInFrustumNoFarClip(bounds[0], bounds[1])))
+		{
+			return;
+		}
+
+		for (OctreeNode::const_element_iter i = branch->getDataBegin(); i != branch->getDataEnd(); ++i)
+		{
+			LLDrawable* drawable = (LLDrawable*)(*i)->getDrawable();
+			if(!drawable)
+		{
+				continue;
+			}
+			renderBoundingBox(drawable, FALSE);			
+		}
+	}
+};
+
+void LLSpatialPartition::renderIntersectingBBoxes(LLCamera* camera)
+{
+	LLOctreePushBBoxVerts pusher(camera);
+	pusher.traverse(mOctree);
+}
+
+class LLOctreeStateCheck final : public OctreeTraveler
+{
+public:
+	U32 mInheritedMask[LLViewerCamera::NUM_CAMERAS];
+
+	LLOctreeStateCheck()
+	{ 
+		for (unsigned int& i : mInheritedMask)
+        {
+            i = 0;
+		}
+	}
+
+    void traverse(const OctreeNode* node) override
+	{
+		LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
+		
+		node->accept(this);
+
+
+		U32 temp[LLViewerCamera::NUM_CAMERAS];
+
+		for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
+		{
+			temp[i] = mInheritedMask[i];
+			mInheritedMask[i] |= group->mOcclusionState[i] & LLSpatialGroup::OCCLUDED; 
+		}
+
+		for (U32 i = 0; i < node->getChildCount(); i++)
+		{
+			traverse(node->getChild(i));
+		}
+
+		for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
+		{
+			mInheritedMask[i] = temp[i];
+		}
+	}
+
+
+    void visit(const OctreeNode* state) override
+	{
+		LLSpatialGroup* group = (LLSpatialGroup*) state->getListener(0);
+
+		for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
+		{
+			if (mInheritedMask[i] && !(group->mOcclusionState[i] & mInheritedMask[i]))
+			{
+				LL_ERRS() << "Spatial group failed inherited mask test." << LL_ENDL;
+			}
+		}
+
+		if (group->hasState(LLSpatialGroup::DIRTY))
+		{
+			assert_parent_state(group, LLSpatialGroup::DIRTY);
+		}
+	}
+
+	void assert_parent_state(LLSpatialGroup* group, U32 state)
+	{
+		LLSpatialGroup* parent = group->getParent();
+		while (parent)
+		{
+			if (!parent->hasState(state))
+			{
+				LL_ERRS() << "Spatial group failed parent state check." << LL_ENDL;
+			}
+			parent = parent->getParent();
+		}
+	}	
+};
+
+
+void LLSpatialPartition::renderPhysicsShapes()
+{
+	LLSpatialBridge* bridge = asBridge();
+	LLCamera* camera = LLViewerCamera::getInstance();
+	
+	if (bridge)
+	{
+		camera = NULL;
+	}
+
+	gGL.flush();
+	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+	gGL.setLineWidth(3.f);
+	LLOctreeRenderPhysicsShapes render_physics(camera);
+	render_physics.traverse(mOctree);
+	gGL.flush();
+	gGL.setLineWidth(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_AVATAR_JOINTS |
+									  LLPipeline::RENDER_DEBUG_AGENT_TARGET |
+									  //LLPipeline::RENDER_DEBUG_BUILD_QUEUE |
+									  LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA |
+									  LLPipeline::RENDER_DEBUG_RENDER_COMPLEXITY |
+									  LLPipeline::RENDER_DEBUG_TEXEL_DENSITY)) 
+	{
+		return;
+	}
+	
+	if (LLGLSLShader::sNoFixedFunction)
+	{
+		gDebugProgram.bind();
+	}
+
+	if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY))
+	{
+		//sLastMaxTexPriority = lerp(sLastMaxTexPriority, sCurMaxTexPriority, gFrameIntervalSeconds);
+		sLastMaxTexPriority = (F32) LLViewerCamera::getInstance()->getScreenPixelArea();
+		sCurMaxTexPriority = 0.f;
+	}
+
+	LLGLDisable cullface(GL_CULL_FACE);
+	LLGLEnable blend(GL_BLEND);
+	gGL.setSceneBlendType(LLRender::BT_ALPHA);
+	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+	gPipeline.disableLights();
+
+	LLSpatialBridge* bridge = asBridge();
+	LLCamera* camera = LLViewerCamera::getInstance();
+	
+	if (bridge)
+	{
+		camera = NULL;
+	}
+
+	LLOctreeStateCheck checker;
+	checker.traverse(mOctree);
+
+	LLOctreeRenderNonOccluded render_debug(camera);
+	render_debug.traverse(mOctree);
+
+
+	if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION))
+	{
+		{
+			LLGLEnable cull(GL_CULL_FACE);
+			
+			LLGLEnable blend(GL_BLEND);
+			LLGLDepthTest depth_under(GL_TRUE, GL_FALSE, GL_GREATER);
+			glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+			gGL.diffuseColor4f(0.5f, 0.0f, 0, 0.25f);
+
+			LLGLEnable offset(GL_POLYGON_OFFSET_LINE);
+			glPolygonOffset(-1.f, -1.f);
+
+			LLOctreeRenderXRay xray(camera);
+			xray.traverse(mOctree);
+
+			glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+		}
+	}
+	if (LLGLSLShader::sNoFixedFunction)
+	{
+		gDebugProgram.unbind();
+	}
+}
+
+void LLSpatialGroup::drawObjectBox(LLColor4 col)
+{
+	gGL.diffuseColor4fv(col.mV);
+	LLVector4a size;
+	size = mObjectBounds[1];
+	size.mul(1.01f);
+	size.add(LLVector4a(0.001f));
+	drawBox(mObjectBounds[0], size);
+}
+
+bool LLSpatialPartition::isHUDPartition() 
+{ 
+	return mPartitionType == LLViewerRegion::PARTITION_HUD ;
+} 
+
+BOOL LLSpatialPartition::isVisible(const LLVector3& v)
+{
+	if (!LLViewerCamera::getInstance()->sphereInFrustum(v, 4.0f))
+	{
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+LL_ALIGN_PREFIX(16)
+class LLOctreeIntersect : public LLOctreeTraveler<LLViewerOctreeEntry>
+{
+public:
+	LL_ALIGN_16(LLVector4a mStart);
+	LL_ALIGN_16(LLVector4a mEnd);
+
+	S32       *mFaceHit;
+	LLVector4a *mIntersection;
+	LLVector2 *mTexCoord;
+	LLVector4a *mNormal;
+	LLVector4a *mTangent;
+	LLDrawable* mHit;
+	BOOL mPickTransparent;
+	BOOL mPickRigged;
+
+	LLOctreeIntersect(const LLVector4a& start, const LLVector4a& end, BOOL pick_transparent, BOOL pick_rigged,
+					  S32* face_hit, LLVector4a* intersection, LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent)
+		: mStart(start),
+		  mEnd(end),
+		  mFaceHit(face_hit),
+		  mIntersection(intersection),
+		  mTexCoord(tex_coord),
+		  mNormal(normal),
+		  mTangent(tangent),
+		  mHit(NULL),
+		  mPickTransparent(pick_transparent),
+		  mPickRigged(pick_rigged)
+	{
+	}
+
+    void visit(const OctreeNode* branch) override
+	{	
+		for (OctreeNode::const_element_iter i = branch->getDataBegin(); i != branch->getDataEnd(); ++i)
+		{
+			check(*i);
+		}
+	}
+
+	virtual LLDrawable* check(const OctreeNode* node)
+	{
+		node->accept(this);
+	
+		for (U32 i = 0; i < node->getChildCount(); i++)
+		{
+			const OctreeNode* child = node->getChild(i);
+			LLVector3 res;
+
+			LLSpatialGroup* group = (LLSpatialGroup*) child->getListener(0);
+			
+			LLVector4a size;
+			LLVector4a center;
+			
+			const LLVector4a* bounds = group->getBounds();
+			size = bounds[1];
+			center = bounds[0];
+			
+			LLVector4a local_start = mStart;
+			LLVector4a local_end   = mEnd;
+
+			if (group->getSpatialPartition()->isBridge())
+			{
+				LLMatrix4a local_matrix4a(group->getSpatialPartition()->asBridge()->mDrawable->getRenderMatrix());
+				local_matrix4a.invert();
+
+				local_matrix4a.affineTransform(mStart, local_start);
+				local_matrix4a.affineTransform(mEnd, local_end);
+			}
+
+			if (LLLineSegmentBoxIntersect(local_start, local_end, center, size))
+			{
+				check(child);
+			}
+		}	
+
+		return mHit;
+	}
+
+	virtual bool check(LLViewerOctreeEntry* entry)
+	{	
+		LLDrawable* drawable = (LLDrawable*)entry->getDrawable();
+	
+		if (!drawable || !gPipeline.hasRenderType(drawable->getRenderType()) || !drawable->isVisible())
+		{
+			return false;
+		}
+
+		if (drawable->isSpatialBridge())
+		{
+			LLSpatialPartition *part = drawable->asPartition();
+			LLSpatialBridge* bridge = part->asBridge();
+			if (bridge && gPipeline.hasRenderType(bridge->mDrawableType))
+			{
+				check(part->mOctree);
+			}
+		}
+		else
+		{
+			LLViewerObject* vobj = drawable->getVObj();
+
+			if (vobj)
+			{
+				LLVector4a intersection;
+				bool skip_check = false;
+				if (vobj->isAvatar())
+				{
+					LLVOAvatar* avatar = (LLVOAvatar*) vobj;
+					if ((mPickRigged) || ((avatar->isSelf()) && (LLFloater::isVisible(gFloaterTools))))
+					{
+						LLViewerObject* hit = avatar->lineSegmentIntersectRiggedAttachments(mStart, mEnd, -1, mPickTransparent, mPickRigged, mFaceHit, &intersection, mTexCoord, mNormal, mTangent);
+						if (hit)
+						{
+							mEnd = intersection;
+							if (mIntersection)
+							{
+								*mIntersection = intersection;
+							}
+							
+							mHit = hit->mDrawable;
+							skip_check = true;
+						}
+
+					}
+				}
+
+				if (!skip_check && vobj->lineSegmentIntersect(mStart, mEnd, -1, mPickTransparent, mPickRigged, mFaceHit, &intersection, mTexCoord, mNormal, mTangent))
+				{
+					mEnd = intersection;  // shorten ray so we only find CLOSER hits
+					if (mIntersection)
+					{
+						*mIntersection = intersection;
+					}
+					
+					mHit = vobj->mDrawable;
+				}
+			}
+		}
+				
+		return false;
+	}
+} LL_ALIGN_POSTFIX(16);
+
+LLDrawable* LLSpatialPartition::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end,
+													 BOOL pick_transparent,
+													 BOOL pick_rigged,
+													 S32* face_hit,                   // return the face hit
+													 LLVector4a* intersection,         // return the intersection point
+													 LLVector2* tex_coord,            // return the texture coordinates of the intersection point
+													 LLVector4a* normal,               // return the surface normal at the intersection point
+													 LLVector4a* tangent			// return the surface tangent at the intersection point
+	)
+
+{
+	LLOctreeIntersect intersect(start, end, pick_transparent, pick_rigged, face_hit, intersection, tex_coord, normal, tangent);
+	LLDrawable* drawable = intersect.check(mOctree);
+
+	return drawable;
+}
+
+LLDrawInfo::LLDrawInfo(U16 start, U16 end, U32 count, U32 offset, 
+					   LLViewerTexture* texture, LLVertexBuffer* buffer,
+					   bool selected,
+					   BOOL fullbright, U8 bump, BOOL particle, F32 part_size)
+:	LLTrace::MemTrackable<LLDrawInfo, 16>("LLDrawInfo"),
+	mVertexBuffer(buffer),
+	mTexture(texture),
+	mTextureMatrix(NULL),
+	mModelMatrix(NULL),
+	mStart(start),
+	mEnd(end),
+	mCount(count),
+	mOffset(offset), 
+	mFullbright(fullbright),
+	mBump(bump),
+	mShiny(0),
+	mParticle(particle),
+	mPartSize(part_size),
+	mVSize(0.f),
+	mGroup(NULL),
+	mFace(NULL),
+	mDistance(0.f),
+	mDrawMode(LLRender::TRIANGLES),
+	mMaterial(NULL),
+	mShaderMask(0),
+	mBlendFuncSrc(LLRender::BF_SOURCE_ALPHA),
+	mBlendFuncDst(LLRender::BF_ONE_MINUS_SOURCE_ALPHA),
+	mHasGlow(FALSE),
+	mSpecColor(1.0f, 1.0f, 1.0f, 0.5f),
+	mEnvIntensity(0.0f),
+	mAlphaMaskCutoff(0.5f),
+	mDiffuseAlphaMode(0),
+	mSelected(selected)
+{
+	mVertexBuffer->validateRange(mStart, mEnd, mCount, mOffset);
+}
+
+LLDrawInfo::~LLDrawInfo()	
+{
+	/*if (LLSpatialGroup::sNoDelete)
+	{
+		LL_ERRS() << "LLDrawInfo deleted illegally!" << LL_ENDL;
+	}*/
+
+	if (mFace)
+	{
+		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)
+{
+	return new LLVertexBuffer(type_mask, usage);
+}
+
+LLCullResult::LLCullResult() 
+{
+	mVisibleGroupsAllocated = 0;
+	mAlphaGroupsAllocated = 0;
+	mOcclusionGroupsAllocated = 0;
+	mDrawableGroupsAllocated = 0;
+	mVisibleListAllocated = 0;
+	mVisibleBridgeAllocated = 0;
+
+	mVisibleGroups.clear();
+	mVisibleGroups.push_back(NULL);
+	mVisibleGroupsEnd = &mVisibleGroups[0];
+	mAlphaGroups.clear();
+	mAlphaGroups.push_back(NULL);
+	mAlphaGroupsEnd = &mAlphaGroups[0];
+	mOcclusionGroups.clear();
+	mOcclusionGroups.push_back(NULL);
+	mOcclusionGroupsEnd = &mOcclusionGroups[0];
+	mDrawableGroups.clear();
+	mDrawableGroups.push_back(NULL);
+	mDrawableGroupsEnd = &mDrawableGroups[0];
+	mVisibleList.clear();
+	mVisibleList.push_back(NULL);
+	mVisibleListEnd = &mVisibleList[0];
+	mVisibleBridge.clear();
+	mVisibleBridge.push_back(NULL);
+	mVisibleBridgeEnd = &mVisibleBridge[0];
+
+	for (U32 i = 0; i < LLRenderPass::NUM_RENDER_TYPES; i++)
+	{
+		mRenderMap[i].clear();
+		mRenderMap[i].push_back(NULL);
+		mRenderMapEnd[i] = &mRenderMap[i][0];
+		mRenderMapAllocated[i] = 0;
+		mRenderMapSize[i] = 0;
+	}
+
+	clear();
+}
+
+template <class T, class V> 
+void LLCullResult::pushBack(T& head, U32& count, V* val)
+{
+	head[count] = val;
+	head.push_back(NULL);
+	count++;
+}
+
+void LLCullResult::clear()
+{
+	mVisibleGroupsSize = 0;
+	mVisibleGroupsEnd = &mVisibleGroups[0];
+
+	mAlphaGroupsSize = 0;
+	mAlphaGroupsEnd = &mAlphaGroups[0];
+
+	mOcclusionGroupsSize = 0;
+	mOcclusionGroupsEnd = &mOcclusionGroups[0];
+
+	mDrawableGroupsSize = 0;
+	mDrawableGroupsEnd = &mDrawableGroups[0];
+
+	mVisibleListSize = 0;
+	mVisibleListEnd = &mVisibleList[0];
+
+	mVisibleBridgeSize = 0;
+	mVisibleBridgeEnd = &mVisibleBridge[0];
+
+
+	for (U32 i = 0; i < LLRenderPass::NUM_RENDER_TYPES; i++)
+	{
+		for (U32 j = 0; j < mRenderMapSize[i]; j++)
+		{
+			mRenderMap[i][j] = 0;
+		}
+		mRenderMapSize[i] = 0;
+		mRenderMapEnd[i] = &(mRenderMap[i][0]);
+	}
+}
+
+LLCullResult::sg_iterator LLCullResult::beginVisibleGroups()
+{
+	return &mVisibleGroups[0];
+}
+
+LLCullResult::sg_iterator LLCullResult::endVisibleGroups()
+{
+	return mVisibleGroupsEnd;
+}
+
+LLCullResult::sg_iterator LLCullResult::beginAlphaGroups()
+{
+	return &mAlphaGroups[0];
+}
+
+LLCullResult::sg_iterator LLCullResult::endAlphaGroups()
+{
+	return mAlphaGroupsEnd;
+}
+
+LLCullResult::sg_iterator LLCullResult::beginOcclusionGroups()
+{
+	return &mOcclusionGroups[0];
+}
+
+LLCullResult::sg_iterator LLCullResult::endOcclusionGroups()
+{
+	return mOcclusionGroupsEnd;
+}
+
+LLCullResult::sg_iterator LLCullResult::beginDrawableGroups()
+{
+	return &mDrawableGroups[0];
+}
+
+LLCullResult::sg_iterator LLCullResult::endDrawableGroups()
+{
+	return mDrawableGroupsEnd;
+}
+
+LLCullResult::drawable_iterator LLCullResult::beginVisibleList()
+{
+	return &mVisibleList[0];
+}
+
+LLCullResult::drawable_iterator LLCullResult::endVisibleList()
+{
+	return mVisibleListEnd;
+}
+
+LLCullResult::bridge_iterator LLCullResult::beginVisibleBridge()
+{
+	return &mVisibleBridge[0];
+}
+
+LLCullResult::bridge_iterator LLCullResult::endVisibleBridge()
+{
+	return mVisibleBridgeEnd;
+}
+
+LLCullResult::drawinfo_iterator LLCullResult::beginRenderMap(U32 type)
+{
+	return &mRenderMap[type][0];
+}
+
+LLCullResult::drawinfo_iterator LLCullResult::endRenderMap(U32 type)
+{
+	return mRenderMapEnd[type];
+}
+
+void LLCullResult::pushVisibleGroup(LLSpatialGroup* group)
+{
+	if (mVisibleGroupsSize < mVisibleGroupsAllocated)
+	{
+		mVisibleGroups[mVisibleGroupsSize] = group;
+	}
+	else
+	{
+		pushBack(mVisibleGroups, mVisibleGroupsAllocated, group);
+	}
+	++mVisibleGroupsSize;
+	mVisibleGroupsEnd = &mVisibleGroups[mVisibleGroupsSize];
+}
+
+void LLCullResult::pushAlphaGroup(LLSpatialGroup* group)
+{
+	if (mAlphaGroupsSize < mAlphaGroupsAllocated)
+	{
+		mAlphaGroups[mAlphaGroupsSize] = group;
+	}
+	else
+	{
+		pushBack(mAlphaGroups, mAlphaGroupsAllocated, group);
+	}
+	++mAlphaGroupsSize;
+	mAlphaGroupsEnd = &mAlphaGroups[mAlphaGroupsSize];
+}
+
+void LLCullResult::pushOcclusionGroup(LLSpatialGroup* group)
+{
+	if (mOcclusionGroupsSize < mOcclusionGroupsAllocated)
+	{
+		mOcclusionGroups[mOcclusionGroupsSize] = group;
+	}
+	else
+	{
+		pushBack(mOcclusionGroups, mOcclusionGroupsAllocated, group);
+	}
+	++mOcclusionGroupsSize;
+	mOcclusionGroupsEnd = &mOcclusionGroups[mOcclusionGroupsSize];
+}
+
+void LLCullResult::pushDrawableGroup(LLSpatialGroup* group)
+{
+	if (mDrawableGroupsSize < mDrawableGroupsAllocated)
+	{
+		mDrawableGroups[mDrawableGroupsSize] = group;
+	}
+	else
+	{
+		pushBack(mDrawableGroups, mDrawableGroupsAllocated, group);
+	}
+	++mDrawableGroupsSize;
+	mDrawableGroupsEnd = &mDrawableGroups[mDrawableGroupsSize];
+}
+
+void LLCullResult::pushDrawable(LLDrawable* drawable)
+{
+	if (mVisibleListSize < mVisibleListAllocated)
+	{
+		mVisibleList[mVisibleListSize] = drawable;
+	}
+	else
+	{
+		pushBack(mVisibleList, mVisibleListAllocated, drawable);
+	}
+	++mVisibleListSize;
+	mVisibleListEnd = &mVisibleList[mVisibleListSize];
+}
+
+void LLCullResult::pushBridge(LLSpatialBridge* bridge)
+{
+	if (mVisibleBridgeSize < mVisibleBridgeAllocated)
+	{
+		mVisibleBridge[mVisibleBridgeSize] = bridge;
+	}
+	else
+	{
+		pushBack(mVisibleBridge, mVisibleBridgeAllocated, bridge);
+	}
+	++mVisibleBridgeSize;
+	mVisibleBridgeEnd = &mVisibleBridge[mVisibleBridgeSize];
+}
+
+void LLCullResult::pushDrawInfo(U32 type, LLDrawInfo* draw_info)
+{
+	if (mRenderMapSize[type] < mRenderMapAllocated[type])
+	{
+		mRenderMap[type][mRenderMapSize[type]] = draw_info;
+	}
+	else
+	{
+		pushBack(mRenderMap[type], mRenderMapAllocated[type], draw_info);
+	}
+	++mRenderMapSize[type];
+	mRenderMapEnd[type] = &(mRenderMap[type][mRenderMapSize[type]]);
+}
+
+
+void LLCullResult::assertDrawMapsEmpty()
+{
+	for (unsigned int i : mRenderMapSize)
+    {
+		if (i != 0)
+		{
+			LL_ERRS() << "Stale LLDrawInfo's in LLCullResult!" << LL_ENDL;
+		}
+	}
+}
+
diff --git a/indra/newview/llviewerbuildconfig.h.in b/indra/newview/llviewerbuildconfig.h.in
index a66a358cd2..ea5d2e8a50 100644
--- a/indra/newview/llviewerbuildconfig.h.in
+++ b/indra/newview/llviewerbuildconfig.h.in
@@ -1,50 +1,50 @@
-/** 
- * @file llviewerbuildconfig.h
- * @brief Viewer build-time config options.
- * @author Rye Mutt <rye@alchemyviewer.org>
- *
- * $LicenseInfo:firstyear=2019&license=viewerlgpl$
- * Alchemy Viewer Source Code
- * Copyright (C) 2019, Rye Mutt <rye@alchemyviewer.org>
- * 
- * 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
- * 
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLVIEWERBUILDCONFIG_H
-#define LL_LLVIEWERBUILDCONFIG_H
-
-// Build Configuration
-#define LLBUILD_CONFIG "@CMAKE_BUILD_TYPE@"
-
-// Version Information
-#define LL_VIEWER_CHANNEL "@VIEWER_CHANNEL@"
-#define LL_VIEWER_VERSION_MAJOR @VIEWER_VERSION_MAJOR@
-#define LL_VIEWER_VERSION_MINOR @VIEWER_VERSION_MINOR@
-#define LL_VIEWER_VERSION_PATCH @VIEWER_VERSION_PATCH@
-#define LL_VIEWER_VERSION_BUILD @VIEWER_VERSION_REVISION@
-
-// Graphics Utils
-#cmakedefine01 USE_NVAPI
-
-// Audio Engines
-#cmakedefine01 USE_FMODSTUDIO
-#cmakedefine01 USE_OPENAL
-
-// Media Plugins
-#cmakedefine01 LIBVLCPLUGIN
-
+/** 
+ * @file llviewerbuildconfig.h
+ * @brief Viewer build-time config options.
+ * @author Rye Mutt <rye@alchemyviewer.org>
+ *
+ * $LicenseInfo:firstyear=2019&license=viewerlgpl$
+ * Alchemy Viewer Source Code
+ * Copyright (C) 2019, Rye Mutt <rye@alchemyviewer.org>
+ * 
+ * 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
+ * 
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLVIEWERBUILDCONFIG_H
+#define LL_LLVIEWERBUILDCONFIG_H
+
+// Build Configuration
+#define LLBUILD_CONFIG "@CMAKE_BUILD_TYPE@"
+
+// Version Information
+#define LL_VIEWER_CHANNEL "@VIEWER_CHANNEL@"
+#define LL_VIEWER_VERSION_MAJOR @VIEWER_VERSION_MAJOR@
+#define LL_VIEWER_VERSION_MINOR @VIEWER_VERSION_MINOR@
+#define LL_VIEWER_VERSION_PATCH @VIEWER_VERSION_PATCH@
+#define LL_VIEWER_VERSION_BUILD @VIEWER_VERSION_REVISION@
+
+// Graphics Utils
+#cmakedefine01 USE_NVAPI
+
+// Audio Engines
+#cmakedefine01 USE_FMODSTUDIO
+#cmakedefine01 USE_OPENAL
+
+// Media Plugins
+#cmakedefine01 LIBVLCPLUGIN
+
 #endif // LL_LLVIEWERBUILDCONFIG_H
\ No newline at end of file
diff --git a/indra/newview/skins/default/xui/en/floater_group_profile.xml b/indra/newview/skins/default/xui/en/floater_group_profile.xml
index 9a2e6d47e5..481f10adff 100644
--- a/indra/newview/skins/default/xui/en/floater_group_profile.xml
+++ b/indra/newview/skins/default/xui/en/floater_group_profile.xml
@@ -1,27 +1,27 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<floater
-  positioning="cascading"
-  can_close="true"
-  can_resize="true"
-  height="580"
-  min_height="350"
-  min_width="260"
-  layout="topleft"
-  name="floater_group_profile"
-  save_rect="true"
-  title="GROUP"
-  width="370">
-  <panel
-    class="panel_group_info_sidetray"
-    name="panel_group_info_sidetray"
-    filename="panel_group_info_sidetray.xml"
-    label="Group Profile"
-    font="SansSerifBold"
-    follows="all"
-    layout="topleft"
-    min_height="350"
-    left="1"
-    right="-1"
-    top="0"
-    bottom="-8"/>
-</floater>
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+  positioning="cascading"
+  can_close="true"
+  can_resize="true"
+  height="580"
+  min_height="350"
+  min_width="260"
+  layout="topleft"
+  name="floater_group_profile"
+  save_rect="true"
+  title="GROUP"
+  width="370">
+  <panel
+    class="panel_group_info_sidetray"
+    name="panel_group_info_sidetray"
+    filename="panel_group_info_sidetray.xml"
+    label="Group Profile"
+    font="SansSerifBold"
+    follows="all"
+    layout="topleft"
+    min_height="350"
+    left="1"
+    right="-1"
+    top="0"
+    bottom="-8"/>
+</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_legacy_profile.xml b/indra/newview/skins/default/xui/en/floater_legacy_profile.xml
index 04c755c72f..f8d259c1f7 100644
--- a/indra/newview/skins/default/xui/en/floater_legacy_profile.xml
+++ b/indra/newview/skins/default/xui/en/floater_legacy_profile.xml
@@ -1,27 +1,27 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<floater
-  positioning="cascading"
-  can_close="true"
-  can_resize="true"
-  height="580"
-  min_height="350"
-  min_width="260"
-  layout="topleft"
-  name="floater_legacy_profile"
-  save_rect="true"
-  title="PROFILE"
-  width="370">
-    <panel
-      class="panel_profile_legacy_sidetray"
-      name="panel_profile_legacy_sidetray"
-      filename="panel_profile_legacy_sidetray.xml"
-      label="Profile"
-      font="SansSerifBold"
-      follows="all"
-      layout="topleft"
-      min_height="350"
-      left="1"
-      right="-1"
-      top="0"
-      bottom="-8"/>
-</floater>
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+  positioning="cascading"
+  can_close="true"
+  can_resize="true"
+  height="580"
+  min_height="350"
+  min_width="260"
+  layout="topleft"
+  name="floater_legacy_profile"
+  save_rect="true"
+  title="PROFILE"
+  width="370">
+    <panel
+      class="panel_profile_legacy_sidetray"
+      name="panel_profile_legacy_sidetray"
+      filename="panel_profile_legacy_sidetray.xml"
+      label="Profile"
+      font="SansSerifBold"
+      follows="all"
+      layout="topleft"
+      min_height="350"
+      left="1"
+      right="-1"
+      top="0"
+      bottom="-8"/>
+</floater>
diff --git a/indra/newview/skins/default/xui/en/panel_people_friends.xml b/indra/newview/skins/default/xui/en/panel_people_friends.xml
index 283b93c298..3e707aed4f 100644
--- a/indra/newview/skins/default/xui/en/panel_people_friends.xml
+++ b/indra/newview/skins/default/xui/en/panel_people_friends.xml
@@ -1,154 +1,154 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-
-<panel
-  background_opaque="true"
-  background_visible="true"
-  bg_alpha_color="DkGray"
-  bg_opaque_color="DkGray"
-  height="350"
-  follows="all"
-  label="FRIENDS"
-  layout="topleft"
-  left="0"
-  help_topic="people_friends_tab"
-  name="friends_panel"
-  width="330"
-  top="0">
-  <panel
-    follows="left|top|right"
-    height="27"
-    label="bottom_panel"
-    layout="topleft"
-    left="0"
-    name="friends_buttons_panel"
-    right="-1"
-    top="0">
-    <filter_editor
-      follows="left|top|right"
-      height="23"
-      layout="topleft"
-      left="6"
-      label="Filter People"
-      max_length_chars="300"
-      name="friends_filter_input"
-      text_pad_left="10"
-      top="4"
-      width="177" />
-    <button
-      commit_callback.function="People.Gear"
-      follows="right"
-      height="25"
-      image_hover_unselected="Toolbar_Middle_Over"
-      image_overlay="OptionsMenu_Off"
-      image_selected="Toolbar_Middle_Selected"
-      image_unselected="Toolbar_Middle_Off"
-      layout="topleft"
-      left_pad="8"
-      name="gear_btn"
-      tool_tip="Actions on selected person"
-      top="3"
-      width="31" />
-    <menu_button
-      follows="right"
-      height="25"
-      image_hover_unselected="Toolbar_Middle_Over"
-      image_overlay="Conv_toolbar_sort"
-      image_selected="Toolbar_Middle_Selected"
-      image_unselected="Toolbar_Middle_Off"
-      layout="topleft"
-      left_pad="2"
-      menu_filename="menu_people_friends_view.xml"
-      menu_position="bottomleft"
-      name="friends_view_btn"
-      tool_tip="View/sort options"
-      top_delta="0"
-      width="31" />
-    <button
-      follows="right"
-      height="25"
-      image_hover_unselected="Toolbar_Middle_Over"
-      image_overlay="AddItem_Off"
-      image_selected="Toolbar_Middle_Selected"
-      image_unselected="Toolbar_Middle_Off"
-      layout="topleft"
-      left_pad="2"
-      name="friends_add_btn"
-      tool_tip="Offer friendship to a resident"
-      top_delta="0"
-      width="31">
-      <commit_callback
-        function="People.AddFriendWizard" />
-    </button>
-    <dnd_button
-      follows="right"
-      height="25"
-      image_hover_unselected="Toolbar_Middle_Over"
-      image_overlay="TrashItem_Off"
-      image_selected="Toolbar_Middle_Selected"
-      image_unselected="Toolbar_Middle_Off"
-      left_pad="2"
-      layout="topleft"
-      name="friends_del_btn"
-      tool_tip="Remove selected person as a friend"
-      top_delta="0"
-      width="31">
-      <commit_callback
-        function="People.DelFriend" />
-    </dnd_button>
-  </panel>
-  <accordion
-    background_visible="true"
-    bg_alpha_color="DkGray2"
-    bg_opaque_color="DkGray2"
-    follows="all"
-    height="322"
-    layout="topleft"
-    left="2"
-    name="friends_accordion"
-    right="-1"
-    top_pad="2">
-    <accordion_tab
-      layout="topleft"
-      height="172"
-      min_height="150"
-      name="tab_online"
-      title="Online">
-      <avatar_list
-        allow_select="true"
-        follows="all"
-        height="172"
-        layout="topleft"
-        left="0"
-        multi_select="true"
-        name="avatars_online"
-        show_permissions_granted="true"
-        top="0"
-        width="307" />
-    </accordion_tab>
-    <accordion_tab
-      layout="topleft"
-      height="173"
-      name="tab_all"
-      title="All">
-      <avatar_list
-        allow_select="true"
-        follows="all"
-        height="173"
-        layout="topleft"
-        left="0"
-        multi_select="true"
-        name="avatars_all"
-        show_permissions_granted="true"
-        top="0"
-        width="307" />
-    </accordion_tab>
-  </accordion>
-  <text
-    follows="top|left|right"
-    height="350"
-    left="13"
-    name="no_friends_help_text"
-    right="-13"
-    top="2"
-    wrap="true" />
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+
+<panel
+  background_opaque="true"
+  background_visible="true"
+  bg_alpha_color="DkGray"
+  bg_opaque_color="DkGray"
+  height="350"
+  follows="all"
+  label="FRIENDS"
+  layout="topleft"
+  left="0"
+  help_topic="people_friends_tab"
+  name="friends_panel"
+  width="330"
+  top="0">
+  <panel
+    follows="left|top|right"
+    height="27"
+    label="bottom_panel"
+    layout="topleft"
+    left="0"
+    name="friends_buttons_panel"
+    right="-1"
+    top="0">
+    <filter_editor
+      follows="left|top|right"
+      height="23"
+      layout="topleft"
+      left="6"
+      label="Filter People"
+      max_length_chars="300"
+      name="friends_filter_input"
+      text_pad_left="10"
+      top="4"
+      width="177" />
+    <button
+      commit_callback.function="People.Gear"
+      follows="right"
+      height="25"
+      image_hover_unselected="Toolbar_Middle_Over"
+      image_overlay="OptionsMenu_Off"
+      image_selected="Toolbar_Middle_Selected"
+      image_unselected="Toolbar_Middle_Off"
+      layout="topleft"
+      left_pad="8"
+      name="gear_btn"
+      tool_tip="Actions on selected person"
+      top="3"
+      width="31" />
+    <menu_button
+      follows="right"
+      height="25"
+      image_hover_unselected="Toolbar_Middle_Over"
+      image_overlay="Conv_toolbar_sort"
+      image_selected="Toolbar_Middle_Selected"
+      image_unselected="Toolbar_Middle_Off"
+      layout="topleft"
+      left_pad="2"
+      menu_filename="menu_people_friends_view.xml"
+      menu_position="bottomleft"
+      name="friends_view_btn"
+      tool_tip="View/sort options"
+      top_delta="0"
+      width="31" />
+    <button
+      follows="right"
+      height="25"
+      image_hover_unselected="Toolbar_Middle_Over"
+      image_overlay="AddItem_Off"
+      image_selected="Toolbar_Middle_Selected"
+      image_unselected="Toolbar_Middle_Off"
+      layout="topleft"
+      left_pad="2"
+      name="friends_add_btn"
+      tool_tip="Offer friendship to a resident"
+      top_delta="0"
+      width="31">
+      <commit_callback
+        function="People.AddFriendWizard" />
+    </button>
+    <dnd_button
+      follows="right"
+      height="25"
+      image_hover_unselected="Toolbar_Middle_Over"
+      image_overlay="TrashItem_Off"
+      image_selected="Toolbar_Middle_Selected"
+      image_unselected="Toolbar_Middle_Off"
+      left_pad="2"
+      layout="topleft"
+      name="friends_del_btn"
+      tool_tip="Remove selected person as a friend"
+      top_delta="0"
+      width="31">
+      <commit_callback
+        function="People.DelFriend" />
+    </dnd_button>
+  </panel>
+  <accordion
+    background_visible="true"
+    bg_alpha_color="DkGray2"
+    bg_opaque_color="DkGray2"
+    follows="all"
+    height="322"
+    layout="topleft"
+    left="2"
+    name="friends_accordion"
+    right="-1"
+    top_pad="2">
+    <accordion_tab
+      layout="topleft"
+      height="172"
+      min_height="150"
+      name="tab_online"
+      title="Online">
+      <avatar_list
+        allow_select="true"
+        follows="all"
+        height="172"
+        layout="topleft"
+        left="0"
+        multi_select="true"
+        name="avatars_online"
+        show_permissions_granted="true"
+        top="0"
+        width="307" />
+    </accordion_tab>
+    <accordion_tab
+      layout="topleft"
+      height="173"
+      name="tab_all"
+      title="All">
+      <avatar_list
+        allow_select="true"
+        follows="all"
+        height="173"
+        layout="topleft"
+        left="0"
+        multi_select="true"
+        name="avatars_all"
+        show_permissions_granted="true"
+        top="0"
+        width="307" />
+    </accordion_tab>
+  </accordion>
+  <text
+    follows="top|left|right"
+    height="350"
+    left="13"
+    name="no_friends_help_text"
+    right="-13"
+    top="2"
+    wrap="true" />
 </panel>
\ No newline at end of file
diff --git a/indra/newview/skins/default/xui/en/panel_people_groups.xml b/indra/newview/skins/default/xui/en/panel_people_groups.xml
index 7e38a1c487..9842c9d28a 100644
--- a/indra/newview/skins/default/xui/en/panel_people_groups.xml
+++ b/indra/newview/skins/default/xui/en/panel_people_groups.xml
@@ -1,126 +1,126 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-
-<panel
-  background_opaque="true"
-  background_visible="true"
-  bg_alpha_color="DkGray"
-  bg_opaque_color="DkGray"
-  height="350"
-  follows="all"
-  label="GROUPS"
-  layout="topleft"
-  left="0"
-  help_topic="people_groups_tab"
-  name="groups_panel"
-  width="330"
-  top="0">
-  <!--
-     *NOTE: no_groups_msg & group_list attributes are not defined as translatable in VLT. See EXT-5931
-     Values are set from appropriate strings at the top of file via LLPeoplePanel::postBuild()
-    -->
-  <panel
-    follows="left|top|right"
-    height="27"
-    label="bottom_panel"
-    layout="topleft"
-    left="0"
-    name="groups_buttons_panel"
-    right="-1"
-    top="0">
-    <filter_editor
-      follows="left|top|right"
-      height="23"
-      layout="topleft"
-      left="6"
-      label="Filter Groups"
-      max_length_chars="300"
-      name="groups_filter_input"
-      text_pad_left="10"
-      top="4"
-      width="177" />
-    <menu_button
-      follows="right"
-      height="25"
-      image_hover_unselected="Toolbar_Middle_Over"
-      image_overlay="OptionsMenu_Off"
-      image_selected="Toolbar_Middle_Selected"
-      image_unselected="Toolbar_Middle_Off"
-      layout="topleft"
-      left_pad="8"
-      name="groups_gear_btn"
-      tool_tip="Actions on selected group"
-      top="3"
-      width="31" />
-    <menu_button
-      follows="right"
-      height="25"
-      image_hover_unselected="Toolbar_Middle_Over"
-      image_overlay="Conv_toolbar_sort"
-      image_selected="Toolbar_Middle_Selected"
-      image_unselected="Toolbar_Middle_Off"
-      layout="topleft"
-      left_pad="2"
-      menu_filename="menu_people_groups_view.xml"
-      menu_position="bottomleft"
-      name="groups_view_btn"
-      tool_tip="View/sort options"
-      top_delta="0"
-      width="31" />
-    <menu_button
-      follows="right"
-      height="25"
-      image_hover_unselected="Toolbar_Middle_Over"
-      image_overlay="AddItem_Off"
-      image_selected="Toolbar_Middle_Selected"
-      image_unselected="Toolbar_Middle_Off"
-      layout="topleft"
-      left_pad="2"
-      menu_filename="menu_group_plus.xml"
-      menu_position="bottomleft"
-      name="plus_btn"
-      tool_tip="Join group/Create new group"
-      top_delta="0"
-      width="31">
-      <validate_callback
-        function="People.Group.Plus.Validate" />
-    </menu_button>
-    <dnd_button
-      follows="right"
-      height="25"
-      image_hover_unselected="Toolbar_Middle_Over"
-      image_overlay="TrashItem_Off"
-      image_selected="Toolbar_Middle_Selected"
-      image_unselected="Toolbar_Middle_Off"
-      left_pad="2"
-      layout="topleft"
-      name="minus_btn"
-      tool_tip="Leave selected group"
-      top_delta="0"
-      width="31">
-      <commit_callback
-        function="People.Group.Minus" />
-    </dnd_button>
-  </panel>
-  <text
-    type="string"
-    length="1"
-    follows="left|top|right"
-    height="14"
-    layout="topleft"
-    right="-10"
-    top_pad="4"
-    left="3"
-    use_ellipses="true"
-    name="groupcount">
-    You belong to [COUNT] groups, and can join [REMAINING] more.
-  </text>
-  <group_list
-    allow_select="true"
-    follows="all"
-    height="302"
-    layout="topleft"
-    left="3"
-    name="group_list"
-    right="-2"
-    top_pad="4" />
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+
+<panel
+  background_opaque="true"
+  background_visible="true"
+  bg_alpha_color="DkGray"
+  bg_opaque_color="DkGray"
+  height="350"
+  follows="all"
+  label="GROUPS"
+  layout="topleft"
+  left="0"
+  help_topic="people_groups_tab"
+  name="groups_panel"
+  width="330"
+  top="0">
+  <!--
+     *NOTE: no_groups_msg & group_list attributes are not defined as translatable in VLT. See EXT-5931
+     Values are set from appropriate strings at the top of file via LLPeoplePanel::postBuild()
+    -->
+  <panel
+    follows="left|top|right"
+    height="27"
+    label="bottom_panel"
+    layout="topleft"
+    left="0"
+    name="groups_buttons_panel"
+    right="-1"
+    top="0">
+    <filter_editor
+      follows="left|top|right"
+      height="23"
+      layout="topleft"
+      left="6"
+      label="Filter Groups"
+      max_length_chars="300"
+      name="groups_filter_input"
+      text_pad_left="10"
+      top="4"
+      width="177" />
+    <menu_button
+      follows="right"
+      height="25"
+      image_hover_unselected="Toolbar_Middle_Over"
+      image_overlay="OptionsMenu_Off"
+      image_selected="Toolbar_Middle_Selected"
+      image_unselected="Toolbar_Middle_Off"
+      layout="topleft"
+      left_pad="8"
+      name="groups_gear_btn"
+      tool_tip="Actions on selected group"
+      top="3"
+      width="31" />
+    <menu_button
+      follows="right"
+      height="25"
+      image_hover_unselected="Toolbar_Middle_Over"
+      image_overlay="Conv_toolbar_sort"
+      image_selected="Toolbar_Middle_Selected"
+      image_unselected="Toolbar_Middle_Off"
+      layout="topleft"
+      left_pad="2"
+      menu_filename="menu_people_groups_view.xml"
+      menu_position="bottomleft"
+      name="groups_view_btn"
+      tool_tip="View/sort options"
+      top_delta="0"
+      width="31" />
+    <menu_button
+      follows="right"
+      height="25"
+      image_hover_unselected="Toolbar_Middle_Over"
+      image_overlay="AddItem_Off"
+      image_selected="Toolbar_Middle_Selected"
+      image_unselected="Toolbar_Middle_Off"
+      layout="topleft"
+      left_pad="2"
+      menu_filename="menu_group_plus.xml"
+      menu_position="bottomleft"
+      name="plus_btn"
+      tool_tip="Join group/Create new group"
+      top_delta="0"
+      width="31">
+      <validate_callback
+        function="People.Group.Plus.Validate" />
+    </menu_button>
+    <dnd_button
+      follows="right"
+      height="25"
+      image_hover_unselected="Toolbar_Middle_Over"
+      image_overlay="TrashItem_Off"
+      image_selected="Toolbar_Middle_Selected"
+      image_unselected="Toolbar_Middle_Off"
+      left_pad="2"
+      layout="topleft"
+      name="minus_btn"
+      tool_tip="Leave selected group"
+      top_delta="0"
+      width="31">
+      <commit_callback
+        function="People.Group.Minus" />
+    </dnd_button>
+  </panel>
+  <text
+    type="string"
+    length="1"
+    follows="left|top|right"
+    height="14"
+    layout="topleft"
+    right="-10"
+    top_pad="4"
+    left="3"
+    use_ellipses="true"
+    name="groupcount">
+    You belong to [COUNT] groups, and can join [REMAINING] more.
+  </text>
+  <group_list
+    allow_select="true"
+    follows="all"
+    height="302"
+    layout="topleft"
+    left="3"
+    name="group_list"
+    right="-2"
+    top_pad="4" />
 </panel>
\ No newline at end of file
diff --git a/indra/newview/skins/default/xui/en/panel_people_nearby.xml b/indra/newview/skins/default/xui/en/panel_people_nearby.xml
index 9de58f74d4..9a1b75a1c3 100644
--- a/indra/newview/skins/default/xui/en/panel_people_nearby.xml
+++ b/indra/newview/skins/default/xui/en/panel_people_nearby.xml
@@ -1,152 +1,152 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-
-<panel
-  background_opaque="true"
-  background_visible="true"
-  bg_alpha_color="DkGray"
-  bg_opaque_color="DkGray"
-  height="350"
-  follows="all"
-  label="NEARBY"
-  layout="topleft"
-  left="2"
-  help_topic="people_nearby_tab"
-  name="nearby_panel"
-  width="330"
-  top="0">
-  <panel
-    follows="left|top|right"
-    height="27"
-    label="bottom_panel"
-    layout="topleft"
-    left="2"
-    name="nearby_buttons_panel"
-    right="-1"
-    top="0">
-    <filter_editor
-      follows="left|top|right"
-      height="23"
-      layout="topleft"
-      left="1"
-      label="Filter People"
-      max_length_chars="300"
-      name="nearby_filter_input"
-      text_pad_left="10"
-      top="4"
-      width="178" />
-    <button
-      commit_callback.function="People.Gear"
-      follows="right"
-      height="25"
-      image_hover_unselected="Toolbar_Middle_Over"
-      image_overlay="OptionsMenu_Off"
-      image_selected="Toolbar_Middle_Selected"
-      image_unselected="Toolbar_Middle_Off"
-      layout="topleft"
-      left_pad="7"
-      name="gear_btn"
-      tool_tip="Actions on selected person"
-      top="3"
-      width="31" />
-    <menu_button
-      follows="right"
-      height="25"
-      image_hover_unselected="Toolbar_Middle_Over"
-      image_overlay="Conv_toolbar_sort"
-      image_selected="Toolbar_Middle_Selected"
-      image_unselected="Toolbar_Middle_Off"
-      layout="topleft"
-      left_pad="2"
-      menu_filename="menu_people_nearby_view.xml"
-      menu_position="bottomleft"
-      name="nearby_view_btn"
-      tool_tip="View/sort options"
-      top_delta="0"
-      width="31" />
-    <button
-      follows="right"
-      height="25"
-      image_hover_unselected="Toolbar_Middle_Over"
-      image_overlay="AddItem_Off"
-      image_selected="Toolbar_Middle_Selected"
-      image_unselected="Toolbar_Middle_Off"
-      layout="topleft"
-      left_pad="2"
-      name="add_friend_btn"
-      tool_tip="Offer friendship to a resident"
-      top_delta="0"
-      width="31">
-      <commit_callback
-        function="People.AddFriend" />
-    </button>
-    <dnd_button
-      enabled="false"
-      follows="right"
-      height="25"
-      image_hover_unselected="Toolbar_Middle_Over"
-      image_overlay="TrashItem_Off"
-      image_selected="Toolbar_Middle_Selected"
-      image_unselected="Toolbar_Middle_Off"
-      left_pad="2"
-      layout="topleft"
-      name="friends_del_btn"
-      tool_tip="Remove selected person as a friend"
-      top_delta="0"
-      width="31">
-      <commit_callback
-        function="People.DelFriend" />
-    </dnd_button>
-  </panel>
-  <layout_stack
-    clip="false"
-    follows="all"
-    height="325"
-    layout="topleft"
-    left="0"
-    mouse_opaque="false"
-    orientation="vertical"
-    right="-1"
-    top_pad="0">
-    <layout_panel
-      height="142"
-      layout="topleft"
-      min_dim="100"
-      mouse_opaque="false"
-      name="Net Map Panel"
-      user_resize="true"
-      visibility_control="NearbyListShowMap"
-      width="313">
-      <net_map
-        bg_color="NetMapBackgroundColor"
-        follows="all"
-        height="140"
-        layout="topleft"
-        left="3"
-        mouse_opaque="false"
-        name="Net Map"
-        right="-1"
-        top="4" />
-    </layout_panel>
-    <layout_panel
-      height="213"
-      layout="topleft"
-      min_dim="100"
-      mouse_opaque="false"
-      right="-1"
-      user_resize="true">
-      <avatar_list
-        show_distance="true"
-        allow_select="true"
-        follows="all"
-        height="211"
-        ignore_online_status="true"
-        layout="topleft"
-        left="3"
-        keep_one_selected="false"
-        multi_select="true"
-        name="avatar_list"
-        right="-1"
-        top="2" />
-    </layout_panel>
-  </layout_stack>
-</panel>
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+
+<panel
+  background_opaque="true"
+  background_visible="true"
+  bg_alpha_color="DkGray"
+  bg_opaque_color="DkGray"
+  height="350"
+  follows="all"
+  label="NEARBY"
+  layout="topleft"
+  left="2"
+  help_topic="people_nearby_tab"
+  name="nearby_panel"
+  width="330"
+  top="0">
+  <panel
+    follows="left|top|right"
+    height="27"
+    label="bottom_panel"
+    layout="topleft"
+    left="2"
+    name="nearby_buttons_panel"
+    right="-1"
+    top="0">
+    <filter_editor
+      follows="left|top|right"
+      height="23"
+      layout="topleft"
+      left="1"
+      label="Filter People"
+      max_length_chars="300"
+      name="nearby_filter_input"
+      text_pad_left="10"
+      top="4"
+      width="178" />
+    <button
+      commit_callback.function="People.Gear"
+      follows="right"
+      height="25"
+      image_hover_unselected="Toolbar_Middle_Over"
+      image_overlay="OptionsMenu_Off"
+      image_selected="Toolbar_Middle_Selected"
+      image_unselected="Toolbar_Middle_Off"
+      layout="topleft"
+      left_pad="7"
+      name="gear_btn"
+      tool_tip="Actions on selected person"
+      top="3"
+      width="31" />
+    <menu_button
+      follows="right"
+      height="25"
+      image_hover_unselected="Toolbar_Middle_Over"
+      image_overlay="Conv_toolbar_sort"
+      image_selected="Toolbar_Middle_Selected"
+      image_unselected="Toolbar_Middle_Off"
+      layout="topleft"
+      left_pad="2"
+      menu_filename="menu_people_nearby_view.xml"
+      menu_position="bottomleft"
+      name="nearby_view_btn"
+      tool_tip="View/sort options"
+      top_delta="0"
+      width="31" />
+    <button
+      follows="right"
+      height="25"
+      image_hover_unselected="Toolbar_Middle_Over"
+      image_overlay="AddItem_Off"
+      image_selected="Toolbar_Middle_Selected"
+      image_unselected="Toolbar_Middle_Off"
+      layout="topleft"
+      left_pad="2"
+      name="add_friend_btn"
+      tool_tip="Offer friendship to a resident"
+      top_delta="0"
+      width="31">
+      <commit_callback
+        function="People.AddFriend" />
+    </button>
+    <dnd_button
+      enabled="false"
+      follows="right"
+      height="25"
+      image_hover_unselected="Toolbar_Middle_Over"
+      image_overlay="TrashItem_Off"
+      image_selected="Toolbar_Middle_Selected"
+      image_unselected="Toolbar_Middle_Off"
+      left_pad="2"
+      layout="topleft"
+      name="friends_del_btn"
+      tool_tip="Remove selected person as a friend"
+      top_delta="0"
+      width="31">
+      <commit_callback
+        function="People.DelFriend" />
+    </dnd_button>
+  </panel>
+  <layout_stack
+    clip="false"
+    follows="all"
+    height="325"
+    layout="topleft"
+    left="0"
+    mouse_opaque="false"
+    orientation="vertical"
+    right="-1"
+    top_pad="0">
+    <layout_panel
+      height="142"
+      layout="topleft"
+      min_dim="100"
+      mouse_opaque="false"
+      name="Net Map Panel"
+      user_resize="true"
+      visibility_control="NearbyListShowMap"
+      width="313">
+      <net_map
+        bg_color="NetMapBackgroundColor"
+        follows="all"
+        height="140"
+        layout="topleft"
+        left="3"
+        mouse_opaque="false"
+        name="Net Map"
+        right="-1"
+        top="4" />
+    </layout_panel>
+    <layout_panel
+      height="213"
+      layout="topleft"
+      min_dim="100"
+      mouse_opaque="false"
+      right="-1"
+      user_resize="true">
+      <avatar_list
+        show_distance="true"
+        allow_select="true"
+        follows="all"
+        height="211"
+        ignore_online_status="true"
+        layout="topleft"
+        left="3"
+        keep_one_selected="false"
+        multi_select="true"
+        name="avatar_list"
+        right="-1"
+        top="2" />
+    </layout_panel>
+  </layout_stack>
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_people_recent.xml b/indra/newview/skins/default/xui/en/panel_people_recent.xml
index 40b171a9c8..49506d5a81 100644
--- a/indra/newview/skins/default/xui/en/panel_people_recent.xml
+++ b/indra/newview/skins/default/xui/en/panel_people_recent.xml
@@ -1,111 +1,111 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-
-<panel
-  background_opaque="true"
-  background_visible="true"
-  bg_alpha_color="DkGray"
-  bg_opaque_color="DkGray"
-  follows="all"
-  height="350"
-  label="RECENT"
-  layout="topleft"
-  left="0"
-  help_topic="people_recent_tab"
-  name="recent_panel"
-  width="330"
-  top="0">
-  <panel
-    follows="left|top|right"
-    height="27"
-    label="bottom_panel"
-    layout="topleft"
-    left="0"
-    name="recent_buttons_panel"
-    right="-1"
-    top="0">
-    <filter_editor
-      follows="left|top|right"
-      height="23"
-      layout="topleft"
-      left="6"
-      label="Filter People"
-      max_length_chars="300"
-      name="recent_filter_input"
-      text_pad_left="10"
-      top="4"
-      width="177" />
-    <button
-      commit_callback.function="People.Gear"
-      follows="right"
-      height="25"
-      image_hover_unselected="Toolbar_Middle_Over"
-      image_overlay="OptionsMenu_Off"
-      image_selected="Toolbar_Middle_Selected"
-      image_unselected="Toolbar_Middle_Off"
-      layout="topleft"
-      left_pad="8"
-      name="gear_btn"
-      tool_tip="Actions on selected person"
-      top="3"
-      width="31" />
-    <menu_button
-      follows="right"
-      height="25"
-      image_hover_unselected="Toolbar_Middle_Over"
-      image_overlay="Conv_toolbar_sort"
-      image_selected="Toolbar_Middle_Selected"
-      image_unselected="Toolbar_Middle_Off"
-      layout="topleft"
-      left_pad="2"
-      menu_filename="menu_people_recent_view.xml"
-      menu_position="bottomleft"
-      name="recent_view_btn"
-      tool_tip="View/sort options"
-      top_delta="0"
-      width="31" />
-    <button
-      follows="right"
-      height="25"
-      image_hover_unselected="Toolbar_Middle_Over"
-      image_overlay="AddItem_Off"
-      image_selected="Toolbar_Middle_Selected"
-      image_unselected="Toolbar_Middle_Off"
-      layout="topleft"
-      left_pad="2"
-      name="add_friend_btn"
-      tool_tip="Offer friendship to a resident"
-      top_delta="0"
-      width="31">
-      <commit_callback
-        function="People.AddFriend" />
-    </button>
-    <dnd_button
-      enabled="false"
-      follows="right"
-      height="25"
-      image_hover_unselected="Toolbar_Middle_Over"
-      image_overlay="TrashItem_Off"
-      image_selected="Toolbar_Middle_Selected"
-      image_unselected="Toolbar_Middle_Off"
-      left_pad="2"
-      layout="topleft"
-      name="friends_del_btn"
-      tool_tip="Remove selected person as a friend"
-      top_delta="0"
-      width="31">
-      <commit_callback
-        function="People.DelFriend" />
-    </dnd_button>
-  </panel>
-  <avatar_list
-    allow_select="true"
-    follows="all"
-    height="320"
-    layout="topleft"
-    left="3"
-    multi_select="true"
-    name="avatar_list"
-    show_last_interaction_time="true"
-    right="-2"
-    top_pad="4" />
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+
+<panel
+  background_opaque="true"
+  background_visible="true"
+  bg_alpha_color="DkGray"
+  bg_opaque_color="DkGray"
+  follows="all"
+  height="350"
+  label="RECENT"
+  layout="topleft"
+  left="0"
+  help_topic="people_recent_tab"
+  name="recent_panel"
+  width="330"
+  top="0">
+  <panel
+    follows="left|top|right"
+    height="27"
+    label="bottom_panel"
+    layout="topleft"
+    left="0"
+    name="recent_buttons_panel"
+    right="-1"
+    top="0">
+    <filter_editor
+      follows="left|top|right"
+      height="23"
+      layout="topleft"
+      left="6"
+      label="Filter People"
+      max_length_chars="300"
+      name="recent_filter_input"
+      text_pad_left="10"
+      top="4"
+      width="177" />
+    <button
+      commit_callback.function="People.Gear"
+      follows="right"
+      height="25"
+      image_hover_unselected="Toolbar_Middle_Over"
+      image_overlay="OptionsMenu_Off"
+      image_selected="Toolbar_Middle_Selected"
+      image_unselected="Toolbar_Middle_Off"
+      layout="topleft"
+      left_pad="8"
+      name="gear_btn"
+      tool_tip="Actions on selected person"
+      top="3"
+      width="31" />
+    <menu_button
+      follows="right"
+      height="25"
+      image_hover_unselected="Toolbar_Middle_Over"
+      image_overlay="Conv_toolbar_sort"
+      image_selected="Toolbar_Middle_Selected"
+      image_unselected="Toolbar_Middle_Off"
+      layout="topleft"
+      left_pad="2"
+      menu_filename="menu_people_recent_view.xml"
+      menu_position="bottomleft"
+      name="recent_view_btn"
+      tool_tip="View/sort options"
+      top_delta="0"
+      width="31" />
+    <button
+      follows="right"
+      height="25"
+      image_hover_unselected="Toolbar_Middle_Over"
+      image_overlay="AddItem_Off"
+      image_selected="Toolbar_Middle_Selected"
+      image_unselected="Toolbar_Middle_Off"
+      layout="topleft"
+      left_pad="2"
+      name="add_friend_btn"
+      tool_tip="Offer friendship to a resident"
+      top_delta="0"
+      width="31">
+      <commit_callback
+        function="People.AddFriend" />
+    </button>
+    <dnd_button
+      enabled="false"
+      follows="right"
+      height="25"
+      image_hover_unselected="Toolbar_Middle_Over"
+      image_overlay="TrashItem_Off"
+      image_selected="Toolbar_Middle_Selected"
+      image_unselected="Toolbar_Middle_Off"
+      left_pad="2"
+      layout="topleft"
+      name="friends_del_btn"
+      tool_tip="Remove selected person as a friend"
+      top_delta="0"
+      width="31">
+      <commit_callback
+        function="People.DelFriend" />
+    </dnd_button>
+  </panel>
+  <avatar_list
+    allow_select="true"
+    follows="all"
+    height="320"
+    layout="topleft"
+    left="3"
+    multi_select="true"
+    name="avatar_list"
+    show_last_interaction_time="true"
+    right="-2"
+    top_pad="4" />
 </panel>
\ No newline at end of file
-- 
GitLab